Skip to content

[flake8-async] Implement yield-in-context-manager-in-async-generator (ASYNC119)#24644

Merged
ntBre merged 7 commits into
astral-sh:mainfrom
loganrosen:loganrosen/feat/async119
Jun 4, 2026
Merged

[flake8-async] Implement yield-in-context-manager-in-async-generator (ASYNC119)#24644
ntBre merged 7 commits into
astral-sh:mainfrom
loganrosen:loganrosen/feat/async119

Conversation

@loganrosen

Copy link
Copy Markdown
Contributor

Summary

Implement ASYNC119 from flake8-async, which detects yield inside a context manager (with or async with) in an async generator function.

This pattern is unsafe because the cleanup of the context manager may be delayed until the generator is closed, at which point await is no longer allowed. This can lead to resource leaks, RuntimeErrors from structured concurrency violations, or other bugs. See PEP 533 for details.

The rule suppresses warnings for functions decorated with:

  • @contextlib.asynccontextmanager
  • @pytest.fixture
  • @pytest_asyncio.fixture

These decorators are known to handle async generator cleanup safely.

Part of #8451

Test plan

  • Added test fixture with error and OK cases
  • Snapshot tests pass
  • cargo dev generate-all run
  • uvx prek run -a passes
  • Tested against a real 500k+ LOC codebase — 56 true positive findings, no false positives

…` (ASYNC119)

## Summary

Implement ASYNC119 from flake8-async, which detects `yield` inside a
context manager (`with` or `async with`) in an async generator function.

This pattern is unsafe because the cleanup of the context manager may be
delayed until the generator is closed, at which point `await` is no
longer allowed. This can lead to resource leaks, RuntimeErrors from
structured concurrency violations, or other bugs. See PEP 533 for
details.

The rule suppresses warnings for functions decorated with:
- `@contextlib.asynccontextmanager`
- `@pytest.fixture`
- `@pytest_asyncio.fixture`

These decorators are known to handle async generator cleanup safely.

Part of astral-sh#8451

## Test Plan

Added test fixture covering:
- Yields inside `with` and `async with` blocks (errors)
- Multiple yields per context manager (errors)
- Nested `with` blocks (errors)
- Yields outside context managers (ok)
- Yields in nested sync/async functions (ok, scope boundary)
- `@asynccontextmanager`-decorated functions (ok)
- `@pytest.fixture`-decorated functions (ok)
- `@pytest_asyncio.fixture`-decorated functions (ok)
- Sync generators (ok)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@astral-sh-bot astral-sh-bot Bot requested a review from ntBre April 14, 2026 21:59

@ntBre ntBre left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks reasonable to me from a really quick skim. I still need to do a full review, but I found a couple of nits while reading through to approve the workflows.

Comment thread crates/ruff_linter/src/checkers/ast/analyze/expression.rs Outdated
Comment thread crates/ruff_linter/src/rules/flake8_async/rules/yield_in_cm_in_async_generator.rs Outdated
@ntBre ntBre added rule Implementing or modifying a lint rule preview Related to preview mode features labels Apr 14, 2026
@astral-sh-bot

astral-sh-bot Bot commented Apr 14, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

loganrosen and others added 2 commits April 14, 2026 22:54
- Rename yield_in_cm_in_async_gen -> yield_in_context_manager_in_async_generator
- Use NEXT_RUFF_VERSION instead of hardcoded 0.15.10
- Fix clippy unnested-or-patterns by nesting pytest/pytest_asyncio

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rewrite doc string to distinguish single-yield (context manager) vs
  multi-yield (true async generator) cases with clear caveats
- Update diagnostic message to match flake8-async style
- Add trio.as_safe_channel to references

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@ntBre ntBre left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks good to me! I just had a few minor suggestions about the docs and diagnostic.

@ntBre ntBre changed the title [flake8-async] Implement yield-in-context-manager-in-async-generator (ASYNC119) [flake8-async] Implement yield-in-context-manager-in-async-generator (ASYNC119) May 18, 2026
loganrosen and others added 4 commits June 3, 2026 22:44
- Split violation message into message() + fix_title()
- Add 'Known problems' section documenting aclosing() and pytest limitations
- Fix reference link format for aclosing()
- Simplify lifetime on enclosing_async_function helper

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@ntBre ntBre left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I pushed a couple of small docs tweaks, but this looks good to me.

@ntBre ntBre merged commit e51e132 into astral-sh:main Jun 4, 2026
45 checks passed
ntBre added a commit that referenced this pull request Jun 8, 2026
Summary
--

I noticed while extending the regex to match human-readable names that
it also didn't cover the
ASYNC rules, which have five letters in the rule code. For example,
#24644 revealed no new
diagnostics in the ecosystem, but a local run on my cached ecosystem
repos revealed many
diagnostics. This won't show up as a diff in CI on this PR but should
help with ecosystem checks on
the ASYNC rules in the future.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Related to preview mode features rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants