Fix false negative dangerous-default-value for typing.NamedTuple (#3716)#10989
Open
hamza-mobeen wants to merge 2 commits intopylint-dev:mainfrom
Open
Fix false negative dangerous-default-value for typing.NamedTuple (#3716)#10989hamza-mobeen wants to merge 2 commits intopylint-dev:mainfrom
hamza-mobeen wants to merge 2 commits intopylint-dev:mainfrom
Conversation
DanielNoord
reviewed
May 3, 2026
| self.linter.stats.node_count["module"] += 1 | ||
|
|
||
| def visit_classdef(self, _: nodes.ClassDef) -> None: | ||
| @utils.only_required_for_messages("dangerous-default-value") |
Collaborator
There was a problem hiding this comment.
This feels incorrect, considering we're also updating statistics here.
| continue | ||
| default = child.value | ||
| try: | ||
| value = next(default.infer()) |
Collaborator
There was a problem hiding this comment.
Should we use safe_infer here?
Contributor
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
Right now, pylint's
dangerous-default-value(W0102) only catches mutable defaults on regular function and method arguments. But the exact same bug can happen withtyping.NamedTuplefield defaults and pylint stays silent about it.Root cause
The existing
_check_dangerous_defaultmethod is only triggered viavisit_functiondef, which inspectsnode.args.defaults. When a class inherits fromtyping.NamedTuple, the field defaults areAnnAssignnodes inside aClassDefbody — the checker never sees them.What this PR does
Adds a new
_check_namedtuple_dangerous_defaultsmethod toBasicCheckerthat:typing.NamedTuple(using the sameancestor.qname()pattern already used invariables.pyanddesign_analysis.py)AnnAssignnodes in the class bodyDEFAULT_ARGUMENT_SYMBOLSmapdangerous-default-valueon the specific field lineThe check is called from
visit_classdef, which was updated with the@utils.only_required_for_messages("dangerous-default-value")decorator.Code change
In
pylint/checkers/base/basic_checker.py:The new
_check_namedtuple_dangerous_defaultsmethod reuses the same mutable-default detection logic from_check_dangerous_default, applied toAnnAssign.valuenodes instead of function argument defaults.Tests
Added a new functional test
dangerous_default_value_namedtuple.pycovering:[],{},set(),{1, 2}(set literal),list(),dict(),collections.deque()defaults → all emit W0102str,int,bool,tuple,frozenset) → no warningCloses #3716
Checklist
skip-newsif the change does not need to be in the changelog.towncrier create <IssueNumber>.<type>which will beincluded in the changelog.
<type>can be one of the types defined in./towncrier.toml.If necessary you can write details or offer examples on how the new change is supposed to work.
tox -e docsDon't hesitate to open multiple PRs if the change requires it. If your review is so
big it requires to actually plan and allocate time to review, it's more likely
that it's going to go stale.
and preferred name in
script/.contributors_aliases.json