Repository navigation
Conversation
The inference tip for a class with type parameters parses a `__class_getitem__` template every time the class is inferred. Parsing applies the registered transforms, and a transform that returns a node clears the global inference cache. That happens in the middle of an inference, and an inference further down that had been answered from the cache now hits the recursion guard instead, so a subclass of a PEP 695 generic class can lose ancestors. A pylint plugin with a FunctionDef transform that returns its node is enough to trigger it. Build the template like the enum brain builds its fake classes, without applying transforms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Type of Changes
Description
In pylint-dev/pylint#10352, a pylint plugin with a
FunctionDeftransform that only returns its node makes pylint reportmissing-function-docstringon a method that overrides a method of a PEP 695 generic class, because the subclass loses its ancestors:Child.ancestors()givesMiddle, Base, object, but onlyMiddlewhen such a transform is registered andMiddle's base was inferred before (pylint does a lot of inference before the docstring checker runs).What happens:
infer_typing_generic_class_pep695parses a__class_getitem__template each time a class with type parameters is inferred.TransformVisitor._transformtreats any non-Nonereturn value as a replacement and calls_invalidate_cache(), which clears the global inference cache.Child's ancestors. Further down,Base[T]is inferred again while it is already on the inference path. Before, the cache answered that. Now it hits the recursion guard,InferenceErroris raised, andancestors()skips the base.The fix builds the template with
AstroidBuilder(..., apply_transforms=False), the same waybrain_namedtuple_enumbuilds its fake enum classes during inference. The template is a fixedclassmethod, and running user transforms on it was not useful anyway.I first tried skipping
_invalidate_cache()when a transform returns the same node it got. That fixes this case but breakstest_tuple_type,test_callable_type,test_namedtuple_advanced_inferenceandtest_mro_with_factories, and three of pylint's typing functional tests: some brains change a node in place, return it, and rely on that invalidation. So I limited the fix to the brain.The new test fails without the change. The rest of the astroid tests and pylint's functional tests (944) pass with it. 6 symlink and
.pyztests fail on my Windows machine with and without this change. The example from the issue no longer getsmissing-function-docstring.Closes pylint-dev/pylint#10352
I used Claude Code for this PR and reviewed the change and the results.