Repository navigation
plugins: tolerate synthesized methods when reprocessing attrs classes - #22291
Open
inchang-ing wants to merge 2 commits into
Open
inchang-ing wants to merge 2 commits into
inchang-ing wants to merge 2 commits into
Conversation
A dependency that is suppressed during graph loading (the importing
module cannot resolve it) and up-suppressed afterwards (another module
resolved it) is re-added by appending it to the end of the dependency
list. The order-sensitive freshness check in State.is_fresh() then sees
a changed list and marks the module stale on every run, even though the
dependency set is identical to the cached one.
After the up-suppress pass, restore the cached order when the current
dependency set is unchanged; a genuine dependency change keeps the new
order and the module is still rechecked.
Reproducer (from the issue):
site/ns/sub/__init__.py (namespace package, no top-level __init__)
a.py: import ns.missing (missing submodule -> suppressed)
b.py: import ns.sub
e.py: import b
PYTHONPATH=site mypy -v a.py e.py # run twice
On the second run, 'Scheduling SCC singleton (a) as inherently stale'
was always logged: a's cached dependency order is
[os, builtins, ns, abc, typing], but the suppress/add round trip
appends ns at the end. With this change the second run reports no
stale SCCs. The second run also used to lose the 'Skipping analyzing
"ns"' error that the first (and non-incremental) run reports, because
the spurious recheck resolved ns differently; restoring the order fixes
that output inconsistency as well.
Fixes python#22159.
The attrs plugin hooks run once per applied decorator, so a class with stacked decorators (e.g. @attrs.define on @attrs.frozen) is analyzed twice. When the class body declares a dunder that the plugin also synthesizes (e.g. __lt__ with the default order=True), the second run found the FuncDef synthesized by the first run in the symbol table and the Var assertion in _analyze_class crashed with an internal error. Skip the synthesized FuncDef on reprocessing: the hook that follows will re-synthesize the method anyway. Fixes python#22290
Contributor
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The attrs plugin hooks run once per applied decorator, so a class with stacked decorators (e.g.
@attrs.defineon@attrs.frozen) is analyzed twice. When the class body declares a dunder that the plugin also synthesizes (here__lt__with the defaultorder=True), the second hook run found theFuncDefsynthesized by the first run in the symbol table, and theVarassertion in_analyze_classcrashed with an internal error.Skip the plugin-synthesized
FuncDefon reprocessing: the hook that follows re-synthesizes the method anyway.Fixes #22290
Testing
testAttrsStackedDecoratorsWithAnnotatedOrderMethod(stacked decorators + annotated__lt__): crashes onmasterwithAssertionError: FuncDef:5(...), passes with the change.check-plugin-attrs.testsuite: 140 passed.mypy/plugins/attrs.py: no new errors (the reportedmypy/util.pyimport-untyped note is a pre-existing baseline item in this environment).Disclosure
Assisted by AI coding tools (ZCode/GLM); I have reviewed and verified the change and can explain every line.