Skip to content

Commit ac2ae53

Browse files
[used-before-assignment] Extend "same test" exception to named expressions (#10062)
1 parent 4e4f04f commit ac2ae53

File tree

5 files changed

+28
-11
lines changed

5 files changed

+28
-11
lines changed

doc/data/messages/p/possibly-used-before-assignment/details.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ This warns:
4848

4949
If you find this surprising, consider that pylint, as a static analysis
5050
tool, does not know if ``guarded()`` is deterministic or talks to
51-
a database. For constants (e.g. ``guarded`` versus ``guarded()``),
51+
a database. For variables (e.g. ``guarded`` versus ``guarded()``),
5252
this is less of an issue, so in this case,
5353
``possibly-used-before-assignment`` acts more like a future-proofing style
5454
preference than an error, per se.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix a false positive for `used-before-assignment` when a variable defined under
2+
an `if` and via a named expression (walrus operator) is used later when guarded
3+
under the same `if` test.
4+
5+
Closes #10061

pylint/checkers/variables.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -765,10 +765,14 @@ def _node_guarded_by_same_test(node: nodes.NodeNG, other_if: nodes.If) -> bool:
765765
or if their inferred values consist only of constants and those constants
766766
are identical, and the if test guarding `node` is not a Name.
767767
"""
768-
other_if_test_as_string = other_if.test.as_string()
769-
other_if_test_all_inferred = utils.infer_all(other_if.test)
768+
if isinstance(other_if.test, nodes.NamedExpr):
769+
other_if_test = other_if.test.target
770+
else:
771+
other_if_test = other_if.test
772+
other_if_test_as_string = other_if_test.as_string()
773+
other_if_test_all_inferred = utils.infer_all(other_if_test)
770774
for ancestor in node.node_ancestors():
771-
if not isinstance(ancestor, nodes.If):
775+
if not isinstance(ancestor, (nodes.If, nodes.IfExp)):
772776
continue
773777
if ancestor.test.as_string() == other_if_test_as_string:
774778
return True

tests/functional/u/used/used_before_assignment.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ def turn_on2(**kwargs):
147147
if 1 in []:
148148
print(PERCENT)
149149

150+
151+
# Always true
152+
if always_true := True:
153+
ONE = 1
154+
155+
print(ONE if always_true else 2)
156+
157+
150158
# Different test
151159
if 1 in [1]:
152160
print(SALE) # [used-before-assignment]

tests/functional/u/used/used_before_assignment.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ possibly-used-before-assignment:75:3:75:7::Possibly using variable 'VAR5' before
1010
used-before-assignment:80:3:80:7::Using variable 'VAR6' before assignment:INFERENCE
1111
used-before-assignment:115:6:115:11::Using variable 'VAR10' before assignment:INFERENCE
1212
possibly-used-before-assignment:121:6:121:11::Possibly using variable 'VAR12' before assignment:CONTROL_FLOW
13-
used-before-assignment:152:10:152:14::Using variable 'SALE' before assignment:INFERENCE
14-
used-before-assignment:184:10:184:18::Using variable 'ALL_DONE' before assignment:INFERENCE
15-
used-before-assignment:195:6:195:24::Using variable 'NOT_ALWAYS_DEFINED' before assignment:INFERENCE
16-
used-before-assignment:231:10:231:11::Using variable 'x' before assignment:CONTROL_FLOW
17-
possibly-used-before-assignment:245:10:245:15:__:Possibly using variable 'fail1' before assignment:CONTROL_FLOW
18-
used-before-assignment:259:18:259:19:outer_.inner_try:Using variable 'a' before assignment:HIGH
19-
used-before-assignment:270:18:270:19:outer_.inner_while:Using variable 'a' before assignment:HIGH
13+
used-before-assignment:160:10:160:14::Using variable 'SALE' before assignment:INFERENCE
14+
used-before-assignment:192:10:192:18::Using variable 'ALL_DONE' before assignment:INFERENCE
15+
used-before-assignment:203:6:203:24::Using variable 'NOT_ALWAYS_DEFINED' before assignment:INFERENCE
16+
used-before-assignment:239:10:239:11::Using variable 'x' before assignment:CONTROL_FLOW
17+
possibly-used-before-assignment:253:10:253:15:__:Possibly using variable 'fail1' before assignment:CONTROL_FLOW
18+
used-before-assignment:267:18:267:19:outer_.inner_try:Using variable 'a' before assignment:HIGH
19+
used-before-assignment:278:18:278:19:outer_.inner_while:Using variable 'a' before assignment:HIGH

0 commit comments

Comments
 (0)