Skip to content

ASYNC101: cover the practical set of 3rd-party CMs with cancel scopes#449

Merged
Zac-HD merged 4 commits intopython-trio:mainfrom
Zac-HD:claude/fix-flake8-async-350-BswDi
Apr 24, 2026
Merged

ASYNC101: cover the practical set of 3rd-party CMs with cancel scopes#449
Zac-HD merged 4 commits intopython-trio:mainfrom
Zac-HD:claude/fix-flake8-async-350-BswDi

Conversation

@Zac-HD
Copy link
Copy Markdown
Member

@Zac-HD Zac-HD commented Apr 23, 2026

Fixes #350.

Also fixes build_cst_matcher to handle bases with 3+ dotted components, and exempts <>.lowlevel.cancel_shielded_checkpoint() from ASYNC120 (#446 (comment)).

claude added 4 commits April 23, 2026 21:20
Replaces the earlier httpx/httpx_ws additions (which use bare
asyncio.create_task internally and don't actually open a cancel scope
across the body) with the verified set of structured-concurrency CMs:

  trio_websocket.{open_websocket, open_websocket_url, serve_websocket}
  trio_asyncio.open_loop
  trio_parallel.open_worker_context
  trio_util.{move_on_when, run_and_cancelling}
  qtrio.{open_emissions_nursery, enter_emissions_channel}
  anyio.from_thread.{BlockingPortal, start_blocking_portal}
  asgi_lifespan.LifespanManager
  apscheduler.AsyncScheduler
  mcp.client.streamable_http.streamablehttp_client
  mcp.client.sse.sse_client

Also fixes build_cst_matcher to handle bases with 3+ dotted components
(it previously crashed on `mcp.client.streamable_http`).
`calls_any_of(node, *qualnames)` takes dotted fully-qualified names like
"trio.open_nursery" or "mcp.client.sse.sse_client", groups them by base
internally, and delegates to `with_has_call`. This flattens the visitor's
chain of `with_has_call(...)` expressions into a single table of strings.
Previously, the test framework's `replace_library` rewrote every substring
occurrence of "trio" / "anyio" / "asyncio", which mangled unrelated package
names like trio_websocket, trio_util, qtrio, and anyio.from_thread in eval
files. Now identifier-like replacements match at word boundaries; library
names additionally allow a leading `_` so the "_trio" suffix in error
codes like "ASYNC103_trio" still rewrites per library.

With the substitution no longer mangling trio_websocket et al., the
library-specific test file async101_trio_pkgs.py is no longer needed --
those cases merge into async101_third_party.py and are now verified
under all three libraries.
This call is explicitly a schedule-but-not-cancel point, so it's safe to
await inside a finally block, a cancelled except, or __aexit__ -- the
same conditions where ASYNC102 / ASYNC120 would otherwise flag an await.
Matches the existing exemption for bare `.aclose()` calls. Also covers
the anyio.lowlevel equivalent for symmetry with the rest of the visitor.
@Zac-HD Zac-HD force-pushed the claude/fix-flake8-async-350-BswDi branch from 676eb62 to 974456b Compare April 23, 2026 21:35
@Zac-HD Zac-HD merged commit f78b772 into python-trio:main Apr 24, 2026
10 checks passed
@Zac-HD Zac-HD deleted the claude/fix-flake8-async-350-BswDi branch April 24, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

include common 3rd-party CM's with internal cancel scopes in ASYNC101

2 participants