Skip to content

Track imports so we can disable ASYNC106#450

Merged
Zac-HD merged 6 commits intopython-trio:mainfrom
Zac-HD:claude/canonical-qualname-rules-CUgdM
Apr 25, 2026
Merged

Track imports so we can disable ASYNC106#450
Zac-HD merged 6 commits intopython-trio:mainfrom
Zac-HD:claude/canonical-qualname-rules-CUgdM

Conversation

@Zac-HD
Copy link
Copy Markdown
Member

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

The ASYNC106 rule existed because it was easier to require users to write exactly import trio rather than track all the various ways that things could be imported and pass that through to all the rules. Happily, Claude has now done that for us 😁

Closes #132.

claude and others added 6 commits April 24, 2026 04:44
Previously the linter only recognised trio/anyio/asyncio-related calls when
they appeared exactly as `trio.open_nursery`, `anyio.create_task_group`, etc.
Aliased imports (`import trio as t`), `from` imports (`from trio import
open_nursery`), and aliased-from imports (`from trio import open_nursery as
on`) silently escaped detection.

This adds a pair of utility visitors (VisitorImportTracker / _cst) that
build a local-name -> canonical-dotted-qualname map, a pair of helpers
(resolve_canonical_ast / _cst) and base-class shortcut `canonical_name()`,
and threads an `imports=` keyword through the existing matcher helpers
(get_matching_call[_cst], fnmatch_qualified_name[_cst], with_has_call,
calls_any_of, critical_except). The tracker only records module-level
imports, so function-local imports don't leak into sibling scopes.

Existing visitors are updated to pass `self.imports` to those helpers, and
ASYNC105/ASYNC115/ASYNC118/ASYNC2xx/ASYNC300 etc. now match via canonical
qualname instead of the literal spelling. ASYNC106 was a workaround for
the old limitation; it's now disabled by default but left in place for
projects that still want to enforce the `import trio` style.

Closes python-trio#132.

https://claude.ai/code/session_018Hc9rcA31SnXcN8Ee5vVwH
- Drop redundant canonical_name() docstrings.
- Simplify fnmatch_qualified_name[_cst] to build a candidate set inline.
- Fold the resolve_canonical_ast recursive arm into one-liners.
- Drop ASYNC21X's bespoke urllib3-import set -- consult the shared imports map.
- Collapse ASYNC22X's raw_name/canonical/func_name triplet into two locals.
- Simplify with_has_call's canonical fallback to a startswith + suffix check.
- Consolidate the CST scope-tracker's three visit/leave pairs into shared helpers.
- Rewrite the narrative "this change" comments as reader-facing rationale,
  both in the code and in the eval-file annotations.

https://claude.ai/code/session_018Hc9rcA31SnXcN8Ee5vVwH
- Move resolve_canonical_ast/cst into a dedicated _canonical module so the
  base-class methods can import them at the top level (PLC0415).
- Flatten nested isinstance chain in get_matching_call_cst (SIM102).
- Reformat the import-tracker example table so ruff stops flagging the
  continuation line as commented-out code (ERA001).
- Inline the isinstance(ast.Call) check in critical_except so mypy's narrowing
  kicks in (attr-defined on "expr").
- Drop the now-unused identifier_to_string import from visitor91x.

https://claude.ai/code/session_018Hc9rcA31SnXcN8Ee5vVwH
The changelog entry `:ref:`ASYNC106 <async106>`` targets a rule that didn't
have a Sphinx label, which made readthedocs fail with `undefined label:
'async106'` under `-W`.

https://claude.ai/code/session_018Hc9rcA31SnXcN8Ee5vVwH
@Zac-HD Zac-HD merged commit 112e892 into python-trio:main Apr 25, 2026
10 checks passed
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.

Add support for from ... import ... and import ... as ...

2 participants