Skip to content

Commit 1db72de

Browse files
drop python3.9, add+fix testing for 3.14 (#416)
* drop python3.9, add+fix testing for 3.14 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix Union -> | * optional is intended for testing --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c2acb89 commit 1db72de

24 files changed

+327
-352
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ jobs:
1313
pyright:
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v5
1717
- name: Set up Python
18-
uses: actions/setup-python@v5
18+
uses: actions/setup-python@v6
1919
with:
2020
cache: pip
2121
- name: Install typing dependencies
@@ -30,14 +30,15 @@ jobs:
3030
runs-on: ubuntu-latest
3131
strategy:
3232
matrix:
33-
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
33+
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
3434
fail-fast: false
3535
steps:
36-
- uses: actions/checkout@v4
36+
- uses: actions/checkout@v5
3737
- name: Set up Python ${{ matrix.python-version }}
38-
uses: actions/setup-python@v5
38+
uses: actions/setup-python@v6
3939
with:
4040
python-version: ${{ matrix.python-version }}
41+
allow-prereleases: true
4142
- name: Install dependencies
4243
run: python -m pip install --upgrade pip setuptools tox
4344
- name: Run tests with flake8
@@ -50,11 +51,11 @@ jobs:
5051
strategy:
5152
fail-fast: false
5253
steps:
53-
- uses: actions/checkout@v4
54-
- name: Set up Python 3.13
55-
uses: actions/setup-python@v5
54+
- uses: actions/checkout@v5
55+
- name: Set up Python 3.14
56+
uses: actions/setup-python@v6
5657
with:
57-
python-version: 3.13
58+
python-version: 3.14
5859
- name: Install dependencies
5960
run: |
6061
python -m pip install --upgrade pip setuptools tox
@@ -67,9 +68,9 @@ jobs:
6768
needs: [pyright, test]
6869
if: github.repository == 'python-trio/flake8-async' && github.ref == 'refs/heads/main'
6970
steps:
70-
- uses: actions/checkout@v4
71-
- name: Set up Python 3
72-
uses: actions/setup-python@v5
71+
- uses: actions/checkout@v5
72+
- name: Set up Python
73+
uses: actions/setup-python@v6
7374
- name: Install tools
7475
run: python -m pip install --upgrade build pip setuptools wheel twine gitpython
7576
- name: Upload new release

.pre-commit-config.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ repos:
2929
rev: v3.21.0
3030
hooks:
3131
- id: pyupgrade
32-
args: [--py39-plus]
33-
exclude: tests/eval_files/async103.py
32+
args: [--py310-plus]
33+
# async232 explicitly tests Optional[]
34+
exclude: tests/eval_files/async(103|232|232_asyncio).py
3435

3536
- repo: https://github.com/pycqa/isort
3637
rev: 7.0.0
@@ -41,8 +42,8 @@ repos:
4142
rev: v1.18.2
4243
hooks:
4344
- id: mypy
44-
# uses py311 syntax, mypy configured for py39
45-
exclude: tests/(eval|autofix)_files/.*_py(310|311).py
45+
# uses py311 syntax, mypy configured for py310
46+
exclude: tests/(eval|autofix)_files/.*_py311.py
4647

4748
- repo: https://github.com/RobertCraigie/pyright-python
4849
rev: v1.1.407

flake8_async/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ def from_source(
151151
) -> Plugin:
152152
plugin = Plugin.__new__(cls)
153153
super(Plugin, plugin).__init__()
154-
plugin._tree = ast.parse(source)
154+
plugin._tree = ast.parse(
155+
source, filename=str(filename) if filename is not None else "<unknown>"
156+
)
155157
plugin.filename = str(filename) if filename else None
156158
plugin.module = cst_parse_module_native(source)
157159
return plugin

flake8_async/visitors/flake8asyncvisitor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import ast
66
from abc import ABC
7-
from typing import TYPE_CHECKING, Any, Union
7+
from typing import TYPE_CHECKING, Any
88

99
import libcst as cst
1010
from libcst.metadata import PositionProvider
@@ -16,7 +16,7 @@
1616

1717
from ..runner import SharedState
1818

19-
HasLineCol = Union[ast.expr, ast.stmt, ast.arg, ast.excepthandler, Statement]
19+
HasLineCol = ast.expr | ast.stmt | ast.arg | ast.excepthandler | Statement
2020

2121

2222
class Flake8AsyncVisitor(ast.NodeVisitor, ABC):

flake8_async/visitors/helpers.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from collections.abc import Sized
1010
from dataclasses import dataclass
1111
from fnmatch import fnmatch
12-
from typing import TYPE_CHECKING, Generic, TypeVar, Union
12+
from typing import TYPE_CHECKING, Generic, TypeVar
1313

1414
import libcst as cst
1515
import libcst.matchers as m
@@ -35,11 +35,9 @@
3535

3636
T = TypeVar("T", bound=Flake8AsyncVisitor)
3737
T_CST = TypeVar("T_CST", bound=Flake8AsyncVisitor_cst)
38-
T_EITHER = TypeVar(
39-
"T_EITHER", bound=Union[Flake8AsyncVisitor, Flake8AsyncVisitor_cst]
40-
)
38+
T_EITHER = TypeVar("T_EITHER", bound=Flake8AsyncVisitor | Flake8AsyncVisitor_cst)
4139

42-
T_Call = TypeVar("T_Call", bound=Union[cst.Call, ast.Call])
40+
T_Call = TypeVar("T_Call", bound=cst.Call | ast.Call)
4341

4442

4543
def error_class(error_class: type[T]) -> type[T]:

flake8_async/visitors/visitor91x.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,12 @@ class LoopState:
166166
default_factory=set[Statement]
167167
)
168168
uncheckpointed_before_break: set[Statement] = field(default_factory=set[Statement])
169-
# pyright emits reportUnknownVariableType, requiring the generic to default_factory
170-
# to be specified.
171-
# But for these we require a union, and `|` doesn't work on py39, and uses of
172-
# `Union` gets autofixed by ruff.
173-
# So.... let's just ignore the error for now
174-
artificial_errors: set[ # pyright: ignore[reportUnknownVariableType]
175-
cst.Return | cst.Yield
176-
] = field(default_factory=set)
177-
nodes_needing_checkpoints: list[ # pyright: ignore[reportUnknownVariableType]
178-
cst.Return | cst.Yield | ArtificialStatement
179-
] = field(default_factory=list)
169+
artificial_errors: set[cst.Return | cst.Yield] = field(
170+
default_factory=set[cst.Return | cst.Yield]
171+
)
172+
nodes_needing_checkpoints: list[cst.Return | cst.Yield | ArtificialStatement] = (
173+
field(default_factory=list[cst.Return | cst.Yield | ArtificialStatement])
174+
)
180175

181176
def copy(self):
182177
return LoopState(

flake8_async/visitors/visitors.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ def visit_With(self, node: ast.With | ast.AsyncWith):
128128
nursery_type = "task group"
129129
start_methods = ("create_task",)
130130
else:
131-
# incorrectly marked as not covered on py39
132-
continue # pragma: no cover # https://github.com/nedbat/coveragepy/issues/198
131+
continue
133132

134133
body_call = node.body[0].value
135134
if isinstance(body_call, ast.Await):

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ skip_glob = "tests/*_files/*"
5454
[tool.mypy]
5555
check_untyped_defs = true
5656
disable_error_code = ["no-untyped-def", "misc", "no-untyped-call", "no-any-return"]
57-
python_version = "3.9"
57+
python_version = "3.10"
5858
strict = true
5959
warn_unreachable = true
6060
warn_unused_ignores = false
@@ -84,7 +84,7 @@ extend-exclude = [
8484
"tests/autofix_files/*"
8585
]
8686
line-length = 90
87-
target-version = "py39"
87+
target-version = "py310"
8888

8989
[tool.ruff.lint]
9090
ignore = [

tests/autofix_files/async910.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -430,23 +430,24 @@ async def try_bare_except_reraises():
430430
...
431431

432432

433-
async def return_in_finally_bare_except_checkpoint():
434-
try:
435-
await trio.sleep(0)
436-
except:
437-
await trio.sleep(0)
438-
finally:
439-
return
440-
441-
442-
async def return_in_finally_bare_except_empty():
443-
try:
444-
await trio.sleep(0)
445-
except:
446-
...
447-
finally:
448-
await trio.lowlevel.checkpoint()
449-
return # error: 8, 'return', Statement('function definition', lineno-6)
433+
# return in finally is a SyntaxError on py314. We currently don't have
434+
# test infra to set a max python version for an eval file.
435+
# async def return_in_finally_bare_except_checkpoint():
436+
# try:
437+
# await trio.sleep(0)
438+
# except:
439+
# await trio.sleep(0)
440+
# finally:
441+
# return
442+
#
443+
#
444+
# async def return_in_finally_bare_except_empty():
445+
# try:
446+
# await trio.sleep(0)
447+
# except:
448+
# ...
449+
# finally:
450+
# return # error: 8, 'return', Statement('function definition', lineno-6)
450451

451452

452453
# early return

tests/autofix_files/async910.py.diff

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,7 @@
154154

155155

156156
# safe
157-
@@ x,16 x,19 @@
158-
except:
159-
...
160-
finally:
161-
+ await trio.lowlevel.checkpoint()
162-
return # error: 8, 'return', Statement('function definition', lineno-6)
163-
157+
@@ x,11 x,13 @@
164158

165159
# early return
166160
async def foo_return_1():

0 commit comments

Comments
 (0)