Skip to content

Commit

Permalink
Improve handling of assignment expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p authored and Pierre-Sassoulas committed Mar 26, 2021
1 parent 09dce02 commit 5d5f657
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 4 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ Release date: TBA

Closes #4218

* Improve handling of assignment expressions, better edge case handling

Closes #3763, #4238


What's New in Pylint 2.7.2?
===========================
Expand Down
23 changes: 22 additions & 1 deletion pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

from pylint.checkers import BaseChecker, utils
from pylint.checkers.utils import is_postponed_evaluation_enabled
from pylint.constants import PY39_PLUS
from pylint.interfaces import HIGH, INFERENCE, INFERENCE_FAILURE, IAstroidChecker
from pylint.utils import get_global_option

Expand Down Expand Up @@ -1410,7 +1411,15 @@ def _is_variable_violation(
# same line as the function definition
maybee0601 = False
elif (
isinstance(defstmt, astroid.Assign)
isinstance(
defstmt,
(
astroid.Assign,
astroid.AnnAssign,
astroid.AugAssign,
astroid.Expr,
),
)
and isinstance(defstmt.value, astroid.IfExp)
and frame is defframe
and defframe.parent_of(node)
Expand All @@ -1433,6 +1442,18 @@ def _is_variable_violation(
and defnode.col_offset < node.col_offset
)
or (defnode.lineno < node.lineno)
or (
# Issue in the `ast` module until py39
# Nodes in a multiline string have the same lineno
# Could be false-positive without check
not PY39_PLUS
and defnode.lineno == node.lineno
and isinstance(
defstmt,
(astroid.Assign, astroid.AnnAssign, astroid.AugAssign),
)
and isinstance(defstmt.value, astroid.JoinedStr)
)
)
):
# Expressions, with assignment expressions
Expand Down
1 change: 1 addition & 0 deletions pylint/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pylint.__pkginfo__ import version as pylint_version

PY38_PLUS = sys.version_info[:2] >= (3, 8)
PY39_PLUS = sys.version_info[:2] >= (3, 9)
PY310_PLUS = sys.version_info[:2] >= (3, 10)


Expand Down
21 changes: 21 additions & 0 deletions tests/functional/a/assignment_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
x = False

x = b if (b := True) else False
x2: bool = b2 if (b2 := True) else False
x3 = 0
x3 += b3 if (b3 := 4) else 6

a = ["a ", "b ", "c "]
c = [text for el in a if (text := el.strip()) == "b"]
Expand Down Expand Up @@ -49,6 +52,24 @@ def func():
print(function())


# https://github.com/PyCQA/pylint/issues/3763
foo if (foo := 3 - 2) > 0 else 0 # [pointless-statement]


# https://github.com/PyCQA/pylint/issues/4238
l1 = f'The number {(count1 := 4)} ' \
f'is equal to {count1}'
l2: str = (
f'The number {(count2 := 4)} '
f'is equal to {count2}'
)
l3 = "Hello "
l3 += (
f'The number {(count3 := 4)} '
f'is equal to {count3}'
)


# check wrong usage
assert err_a, (err_a := 2) # [used-before-assignment]
print(err_b and (err_b := 2)) # [used-before-assignment]
Expand Down
7 changes: 4 additions & 3 deletions tests/functional/a/assignment_expression.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
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
pointless-statement:56:0::Statement seems to have no effect
used-before-assignment:74:7::Using variable 'err_a' before assignment
used-before-assignment:75:6::Using variable 'err_b' before assignment
used-before-assignment:77:13::Using variable 'err_d' before assignment

0 comments on commit 5d5f657

Please sign in to comment.