Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of assignment expressions #4253

Merged
merged 1 commit into from
Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
cdce8p marked this conversation as resolved.
Show resolved Hide resolved
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
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
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