Skip to content

Commit 4245668

Browse files
authored
102 now also checks __aexit__ (#306)
* 102 now also checks __aexit__
1 parent b94c04c commit 4245668

File tree

7 files changed

+23
-5
lines changed

7 files changed

+23
-5
lines changed

docs/changelog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Changelog
44

55
`CalVer, YY.month.patch <https://calver.org/>`_
66

7+
24.10.2
8+
=======
9+
- :ref:`ASYNC102 <async102>` now also warns about ``await()`` inside ``__aexit__``.
10+
711
24.10.1
812
=======
913
- Add :ref:`ASYNC123 <async123>` bad-exception-group-flattening

docs/rules.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ ASYNC101 : yield-in-cancel-scope
2121
This has substantial overlap with :ref:`ASYNC119 <ASYNC119>`, which will warn on almost all instances of ASYNC101, but ASYNC101 is about a conceptually different problem that will not get resolved by `PEP 533 <https://peps.python.org/pep-0533/>`_.
2222

2323
_`ASYNC102` : await-in-finally-or-cancelled
24-
``await`` inside ``finally`` or :ref:`cancelled-catching <cancelled>` ``except:`` must have shielded :ref:`cancel scope <cancel_scope>` with timeout.
25-
If not, the async call will immediately raise a new cancellation, suppressing the cancellation that was caught.
24+
``await`` inside ``finally``, :ref:`cancelled-catching <cancelled>` ``except:``, or ``__aexit__`` must have shielded :ref:`cancel scope <cancel_scope>` with timeout.
25+
If not, the async call will immediately raise a new cancellation, suppressing any cancellation that was caught.
2626
See :ref:`ASYNC120 <async120>` for the general case where other exceptions might get suppressed.
2727
This is currently not able to detect asyncio shields.
2828

flake8_async/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939

4040
# CalVer: YY.month.patch, e.g. first release of July 2022 == "22.7.1"
41-
__version__ = "24.10.1"
41+
__version__ = "24.10.2"
4242

4343

4444
# taken from https://github.com/Zac-HD/shed

flake8_async/visitors/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
visitor2xx,
3232
visitor91x,
3333
visitor101,
34-
visitor102,
34+
visitor102_120,
3535
visitor103_104,
3636
visitor105,
3737
visitor111,

flake8_async/visitors/visitor102.py flake8_async/visitors/visitor102_120.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""Visitor102, which warns on unprotected `await` inside `finally`.
1+
"""Contains Visitor102 with ASYNC102 and ASYNC120.
2+
3+
ASYNC102: await-in-finally-or-cancelled
4+
ASYNC120: await-in-except
5+
26
37
To properly protect they must be inside a shielded cancel scope with a timeout.
48
"""
@@ -222,6 +226,10 @@ def visit_FunctionDef(
222226

223227
self._potential_120 = []
224228

229+
# lambda doesn't have `name` attribute
230+
if getattr(node, "name", None) == "__aexit__":
231+
self._critical_scope = Statement("__aexit__", node.lineno, node.col_offset)
232+
225233
visit_AsyncFunctionDef = visit_FunctionDef
226234
# lambda can't contain await, try, except, raise, with, or assignments.
227235
# You also can't do assignment expressions with attributes. So we don't need to

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ ignore = [
6565
"D105",
6666
"D106",
6767
"D107",
68+
"D400", # ends-in-period, stricter version of ends-in-punctuation
6869
"S101",
6970
"D203", # one-blank-line-before-class
7071
"D213", # multi-line-summary-second-line

tests/eval_files/async102.py

+5
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,8 @@ async def foo_nested_cs():
304304
await foo() # error: 12, Statement("bare except", lineno-12)
305305
cs1.shield = True
306306
await foo()
307+
308+
309+
# treat __aexit__ as a critical scope
310+
async def __aexit__():
311+
await foo() # error: 4, Statement("__aexit__", lineno-1)

0 commit comments

Comments
 (0)