From 469523792af946da2fa6ae44f17f6238f2c07779 Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Fri, 25 Oct 2024 16:52:16 +0200
Subject: [PATCH 1/2] 102 now also checks __aexit__
---
docs/changelog.rst | 4 ++++
docs/rules.rst | 4 ++--
flake8_async/__init__.py | 2 +-
flake8_async/visitors/__init__.py | 2 +-
.../visitors/{visitor102.py => visitor102_120.py} | 10 +++++++++-
pyproject.toml | 1 +
tests/eval_files/async102.py | 5 +++++
7 files changed, 23 insertions(+), 5 deletions(-)
rename flake8_async/visitors/{visitor102.py => visitor102_120.py} (96%)
diff --git a/docs/changelog.rst b/docs/changelog.rst
index d81bb8af..41b4d2bd 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,6 +4,10 @@ Changelog
`CalVer, YY.month.patch `_
+24.10.2
+=======
+- :ref:`ASYNC102` ` now also warns about ``await()`` inside ``__aexit__``.
+
24.10.1
=======
- Add :ref:`ASYNC123 ` bad-exception-group-flattening
diff --git a/docs/rules.rst b/docs/rules.rst
index c3c8edbc..c3b7566d 100644
--- a/docs/rules.rst
+++ b/docs/rules.rst
@@ -21,8 +21,8 @@ ASYNC101 : yield-in-cancel-scope
This has substantial overlap with :ref:`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 `_.
_`ASYNC102` : await-in-finally-or-cancelled
- ``await`` inside ``finally`` or :ref:`cancelled-catching ` ``except:`` must have shielded :ref:`cancel scope ` with timeout.
- If not, the async call will immediately raise a new cancellation, suppressing the cancellation that was caught.
+ ``await`` inside ``finally``, :ref:`cancelled-catching ` ``except:``, or ``__aexit__`` must have shielded :ref:`cancel scope ` with timeout.
+ If not, the async call will immediately raise a new cancellation, suppressing any cancellation that was caught.
See :ref:`ASYNC120 ` for the general case where other exceptions might get suppressed.
This is currently not able to detect asyncio shields.
diff --git a/flake8_async/__init__.py b/flake8_async/__init__.py
index b9bbaf99..83c5d570 100644
--- a/flake8_async/__init__.py
+++ b/flake8_async/__init__.py
@@ -38,7 +38,7 @@
# CalVer: YY.month.patch, e.g. first release of July 2022 == "22.7.1"
-__version__ = "24.10.1"
+__version__ = "24.10.2"
# taken from https://github.com/Zac-HD/shed
diff --git a/flake8_async/visitors/__init__.py b/flake8_async/visitors/__init__.py
index f1b61995..652e8850 100644
--- a/flake8_async/visitors/__init__.py
+++ b/flake8_async/visitors/__init__.py
@@ -31,7 +31,7 @@
visitor2xx,
visitor91x,
visitor101,
- visitor102,
+ visitor102_120,
visitor103_104,
visitor105,
visitor111,
diff --git a/flake8_async/visitors/visitor102.py b/flake8_async/visitors/visitor102_120.py
similarity index 96%
rename from flake8_async/visitors/visitor102.py
rename to flake8_async/visitors/visitor102_120.py
index e1837cb9..61f1e32f 100644
--- a/flake8_async/visitors/visitor102.py
+++ b/flake8_async/visitors/visitor102_120.py
@@ -1,4 +1,8 @@
-"""Visitor102, which warns on unprotected `await` inside `finally`.
+"""Contains Visitor102 with ASYNC102 and ASYNC120.
+
+ASYNC102: await-in-finally-or-cancelled
+ASYNC120: await-in-except
+
To properly protect they must be inside a shielded cancel scope with a timeout.
"""
@@ -222,6 +226,10 @@ def visit_FunctionDef(
self._potential_120 = []
+ # lambda doesn't have `name` attribute
+ if getattr(node, "name", None) == "__aexit__":
+ self._critical_scope = Statement("__aexit__", node.lineno, node.col_offset)
+
visit_AsyncFunctionDef = visit_FunctionDef
# lambda can't contain await, try, except, raise, with, or assignments.
# You also can't do assignment expressions with attributes. So we don't need to
diff --git a/pyproject.toml b/pyproject.toml
index 8d49c151..b48579e3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -65,6 +65,7 @@ ignore = [
"D105",
"D106",
"D107",
+ "D400", # ends-in-period, stricter version of ends-in-punctuation
"S101",
"D203", # one-blank-line-before-class
"D213", # multi-line-summary-second-line
diff --git a/tests/eval_files/async102.py b/tests/eval_files/async102.py
index 732fd7a7..a52333b6 100644
--- a/tests/eval_files/async102.py
+++ b/tests/eval_files/async102.py
@@ -304,3 +304,8 @@ async def foo_nested_cs():
await foo() # error: 12, Statement("bare except", lineno-12)
cs1.shield = True
await foo()
+
+
+# treat __aexit__ as a critical scope
+async def __aexit__():
+ await foo() # error: 4, Statement("__aexit__", lineno-1)
From ae78aa43e274cd421aa568b0f0212a96c69d652f Mon Sep 17 00:00:00 2001
From: John Litborn <11260241+jakkdl@users.noreply.github.com>
Date: Mon, 28 Oct 2024 13:37:03 +0100
Subject: [PATCH 2/2] Update docs/changelog.rst
---
docs/changelog.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 41b4d2bd..2672b087 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -6,7 +6,7 @@ Changelog
24.10.2
=======
-- :ref:`ASYNC102` ` now also warns about ``await()`` inside ``__aexit__``.
+- :ref:`ASYNC102 ` now also warns about ``await()`` inside ``__aexit__``.
24.10.1
=======