diff --git a/docs/changelog.rst b/docs/changelog.rst index 87b7b726..f306eea6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,11 @@ Changelog `CalVer, YY.month.patch `_ +24.9.2 +====== +- Fix false alarm in :ref:`ASYNC113 ` and :ref:`ASYNC121 ` with sync functions nested inside an async function. + + 24.9.1 ====== - Add :ref:`ASYNC121 ` control-flow-in-taskgroup diff --git a/flake8_async/__init__.py b/flake8_async/__init__.py index d4827f86..6ac873fc 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.9.1" +__version__ = "24.9.2" # taken from https://github.com/Zac-HD/shed diff --git a/flake8_async/visitors/visitors.py b/flake8_async/visitors/visitors.py index 6d9ca23f..ec7ee1d5 100644 --- a/flake8_async/visitors/visitors.py +++ b/flake8_async/visitors/visitors.py @@ -188,6 +188,11 @@ def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef): node, "asynccontextmanager" ) + def visit_FunctionDef(self, node: ast.FunctionDef): + self.save_state(node, "aenter") + # sync function should never be named __aenter__ or have @asynccontextmanager + self.aenter = False + def visit_Yield(self, node: ast.Yield): self.aenter = False @@ -398,10 +403,12 @@ def visit_Return(self, node: ast.Return) -> None: if unsafe_cm in self.unsafe_stack: self.error(node, "return", unsafe_cm) - def visit_FunctionDef(self, node: ast.FunctionDef): + def visit_FunctionDef(self, node: ast.FunctionDef | ast.AsyncFunctionDef): self.save_state(node, "unsafe_stack", copy=True) self.unsafe_stack = [] + visit_AsyncFunctionDef = visit_FunctionDef + @error_class_cst class Visitor300(Flake8AsyncVisitor_cst): diff --git a/tests/eval_files/async113.py b/tests/eval_files/async113.py index ebddc5be..22fedc28 100644 --- a/tests/eval_files/async113.py +++ b/tests/eval_files/async113.py @@ -105,3 +105,13 @@ async def __aenter__(self): async def __aexit__(self, *args): assert self.moo is not None await self.nursery_manager.__aexit__(*args) + + +@asynccontextmanager +async def foo_nested_sync_def(): + with trio.open_nursery() as bar: + + def non_async_func(): + bar.start_soon(trio.run_process) + + yield diff --git a/tests/eval_files/async121.py b/tests/eval_files/async121.py index 78a6b6c4..b55f21b9 100644 --- a/tests/eval_files/async121.py +++ b/tests/eval_files/async121.py @@ -30,6 +30,9 @@ async def foo_return_nested(): def bar(): return # safe + async def bar(): + return # safe + async def foo_while_safe(): async with trio.open_nursery():