From bcd4ca3052411e8c0823712d38cb970e354713f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Noord?= <13665637+DanielNoord@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:06:40 +0200 Subject: [PATCH] Fix crash while iteraring over a class attribute (#7386) Co-authored-by: orSolocate <38433858+orSolocate@users.noreply.github.com> --- doc/whatsnew/fragments/7380.bugfix | 3 +++ pylint/checkers/modified_iterating_checker.py | 8 ++++++-- tests/functional/m/modified_iterating.py | 16 ++++++++++++++-- tests/functional/m/modified_iterating.txt | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 doc/whatsnew/fragments/7380.bugfix diff --git a/doc/whatsnew/fragments/7380.bugfix b/doc/whatsnew/fragments/7380.bugfix new file mode 100644 index 0000000000..dc5ea5fa6b --- /dev/null +++ b/doc/whatsnew/fragments/7380.bugfix @@ -0,0 +1,3 @@ +Update ``modified_iterating`` checker to fix a crash with ``for`` loops on empty list. + +Closes #7380 diff --git a/pylint/checkers/modified_iterating_checker.py b/pylint/checkers/modified_iterating_checker.py index bdabc26503..62e887a954 100644 --- a/pylint/checkers/modified_iterating_checker.py +++ b/pylint/checkers/modified_iterating_checker.py @@ -81,7 +81,7 @@ def _modified_iterating_check( msg_id = "modified-iterating-dict" elif isinstance(inferred, nodes.Set): msg_id = "modified-iterating-set" - elif not isinstance(iter_obj, nodes.Name): + elif not isinstance(iter_obj, (nodes.Name, nodes.Attribute)): pass elif self._modified_iterating_list_cond(node, iter_obj): msg_id = "modified-iterating-list" @@ -90,10 +90,14 @@ def _modified_iterating_check( elif self._modified_iterating_set_cond(node, iter_obj): msg_id = "modified-iterating-set" if msg_id: + if isinstance(iter_obj, nodes.Attribute): + obj_name = iter_obj.attrname + else: + obj_name = iter_obj.name self.add_message( msg_id, node=node, - args=(iter_obj.name,), + args=(obj_name,), confidence=interfaces.INFERENCE, ) diff --git a/tests/functional/m/modified_iterating.py b/tests/functional/m/modified_iterating.py index 166bf4f6c4..527ce358cb 100644 --- a/tests/functional/m/modified_iterating.py +++ b/tests/functional/m/modified_iterating.py @@ -1,5 +1,5 @@ """Tests for iterating-modified messages""" -# pylint: disable=not-callable,unnecessary-comprehension +# pylint: disable=not-callable,unnecessary-comprehension,too-few-public-methods import copy @@ -26,7 +26,7 @@ i = 1 for item in my_dict: item_list[0] = i # for coverage, see reference at /pull/5628#discussion_r792181642 - my_dict[i] = 1 # [modified-iterating-dict] + my_dict[i] = 1 # [modified-iterating-dict] i += 1 i = 1 @@ -93,3 +93,15 @@ def update_existing_key(): for key in my_dict: new_key = key.lower() my_dict[new_key] = 1 # [modified-iterating-dict] + + +class MyClass: + """Regression test for https://github.com/PyCQA/pylint/issues/7380""" + + def __init__(self) -> None: + self.attribute = [1, 2, 3] + + def my_method(self): + """This should raise as we are deleting.""" + for var in self.attribute: + del var # [modified-iterating-list] diff --git a/tests/functional/m/modified_iterating.txt b/tests/functional/m/modified_iterating.txt index c63095556f..7d5e3014d7 100644 --- a/tests/functional/m/modified_iterating.txt +++ b/tests/functional/m/modified_iterating.txt @@ -13,3 +13,4 @@ modified-iterating-list:64:4:64:23::Iterated list 'item_list' is being modified modified-iterating-list:67:12:67:31::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-list:69:16:69:35::Iterated list 'item_list' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE modified-iterating-dict:95:8:95:28:update_existing_key:Iterated dict 'my_dict' is being modified inside for loop body, iterate through a copy of it instead.:INFERENCE +modified-iterating-list:107:12:107:19:MyClass.my_method:Iterated list 'attribute' is being modified inside for loop body, consider iterating through a copy of it instead.:INFERENCE