diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 10 | ||||
-rw-r--r-- | tests/functional/u/unbalanced_tuple_unpacking.py | 24 | ||||
-rw-r--r-- | tests/functional/u/unbalanced_tuple_unpacking.txt | 12 | ||||
-rw-r--r-- | tests/functional/u/unpacking_non_sequence.py | 10 | ||||
-rw-r--r-- | tests/functional/u/unpacking_non_sequence.txt | 20 |
6 files changed, 63 insertions, 17 deletions
@@ -18,6 +18,10 @@ Release date: TBA Closes #4716 +* Fix false positive - Allow unpacking of ``self`` in a subclass of ``typing.NamedTuple``. + + Closes #5312 + * Fix false negative for ``consider-iterating-dictionary`` during membership checks encapsulated in iterables or ``not in`` checks diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index f5605260a..f2bba355c 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2130,9 +2130,17 @@ class VariablesChecker(BaseChecker): ): # Variable-length argument, we can't determine the length. return + + # Attempt to check unpacking is properly balanced + values: Optional[List] = None if isinstance(inferred, (nodes.Tuple, nodes.List)): - # attempt to check unpacking is properly balanced values = inferred.itered() + elif isinstance(inferred, astroid.Instance) and any( + ancestor.qname() == "typing.NamedTuple" for ancestor in inferred.ancestors() + ): + values = [i for i in inferred.values() if isinstance(i, nodes.AssignName)] + + if values: if len(targets) != len(values): # Check if we have starred nodes. if any(isinstance(target, nodes.Starred) for target in targets): diff --git a/tests/functional/u/unbalanced_tuple_unpacking.py b/tests/functional/u/unbalanced_tuple_unpacking.py index ed807c0d7..4deb6ce37 100644 --- a/tests/functional/u/unbalanced_tuple_unpacking.py +++ b/tests/functional/u/unbalanced_tuple_unpacking.py @@ -1,8 +1,9 @@ """Check possible unbalanced tuple unpacking """ from __future__ import absolute_import +from typing import NamedTuple from functional.u.unpacking import unpack -# pylint: disable=using-constant-test, useless-object-inheritance,import-outside-toplevel +# pylint: disable=missing-class-docstring, missing-function-docstring, using-constant-test, useless-object-inheritance,import-outside-toplevel def do_stuff(): """This is not right.""" @@ -106,3 +107,24 @@ def test_issue_559(): from ctypes import c_int root_x, root_y, win_x, win_y = [c_int()] * 4 return root_x, root_y, win_x, win_y + + +class MyClass(NamedTuple): + first: float + second: float + third: float = 1.0 + + def my_sum(self): + """Unpack 3 variables""" + first, second, third = self + return first + second + third + + def sum_unpack_3_into_4(self): + """Attempt to unpack 3 variables into 4""" + first, second, third, fourth = self # [unbalanced-tuple-unpacking] + return first + second + third + fourth + + def sum_unpack_3_into_2(self): + """Attempt to unpack 3 variables into 2""" + first, second = self # [unbalanced-tuple-unpacking] + return first + second diff --git a/tests/functional/u/unbalanced_tuple_unpacking.txt b/tests/functional/u/unbalanced_tuple_unpacking.txt index 20aa5f40f..c64c1c2ad 100644 --- a/tests/functional/u/unbalanced_tuple_unpacking.txt +++ b/tests/functional/u/unbalanced_tuple_unpacking.txt @@ -1,5 +1,7 @@ -unbalanced-tuple-unpacking:9:4:9:27:do_stuff:"Possible unbalanced tuple unpacking with sequence (1, 2, 3): left side has 2 label(s), right side has 3 value(s)":UNDEFINED -unbalanced-tuple-unpacking:14:4:14:29:do_stuff1:"Possible unbalanced tuple unpacking with sequence [1, 2, 3]: left side has 2 label(s), right side has 3 value(s)":UNDEFINED -unbalanced-tuple-unpacking:19:4:19:29:do_stuff2:"Possible unbalanced tuple unpacking with sequence (1, 2, 3): left side has 2 label(s), right side has 3 value(s)":UNDEFINED -unbalanced-tuple-unpacking:69:4:69:28:do_stuff9:"Possible unbalanced tuple unpacking with sequence defined at line 7 of functional.u.unpacking: left side has 2 label(s), right side has 3 value(s)":UNDEFINED -unbalanced-tuple-unpacking:81:8:81:33:UnbalancedUnpacking.test:"Possible unbalanced tuple unpacking with sequence defined at line 7 of functional.u.unpacking: left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:10:4:10:27:do_stuff:"Possible unbalanced tuple unpacking with sequence (1, 2, 3): left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:15:4:15:29:do_stuff1:"Possible unbalanced tuple unpacking with sequence [1, 2, 3]: left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:20:4:20:29:do_stuff2:"Possible unbalanced tuple unpacking with sequence (1, 2, 3): left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:70:4:70:28:do_stuff9:"Possible unbalanced tuple unpacking with sequence defined at line 7 of functional.u.unpacking: left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:82:8:82:33:UnbalancedUnpacking.test:"Possible unbalanced tuple unpacking with sequence defined at line 7 of functional.u.unpacking: left side has 2 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:124:8:124:43:MyClass.sum_unpack_3_into_4:"Possible unbalanced tuple unpacking with sequence defined at line 112: left side has 4 label(s), right side has 3 value(s)":UNDEFINED +unbalanced-tuple-unpacking:129:8:129:28:MyClass.sum_unpack_3_into_2:"Possible unbalanced tuple unpacking with sequence defined at line 112: left side has 2 label(s), right side has 3 value(s)":UNDEFINED diff --git a/tests/functional/u/unpacking_non_sequence.py b/tests/functional/u/unpacking_non_sequence.py index b7ea2189c..e9c23b388 100644 --- a/tests/functional/u/unpacking_non_sequence.py +++ b/tests/functional/u/unpacking_non_sequence.py @@ -4,6 +4,7 @@ # pylint: disable=using-constant-test, no-init, missing-docstring, wrong-import-order,wrong-import-position,no-else-return, useless-object-inheritance from os import rename as nonseq_func from functional.u.unpacking import nonseq +from typing import NamedTuple __revision__ = 0 @@ -137,3 +138,12 @@ def flow_control_unpacking(var=None): var0, var1 = var return var0, var1 return None + + +class MyClass(NamedTuple): + x: float + y: float + + def sum(self): + x, y = self + return x + y diff --git a/tests/functional/u/unpacking_non_sequence.txt b/tests/functional/u/unpacking_non_sequence.txt index 7a8b8a85c..d657af177 100644 --- a/tests/functional/u/unpacking_non_sequence.txt +++ b/tests/functional/u/unpacking_non_sequence.txt @@ -1,10 +1,10 @@ -unpacking-non-sequence:77:0:77:15::Attempting to unpack a non-sequence defined at line 74:UNDEFINED -unpacking-non-sequence:78:0:78:17::Attempting to unpack a non-sequence:UNDEFINED -unpacking-non-sequence:79:0:79:11::Attempting to unpack a non-sequence None:UNDEFINED -unpacking-non-sequence:80:0:80:8::Attempting to unpack a non-sequence 1:UNDEFINED -unpacking-non-sequence:81:0:81:13::Attempting to unpack a non-sequence defined at line 9 of functional.u.unpacking:UNDEFINED -unpacking-non-sequence:82:0:82:15::Attempting to unpack a non-sequence defined at line 11 of functional.u.unpacking:UNDEFINED -unpacking-non-sequence:83:0:83:18::Attempting to unpack a non-sequence:UNDEFINED -unpacking-non-sequence:98:8:98:33:ClassUnpacking.test:Attempting to unpack a non-sequence defined at line 74:UNDEFINED -unpacking-non-sequence:99:8:99:35:ClassUnpacking.test:Attempting to unpack a non-sequence:UNDEFINED -unpacking-non-sequence:100:8:100:31:ClassUnpacking.test:Attempting to unpack a non-sequence:UNDEFINED +unpacking-non-sequence:78:0:78:15::Attempting to unpack a non-sequence defined at line 75:UNDEFINED +unpacking-non-sequence:79:0:79:17::Attempting to unpack a non-sequence:UNDEFINED +unpacking-non-sequence:80:0:80:11::Attempting to unpack a non-sequence None:UNDEFINED +unpacking-non-sequence:81:0:81:8::Attempting to unpack a non-sequence 1:UNDEFINED +unpacking-non-sequence:82:0:82:13::Attempting to unpack a non-sequence defined at line 9 of functional.u.unpacking:UNDEFINED +unpacking-non-sequence:83:0:83:15::Attempting to unpack a non-sequence defined at line 11 of functional.u.unpacking:UNDEFINED +unpacking-non-sequence:84:0:84:18::Attempting to unpack a non-sequence:UNDEFINED +unpacking-non-sequence:99:8:99:33:ClassUnpacking.test:Attempting to unpack a non-sequence defined at line 75:UNDEFINED +unpacking-non-sequence:100:8:100:35:ClassUnpacking.test:Attempting to unpack a non-sequence:UNDEFINED +unpacking-non-sequence:101:8:101:31:ClassUnpacking.test:Attempting to unpack a non-sequence:UNDEFINED |