Skip to content

Commit 791fc88

Browse files
committed
Only flag __aenter__ when neither CM method checkpoints
When both `__aenter__` and `__aexit__` are defined and neither contains a checkpoint, we used to flag (and autofix) both methods, which produced redundant `lowlevel.checkpoint()` calls -- only one is needed for the async context manager to checkpoint. Prefer to report and fix `__aenter__` in this case; `__aexit__` is exempted since adding a checkpoint to either satisfies the rule. https://claude.ai/code/session_014jAydKywq31Ew4fVYGJdiG
1 parent f2968d4 commit 791fc88

4 files changed

Lines changed: 14 additions & 15 deletions

File tree

flake8_async/visitors/visitor91x.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -590,12 +590,16 @@ def _is_exempt_async_cm_method(self, node: cst.FunctionDef) -> bool:
590590
if self.async_cm_class[name]:
591591
return False
592592
partner = "__aexit__" if name == "__aenter__" else "__aenter__"
593-
if partner not in self.async_cm_class:
594-
# Partner is not defined on this class; only assume it is inherited
595-
# (and contains a checkpoint) if the class inherits from something.
596-
return self.async_cm_class_has_bases
597-
# Partner defined; exempt iff it contains a checkpoint.
598-
return self.async_cm_class[partner]
593+
if partner in self.async_cm_class:
594+
# Partner is defined on the class; if it checkpoints, we're fine.
595+
if self.async_cm_class[partner]:
596+
return True
597+
# Neither method checkpoints -- to avoid double-flagging (and a
598+
# redundant autofix), we report and fix only `__aenter__`.
599+
return name == "__aexit__"
600+
# Partner is not defined on this class; only assume it is inherited
601+
# (and contains a checkpoint) if the class inherits from something.
602+
return self.async_cm_class_has_bases
599603

600604
def visit_FunctionDef(self, node: cst.FunctionDef) -> bool:
601605
# `await` in default values happen in parent scope

tests/autofix_files/async910.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,9 +674,8 @@ async def __aenter__(self): # error: 4, "exit", Stmt("function definition", lin
674674
print("setup")
675675
await trio.lowlevel.checkpoint()
676676

677-
async def __aexit__(self, *a): # error: 4, "exit", Stmt("function definition", line)
677+
async def __aexit__(self, *a): # only __aenter__ is flagged to avoid redundancy
678678
print("teardown")
679-
await trio.lowlevel.checkpoint()
680679
# fmt: on
681680

682681

tests/autofix_files/async910.py.diff

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,18 +223,14 @@
223223

224224

225225
async def foo_nested_empty_async():
226-
@@ x,9 x,11 @@
226+
@@ x,6 x,7 @@
227227
class CtxNeitherCheckpoint:
228228
async def __aenter__(self): # error: 4, "exit", Stmt("function definition", line)
229229
print("setup")
230230
+ await trio.lowlevel.checkpoint()
231231

232-
async def __aexit__(self, *a): # error: 4, "exit", Stmt("function definition", line)
232+
async def __aexit__(self, *a): # only __aenter__ is flagged to avoid redundancy
233233
print("teardown")
234-
+ await trio.lowlevel.checkpoint()
235-
# fmt: on
236-
237-
238234
@@ x,6 x,7 @@
239235
async def __aenter__(self): # error: 4, "exit", Stmt("function definition", line)
240236
if _:

tests/eval_files/async910.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ class CtxNeitherCheckpoint:
643643
async def __aenter__(self): # error: 4, "exit", Stmt("function definition", line)
644644
print("setup")
645645

646-
async def __aexit__(self, *a): # error: 4, "exit", Stmt("function definition", line)
646+
async def __aexit__(self, *a): # only __aenter__ is flagged to avoid redundancy
647647
print("teardown")
648648
# fmt: on
649649

0 commit comments

Comments
 (0)