diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 45d0be6..801d084 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.13 + rev: v0.12.2 hooks: - id: ruff args: [--fix] @@ -38,14 +38,14 @@ repos: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.0 + rev: v1.16.1 hooks: - id: mypy # uses py311 syntax, mypy configured for py39 exclude: tests/(eval|autofix)_files/.*_py(310|311).py - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.401 + rev: v1.1.402 hooks: - id: pyright # ignore warnings about new version being available, no other warnings @@ -92,7 +92,7 @@ repos: - id: yamlfmt - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.14.0 + rev: v2.15.0 hooks: - id: pretty-format-toml args: [--autofix] diff --git a/flake8_async/base.py b/flake8_async/base.py index 173bdfb..d0127b1 100644 --- a/flake8_async/base.py +++ b/flake8_async/base.py @@ -102,3 +102,6 @@ def __repr__(self) -> str: # pragma: no cover def __str__(self) -> str: # flake8 adds 1 to the yielded column from `__iter__`, so we do the same here return f"{self.line}:{self.col+1}: {self.format_message()}" + + def __hash__(self) -> int: + return hash(self.cmp()) diff --git a/flake8_async/visitors/helpers.py b/flake8_async/visitors/helpers.py index 361755c..7821dcd 100644 --- a/flake8_async/visitors/helpers.py +++ b/flake8_async/visitors/helpers.py @@ -140,9 +140,14 @@ def iter_guaranteed_once(iterable: ast.expr) -> bool: else: return True return False - + # once we drop 3.9 we can add `and not isinstance(iterable.value, types.EllipsisType)` + # to get rid of `type: ignore`. Or just live with the fact that pyright doesn't + # make use of the `hasattr`. if isinstance(iterable, ast.Constant): - return hasattr(iterable.value, "__len__") and len(iterable.value) > 0 + return ( + hasattr(iterable.value, "__len__") + and len(iterable.value) > 0 # pyright: ignore[reportArgumentType] + ) if isinstance(iterable, ast.Dict): for key, val in zip(iterable.keys, iterable.values): diff --git a/flake8_async/visitors/visitor102_120.py b/flake8_async/visitors/visitor102_120.py index ac70b3a..1187e27 100644 --- a/flake8_async/visitors/visitor102_120.py +++ b/flake8_async/visitors/visitor102_120.py @@ -46,7 +46,7 @@ def __init__(self, node: ast.Call, funcname: str): for kw in node.keywords: # Only accepts constant values if kw.arg == "shield" and isinstance(kw.value, ast.Constant): - self.shielded = kw.value.value + self.shielded = bool(kw.value.value) def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) @@ -200,7 +200,7 @@ def visit_Assign(self, node: ast.Assign): ) ) ): - scope.shielded = node.value.value + scope.shielded = bool(node.value.value) def visit_FunctionDef( self, node: ast.FunctionDef | ast.AsyncFunctionDef | ast.Lambda diff --git a/tests/check_changelog_and_version.py b/tests/check_changelog_and_version.py index c8adb32..1f77013 100755 --- a/tests/check_changelog_and_version.py +++ b/tests/check_changelog_and_version.py @@ -8,6 +8,7 @@ from pathlib import Path from typing import TYPE_CHECKING, NamedTuple, TypeVar +from git.repo import Repo from typing_extensions import Self if TYPE_CHECKING: @@ -90,8 +91,6 @@ def test_version_increments_are_correct() -> None: def ensure_tagged() -> None: - from git.repo import Repo - last_version = next(iter(get_releases())) repo = Repo(ROOT_PATH) if str(last_version) not in iter(map(str, repo.tags)): diff --git a/tests/test_config_and_args.py b/tests/test_config_and_args.py index 3d3c03e..2951b9a 100644 --- a/tests/test_config_and_args.py +++ b/tests/test_config_and_args.py @@ -76,7 +76,7 @@ def test_systemexit_0( tmp_path.joinpath("example.py").write_text("") with pytest.raises(SystemExit) as exc_info: - from flake8_async import __main__ # noqa: F401 + from flake8_async import __main__ # noqa: F401, PLC0415 assert exc_info.value.code == 0 out, err = capsys.readouterr() @@ -91,7 +91,7 @@ def test_systemexit_1( monkeypatch_argv(monkeypatch, tmp_path) with pytest.raises(SystemExit) as exc_info: - from flake8_async import __main__ # noqa: F401 + from flake8_async import __main__ # noqa: F401, PLC0415 assert exc_info.value.code == 1 out, err = capsys.readouterr() @@ -174,7 +174,7 @@ def test_anyio_from_config(tmp_path: Path, capsys: pytest.CaptureFixture[str]): """ ) - from flake8_async.visitors.visitor2xx import Visitor22X + from flake8_async.visitors.visitor2xx import Visitor22X # noqa: PLC0415 err_msg = Visitor22X.error_codes["ASYNC220"].format( "subprocess.Popen", @@ -193,7 +193,7 @@ def test_anyio_from_config(tmp_path: Path, capsys: pytest.CaptureFixture[str]): # construct the full error message expected = f"{err_file}:{lineno}:5: ASYNC220 {err_msg}\n" - from flake8.main.cli import main + from flake8.main.cli import main # noqa: PLC0415 returnvalue = main( argv=[ @@ -246,7 +246,7 @@ def test_200_from_config_flake8_internals( # replace ./ with tmp_path/ err_msg = str(tmp_path) + EXAMPLE_PY_TEXT[1:] - from flake8.main.cli import main + from flake8.main.cli import main # noqa: PLC0415 returnvalue = main( argv=[ @@ -330,7 +330,7 @@ def test_900_default_off(): @pytest.mark.skipif(flake8 is None, reason="flake8 is not installed") def test_900_default_off_flake8(capsys: pytest.CaptureFixture[str]): - from flake8.main.cli import main + from flake8.main.cli import main # noqa: PLC0415 returnvalue = main( argv=[