Skip to content

Commit

Permalink
Prevent warnings on dict / list index lookup with destructuring assig…
Browse files Browse the repository at this point in the history
…nment (#6808)


Co-authored-by: Jacob Walls <[email protected]>
  • Loading branch information
2 people authored and Pierre-Sassoulas committed Jun 5, 2022
1 parent 72a91e9 commit 8bd5598
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 10 deletions.
5 changes: 5 additions & 0 deletions doc/whatsnew/2/2.14/full.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ What's New in Pylint 2.14.1?
----------------------------
Release date: TBA

* Avoid reporting ``unnecessary-dict-index-lookup`` or ``unnecessary-list-index-lookup``
when the index lookup is part of a destructuring assignment.

Closes #6788

* Fixed parsing of unrelated options in ``tox.ini``.

Closes #6800
Expand Down
34 changes: 24 additions & 10 deletions pylint/checkers/refactoring/refactoring_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,25 @@ def _will_be_released_automatically(node: nodes.Call) -> bool:
return func.qname() in callables_taking_care_of_exit


def _is_part_of_assignment_target(node: nodes.NodeNG) -> bool:
"""Check whether use of a variable is happening as part of the left-hand
side of an assignment.
This requires recursive checking, because destructuring assignment can have
arbitrarily nested tuples and lists to unpack.
"""
if isinstance(node.parent, nodes.Assign):
return node in node.parent.targets

if isinstance(node.parent, nodes.AugAssign):
return node == node.parent.target

if isinstance(node.parent, (nodes.Tuple, nodes.List)):
return _is_part_of_assignment_target(node.parent)

return False


class ConsiderUsingWithStack(NamedTuple):
"""Stack for objects that may potentially trigger a R1732 message
if they are not used in a ``with`` block later on.
Expand Down Expand Up @@ -1917,15 +1936,13 @@ def _check_unnecessary_dict_index_lookup(

value = subscript.slice

if isinstance(node, nodes.For) and (
isinstance(subscript.parent, nodes.Assign)
and subscript in subscript.parent.targets
or isinstance(subscript.parent, nodes.AugAssign)
and subscript == subscript.parent.target
if isinstance(node, nodes.For) and _is_part_of_assignment_target(
subscript
):
# Ignore this subscript if it is the target of an assignment
# Early termination; after reassignment dict index lookup will be necessary
return

if isinstance(subscript.parent, nodes.Delete):
# Ignore this subscript if it's used with the delete keyword
return
Expand Down Expand Up @@ -2017,11 +2034,8 @@ def _check_unnecessary_list_index_lookup(
)
for child in children:
for subscript in child.nodes_of_class(nodes.Subscript):
if isinstance(node, nodes.For) and (
isinstance(subscript.parent, nodes.Assign)
and subscript in subscript.parent.targets
or isinstance(subscript.parent, nodes.AugAssign)
and subscript == subscript.parent.target
if isinstance(node, nodes.For) and _is_part_of_assignment_target(
subscript
):
# Ignore this subscript if it is the target of an assignment
# Early termination; after reassignment index lookup will be necessary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,8 @@ class Foo:
for input_output in d.items():
f.input_output = input_output # pylint: disable=attribute-defined-outside-init
print(d[f.input_output[0]])

# Regression test for https://github.com/PyCQA/pylint/issues/6788
d = {'a': 1, 'b': 2, 'c': 3}
for key, val in d.items():
([d[key], x], y) = ([1, 2], 3)
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,12 @@ def process_list_again(data):
# Regression test for https://github.com/PyCQA/pylint/issues/6603
for i, num in enumerate(): # raises TypeError, but shouldn't crash pylint
pass

# Regression test for https://github.com/PyCQA/pylint/issues/6788
num_list = [1, 2, 3]
for a, b in enumerate(num_list):
num_list[a], _ = (2, 1)

num_list = [1, 2, 3]
for a, b in enumerate(num_list):
([x, num_list[a]], _) = ([5, 6], 1)

0 comments on commit 8bd5598

Please sign in to comment.