summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2023-02-11 17:34:41 +0100
committerGitHub <noreply@github.com>2023-02-11 17:34:41 +0100
commitc2cd7c6afe989f301c7f2a469770933018eaeb92 (patch)
treeefa72a5abed976ea2a044e0249d23256c0125fc7
parent4aedc4f9589b49fbb0a598a53d04ad600129cba6 (diff)
downloadpylint-git-c2cd7c6afe989f301c7f2a469770933018eaeb92.tar.gz
Fix FP for used-before-assignment with assignment expressions in containers (#8253) (#8262)
(cherry picked from commit a0b28f9019fabddd8ef428be75659082377abb4c) Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
-rw-r--r--doc/whatsnew/fragments/8252.false_positive4
-rw-r--r--pylint/checkers/variables.py37
-rw-r--r--tests/functional/u/undefined/undefined_variable_py38.py10
-rw-r--r--tests/functional/u/undefined/undefined_variable_py38.txt5
4 files changed, 32 insertions, 24 deletions
diff --git a/doc/whatsnew/fragments/8252.false_positive b/doc/whatsnew/fragments/8252.false_positive
new file mode 100644
index 000000000..2c449ac36
--- /dev/null
+++ b/doc/whatsnew/fragments/8252.false_positive
@@ -0,0 +1,4 @@
+Fix false positive for ``used-before-assignment`` for named expressions
+appearing after the first element in a list, tuple, or set.
+
+Closes #8252
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 6df00d01a..76faf5cc8 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -115,6 +115,15 @@ DICT_TYPES = (
astroid.nodes.node_classes.Dict,
)
+NODES_WITH_VALUE_ATTR = (
+ nodes.Assign,
+ nodes.AnnAssign,
+ nodes.AugAssign,
+ nodes.Expr,
+ nodes.Return,
+ nodes.Match,
+)
+
class VariableVisitConsumerAction(Enum):
"""Reported by _check_consumer() and its sub-methods to determine the
@@ -2128,17 +2137,7 @@ class VariablesChecker(BaseChecker):
# same line as the function definition
maybe_before_assign = False
elif (
- isinstance(
- defstmt,
- (
- nodes.Assign,
- nodes.AnnAssign,
- nodes.AugAssign,
- nodes.Expr,
- nodes.Return,
- nodes.Match,
- ),
- )
+ isinstance(defstmt, NODES_WITH_VALUE_ATTR)
and VariablesChecker._maybe_used_and_assigned_at_once(defstmt)
and frame is defframe
and defframe.parent_of(node)
@@ -2234,13 +2233,15 @@ class VariablesChecker(BaseChecker):
"""
if isinstance(defstmt, nodes.Match):
return any(case.guard for case in defstmt.cases)
- if isinstance(defstmt.value, nodes.BaseContainer) and defstmt.value.elts:
- # The assignment must happen as part of the first element
- # e.g. "assert (x:= True), x"
- # NOT "assert x, (x:= True)"
- value = defstmt.value.elts[0]
- else:
- value = defstmt.value
+ if isinstance(defstmt, nodes.IfExp):
+ return True
+ if isinstance(defstmt.value, nodes.BaseContainer):
+ return any(
+ VariablesChecker._maybe_used_and_assigned_at_once(elt)
+ for elt in defstmt.value.elts
+ if isinstance(elt, NODES_WITH_VALUE_ATTR + (nodes.IfExp, nodes.Match))
+ )
+ value = defstmt.value
if isinstance(value, nodes.IfExp):
return True
if isinstance(value, nodes.Lambda) and isinstance(value.body, nodes.IfExp):
diff --git a/tests/functional/u/undefined/undefined_variable_py38.py b/tests/functional/u/undefined/undefined_variable_py38.py
index ef774e53a..6fb543e80 100644
--- a/tests/functional/u/undefined/undefined_variable_py38.py
+++ b/tests/functional/u/undefined/undefined_variable_py38.py
@@ -173,9 +173,13 @@ def expression_in_ternary_operator_inside_container_tuple():
return [(val3, val3) if (val3 := 'something') else 'anything']
-def expression_in_ternary_operator_inside_container_wrong_position():
- """2-element list where named expression comes too late"""
- return [val3, val3 if (val3 := 'something') else 'anything'] # [used-before-assignment]
+def expression_in_ternary_operator_inside_container_later_position():
+ """
+ Named expression follows unrelated item in container.
+
+ If 23 is replaced with `val3`, there is currently a false negative,
+ but the false positive here is more important and likely to occur."""
+ return [23, val3 if (val3 := 'something') else 'anything']
# Self-referencing
diff --git a/tests/functional/u/undefined/undefined_variable_py38.txt b/tests/functional/u/undefined/undefined_variable_py38.txt
index 832d8dd11..1674707a5 100644
--- a/tests/functional/u/undefined/undefined_variable_py38.txt
+++ b/tests/functional/u/undefined/undefined_variable_py38.txt
@@ -6,6 +6,5 @@ undefined-variable:83:6:83:19::Undefined variable 'else_assign_1':INFERENCE
undefined-variable:106:6:106:19::Undefined variable 'else_assign_2':INFERENCE
used-before-assignment:141:10:141:16:type_annotation_used_improperly_after_comprehension:Using variable 'my_int' before assignment:HIGH
used-before-assignment:148:10:148:16:type_annotation_used_improperly_after_comprehension_2:Using variable 'my_int' before assignment:HIGH
-used-before-assignment:178:12:178:16:expression_in_ternary_operator_inside_container_wrong_position:Using variable 'val3' before assignment:HIGH
-used-before-assignment:182:9:182:10::Using variable 'z' before assignment:HIGH
-used-before-assignment:189:6:189:19::Using variable 'NEVER_DEFINED' before assignment:CONTROL_FLOW
+used-before-assignment:186:9:186:10::Using variable 'z' before assignment:HIGH
+used-before-assignment:193:6:193:19::Using variable 'NEVER_DEFINED' before assignment:CONTROL_FLOW