From c18c7014db175aaa1cccd8d6048426c37dedeb01 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Tue, 13 Feb 2024 18:23:10 +0100
Subject: [PATCH 01/10] update pre-commit, fix pyright/mypy/ruff errors, remove
flake8, add py312 testing, fix TRIO91X for empty-body-on-same-line found due
to new black style
---
.github/workflows/ci.yml | 26 ++++----
.pre-commit-config.yaml | 45 ++++---------
flake8_trio/__main__.py | 1 +
flake8_trio/base.py | 12 ++--
flake8_trio/visitors/flake8triovisitor.py | 6 +-
flake8_trio/visitors/visitor100.py | 3 +-
flake8_trio/visitors/visitor101.py | 1 +
flake8_trio/visitors/visitor103_104.py | 1 -
flake8_trio/visitors/visitor118.py | 1 -
flake8_trio/visitors/visitor91x.py | 21 ++++--
pyproject.toml | 19 ++++--
tests/autofix_files/trio910.py | 18 +++---
tests/autofix_files/trio911.py | 72 +++++++++++----------
tests/autofix_files/trio911.py.diff | 16 ++---
tests/autofix_files/trio91x_autofix.py | 22 +++----
tests/autofix_files/trio91x_autofix.py.diff | 10 +--
tests/eval_files/noqa_no_autofix.py | 3 +-
tests/eval_files/trio102.py | 4 +-
tests/eval_files/trio102_anyio.py | 3 +-
tests/eval_files/trio102_trio.py | 3 +-
tests/eval_files/trio103.py | 16 ++---
tests/eval_files/trio103_no_104.py | 3 +-
tests/eval_files/trio103_trio.py | 3 +-
tests/eval_files/trio105.py | 3 +-
tests/eval_files/trio109.py | 36 ++++-------
tests/eval_files/trio110.py | 3 +-
tests/eval_files/trio113_trio.py | 3 +-
tests/eval_files/trio114.py | 12 ++--
tests/eval_files/trio117.py | 3 +-
tests/eval_files/trio910.py | 18 +++---
tests/eval_files/trio911.py | 72 +++++++++++----------
tests/eval_files/trio91x_autofix.py | 22 +++----
tests/test_config_and_args.py | 17 +++--
tests/test_flake8_trio.py | 14 ++--
tox.ini | 18 +-----
typings/flake8/main/application.pyi | 13 +++-
typings/flake8/options/manager.pyi | 8 +++
37 files changed, 264 insertions(+), 287 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 933719a..924f919 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,11 +11,11 @@ jobs:
check:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - name: Set up Python 3.11
- uses: actions/setup-python@v3
+ - uses: actions/checkout@v4
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v5
with:
- python-version: '3.11'
+ python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools pre-commit
@@ -27,12 +27,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ['3.9', '3.10', '3.11']
+ python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
fail-fast: false
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
@@ -47,11 +47,11 @@ jobs:
strategy:
fail-fast: false
steps:
- - uses: actions/checkout@v3
- - name: Set up Python 3.11
- uses: actions/setup-python@v3
+ - uses: actions/checkout@v4
+ - name: Set up Python 3.12
+ uses: actions/setup-python@v5
with:
- python-version: 3.11
+ python-version: 3.12
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools tox
@@ -64,9 +64,9 @@ jobs:
needs: [check, test]
if: github.repository == 'Zac-HD/flake8-trio' && github.ref == 'refs/heads/main'
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python 3
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v5
- name: Install tools
run: python -m pip install --upgrade build pip setuptools wheel twine gitpython
- name: Upload new release
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 55e8de1..598ce1d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,34 +8,34 @@ ci:
repos:
- repo: https://github.com/psf/black
- rev: 23.1.0
+ rev: 24.2.0
hooks:
- id: black
args: [--preview]
- repo: https://github.com/PyCQA/autoflake
- rev: v2.0.2
+ rev: v2.2.1
hooks:
- id: autoflake
- repo: https://github.com/asottile/pyupgrade
- rev: v3.3.1
+ rev: v3.15.0
hooks:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/pycqa/isort
- rev: 5.12.0
+ rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.1.1
+ rev: v1.8.0
hooks:
- id: mypy
- repo: https://github.com/RobertCraigie/pyright-python
- rev: v1.1.299
+ rev: v1.1.350
hooks:
- id: pyright
# ignore warnings about new version being available, no other warnings
@@ -53,14 +53,14 @@ repos:
- trio
- repo: https://github.com/codespell-project/codespell
- rev: v2.2.4
+ rev: v2.2.6
hooks:
- id: codespell
additional_dependencies:
- tomli
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v4.5.0
hooks:
- id: check-merge-conflict
- id: check-toml
@@ -74,40 +74,17 @@ repos:
args: ['--markdown-linebreak-ext=md,markdown']
- repo: https://github.com/charliermarsh/ruff-pre-commit
- rev: v0.0.269
+ rev: v0.2.1
hooks:
- id: ruff
- - repo: https://github.com/PyCQA/flake8
- rev: 6.0.0
- hooks:
- - id: flake8
- # this doesn't seem to work, pyi files don't get checked with --all-files
- types_or: [python, pyi]
- language_version: python3
- additional_dependencies:
- - flake8-2020
- - flake8-bugbear
- - flake8-builtins
- - flake8-comprehensions
- - flake8-datetimez
- - flake8-docstrings
- - flake8-mutable # not official supported by ruff
- - flake8-pie
- - flake8-pyi
- - flake8-pytest-style
- - flake8-return
- - flake8-simplify
- - flake8-type-checking
- # all other are
-
- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
- rev: 0.2.2
+ rev: 0.2.3
hooks:
- id: yamlfmt
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
- rev: v2.8.0
+ rev: v2.12.0
hooks:
- id: pretty-format-toml
args: [--autofix]
diff --git a/flake8_trio/__main__.py b/flake8_trio/__main__.py
index 4f399f5..01e07dc 100644
--- a/flake8_trio/__main__.py
+++ b/flake8_trio/__main__.py
@@ -1,4 +1,5 @@
"""Entry file when executed with `python -m`."""
+
import sys
from . import main
diff --git a/flake8_trio/base.py b/flake8_trio/base.py
index 8b05507..853afc7 100644
--- a/flake8_trio/base.py
+++ b/flake8_trio/base.py
@@ -3,7 +3,7 @@
from __future__ import annotations
from dataclasses import dataclass
-from typing import TYPE_CHECKING, Any, NamedTuple
+from typing import TYPE_CHECKING, NamedTuple
if TYPE_CHECKING:
from collections.abc import Collection
@@ -29,10 +29,12 @@ class Statement(NamedTuple):
lineno: int
col_offset: int = -1
- def __eq__(self, other: Any) -> bool:
+ # pyright is unhappy about defining __eq__ but not __hash__ .. which it should
+ # but it works :tm: and needs changing in a couple places to avoid it.
+ def __eq__(self, other: object) -> bool:
return (
isinstance(other, Statement)
- and self[:2] == other[:2] # type: ignore
+ and self[:2] == other[:2]
and (
self.col_offset == other.col_offset
or -1 in (self.col_offset, other.col_offset)
@@ -68,11 +70,11 @@ def cmp(self):
return self.line, self.code, self.args, self.col
# for sorting in tests
- def __lt__(self, other: Any) -> bool:
+ def __lt__(self, other: Error) -> bool:
assert isinstance(other, Error)
return self.cmp() < other.cmp()
- def __eq__(self, other: Any) -> bool:
+ def __eq__(self, other: object) -> bool:
return isinstance(other, Error) and self.cmp() == other.cmp()
def __repr__(self) -> str: # pragma: no cover
diff --git a/flake8_trio/visitors/flake8triovisitor.py b/flake8_trio/visitors/flake8triovisitor.py
index 14eb78e..4c4bf48 100644
--- a/flake8_trio/visitors/flake8triovisitor.py
+++ b/flake8_trio/visitors/flake8triovisitor.py
@@ -4,7 +4,7 @@
import ast
from abc import ABC
-from typing import TYPE_CHECKING, Any, Union
+from typing import TYPE_CHECKING, Any, ClassVar, Union
import libcst as cst
from libcst.metadata import PositionProvider
@@ -23,7 +23,9 @@
class Flake8TrioVisitor(ast.NodeVisitor, ABC):
# abstract attribute by not providing a value
- error_codes: dict[str, str] # pyright: ignore[reportUninitializedInstanceVariable]
+ error_codes: ClassVar[
+ dict[str, str]
+ ] # pyright: ignore[reportUninitializedInstanceVariable]
def __init__(self, shared_state: SharedState):
super().__init__()
diff --git a/flake8_trio/visitors/visitor100.py b/flake8_trio/visitors/visitor100.py
index db698ab..157c541 100644
--- a/flake8_trio/visitors/visitor100.py
+++ b/flake8_trio/visitors/visitor100.py
@@ -5,11 +5,12 @@
the timeout can only be triggered by a checkpoint.
Checkpoints on Await, Async For and Async With
"""
+
from __future__ import annotations
from typing import Any
-import libcst as cst # noqa: TCH002
+import libcst as cst
import libcst.matchers as m
from .flake8triovisitor import Flake8TrioVisitor_cst
diff --git a/flake8_trio/visitors/visitor101.py b/flake8_trio/visitors/visitor101.py
index 53a819d..ae2e873 100644
--- a/flake8_trio/visitors/visitor101.py
+++ b/flake8_trio/visitors/visitor101.py
@@ -3,6 +3,7 @@
`yield` inside a nursery or cancel scope is only safe when implementing a context manager
- otherwise, it breaks exception handling.
"""
+
from __future__ import annotations
from typing import TYPE_CHECKING, Any
diff --git a/flake8_trio/visitors/visitor103_104.py b/flake8_trio/visitors/visitor103_104.py
index 7963627..ee2c7ca 100644
--- a/flake8_trio/visitors/visitor103_104.py
+++ b/flake8_trio/visitors/visitor103_104.py
@@ -6,7 +6,6 @@
an improper raise, or other flow control, is encountered.
"""
-
from __future__ import annotations
import ast
diff --git a/flake8_trio/visitors/visitor118.py b/flake8_trio/visitors/visitor118.py
index 9a5bd85..6fff6a0 100644
--- a/flake8_trio/visitors/visitor118.py
+++ b/flake8_trio/visitors/visitor118.py
@@ -4,7 +4,6 @@
that breaks linter checks and multi-backend programs.
"""
-
from __future__ import annotations
import ast
diff --git a/flake8_trio/visitors/visitor91x.py b/flake8_trio/visitors/visitor91x.py
index 15e1275..6390186 100644
--- a/flake8_trio/visitors/visitor91x.py
+++ b/flake8_trio/visitors/visitor91x.py
@@ -35,10 +35,16 @@
def func_empty_body(node: cst.FunctionDef) -> bool:
"""Check if function body consist of `pass`, `...`, and/or (doc)string literals."""
empty_statement = m.Pass() | m.Expr(m.Ellipsis() | m.SimpleString())
+
return m.matches(
node.body,
- m.IndentedBlock(
- [m.ZeroOrMore(m.SimpleStatementLine([m.ZeroOrMore(empty_statement)]))]
+ m.OneOf(
+ # newline + indented statements
+ m.IndentedBlock(
+ [m.ZeroOrMore(m.SimpleStatementLine([m.ZeroOrMore(empty_statement)]))]
+ ),
+ # same-line statement[s]
+ m.SimpleStatementSuite(body=[m.ZeroOrMore(empty_statement)]),
),
)
@@ -114,12 +120,10 @@ def __init__(self):
@property
@abstractmethod
- def library(self) -> tuple[str, ...]:
- ...
+ def library(self) -> tuple[str, ...]: ...
@abstractmethod
- def should_autofix(self, node: cst.CSTNode, code: str | None = None) -> bool:
- ...
+ def should_autofix(self, node: cst.CSTNode, code: str | None = None) -> bool: ...
# instead of trying to exclude yields found in all the weird places from
# setting self.add_statement, we instead clear it upon each new line.
@@ -587,7 +591,10 @@ def visit_While_body(self, node: cst.For | cst.While):
if getattr(node, "asynchronous", None):
self.uncheckpointed_statements = set()
else:
- self.uncheckpointed_statements = {ARTIFICIAL_STATEMENT}
+ # pyright correctly dislikes Statement defining __eq__ but not __hash__
+ # but it works:tm:, and changing it touches on various bits of code, so
+ # leaving it for another time.
+ self.uncheckpointed_statements = {ARTIFICIAL_STATEMENT} # pyright: ignore
self.loop_state.uncheckpointed_before_continue = set()
self.loop_state.uncheckpointed_before_break = set()
diff --git a/pyproject.toml b/pyproject.toml
index 3190c8f..579b6ed 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -42,6 +42,10 @@ extend-exclude = [
"tests/eval_files/*",
"tests/autofix_files/*"
]
+line-length = 90
+target-version = "py39"
+
+[tool.ruff.lint]
ignore = [
"COM", # flake8-comma, handled by black
"ANN", # annotations, handled by pyright/mypy
@@ -58,7 +62,7 @@ ignore = [
"D213", # multi-line-summary-second-line
"EM101", # exception must not use a string literal
"EM102", # exception must not use an f-string literal
- 'PGH001', # No builtin `eval()` allowed
+ 'S307', # No builtin `eval()` allowed
'N802', # function name should be lowercase - not an option with inheritance
'PTH123', # `open()` should be replaced by `Path.open()`
'PYI021', # docstring in stub
@@ -86,16 +90,17 @@ ignore = [
'TD002', # missing author in TODO
'TD003', # missing issue link in TODO
'TRY003', # Avoid specifying long messages outside the exception class
- 'TRY200', # Use `raise from` to specify exception cause
- 'TRY201' # Use `raise` without specifying exception name
+ 'B904', # Use `raise from` to specify exception cause
+ 'TRY201', # Use `raise` without specifying exception name
+ 'FIX002', # line contains #TODO
+ 'RUF012' # Mutable class attribute should be annotated with `typing.ClassVar`
]
-line-length = 90
+# RUF012 occurs in 25 places ... I'm not going to fix that unless type checkers also complain
select = ["ALL"]
-target-version = "py39"
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
# docstrings, and arguments we can't modify
-"*.pyi" = ["D", 'FBT001', 'PLR0913']
+"*.pyi" = ["D", 'FBT001', 'PLR0913', "PIE790", "PYI048"]
# imports
"flake8_trio/visitors/__init__.py" = [
"F401",
diff --git a/tests/autofix_files/trio910.py b/tests/autofix_files/trio910.py
index fe301a1..bd752dd 100644
--- a/tests/autofix_files/trio910.py
+++ b/tests/autofix_files/trio910.py
@@ -15,8 +15,7 @@ async def foo() -> Any:
await foo()
-def bar() -> Any:
- ...
+def bar() -> Any: ...
# ARG --enable=TRIO910,TRIO911
@@ -24,8 +23,12 @@ def bar() -> Any:
# function whose body solely consists of pass, ellipsis, or string constants is safe
-async def foo_empty_1():
+# fmt: off
+async def foo_empty_1a():
...
+async def foo_empty_1b(): ...
+async def foo_empty_1c(): ...; ...
+# fmt: on
async def foo_empty_2():
@@ -124,19 +127,16 @@ def foo_normal_func_1():
return
-def foo_normal_func_2():
- ...
+def foo_normal_func_2(): ...
# overload decorator
@overload
-async def foo_overload_1(_: bytes):
- ...
+async def foo_overload_1(_: bytes): ...
@typing.overload
-async def foo_overload_1(_: str):
- ...
+async def foo_overload_1(_: str): ...
async def foo_overload_1(_: bytes | str):
diff --git a/tests/autofix_files/trio911.py b/tests/autofix_files/trio911.py
index 501018d..3cfcca1 100644
--- a/tests/autofix_files/trio911.py
+++ b/tests/autofix_files/trio911.py
@@ -13,8 +13,11 @@ async def foo() -> Any:
await foo()
-def bar(*args) -> Any:
- ...
+def bar(*args) -> Any: ...
+
+
+# mypy now treats `if ...` as `if True`, so we have another arbitrary function instead
+def condition() -> Any: ...
async def foo_yield_1():
@@ -94,7 +97,7 @@ async def foo_async_for(): # error: 0, "exit", Statement("yield", lineno+4)
async def foo_async_for_2(): # error: 0, "exit", Statement("yield", lineno+2)
async for i in trio.trick_pyright:
yield
- if ...:
+ if condition():
break
await trio.lowlevel.checkpoint()
@@ -211,7 +214,7 @@ async def foo_while_continue_1(): # error: 0, "exit", Statement("yield", lineno
while foo():
await trio.lowlevel.checkpoint()
yield # error: 8, "yield", Statement("yield", lineno)
- if ...:
+ if condition():
continue
await foo()
await trio.lowlevel.checkpoint()
@@ -226,7 +229,7 @@ async def foo_while_continue_2(): # error: 0, "exit", Statement("yield", lineno
if foo():
continue
await foo()
- if ...:
+ if condition():
continue
while foo():
yield # safe
@@ -238,7 +241,7 @@ async def foo_while_continue_2(): # error: 0, "exit", Statement("yield", lineno
# else might not run
async def foo_while_break_1(): # error: 0, "exit", Statement("yield", lineno+6)
while foo():
- if ...:
+ if condition():
break
else:
await foo()
@@ -252,7 +255,7 @@ async def foo_while_break_2(): # error: 0, "exit", Statement("yield", lineno+3)
await foo()
while foo():
yield # safe
- if ...:
+ if condition():
break
await foo()
await trio.lowlevel.checkpoint()
@@ -262,7 +265,7 @@ async def foo_while_break_2(): # error: 0, "exit", Statement("yield", lineno+3)
async def foo_while_break_3(): # error: 0, "exit", Statement("yield", lineno+7)
while foo():
await foo()
- if ...:
+ if condition():
break # if it breaks, have checkpointed
else:
await foo() # runs if 0-iter
@@ -273,7 +276,7 @@ async def foo_while_break_3(): # error: 0, "exit", Statement("yield", lineno+7)
# break at non-guaranteed checkpoint
async def foo_while_break_4(): # error: 0, "exit", Statement("yield", lineno+7)
while foo():
- if ...:
+ if condition():
break
await foo() # might not run
else:
@@ -288,7 +291,7 @@ async def foo_while_break_5(): # error: 0, "exit", Statement("yield", lineno+12
await foo()
while foo():
yield
- if ...:
+ if condition():
break
await foo()
while foo():
@@ -306,12 +309,12 @@ async def foo_while_break_6(): # error: 0, "exit", Statement("yield", lineno+11
await foo()
while foo():
yield
- if ...:
+ if condition():
break
await foo()
yield
await foo()
- if ...:
+ if condition():
break
await trio.lowlevel.checkpoint()
yield # error: 4, "yield", Statement("yield", lineno-8)
@@ -321,7 +324,7 @@ async def foo_while_break_6(): # error: 0, "exit", Statement("yield", lineno+11
async def foo_while_break_7(): # error: 0, "exit", Statement("function definition", lineno)# error: 0, "exit", Statement("yield", lineno+5)
while foo():
await foo()
- if ...:
+ if condition():
break
yield
break
@@ -517,7 +520,7 @@ async def foo_try_10_no_except():
# if
async def foo_if_1():
- if ...:
+ if condition():
await trio.lowlevel.checkpoint()
yield # error: 8, "yield", Statement("function definition", lineno-2)
await foo()
@@ -529,7 +532,7 @@ async def foo_if_1():
async def foo_if_2(): # error: 0, "exit", Statement("yield", lineno+6)
await foo()
- if ...:
+ if condition():
...
else:
yield
@@ -540,7 +543,7 @@ async def foo_if_2(): # error: 0, "exit", Statement("yield", lineno+6)
async def foo_if_3(): # error: 0, "exit", Statement("yield", lineno+6)
await foo()
- if ...:
+ if condition():
yield
else:
...
@@ -552,7 +555,7 @@ async def foo_if_3(): # error: 0, "exit", Statement("yield", lineno+6)
async def foo_if_4(): # error: 0, "exit", Statement("yield", lineno+7)
await foo()
yield
- if ...:
+ if condition():
await foo()
else:
...
@@ -563,7 +566,7 @@ async def foo_if_4(): # error: 0, "exit", Statement("yield", lineno+7)
async def foo_if_5(): # error: 0, "exit", Statement("yield", lineno+8)
await foo()
- if ...:
+ if condition():
yield
await foo()
else:
@@ -576,7 +579,7 @@ async def foo_if_5(): # error: 0, "exit", Statement("yield", lineno+8)
async def foo_if_6(): # error: 0, "exit", Statement("yield", lineno+8)
await foo()
- if ...:
+ if condition():
yield
else:
yield
@@ -588,7 +591,7 @@ async def foo_if_6(): # error: 0, "exit", Statement("yield", lineno+8)
async def foo_if_7(): # error: 0, "exit", Statement("function definition", lineno)
- if ...:
+ if condition():
await foo()
yield
await foo()
@@ -596,7 +599,7 @@ async def foo_if_7(): # error: 0, "exit", Statement("function definition", line
async def foo_if_8(): # error: 0, "exit", Statement("function definition", lineno)
- if ...:
+ if condition():
...
else:
await foo()
@@ -617,7 +620,7 @@ async def foo_ifexp_2(): # error: 0, "exit", Statement("yield", lineno+2)
await trio.lowlevel.checkpoint()
print(
(yield) # error: 9, "yield", Statement("function definition", lineno-2)
- if ... and await foo()
+ if condition() and await foo()
else await foo()
)
await trio.lowlevel.checkpoint()
@@ -628,8 +631,7 @@ def foo_sync_1():
return
-def foo_sync_2():
- ...
+def foo_sync_2(): ...
def foo_sync_3():
@@ -637,13 +639,13 @@ def foo_sync_3():
def foo_sync_4():
- if ...:
+ if condition():
return
yield
def foo_sync_5():
- if ...:
+ if condition():
return
yield
@@ -655,7 +657,7 @@ def foo_sync_6():
def foo_sync_7():
while foo():
- if ...:
+ if condition():
return
yield
@@ -714,7 +716,7 @@ async def foo_loop_static():
for _ in [1, 2, 3]:
await foo()
- if ...:
+ if condition():
break
else:
yield
@@ -723,7 +725,7 @@ async def foo_loop_static():
# continue
for _ in [1, 2, 3]:
- if ...:
+ if condition():
continue
await foo()
await trio.lowlevel.checkpoint()
@@ -731,7 +733,7 @@ async def foo_loop_static():
# continue/else
for _ in [1, 2, 3]:
- if ...:
+ if condition():
continue
await foo()
else:
@@ -742,7 +744,7 @@ async def foo_loop_static():
for _ in [1, 2, 3]:
await foo()
- if ...:
+ if condition():
break
else:
yield
@@ -876,22 +878,22 @@ async def foo_loop_static():
# while
while True:
await foo()
- if ...:
+ if condition():
break
yield
while True:
- if ...:
+ if condition():
break
await foo()
await trio.lowlevel.checkpoint()
yield # error: 4, "yield", Stmt("yield", line-6)
while True:
- if ...:
+ if condition():
continue
await foo()
- if ...:
+ if condition():
break
yield
diff --git a/tests/autofix_files/trio911.py.diff b/tests/autofix_files/trio911.py.diff
index 91e9bb7..bf853b9 100644
--- a/tests/autofix_files/trio911.py.diff
+++ b/tests/autofix_files/trio911.py.diff
@@ -58,7 +58,7 @@
# await anext(iter) is not called on break
@@ x,6 x,7 @@
yield
- if ...:
+ if condition():
break
+ await trio.lowlevel.checkpoint()
@@ -157,7 +157,7 @@
while foo():
+ await trio.lowlevel.checkpoint()
yield # error: 8, "yield", Statement("yield", lineno)
- if ...:
+ if condition():
continue
await foo()
+ await trio.lowlevel.checkpoint()
@@ -190,7 +190,7 @@
# no checkpoint on break
@@ x,6 x,7 @@
- if ...:
+ if condition():
break
await foo()
+ await trio.lowlevel.checkpoint()
@@ -227,7 +227,7 @@
# check multiple breaks
@@ x,7 x,9 @@
await foo()
- if ...:
+ if condition():
break
+ await trio.lowlevel.checkpoint()
yield # error: 4, "yield", Statement("yield", lineno-8)
@@ -364,7 +364,7 @@
@@ x,9 x,11 @@
# if
async def foo_if_1():
- if ...:
+ if condition():
+ await trio.lowlevel.checkpoint()
yield # error: 8, "yield", Statement("function definition", lineno-2)
await foo()
@@ -450,7 +450,7 @@
+ await trio.lowlevel.checkpoint()
print(
(yield) # error: 9, "yield", Statement("function definition", lineno-2)
- if ... and await foo()
+ if condition() and await foo()
else await foo()
)
+ await trio.lowlevel.checkpoint()
@@ -491,7 +491,7 @@
# loop over non-empty static collection
@@ x,6 x,7 @@
- if ...:
+ if condition():
continue
await foo()
+ await trio.lowlevel.checkpoint()
@@ -585,7 +585,7 @@
# while
@@ x,6 x,7 @@
- if ...:
+ if condition():
break
await foo()
+ await trio.lowlevel.checkpoint()
diff --git a/tests/autofix_files/trio91x_autofix.py b/tests/autofix_files/trio91x_autofix.py
index 874b6fe..685608c 100644
--- a/tests/autofix_files/trio91x_autofix.py
+++ b/tests/autofix_files/trio91x_autofix.py
@@ -12,8 +12,7 @@
import trio
-def bar() -> Any:
- ...
+def bar() -> Any: ...
async def foo() -> Any:
@@ -39,10 +38,10 @@ async def foo_yield(): # TRIO911: 0, "exit", Statement("yield", lineno+2)
async def foo_if():
- if ...:
+ if foo():
await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif ...:
+ elif foo():
await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
@@ -67,7 +66,7 @@ async def foo_while2():
async def foo_while3():
await foo()
while True:
- if ...:
+ if foo():
return
await foo()
@@ -75,10 +74,10 @@ async def foo_while3():
# check that multiple checkpoints don't get inserted
async def foo_while4():
while True:
- if ...:
+ if foo():
await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if ...:
+ if foo():
await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
@@ -103,7 +102,7 @@ async def foo_while_nested_func():
yield # TRIO911: 8, "yield", Statement("function definition", lineno-2) # TRIO911: 8, "yield", Statement("yield", lineno)
async def bar():
- while ...:
+ while foo():
...
await foo()
@@ -111,17 +110,16 @@ async def bar():
# Code coverage: visitors run when inside a sync function that has an async function.
# When sync funcs don't contain an async func the body is not visited.
def sync_func():
- async def async_func():
- ...
+ async def async_func(): ...
try:
...
except:
...
- if ... and ...:
+ if foo() and foo():
...
while ...:
- if ...:
+ if foo():
continue
break
[... for i in range(5)]
diff --git a/tests/autofix_files/trio91x_autofix.py.diff b/tests/autofix_files/trio91x_autofix.py.diff
index 34a1cf9..08a2ea8 100644
--- a/tests/autofix_files/trio91x_autofix.py.diff
+++ b/tests/autofix_files/trio91x_autofix.py.diff
@@ -7,7 +7,7 @@
+import trio
- def bar() -> Any:
+ def bar() -> Any: ...
@@ x,30 x,38 @@
async def foo1(): # TRIO910: 0, "exit", Statement("function definition", lineno)
@@ -29,10 +29,10 @@
async def foo_if():
- if ...:
+ if foo():
+ await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif ...:
+ elif foo():
+ await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
@@ -50,10 +50,10 @@
@@ x,8 x,10 @@
async def foo_while4():
while True:
- if ...:
+ if foo():
+ await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if ...:
+ if foo():
+ await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
diff --git a/tests/eval_files/noqa_no_autofix.py b/tests/eval_files/noqa_no_autofix.py
index 8dcc56b..c179b75 100644
--- a/tests/eval_files/noqa_no_autofix.py
+++ b/tests/eval_files/noqa_no_autofix.py
@@ -5,8 +5,7 @@
# errors from AST visitors
-async def foo() -> Any:
- ...
+async def foo() -> Any: ...
async def foo_no_noqa_102():
diff --git a/tests/eval_files/trio102.py b/tests/eval_files/trio102.py
index 5560e9a..2d501f1 100644
--- a/tests/eval_files/trio102.py
+++ b/tests/eval_files/trio102.py
@@ -120,7 +120,9 @@ async def foo():
try:
pass
finally:
- async for i in trio.bypasslinters: # error: 8, Statement("try/finally", lineno-3)
+ async for ( # error: 8, Statement("try/finally", lineno-3)
+ i
+ ) in trio.bypasslinters:
pass
try:
pass
diff --git a/tests/eval_files/trio102_anyio.py b/tests/eval_files/trio102_anyio.py
index 29f42c5..ec71f48 100644
--- a/tests/eval_files/trio102_anyio.py
+++ b/tests/eval_files/trio102_anyio.py
@@ -5,8 +5,7 @@
# this one is fine to also run with TRIO
-async def foo():
- ...
+async def foo(): ...
async def foo_anyio():
diff --git a/tests/eval_files/trio102_trio.py b/tests/eval_files/trio102_trio.py
index 20c8abb..58d58a5 100644
--- a/tests/eval_files/trio102_trio.py
+++ b/tests/eval_files/trio102_trio.py
@@ -2,8 +2,7 @@
import trio
-async def foo():
- ...
+async def foo(): ...
# except cancelled/baseexception are also critical
diff --git a/tests/eval_files/trio103.py b/tests/eval_files/trio103.py
index bbf3e42..52829fc 100644
--- a/tests/eval_files/trio103.py
+++ b/tests/eval_files/trio103.py
@@ -3,8 +3,7 @@
from typing import Any
-def foo() -> Any:
- ...
+def foo() -> Any: ...
# fmt: off
@@ -48,9 +47,9 @@ def foo() -> Any:
try:
...
except BaseException as e: # TRIO103_trio: 7, "BaseException"
- if ...:
+ if foo():
raise e
- elif ...:
+ elif foo():
...
else:
raise e
@@ -64,9 +63,9 @@ def foo() -> Any:
try:
...
except BaseException: # safe
- if ...:
+ if foo():
raise
- elif ...:
+ elif foo():
raise
else:
raise
@@ -199,9 +198,8 @@ def foo() -> Any:
except (
my_super_mega_long_exception_so_it_gets_split,
SyntaxError,
- BaseException, # TRIO103_trio: 4, "BaseException"
- ValueError,
- BaseException, # no complaint on this line
+ BaseException, # TRIO103_trio: 4, "BaseException"
+ ValueError, # no complaint on this line
):
...
diff --git a/tests/eval_files/trio103_no_104.py b/tests/eval_files/trio103_no_104.py
index 91c4646..63c37b1 100644
--- a/tests/eval_files/trio103_no_104.py
+++ b/tests/eval_files/trio103_no_104.py
@@ -3,8 +3,7 @@
from typing import Any
-def foo() -> Any:
- ...
+def foo() -> Any: ...
# nested try
diff --git a/tests/eval_files/trio103_trio.py b/tests/eval_files/trio103_trio.py
index 37a17d1..870acc9 100644
--- a/tests/eval_files/trio103_trio.py
+++ b/tests/eval_files/trio103_trio.py
@@ -6,8 +6,7 @@
import trio
-def foo() -> Any:
- ...
+def foo() -> Any: ...
# fmt: off
diff --git a/tests/eval_files/trio105.py b/tests/eval_files/trio105.py
index 067d6cc..8e18cae 100644
--- a/tests/eval_files/trio105.py
+++ b/tests/eval_files/trio105.py
@@ -8,8 +8,7 @@
async_funpar: Coroutine[Any, Any, Any] = ... # type: ignore
-async def myasyncfun(task_status):
- ...
+async def myasyncfun(task_status): ...
# calls that don't return
diff --git a/tests/eval_files/trio109.py b/tests/eval_files/trio109.py
index b652c10..139e2e5 100644
--- a/tests/eval_files/trio109.py
+++ b/tests/eval_files/trio109.py
@@ -5,8 +5,7 @@
timeout = 10
-async def foo():
- ...
+async def foo(): ...
# args
@@ -36,8 +35,7 @@ async def foo_5(
my_timeout,
timeout_,
timeout, # error: 4, "trio"
-):
- ...
+): ...
# posonlyargs
@@ -45,54 +43,44 @@ async def foo_6(
timeout, # error: 4, "trio"
/,
bar,
-):
- ...
+): ...
# kwonlyargs
async def foo_7(
*,
timeout, # error: 4, "trio"
-):
- ...
+): ...
# kwonlyargs (and kw_defaults)
async def foo_8(
*,
timeout=5, # error: 4, "trio"
-):
- ...
+): ...
-async def foo_9(k=timeout):
- ...
+async def foo_9(k=timeout): ...
# normal functions are not checked
-def foo_10(timeout):
- ...
+def foo_10(timeout): ...
-def foo_11(timeout, /):
- ...
+def foo_11(timeout, /): ...
-def foo_12(*, timeout):
- ...
+def foo_12(*, timeout): ...
# ignore all functions with a decorator
@anything.anything
-async def foo_decorator_1(timeout):
- ...
+async def foo_decorator_1(timeout): ...
@anything.anything
-async def foo_decorator_2(*, timeout):
- ...
+async def foo_decorator_2(*, timeout): ...
@anything
-async def foo_decorator_3(timeout, /):
- ...
+async def foo_decorator_3(timeout, /): ...
diff --git a/tests/eval_files/trio110.py b/tests/eval_files/trio110.py
index 11aad54..2052f8d 100644
--- a/tests/eval_files/trio110.py
+++ b/tests/eval_files/trio110.py
@@ -41,8 +41,7 @@ async def foo():
while ...:
await noerror.sleep()
- async def sleep():
- ...
+ async def sleep(): ...
while ...:
await sleep()
diff --git a/tests/eval_files/trio113_trio.py b/tests/eval_files/trio113_trio.py
index 3b6cc4f..b03dda9 100644
--- a/tests/eval_files/trio113_trio.py
+++ b/tests/eval_files/trio113_trio.py
@@ -125,5 +125,4 @@ async def contextlib_import_alias_acm():
# code coverage for non-name, non-attribute decorator
@None # type: ignore
-async def foo4():
- ...
+async def foo4(): ...
diff --git a/tests/eval_files/trio114.py b/tests/eval_files/trio114.py
index ea9fcd9..c4f7b5c 100644
--- a/tests/eval_files/trio114.py
+++ b/tests/eval_files/trio114.py
@@ -3,8 +3,7 @@
# ARG --startable-in-context-manager=foo
-async def foo(task_status):
- ...
+async def foo(task_status): ...
async def bar(task_status): # error: 0, "bar"
@@ -25,16 +24,13 @@ async def foo3(*, task_status): # error: 0, "foo3"
# don't error on pos-only parameter
-async def foo4(task_status, /):
- ...
+async def foo4(task_status, /): ...
-async def foo5(*task_status):
- ...
+async def foo5(*task_status): ...
-async def foo6(**task_status):
- ...
+async def foo6(**task_status): ...
def sync():
diff --git a/tests/eval_files/trio117.py b/tests/eval_files/trio117.py
index 6185136..f03f7b9 100644
--- a/tests/eval_files/trio117.py
+++ b/tests/eval_files/trio117.py
@@ -39,8 +39,7 @@ def bar(x: MultiError): # TRIO117: 11, "MultiError"
# args are not ast.Name's, so this one (surprisingly!) isn't a false positive
# (though any use of the variable will be)
-def foo(MultiError: int):
- ...
+def foo(MultiError: int): ...
# only triggers on *trio*.MultiError
diff --git a/tests/eval_files/trio910.py b/tests/eval_files/trio910.py
index 8770788..c4aaa64 100644
--- a/tests/eval_files/trio910.py
+++ b/tests/eval_files/trio910.py
@@ -15,8 +15,7 @@ async def foo() -> Any:
await foo()
-def bar() -> Any:
- ...
+def bar() -> Any: ...
# ARG --enable=TRIO910,TRIO911
@@ -24,8 +23,12 @@ def bar() -> Any:
# function whose body solely consists of pass, ellipsis, or string constants is safe
-async def foo_empty_1():
+# fmt: off
+async def foo_empty_1a():
...
+async def foo_empty_1b(): ...
+async def foo_empty_1c(): ...; ...
+# fmt: on
async def foo_empty_2():
@@ -116,19 +119,16 @@ def foo_normal_func_1():
return
-def foo_normal_func_2():
- ...
+def foo_normal_func_2(): ...
# overload decorator
@overload
-async def foo_overload_1(_: bytes):
- ...
+async def foo_overload_1(_: bytes): ...
@typing.overload
-async def foo_overload_1(_: str):
- ...
+async def foo_overload_1(_: str): ...
async def foo_overload_1(_: bytes | str):
diff --git a/tests/eval_files/trio911.py b/tests/eval_files/trio911.py
index 68f4a76..465b473 100644
--- a/tests/eval_files/trio911.py
+++ b/tests/eval_files/trio911.py
@@ -13,8 +13,11 @@ async def foo() -> Any:
await foo()
-def bar(*args) -> Any:
- ...
+def bar(*args) -> Any: ...
+
+
+# mypy now treats `if ...` as `if True`, so we have another arbitrary function instead
+def condition() -> Any: ...
async def foo_yield_1():
@@ -83,7 +86,7 @@ async def foo_async_for(): # error: 0, "exit", Statement("yield", lineno+4)
async def foo_async_for_2(): # error: 0, "exit", Statement("yield", lineno+2)
async for i in trio.trick_pyright:
yield
- if ...:
+ if condition():
break
@@ -179,7 +182,7 @@ async def foo_while_continue_1(): # error: 0, "exit", Statement("yield", lineno
await foo()
while foo():
yield # error: 8, "yield", Statement("yield", lineno)
- if ...:
+ if condition():
continue
await foo()
@@ -192,7 +195,7 @@ async def foo_while_continue_2(): # error: 0, "exit", Statement("yield", lineno
if foo():
continue
await foo()
- if ...:
+ if condition():
continue
while foo():
yield # safe
@@ -203,7 +206,7 @@ async def foo_while_continue_2(): # error: 0, "exit", Statement("yield", lineno
# else might not run
async def foo_while_break_1(): # error: 0, "exit", Statement("yield", lineno+6)
while foo():
- if ...:
+ if condition():
break
else:
await foo()
@@ -215,7 +218,7 @@ async def foo_while_break_2(): # error: 0, "exit", Statement("yield", lineno+3)
await foo()
while foo():
yield # safe
- if ...:
+ if condition():
break
await foo()
@@ -224,7 +227,7 @@ async def foo_while_break_2(): # error: 0, "exit", Statement("yield", lineno+3)
async def foo_while_break_3(): # error: 0, "exit", Statement("yield", lineno+7)
while foo():
await foo()
- if ...:
+ if condition():
break # if it breaks, have checkpointed
else:
await foo() # runs if 0-iter
@@ -234,7 +237,7 @@ async def foo_while_break_3(): # error: 0, "exit", Statement("yield", lineno+7)
# break at non-guaranteed checkpoint
async def foo_while_break_4(): # error: 0, "exit", Statement("yield", lineno+7)
while foo():
- if ...:
+ if condition():
break
await foo() # might not run
else:
@@ -247,7 +250,7 @@ async def foo_while_break_5(): # error: 0, "exit", Statement("yield", lineno+12
await foo()
while foo():
yield
- if ...:
+ if condition():
break
await foo()
while foo():
@@ -263,12 +266,12 @@ async def foo_while_break_6(): # error: 0, "exit", Statement("yield", lineno+11
await foo()
while foo():
yield
- if ...:
+ if condition():
break
await foo()
yield
await foo()
- if ...:
+ if condition():
break
yield # error: 4, "yield", Statement("yield", lineno-8)
@@ -276,7 +279,7 @@ async def foo_while_break_6(): # error: 0, "exit", Statement("yield", lineno+11
async def foo_while_break_7(): # error: 0, "exit", Statement("function definition", lineno)# error: 0, "exit", Statement("yield", lineno+5)
while foo():
await foo()
- if ...:
+ if condition():
break
yield
break
@@ -454,7 +457,7 @@ async def foo_try_10_no_except():
# if
async def foo_if_1():
- if ...:
+ if condition():
yield # error: 8, "yield", Statement("function definition", lineno-2)
await foo()
else:
@@ -464,7 +467,7 @@ async def foo_if_1():
async def foo_if_2(): # error: 0, "exit", Statement("yield", lineno+6)
await foo()
- if ...:
+ if condition():
...
else:
yield
@@ -473,7 +476,7 @@ async def foo_if_2(): # error: 0, "exit", Statement("yield", lineno+6)
async def foo_if_3(): # error: 0, "exit", Statement("yield", lineno+6)
await foo()
- if ...:
+ if condition():
yield
else:
...
@@ -483,7 +486,7 @@ async def foo_if_3(): # error: 0, "exit", Statement("yield", lineno+6)
async def foo_if_4(): # error: 0, "exit", Statement("yield", lineno+7)
await foo()
yield
- if ...:
+ if condition():
await foo()
else:
...
@@ -492,7 +495,7 @@ async def foo_if_4(): # error: 0, "exit", Statement("yield", lineno+7)
async def foo_if_5(): # error: 0, "exit", Statement("yield", lineno+8)
await foo()
- if ...:
+ if condition():
yield
await foo()
else:
@@ -503,7 +506,7 @@ async def foo_if_5(): # error: 0, "exit", Statement("yield", lineno+8)
async def foo_if_6(): # error: 0, "exit", Statement("yield", lineno+8)
await foo()
- if ...:
+ if condition():
yield
else:
yield
@@ -513,14 +516,14 @@ async def foo_if_6(): # error: 0, "exit", Statement("yield", lineno+8)
async def foo_if_7(): # error: 0, "exit", Statement("function definition", lineno)
- if ...:
+ if condition():
await foo()
yield
await foo()
async def foo_if_8(): # error: 0, "exit", Statement("function definition", lineno)
- if ...:
+ if condition():
...
else:
await foo()
@@ -538,7 +541,7 @@ async def foo_ifexp_1(): # error: 0, "exit", Statement("yield", lineno+1) # err
async def foo_ifexp_2(): # error: 0, "exit", Statement("yield", lineno+2)
print(
(yield) # error: 9, "yield", Statement("function definition", lineno-2)
- if ... and await foo()
+ if condition() and await foo()
else await foo()
)
@@ -548,8 +551,7 @@ def foo_sync_1():
return
-def foo_sync_2():
- ...
+def foo_sync_2(): ...
def foo_sync_3():
@@ -557,13 +559,13 @@ def foo_sync_3():
def foo_sync_4():
- if ...:
+ if condition():
return
yield
def foo_sync_5():
- if ...:
+ if condition():
return
yield
@@ -575,7 +577,7 @@ def foo_sync_6():
def foo_sync_7():
while foo():
- if ...:
+ if condition():
return
yield
@@ -629,7 +631,7 @@ async def foo_loop_static():
for _ in [1, 2, 3]:
await foo()
- if ...:
+ if condition():
break
else:
yield
@@ -638,14 +640,14 @@ async def foo_loop_static():
# continue
for _ in [1, 2, 3]:
- if ...:
+ if condition():
continue
await foo()
yield # error: 4, "yield", Stmt("yield", line-7)
# continue/else
for _ in [1, 2, 3]:
- if ...:
+ if condition():
continue
await foo()
else:
@@ -655,7 +657,7 @@ async def foo_loop_static():
for _ in [1, 2, 3]:
await foo()
- if ...:
+ if condition():
break
else:
yield
@@ -776,21 +778,21 @@ async def foo_loop_static():
# while
while True:
await foo()
- if ...:
+ if condition():
break
yield
while True:
- if ...:
+ if condition():
break
await foo()
yield # error: 4, "yield", Stmt("yield", line-6)
while True:
- if ...:
+ if condition():
continue
await foo()
- if ...:
+ if condition():
break
yield
diff --git a/tests/eval_files/trio91x_autofix.py b/tests/eval_files/trio91x_autofix.py
index 8581b9b..c523ffb 100644
--- a/tests/eval_files/trio91x_autofix.py
+++ b/tests/eval_files/trio91x_autofix.py
@@ -11,8 +11,7 @@
from typing import Any
-def bar() -> Any:
- ...
+def bar() -> Any: ...
async def foo() -> Any:
@@ -34,9 +33,9 @@ async def foo_yield(): # TRIO911: 0, "exit", Statement("yield", lineno+2)
async def foo_if():
- if ...:
+ if foo():
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif ...:
+ elif foo():
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
return # TRIO910: 8, "return", Statement("function definition", lineno-6)
@@ -58,7 +57,7 @@ async def foo_while2():
async def foo_while3():
await foo()
while True:
- if ...:
+ if foo():
return
await foo()
@@ -66,9 +65,9 @@ async def foo_while3():
# check that multiple checkpoints don't get inserted
async def foo_while4():
while True:
- if ...:
+ if foo():
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if ...:
+ if foo():
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
@@ -88,7 +87,7 @@ async def foo_while_nested_func():
yield # TRIO911: 8, "yield", Statement("function definition", lineno-2) # TRIO911: 8, "yield", Statement("yield", lineno)
async def bar():
- while ...:
+ while foo():
...
await foo()
@@ -96,17 +95,16 @@ async def bar():
# Code coverage: visitors run when inside a sync function that has an async function.
# When sync funcs don't contain an async func the body is not visited.
def sync_func():
- async def async_func():
- ...
+ async def async_func(): ...
try:
...
except:
...
- if ... and ...:
+ if foo() and foo():
...
while ...:
- if ...:
+ if foo():
continue
break
[... for i in range(5)]
diff --git a/tests/test_config_and_args.py b/tests/test_config_and_args.py
index 7e14c72..e3449ef 100644
--- a/tests/test_config_and_args.py
+++ b/tests/test_config_and_args.py
@@ -1,4 +1,5 @@
"""Various tests for testing argument and config parsing."""
+
from __future__ import annotations
import ast
@@ -55,6 +56,7 @@ def test_run_flake8_trio(tmp_path: Path):
],
cwd=tmp_path,
capture_output=True,
+ check=False,
)
assert res.returncode == 1
assert not res.stderr
@@ -94,14 +96,15 @@ def test_systemexit_1(
def test_run_in_git_repo(tmp_path: Path):
write_examplepy(tmp_path)
- assert subprocess.run(["git", "init"], cwd=tmp_path, capture_output=True)
- assert subprocess.run(["git", "add", "example.py"], cwd=tmp_path)
+ subprocess.run(["git", "init"], cwd=tmp_path, capture_output=True, check=True)
+ subprocess.run(["git", "add", "example.py"], cwd=tmp_path, check=True)
res = subprocess.run(
[
"flake8-trio",
],
cwd=tmp_path,
capture_output=True,
+ check=False,
)
assert res.returncode == 1
assert not res.stderr
@@ -240,7 +243,7 @@ def test_200_from_config_flake8_internals(
def test_200_from_config_subprocess(tmp_path: Path):
err_msg = _test_trio200_from_config_common(tmp_path)
- res = subprocess.run(["flake8"], cwd=tmp_path, capture_output=True)
+ res = subprocess.run(["flake8"], cwd=tmp_path, capture_output=True, check=False)
assert res.returncode == 1
assert not res.stderr
assert res.stdout == err_msg.encode("ascii")
@@ -269,8 +272,7 @@ def test_enable(
monkeypatch_argv(monkeypatch, tmp_path, argv)
def _helper(*args: str, error: bool = False, autofix: bool = False) -> None:
- for arg in args:
- argv.append(arg)
+ argv.extend(args)
main()
out, err = capsys.readouterr()
if error:
@@ -333,7 +335,9 @@ def test_flake8_plugin_with_autofix_fails(tmp_path: Path):
],
cwd=tmp_path,
capture_output=True,
+ check=False,
)
+ assert res.returncode == 1
assert not res.stdout
assert res.stderr == b"Cannot autofix when run as a flake8 plugin.\n"
@@ -365,8 +369,7 @@ def test_disable_noqa_cst(
out, err = capsys.readouterr()
assert not err
assert (
- out
- == "./example.py:2:6: TRIO100 trio.move_on_after context contains no"
+ out == "./example.py:2:6: TRIO100 trio.move_on_after context contains no"
" checkpoints, remove the context or add `await"
" trio.lowlevel.checkpoint()`.\n"
)
diff --git a/tests/test_flake8_trio.py b/tests/test_flake8_trio.py
index cc6dfa3..7d95e88 100644
--- a/tests/test_flake8_trio.py
+++ b/tests/test_flake8_trio.py
@@ -47,8 +47,7 @@
), f"no eval file for autofix file[s] {extra_autofix_files}"
-class ParseError(Exception):
- ...
+class ParseError(Exception): ...
# check for presence of _pyXX, skip if version is later, and prune parameter
@@ -500,11 +499,11 @@ def print_first_diff(errors: Sequence[Error], expected: Sequence[Error]):
def assert_correct_lines_and_codes(errors: Iterable[Error], expected: Iterable[Error]):
"""Check that errors are on correct lines."""
- MyDict = defaultdict[int, defaultdict[str, int]] # TypeAlias
-
all_lines = sorted({e.line for e in (*errors, *expected)})
- error_dict: MyDict = defaultdict(lambda: defaultdict(int))
+ error_dict: defaultdict[int, defaultdict[str, int]] = defaultdict(
+ lambda: defaultdict(int)
+ )
expected_dict = copy.deepcopy(error_dict)
# populate dicts with number of errors per line
@@ -589,7 +588,8 @@ def info_tuple(error: Error):
for err, exp in zip(errors, expected):
err_msg = info_tuple(err)
for err, type_ in zip(err_msg, (int, int, str, type(None))):
- assert isinstance(err, type_)
+ # mypy fails to track types across the zip
+ assert isinstance(err, type_) # type: ignore[arg-type]
assert err_msg == info_tuple(exp)
@@ -751,5 +751,5 @@ def test_does_not_crash_on_site_code(enable_codes: str):
plugin = Plugin.from_filename(str(path))
initialize_options(plugin, [f"--enable={enable_codes}"])
consume(plugin.run())
- except Exception as err:
+ except Exception as err: # noqa: PERF203 # try-except in loop
raise AssertionError(f"Failed on {path}") from err
diff --git a/tox.ini b/tox.ini
index 35086d9..1ac13e0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
# The test environment and commands
[tox]
# default environments to run without `-e`
-envlist = py{39,310,311}-{flake8_5,flake8_6}
+envlist = py{39,310,311,312}-{flake8_5,flake8_6}
# create a default testenv, whose behaviour will depend on the name it's called with.
# for CI you can call with `-e flake8_5,flake8_6` and let the CI handle python version
@@ -16,6 +16,7 @@ deps =
hypothesis
hypothesmith
trio
+ ipdb
commands =
pytest {posargs} #{posargs:-n auto}
@@ -45,18 +46,3 @@ exclude_lines =
# Don't check guarded type imports
if (typing.)?TYPE_CHECKING:
-
-[flake8]
-max-line-length = 90
-# not supported by ruff + want to `noqa` them, so instead ignoring them: PIE786, R504
-extend-ignore = S101, D101, D102, D103, D105, D106, D107, PIE786, R504
-extend-enable = TC10
-exclude = .*, tests/eval_files/*, tests/autofix_files/*
-per-file-ignores =
- flake8_trio/visitors/__init__.py: F401, E402
-# visitor_utility contains comments specifying how it parses noqa comments, which get
-# parsed as noqa comments
- flake8_trio/visitors/visitor_utility.py: NQA101, NQA102
-# (E301, E302) black formats stub files without excessive blank lines
-# (D) we don't care about docstrings in stub files
- *.pyi: D, E301, E302
diff --git a/typings/flake8/main/application.pyi b/typings/flake8/main/application.pyi
index b8ffe9a..3551a77 100644
--- a/typings/flake8/main/application.pyi
+++ b/typings/flake8/main/application.pyi
@@ -13,29 +13,36 @@ class Application:
def __init__(self) -> None:
"""Initialize our application."""
...
+
def exit_code(self) -> int:
"""Return the program exit code."""
...
+
def make_formatter(self) -> None:
"""Initialize a formatter based on the parsed options."""
...
+
def make_guide(self) -> None:
"""Initialize our StyleGuide."""
...
+
def make_file_checker_manager(self, argv: Sequence[str]) -> None:
"""Initialize our FileChecker Manager."""
...
+
def run_checks(self) -> None:
"""Run the actual checks with the FileChecker Manager.
This method encapsulates the logic to make a
- :class:`~flake8.checker.Manger` instance run the checks it is
+ :class:`~flake8.checker.Manager` instance run the checks it is
managing.
"""
...
+
def report_benchmarks(self) -> None:
"""Aggregate, calculate, and report benchmarks for this run."""
...
+
def report_errors(self) -> None:
"""Report all the errors found by flake8 3.0.
@@ -43,9 +50,11 @@ class Application:
number of errors, warnings, and other messages found.
"""
...
+
def report_statistics(self) -> None:
"""Aggregate and report statistics from this run."""
...
+
def initialize(self, argv: Sequence[str]) -> None:
"""Initialize the application to be run.
@@ -53,9 +62,11 @@ class Application:
command-line arguments.
"""
...
+
def report(self) -> None:
"""Report errors, statistics, and benchmarks."""
...
+
def run(self, argv: Sequence[str]) -> None:
"""Run our application.
diff --git a/typings/flake8/options/manager.pyi b/typings/flake8/options/manager.pyi
index 914a91c..3d68eb8 100644
--- a/typings/flake8/options/manager.pyi
+++ b/typings/flake8/options/manager.pyi
@@ -123,13 +123,16 @@ class Option:
attempt to normalize the paths to absolute paths.
"""
...
+
@property
def filtered_option_kwargs(self) -> dict[str, Any]:
"""Return any actually-specified arguments."""
...
+
def normalize(self, value: Any, *normalize_args: str) -> Any:
"""Normalize the value based on the option configuration."""
...
+
def to_argparse(self) -> tuple[list[str], dict[str, Any]]:
"""Convert a Flake8 Option to argparse ``add_argument`` arguments."""
...
@@ -157,9 +160,11 @@ class OptionManager:
included.
"""
...
+
def register_plugins(self, plugins: Plugins) -> None:
"""Register the plugin options (if needed)."""
...
+
def add_option(self, *args: Any, **kwargs: Any) -> None:
"""Create and register a new option.
@@ -172,6 +177,7 @@ class OptionManager:
positionally as they are with argparse normally.
"""
...
+
def extend_default_ignore(self, error_codes: Sequence[str]) -> None:
"""Extend the default ignore list with the error codes provided.
@@ -180,6 +186,7 @@ class OptionManager:
extend the default ignore list.
"""
...
+
def extend_default_select(self, error_codes: Sequence[str]) -> None:
"""Extend the default select list with the error codes provided.
@@ -188,6 +195,7 @@ class OptionManager:
to extend the default select list.
"""
...
+
def parse_args(
self,
args: Sequence[str] | None = ...,
From 3cf9d97c4b75c5d0b781ff8570eb5b2bcb4c4ceb Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 10:48:15 +0100
Subject: [PATCH 02/10] undo pyupgrade breaking trio103 eval file, exclude it
in pre-commit revert adding ipdb to tox (was briefly used when testing stuff)
---
.pre-commit-config.yaml | 1 +
tests/eval_files/trio103.py | 5 +++--
tox.ini | 1 -
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 598ce1d..af32387 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,6 +23,7 @@ repos:
hooks:
- id: pyupgrade
args: [--py39-plus]
+ exclude: tests/eval_files/trio103.py
- repo: https://github.com/pycqa/isort
rev: 5.13.2
diff --git a/tests/eval_files/trio103.py b/tests/eval_files/trio103.py
index 52829fc..a4e39be 100644
--- a/tests/eval_files/trio103.py
+++ b/tests/eval_files/trio103.py
@@ -198,8 +198,9 @@ def foo() -> Any: ...
except (
my_super_mega_long_exception_so_it_gets_split,
SyntaxError,
- BaseException, # TRIO103_trio: 4, "BaseException"
- ValueError, # no complaint on this line
+ BaseException, # TRIO103_trio: 4, "BaseException"
+ ValueError,
+ BaseException, # no complaint on this line
):
...
diff --git a/tox.ini b/tox.ini
index 1ac13e0..c7fd716 100644
--- a/tox.ini
+++ b/tox.ini
@@ -16,7 +16,6 @@ deps =
hypothesis
hypothesmith
trio
- ipdb
commands =
pytest {posargs} #{posargs:-n auto}
From 7711b928dc8c8e9e301ee8be774e67352034d46d Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 12:43:48 +0100
Subject: [PATCH 03/10] bump minimum flake8 version, and bump libcst version to
match reality
---
.github/workflows/ci.yml | 10 +++++-----
setup.py | 2 +-
tox.ini | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 924f919..d74bbb6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,11 +36,11 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
- run: |
- python -m pip install --upgrade pip setuptools tox
- python -m tox --notest --recreate -e flake8_5,flake8_6
- - name: Run tests
- run: python -m tox -e flake8_5,flake8_6
+ run: python -m pip install --upgrade pip setuptools tox
+ - name: Run tests with flake8_6
+ run: python -m tox -e flake8_6
+ - name: Run tests with flake8_7+
+ run: python -m tox -e flake8_7
slow_tests:
runs-on: ubuntu-latest
diff --git a/setup.py b/setup.py
index 22a26ed..bbc41fe 100755
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,7 @@ def local_file(name: str) -> Path:
license="MIT",
description="A highly opinionated flake8 plugin for Trio-related problems.",
zip_safe=False,
- install_requires=["flake8>=5", "libcst>=0.4"],
+ install_requires=["flake8>=6", "libcst>=1.0.1"],
python_requires=">=3.9",
classifiers=[
"Development Status :: 3 - Alpha",
diff --git a/tox.ini b/tox.ini
index c7fd716..fd02161 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,8 +8,8 @@ envlist = py{39,310,311,312}-{flake8_5,flake8_6}
[testenv]
description = Runs pytest, optionally with posargs
deps =
- flake8_6: flake8>=6.0
- flake8_5: flake8>=5.0,<6.0
+ flake8_7: flake8>=7.0
+ flake8_6: flake8>=6.0, <7.0
pytest
pytest-cov
pytest-xdist
From afdea1396594078c333e7cd24b86832ea45ee8d7 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 12:45:07 +0100
Subject: [PATCH 04/10] remove 3.13 from CI, pending hyposmith being importable
on it. Update tags in setup.py to specify we support 3.12
---
.github/workflows/ci.yml | 2 +-
setup.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d74bbb6..386b47c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
+ python-version: ['3.9', '3.10', '3.11', '3.12']
fail-fast: false
steps:
- uses: actions/checkout@v4
diff --git a/setup.py b/setup.py
index bbc41fe..a6bdf55 100755
--- a/setup.py
+++ b/setup.py
@@ -41,6 +41,7 @@ def local_file(name: str) -> Path:
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
],
long_description=(
local_file("README.md").open().read()
From 38d6281d3da23f679203799499eab0fd8bacffa6 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 12:46:54 +0100
Subject: [PATCH 05/10] start using pytest-xdist in CI, let's hope it's faster
than 90s
---
tox.ini | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tox.ini b/tox.ini
index fd02161..33d307d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,7 +17,7 @@ deps =
hypothesmith
trio
commands =
- pytest {posargs} #{posargs:-n auto}
+ pytest {posargs:-n auto}
# Settings for other tools
[pytest]
From dde4479842315a6a64f2f56d3875931ead9f0af3 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 15:09:51 +0100
Subject: [PATCH 06/10] use flake8_7 with CI --run-slow, fix typing issues
---
.github/workflows/ci.yml | 4 ++--
flake8_trio/visitors/helpers.py | 6 ++++--
flake8_trio/visitors/visitor_utility.py | 8 ++++++--
pyproject.toml | 1 +
tests/autofix_files/trio910.py | 2 ++
tests/eval_files/trio200.py | 4 ++--
tests/eval_files/trio910.py | 1 +
tests/eval_files/trio91x_noautofix.py | 5 ++++-
tests/test_changelog_and_version.py | 2 ++
9 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 386b47c..a76059d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -55,9 +55,9 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools tox
- python -m tox --notest --recreate -e flake8_6
+ python -m tox --notest --recreate -e flake8_7
- name: Run tests
- run: python -m tox -e flake8_6 -- --onlyfuzz --no-cov -n auto
+ run: python -m tox -e flake8_7 -- --onlyfuzz --no-cov -n auto
release:
runs-on: ubuntu-latest
diff --git a/flake8_trio/visitors/helpers.py b/flake8_trio/visitors/helpers.py
index 03b7eff..d953e2e 100644
--- a/flake8_trio/visitors/helpers.py
+++ b/flake8_trio/visitors/helpers.py
@@ -7,7 +7,7 @@
import ast
from fnmatch import fnmatch
-from typing import TYPE_CHECKING, NamedTuple, TypeVar
+from typing import TYPE_CHECKING, NamedTuple, TypeVar, Union
import libcst as cst
import libcst.matchers as m
@@ -29,7 +29,9 @@
T = TypeVar("T", bound=Flake8TrioVisitor)
T_CST = TypeVar("T_CST", bound=Flake8TrioVisitor_cst)
- T_EITHER = TypeVar("T_EITHER", bound=Flake8TrioVisitor | Flake8TrioVisitor_cst)
+ T_EITHER = TypeVar(
+ "T_EITHER", bound=Union[Flake8TrioVisitor, Flake8TrioVisitor_cst]
+ )
def error_class(error_class: type[T]) -> type[T]:
diff --git a/flake8_trio/visitors/visitor_utility.py b/flake8_trio/visitors/visitor_utility.py
index a2f31e7..35efe59 100644
--- a/flake8_trio/visitors/visitor_utility.py
+++ b/flake8_trio/visitors/visitor_utility.py
@@ -5,7 +5,7 @@
import ast
import functools
import re
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, cast
import libcst.matchers as m
from libcst.metadata import PositionProvider
@@ -17,6 +17,7 @@
from re import Match
import libcst as cst
+ from libcst._position import CodeRange
@utility_visitor
@@ -178,7 +179,10 @@ def visit_Comment(self, node: cst.Comment):
return False
codes_str = noqa_match.groupdict()["codes"]
- pos = self.get_metadata(PositionProvider, node).start
+
+ # see https://github.com/Instagram/LibCST/issues/1107
+ metadata = cast("CodeRange", self.get_metadata(PositionProvider, node))
+ pos = metadata.start
codes: set[str]
diff --git a/pyproject.toml b/pyproject.toml
index 579b6ed..38f6ec5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,6 +21,7 @@ skip_glob = "tests/eval_files/*"
[tool.mypy]
check_untyped_defs = true
disable_error_code = ["no-untyped-def", "misc", "no-untyped-call", "no-any-return"]
+python_version = "3.9"
strict = true
warn_unreachable = true
warn_unused_ignores = false
diff --git a/tests/autofix_files/trio910.py b/tests/autofix_files/trio910.py
index bd752dd..3e23199 100644
--- a/tests/autofix_files/trio910.py
+++ b/tests/autofix_files/trio910.py
@@ -1,5 +1,7 @@
# AUTOFIX
# mypy: disable-error-code="unreachable"
+from __future__ import annotations
+
import typing
from typing import Any, overload
diff --git a/tests/eval_files/trio200.py b/tests/eval_files/trio200.py
index 93ee5c5..7526ccb 100644
--- a/tests/eval_files/trio200.py
+++ b/tests/eval_files/trio200.py
@@ -37,10 +37,10 @@ async def afoo():
lambda: bar()
# check that states are properly set/reset on nested functions
- def bar():
+ def bar2():
bar()
- async def bar():
+ async def bar3():
bar() # TRIO200: 12, "bar", "BAR"
bar() # TRIO200: 4, "bar", "BAR"
diff --git a/tests/eval_files/trio910.py b/tests/eval_files/trio910.py
index c4aaa64..794744c 100644
--- a/tests/eval_files/trio910.py
+++ b/tests/eval_files/trio910.py
@@ -1,5 +1,6 @@
# AUTOFIX
# mypy: disable-error-code="unreachable"
+from __future__ import annotations
import typing
from typing import Any, overload
diff --git a/tests/eval_files/trio91x_noautofix.py b/tests/eval_files/trio91x_noautofix.py
index 1f29e62..652f3dd 100644
--- a/tests/eval_files/trio91x_noautofix.py
+++ b/tests/eval_files/trio91x_noautofix.py
@@ -2,6 +2,9 @@
from typing import Any
+def condition() -> Any: ...
+
+
async def foo() -> Any:
await foo()
@@ -40,7 +43,7 @@ async def foo_async_with_2():
# fmt: off
async def foo_boolops_3():
_ = (await foo() or (yield) or await foo()) or (
- ...
+ condition()
or (
(yield) # TRIO911: 13, "yield", Stmt("yield", line-3)
and (yield)) # TRIO911: 17, "yield", Stmt("yield", line-1)
diff --git a/tests/test_changelog_and_version.py b/tests/test_changelog_and_version.py
index 46358dd..2a53ad2 100755
--- a/tests/test_changelog_and_version.py
+++ b/tests/test_changelog_and_version.py
@@ -36,6 +36,8 @@ def __str__(self) -> str:
if m := re.match(r'__version__ = "(\d*\.\d*\.\d*)"', line):
VERSION = Version.from_string(m.groups()[0])
break
+else:
+ raise RuntimeError("No version detected.")
def get_releases() -> Iterable[Version]:
From fe2124ce87fb44f8a0ac18a4f96319abf99dc7ba Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 15:15:41 +0100
Subject: [PATCH 07/10] isort messed up autofix diff file
---
tests/eval_files/trio910.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/eval_files/trio910.py b/tests/eval_files/trio910.py
index 794744c..5a4c372 100644
--- a/tests/eval_files/trio910.py
+++ b/tests/eval_files/trio910.py
@@ -1,6 +1,7 @@
# AUTOFIX
# mypy: disable-error-code="unreachable"
from __future__ import annotations
+
import typing
from typing import Any, overload
From c124786326677b75cd93cc3521d68317444f1691 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Thu, 15 Feb 2024 15:25:30 +0100
Subject: [PATCH 08/10] bump default_language_version to 3.12 in
pre-commit-config
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index af32387..5297280 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
---
default_language_version:
- python: python3.11
+ python: python3.12
# pyright requires internet connection to run, which the pre-commit ci app doesn't have.
# Not used in this repo.
ci:
From 41539a0eafe1de8f087879098a0a0f9b1377338a Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Fri, 16 Feb 2024 13:38:12 +0100
Subject: [PATCH 09/10] remove unnecessary pyright: ignore
---
flake8_trio/visitors/flake8triovisitor.py | 6 ++----
pyproject.toml | 2 ++
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/flake8_trio/visitors/flake8triovisitor.py b/flake8_trio/visitors/flake8triovisitor.py
index 4c4bf48..fdf5bf8 100644
--- a/flake8_trio/visitors/flake8triovisitor.py
+++ b/flake8_trio/visitors/flake8triovisitor.py
@@ -23,9 +23,7 @@
class Flake8TrioVisitor(ast.NodeVisitor, ABC):
# abstract attribute by not providing a value
- error_codes: ClassVar[
- dict[str, str]
- ] # pyright: ignore[reportUninitializedInstanceVariable]
+ error_codes: ClassVar[dict[str, str]]
def __init__(self, shared_state: SharedState):
super().__init__()
@@ -160,7 +158,7 @@ def add_library(self, name: str) -> None:
class Flake8TrioVisitor_cst(cst.CSTTransformer, ABC):
# abstract attribute by not providing a value
- error_codes: dict[str, str] # pyright: ignore[reportUninitializedInstanceVariable]
+ error_codes: dict[str, str]
METADATA_DEPENDENCIES = (PositionProvider,)
def __init__(self, shared_state: SharedState):
diff --git a/pyproject.toml b/pyproject.toml
index 38f6ec5..f0a4e3b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,6 +34,8 @@ reportMissingSuperCall = true
reportPropertyTypeMismatch = true
reportShadowedImports = true
reportUninitializedInstanceVariable = true
+# can't enable until https://github.com/python/mypy/issues/12358
+reportUnnecessaryTypeIgnoreComment = false
reportUnusedCallResult = false
strict = ["*.py", "tests/*.py", "flake8_trio/**/*.py"]
From 6f0f574cf4fa85d284da2cdd327630099726710c Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Mon, 19 Feb 2024 09:32:57 +0100
Subject: [PATCH 10/10] foo-> bar in some test files, replace a couple
instances of flake8_5 I missed, add py313 support now that hypothesmith is
updated
---
.github/workflows/ci.yml | 2 +-
setup.py | 1 +
tests/autofix_files/trio91x_autofix.py | 16 ++++++++--------
tests/autofix_files/trio91x_autofix.py.diff | 8 ++++----
tests/eval_files/trio91x_autofix.py | 16 ++++++++--------
tox.ini | 7 ++++---
6 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a76059d..1368e30 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ['3.9', '3.10', '3.11', '3.12']
+ python-version: ['3.9', '3.10', '3.11', '3.12', 3.13-dev]
fail-fast: false
steps:
- uses: actions/checkout@v4
diff --git a/setup.py b/setup.py
index a6bdf55..86db921 100755
--- a/setup.py
+++ b/setup.py
@@ -42,6 +42,7 @@ def local_file(name: str) -> Path:
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
],
long_description=(
local_file("README.md").open().read()
diff --git a/tests/autofix_files/trio91x_autofix.py b/tests/autofix_files/trio91x_autofix.py
index 685608c..aa58e88 100644
--- a/tests/autofix_files/trio91x_autofix.py
+++ b/tests/autofix_files/trio91x_autofix.py
@@ -38,10 +38,10 @@ async def foo_yield(): # TRIO911: 0, "exit", Statement("yield", lineno+2)
async def foo_if():
- if foo():
+ if bar():
await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif foo():
+ elif bar():
await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
@@ -66,7 +66,7 @@ async def foo_while2():
async def foo_while3():
await foo()
while True:
- if foo():
+ if bar():
return
await foo()
@@ -74,10 +74,10 @@ async def foo_while3():
# check that multiple checkpoints don't get inserted
async def foo_while4():
while True:
- if foo():
+ if bar():
await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if foo():
+ if bar():
await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
@@ -102,7 +102,7 @@ async def foo_while_nested_func():
yield # TRIO911: 8, "yield", Statement("function definition", lineno-2) # TRIO911: 8, "yield", Statement("yield", lineno)
async def bar():
- while foo():
+ while bar():
...
await foo()
@@ -116,10 +116,10 @@ async def async_func(): ...
...
except:
...
- if foo() and foo():
+ if bar() and bar():
...
while ...:
- if foo():
+ if bar():
continue
break
[... for i in range(5)]
diff --git a/tests/autofix_files/trio91x_autofix.py.diff b/tests/autofix_files/trio91x_autofix.py.diff
index 08a2ea8..3b22f13 100644
--- a/tests/autofix_files/trio91x_autofix.py.diff
+++ b/tests/autofix_files/trio91x_autofix.py.diff
@@ -29,10 +29,10 @@
async def foo_if():
- if foo():
+ if bar():
+ await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif foo():
+ elif bar():
+ await trio.lowlevel.checkpoint()
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
@@ -50,10 +50,10 @@
@@ x,8 x,10 @@
async def foo_while4():
while True:
- if foo():
+ if bar():
+ await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if foo():
+ if bar():
+ await trio.lowlevel.checkpoint()
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
diff --git a/tests/eval_files/trio91x_autofix.py b/tests/eval_files/trio91x_autofix.py
index c523ffb..78b3fc4 100644
--- a/tests/eval_files/trio91x_autofix.py
+++ b/tests/eval_files/trio91x_autofix.py
@@ -33,9 +33,9 @@ async def foo_yield(): # TRIO911: 0, "exit", Statement("yield", lineno+2)
async def foo_if():
- if foo():
+ if bar():
return # TRIO910: 8, "return", Statement("function definition", lineno-2)
- elif foo():
+ elif bar():
return # TRIO910: 8, "return", Statement("function definition", lineno-4)
else:
return # TRIO910: 8, "return", Statement("function definition", lineno-6)
@@ -57,7 +57,7 @@ async def foo_while2():
async def foo_while3():
await foo()
while True:
- if foo():
+ if bar():
return
await foo()
@@ -65,9 +65,9 @@ async def foo_while3():
# check that multiple checkpoints don't get inserted
async def foo_while4():
while True:
- if foo():
+ if bar():
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno+2) # TRIO911: 12, "yield", Statement("function definition", lineno-3)
- if foo():
+ if bar():
yield # TRIO911: 12, "yield", Statement("yield", lineno) # TRIO911: 12, "yield", Statement("yield", lineno-2) # TRIO911: 12, "yield", Statement("function definition", lineno-5) # TRIO911: 12, "yield", Statement("yield", lineno-2)
# this warns about the yield on lineno-2 twice, since it can arrive here from it in two different ways
@@ -87,7 +87,7 @@ async def foo_while_nested_func():
yield # TRIO911: 8, "yield", Statement("function definition", lineno-2) # TRIO911: 8, "yield", Statement("yield", lineno)
async def bar():
- while foo():
+ while bar():
...
await foo()
@@ -101,10 +101,10 @@ async def async_func(): ...
...
except:
...
- if foo() and foo():
+ if bar() and bar():
...
while ...:
- if foo():
+ if bar():
continue
break
[... for i in range(5)]
diff --git a/tox.ini b/tox.ini
index 33d307d..1222de8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,10 @@
# The test environment and commands
[tox]
# default environments to run without `-e`
-envlist = py{39,310,311,312}-{flake8_5,flake8_6}
+envlist = py{39,310,311,312,313}-{flake8_6,flake8_7}
# create a default testenv, whose behaviour will depend on the name it's called with.
-# for CI you can call with `-e flake8_5,flake8_6` and let the CI handle python version
+# for CI you can call with `-e flake8_6,flake8_7` and let the CI handle python version
[testenv]
description = Runs pytest, optionally with posargs
deps =
@@ -14,7 +14,8 @@ deps =
pytest-cov
pytest-xdist
hypothesis
- hypothesmith
+ # 0.3.3 adds py313 support
+ hypothesmith >= 0.3.3
trio
commands =
pytest {posargs:-n auto}