Skip to content

Commit 6f3ee3b

Browse files
authored
Merge pull request #196 from jakkdl/ruff
replace flake8-eradicate with ruff ... and enable a ton of more lint rules, fixing a couple of them.
2 parents 0df3b80 + 58c2ed2 commit 6f3ee3b

13 files changed

+113
-42
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.ruff_cache
12
# Byte-compiled / optimized / DLL files
23
__pycache__/
34
*.py[cod]

.pre-commit-config.yaml

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,16 @@ repos:
7373
- id: trailing-whitespace
7474
args: ['--markdown-linebreak-ext=md,markdown']
7575

76+
- repo: https://github.com/charliermarsh/ruff-pre-commit
77+
rev: v0.0.269
78+
hooks:
79+
- id: ruff
80+
7681
- repo: https://github.com/PyCQA/flake8
7782
rev: 6.0.0
7883
hooks:
7984
- id: flake8
85+
# this doesn't seem to work, pyi files don't get checked with --all-files
8086
types_or: [python, pyi]
8187
language_version: python3
8288
additional_dependencies:
@@ -86,26 +92,14 @@ repos:
8692
- flake8-comprehensions
8793
- flake8-datetimez
8894
- flake8-docstrings
89-
- flake8-mutable
90-
- flake8-noqa
95+
- flake8-mutable # not official supported by ruff
9196
- flake8-pie
9297
- flake8-pyi
9398
- flake8-pytest-style
9499
- flake8-return
95100
- flake8-simplify
96101
- flake8-type-checking
97-
98-
# Pinned to flake8 5.0.4 since flake8-eradicate is not updated to work with flake8 6
99-
# https://github.com/wemake-services/flake8-eradicate/pull/271
100-
- repo: https://github.com/PyCQA/flake8
101-
rev: 5.0.4
102-
hooks:
103-
- id: flake8
104-
name: flake8-eradicate
105-
args: [--select=E800]
106-
language_version: python3
107-
additional_dependencies:
108-
- flake8-eradicate
102+
# all other are
109103

110104
- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
111105
rev: 0.2.2

flake8_trio/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ def get_matching_codes(
312312
all_codes: set[str] = {
313313
err_code
314314
for err_class in (*ERROR_CLASSES, *ERROR_CLASSES_CST)
315-
for err_code in err_class.error_codes.keys() # type: ignore[attr-defined]
315+
for err_code in err_class.error_codes # type: ignore[attr-defined]
316316
if len(err_code) == 7 # exclude e.g. TRIO103_anyio_trio
317317
}
318318

@@ -367,7 +367,7 @@ def parse_trio200_dict(raw_value: str) -> dict[str, str]:
367367
# if we raise it as ValueError
368368
raise ArgumentTypeError(
369369
f"Invalid number ({len(split_values)-1}) of splitter "
370-
+ f"tokens {splitter!r} in {value!r}"
370+
f"tokens {splitter!r} in {value!r}"
371371
)
372372
res[split_values[0]] = split_values[1]
373373
return res

flake8_trio/visitors/flake8triovisitor.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def library_str(self) -> str:
153153

154154
def add_library(self, name: str) -> None:
155155
if name not in self.__state.library:
156-
self.__state.library = self.__state.library + (name,)
156+
self.__state.library = (*self.__state.library, name)
157157

158158

159159
class Flake8TrioVisitor_cst(cst.CSTTransformer, ABC):
@@ -200,8 +200,9 @@ def restore_state(self, node: cst.CSTNode):
200200
def is_noqa(self, node: cst.CSTNode, code: str):
201201
if self.options.disable_noqa:
202202
return False
203-
pos = self.get_metadata(PositionProvider, node).start
204-
noqas = self.noqas.get(pos.line)
203+
# pyright + get_metadata is acting up
204+
pos = self.get_metadata(PositionProvider, node).start # type: ignore
205+
noqas = self.noqas.get(pos.line) # type: ignore
205206
return noqas is not None and (noqas == set() or code in noqas)
206207

207208
def error(
@@ -223,13 +224,14 @@ def error(
223224
if self.is_noqa(node, error_code):
224225
return False
225226

226-
pos = self.get_metadata(PositionProvider, node).start
227+
# pyright + get_metadata is acting up
228+
pos = self.get_metadata(PositionProvider, node).start # type: ignore
227229
self.__state.problems.append(
228230
Error(
229231
# 7 == len('TRIO...'), so alt messages raise the original code
230232
error_code[:7],
231-
pos.line,
232-
pos.column,
233+
pos.line, # type: ignore
234+
pos.column, # type: ignore
233235
self.error_codes[error_code],
234236
*args,
235237
)
@@ -253,4 +255,4 @@ def library(self) -> tuple[str, ...]:
253255

254256
def add_library(self, name: str) -> None:
255257
if name not in self.__state.library:
256-
self.__state.library = self.__state.library + (name,)
258+
self.__state.library = (*self.__state.library, name)

flake8_trio/visitors/visitor100.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from typing import Any
1111

12-
import libcst as cst
12+
import libcst as cst # noqa: TCH002
1313
import libcst.matchers as m
1414

1515
from .flake8triovisitor import Flake8TrioVisitor_cst

flake8_trio/visitors/visitor91x.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,9 @@ def visit_FunctionDef(self, node: cst.FunctionDef) -> bool:
284284
# this should improve performance on codebases with many sync functions
285285
return any(m.findall(node, m.FunctionDef(asynchronous=m.Asynchronous())))
286286

287-
pos = self.get_metadata(PositionProvider, node).start
287+
pos = self.get_metadata(PositionProvider, node).start # type: ignore
288288
self.uncheckpointed_statements = {
289-
Statement("function definition", pos.line, pos.column)
289+
Statement("function definition", pos.line, pos.column) # type: ignore
290290
}
291291
return True
292292

@@ -419,8 +419,10 @@ def leave_Yield(
419419
self.add_statement = self.checkpoint_statement()
420420

421421
# mark as requiring checkpoint after
422-
pos = self.get_metadata(PositionProvider, original_node).start
423-
self.uncheckpointed_statements = {Statement("yield", pos.line, pos.column)}
422+
pos = self.get_metadata(PositionProvider, original_node).start # type: ignore
423+
self.uncheckpointed_statements = {
424+
Statement("yield", pos.line, pos.column) # type: ignore
425+
}
424426
# return original to avoid problems with identity equality
425427
assert original_node.deep_equals(updated_node)
426428
return original_node
@@ -442,9 +444,9 @@ def visit_Try(self, node: cst.Try):
442444
)
443445
# yields inside `try` can always be uncheckpointed
444446
for inner_node in m.findall(node.body, m.Yield()):
445-
pos = self.get_metadata(PositionProvider, inner_node).start
447+
pos = self.get_metadata(PositionProvider, inner_node).start # type: ignore
446448
self.try_state.body_uncheckpointed_statements.add(
447-
Statement("yield", pos.line, pos.column)
449+
Statement("yield", pos.line, pos.column) # type: ignore
448450
)
449451

450452
def leave_Try_body(self, node: cst.Try):
@@ -657,7 +659,7 @@ def leave_While_orelse(self, node: cst.For | cst.While):
657659
else:
658660
# We may exit from:
659661
# orelse (covering: no body, body until continue, and all body)
660-
# break
662+
# `break`
661663
self.uncheckpointed_statements.update(
662664
self.loop_state.uncheckpointed_before_break
663665
)

flake8_trio/visitors/visitor_utility.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import re
88
from typing import TYPE_CHECKING, Any
99

10-
import libcst as cst
1110
import libcst.matchers as m
1211
from libcst.metadata import PositionProvider
1312

@@ -17,6 +16,8 @@
1716
if TYPE_CHECKING:
1817
from re import Match
1918

19+
import libcst as cst
20+
2021

2122
@utility_visitor
2223
class VisitorTypeTracker(Flake8TrioVisitor):

pyproject.toml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,75 @@ reportShadowedImports = true
3535
reportUninitializedInstanceVariable = true
3636
reportUnusedCallResult = false
3737
strict = ["*.py", "tests/*.py", "flake8_trio/**/*.py"]
38+
39+
[tool.ruff]
40+
extend-exclude = [
41+
".*",
42+
"tests/eval_files/*",
43+
"tests/autofix_files/*"
44+
]
45+
ignore = [
46+
"COM", # flake8-comma, handled by black
47+
"ANN", # annotations, handled by pyright/mypy
48+
"T20", # flake8-print
49+
"TID252", # relative imports from parent modules https://github.com/Zac-HD/flake8-trio/pull/196#discussion_r1200413372
50+
"D101",
51+
"D102",
52+
"D103",
53+
"D105",
54+
"D106",
55+
"D107",
56+
"S101",
57+
"D203", # one-blank-line-before-class
58+
"D213", # multi-line-summary-second-line
59+
"EM101", # exception must not use a string literal
60+
"EM102", # exception must not use an f-string literal
61+
'PGH001', # No builtin `eval()` allowed
62+
'N802', # function name should be lowercase - not an option with inheritance
63+
'PTH123', # `open()` should be replaced by `Path.open()`
64+
'PYI021', # docstring in stub
65+
'S603', # `subprocess` call: check for execution of untrusted input
66+
'N815', # Variable `visit_AsyncWith` in class scope should not be mixedCase
67+
'PLR091', # Too many return statements/branches/arguments
68+
'C901', # function is too complex
69+
# maybe should be ignored in-place
70+
'N806', # Variable `MyDict` in function should be lowercase
71+
# --- maybe should be fixed / ignored in-place ---
72+
'ARG001', # Unused function argument
73+
'ARG002', # Unused method argument
74+
'B904', # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
75+
'B905', # zip without explicit strict parameter
76+
'BLE001', # Do not catch blind exception: `Exception`
77+
'FBT001', # Boolean positional arg in function definition
78+
'FBT002', # Boolean default value in function definition
79+
'N801', # Class name {} should use CapWords convention
80+
'PGH003', # Use specific rule codes when ignoring type issues
81+
'PLR2004', # Magic value used in comparison
82+
'PLW2901', # Outer `for` loop variable `err` overwritten by inner `for` loop target
83+
'PTH118', # `os.path.join()` should be replaced by `Path` with `/` operator
84+
'S607', # Starting a process with a partial executable path
85+
'SLF001', # Private member accessed: `_tree`
86+
'TD002', # missing author in TODO
87+
'TD003', # missing issue link in TODO
88+
'TRY003', # Avoid specifying long messages outside the exception class
89+
'TRY200', # Use `raise from` to specify exception cause
90+
'TRY201', # Use `raise` without specifying exception name
91+
# enable if flake8/plugins are removed
92+
'PGH004', # Use specific rule codes when using `noqa`
93+
'RUF100' # Unused `noqa` - enable only if flake8 is no longer used
94+
]
95+
line-length = 90
96+
select = ["ALL"]
97+
target-version = "py39"
98+
99+
[tool.ruff.per-file-ignores]
100+
# docstrings, and arguments we can't modify
101+
"*.pyi" = ["D", 'FBT001', 'PLR0913']
102+
# imports
103+
"flake8_trio/visitors/__init__.py" = [
104+
"F401",
105+
"E402"
106+
]
107+
# visitor_utility contains comments specifying how it parses noqa comments, which get
108+
# parsed as noqa comments
109+
"flake8_trio/visitors/visitor_utility.py" = ["RUF100", "PGH004"]

tests/test_changelog_and_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def ensure_tagged() -> None:
8383
def update_version() -> None:
8484
# If we've added a new version to the changelog, update __version__ to match
8585
last_version = next(iter(get_releases()))
86-
if VERSION != last_version:
86+
if last_version != VERSION:
8787
INIT_FILE = ROOT_PATH / "flake8_trio" / "__init__.py"
8888
subs = (f'__version__ = "{VERSION}"', f'__version__ = "{last_version}"')
8989
INIT_FILE.write_text(INIT_FILE.read_text().replace(*subs))

tests/test_decorator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def test_pep614():
9494

9595

9696
def test_command_line_1(capfd: pytest.CaptureFixture[str]):
97-
Application().run(common_flags + ["--no-checkpoint-warning-decorators=app.route"])
97+
Application().run([*common_flags, "--no-checkpoint-warning-decorators=app.route"])
9898
assert capfd.readouterr() == ("", "")
9999

100100

@@ -115,7 +115,7 @@ def test_command_line_1(capfd: pytest.CaptureFixture[str]):
115115

116116

117117
def test_command_line_2(capfd: pytest.CaptureFixture[str]):
118-
Application().run(common_flags + ["--no-checkpoint-warning-decorators=app"])
118+
Application().run([*common_flags, "--no-checkpoint-warning-decorators=app"])
119119
assert capfd.readouterr() == (expected_out, "")
120120

121121

tests/test_flake8_trio.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import tokenize
1414
import unittest
1515
from argparse import ArgumentParser
16-
from collections import deque
16+
from collections import defaultdict, deque
1717
from dataclasses import dataclass, fields
1818
from pathlib import Path
19-
from typing import TYPE_CHECKING, Any, DefaultDict
19+
from typing import TYPE_CHECKING, Any
2020

2121
import libcst as cst
2222
import pytest
@@ -66,7 +66,7 @@ def check_version(test: str):
6666
ERROR_CODES: dict[str, Flake8TrioVisitor] = {
6767
err_code: err_class # type: ignore[misc]
6868
for err_class in (*ERROR_CLASSES, *ERROR_CLASSES_CST)
69-
for err_code in err_class.error_codes.keys() # type: ignore[attr-defined]
69+
for err_code in err_class.error_codes # type: ignore[attr-defined]
7070
}
7171

7272

@@ -500,11 +500,11 @@ def print_first_diff(errors: Sequence[Error], expected: Sequence[Error]):
500500

501501
def assert_correct_lines_and_codes(errors: Iterable[Error], expected: Iterable[Error]):
502502
"""Check that errors are on correct lines."""
503-
MyDict = DefaultDict[int, DefaultDict[str, int]] # TypeAlias
503+
MyDict = defaultdict[int, defaultdict[str, int]] # TypeAlias
504504

505505
all_lines = sorted({e.line for e in (*errors, *expected)})
506506

507-
error_dict: MyDict = DefaultDict(lambda: DefaultDict(int))
507+
error_dict: MyDict = defaultdict(lambda: defaultdict(int))
508508
expected_dict = copy.deepcopy(error_dict)
509509

510510
# populate dicts with number of errors per line
@@ -622,7 +622,6 @@ def test_line_numbers_match_end_result():
622622
plugin = Plugin.from_source(text)
623623
initialize_options(plugin, args=["--enable=TRIO100,TRIO115", "--autofix=TRIO100"])
624624
errors = tuple(plugin.run())
625-
plugin.module.code
626625
assert errors[1].line != plugin.module.code.split("\n").index("trio.sleep(0)") + 1
627626

628627

tests/test_messages_documented.py

100644100755
File mode changed.

typings/flake8/options/manager.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Generated for flake8 5, so OptionManager signature is incorrect for flake8 6
77
import argparse
88
import enum
99
from collections.abc import Callable, Mapping, Sequence
10-
from typing import Any, TypeAlias
10+
from typing import Any
1111

1212
from flake8.plugins.finder import Plugins
1313

0 commit comments

Comments
 (0)