summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Mueller <30130371+cdce8p@users.noreply.github.com>2021-02-03 01:08:14 +0100
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-02-15 16:16:27 +0100
commit1282688abc6284124f9c3163838cdfa1d7f60f62 (patch)
treed835cfd621cf7f1ca37dcca8f4c26acf0d865260
parent1175b6e9110d2319a3cb4d4e8481b774b6a3cbb9 (diff)
downloadpylint-git-1282688abc6284124f9c3163838cdfa1d7f60f62.tar.gz
Fix multiple false positives with assignment expressions
* Used-before-assignment false positive * Undefined-variable false positive
-rw-r--r--ChangeLog4
-rw-r--r--pylint/checkers/variables.py30
-rw-r--r--tests/functional/a/assignment_expression.py58
-rw-r--r--tests/functional/a/assignment_expression.rc2
-rw-r--r--tests/functional/a/assignment_expression.txt3
5 files changed, 97 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 5a4ad73d6..f1118eca6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -39,6 +39,10 @@ Pylint's ChangeLog
Closes #4065
+* Fix multiple false positives with assignment expressions
+
+ Closes #3347, #3953, #3865, #3275
+
What's New in Pylint 2.6.1?
===========================
Release date: TBA
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 986f76fd2..5c3380c9d 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -1407,6 +1407,36 @@ class VariablesChecker(BaseChecker):
# Single statement function, with the statement on the
# same line as the function definition
maybee0601 = False
+ elif (
+ isinstance(defstmt, astroid.Assign)
+ and isinstance(defstmt.value, astroid.IfExp)
+ and frame is defframe
+ and defframe.parent_of(node)
+ and stmt is defstmt
+ ):
+ # Single statement if, with assingment expression on same
+ # line as assigment
+ # x = b if (b := True) else False
+ maybee0601 = False
+ elif (
+ isinstance( # pylint: disable=too-many-boolean-expressions
+ defnode, astroid.NamedExpr
+ )
+ and frame is defframe
+ and defframe.parent_of(stmt)
+ and stmt is defstmt
+ and (
+ (
+ defnode.lineno == node.lineno
+ and defnode.col_offset < node.col_offset
+ )
+ or (defnode.lineno < node.lineno)
+ )
+ ):
+ # Expressions, with assignment expressions
+ # Use only after assignment
+ # b = (c := 2) and c
+ maybee0601 = False
# Look for type checking definitions inside a type checking guard.
if isinstance(defstmt, (astroid.Import, astroid.ImportFrom)):
diff --git a/tests/functional/a/assignment_expression.py b/tests/functional/a/assignment_expression.py
new file mode 100644
index 000000000..ed8400163
--- /dev/null
+++ b/tests/functional/a/assignment_expression.py
@@ -0,0 +1,58 @@
+"""Test assignment expressions"""
+# pylint: disable=missing-docstring,unused-argument,unused-import,invalid-name,blacklisted-name,unused-variable
+import re
+
+if (a := True):
+ x = a
+else:
+ x = False
+
+x = b if (b := True) else False
+
+a = ["a ", "b ", "c "]
+c = [text for el in a if (text := el.strip()) == "b"]
+
+
+# https://github.com/PyCQA/pylint/issues/3347
+s = 'foo' if (fval := lambda: 1) is None else fval
+
+
+# https://github.com/PyCQA/pylint/issues/3953
+assert (n := 2) == 1, f"Expected 1, but got {n}"
+dict({1: (o := 2)}, data=o)
+assert (p := 2) == 1, \
+ p
+
+FOO_PATT = re.compile("")
+foo = m.group("foo") if (m := FOO_PATT.match("")) else False
+
+
+# https://github.com/PyCQA/pylint/issues/3865
+if (c := lambda: 2) and c():
+ print("ok")
+
+def func():
+ print((d := lambda: 2) and d)
+
+
+# https://github.com/PyCQA/pylint/issues/3275
+values = (
+ e := 1,
+ f := e,
+)
+print(values)
+
+function = lambda: (
+ h := 1,
+ i := h,
+)
+print(function())
+
+
+# check wrong usage
+assert err_a, (err_a := 2) # [used-before-assignment]
+print(err_b and (err_b := 2)) # [used-before-assignment]
+values = (
+ err_c := err_d, # [used-before-assignment]
+ err_d := 2,
+)
diff --git a/tests/functional/a/assignment_expression.rc b/tests/functional/a/assignment_expression.rc
new file mode 100644
index 000000000..85fc502b3
--- /dev/null
+++ b/tests/functional/a/assignment_expression.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.8
diff --git a/tests/functional/a/assignment_expression.txt b/tests/functional/a/assignment_expression.txt
new file mode 100644
index 000000000..df472fdd2
--- /dev/null
+++ b/tests/functional/a/assignment_expression.txt
@@ -0,0 +1,3 @@
+used-before-assignment:53:7::Using variable 'err_a' before assignment
+used-before-assignment:54:6::Using variable 'err_b' before assignment
+used-before-assignment:56:13::Using variable 'err_d' before assignment