Fix nested subscript assignment inference - #11255
Conversation
When a nested literal-key subscript is assigned immediately after the same slot receives a value, prefer that adjacent assignment over stale inference from the original container literal. Restrict the fallback to built-in list or dictionary roots and exact name-rooted literal-key chains. Preserve the diagnostic for custom setters and when the adjacent value is not subscriptable. Fixes pylint-dev#10050. Signed-off-by: Abhinav Gorrepati <gorrepatiabhinav1@gmail.com> Co-authored-by: OpenAI Codex <noreply@openai.com>
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
Thank you for contributing to pylint. Not looking too much into the details, it seems it adds a lot of complexity. Could it be 'hidden' by a better astroid inference ?
|
Thanks—that makes sense. I confirmed the underlying behavior is Astroid inference: at the final assignment, |
|
Follow-up: I opened pylint-dev/astroid#3220 with the narrow inference fix, including downstream Pylint regression coverage and adversarial custom-mapping/property cases. If that lands, I’ll simplify this PR to remove the checker-side inference fallback and retain only the Pylint regression/news plus the required Astroid dependency update. |
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
Thank you for working on pylint, I'm going to add some test cases, it's going to be easier than describing them :)
The adjacent-assignment fallback only recovers the exact shape reported in pylint-dev#10050: a Store subscript whose replacement was assigned by the immediately preceding sibling statement. Add functional tests for the neighbouring shapes that still emit, so the remaining false positives are visible and a broader fix can flip them in one place: * an unrelated statement between the two assignments * the item read (unsubscriptable-object) or deleted (unsupported-delete-operation) instead of written * a three level chain, where only the outermost subscript is covered * the replacement stored through an alias of the same dictionary * an ambiguous replacement value, where safe_infer returns None and the stale container literal is used instead of bailing out Also guard the shapes that already work: a function scope, a list root and an augmented assignment.
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (96.29%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #11255 +/- ##
==========================================
+ Coverage 96.36% 96.40% +0.04%
==========================================
Files 178 178
Lines 19952 20069 +117
==========================================
+ Hits 19227 19348 +121
+ Misses 725 721 -4
🚀 New features to boost your workflow:
|
|
🤖 According to the primer, this change has no effect on the checked open source code. 🤖🎉 This comment was generated for commit dc9e001 |
|
Thanks—the added cases made the limitation clear. I generalized pylint-dev/astroid#3220 in 6546320 so the inference layer now handles the six new shapes here: intervening statements, reads, deletes, deeper chains, aliases, and ambiguous writes. Running this branch against that Astroid commit removes all six newly documented false positives. Astroid's 483 inference tests and all changed-file hooks pass; its remaining full-suite failures reproduce unchanged on the parent commit. Once the Astroid change is available, I will remove the checker-side fallback from this PR and keep the Pylint functional coverage and release note. |
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
Could add some coverage or remove the code that can't be reached, please ?
Type of Changes
Description
Pylint could infer the original
Nonevalue from a nested dictionary literal even when the same key was assigned a dictionary immediately before the nested assignment. That producedunsupported-assignment-operationfor valid code.This adds a narrow fallback for adjacent assignments to the exact same literal-key chain when the root is inferred as a built-in dictionary or list. Custom mappings and non-subscriptable replacement values still emit E1137; the regression suite covers both cases.
Validation:
pre-commit run --all-files: passedCloses #10050
Implementation and tests were developed with OpenAI Codex assistance and reviewed against custom-mapping and aliasing edge cases before submission.