From 8e05ff6acf30deae5d83ea3847ec47ed0bf049a4 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 16 Sep 2022 03:24:19 -0400 Subject: [PATCH] Fix a crash in the `modified-iterating-dict` checker involving instance attributes (#7472) --- doc/whatsnew/fragments/7461.bugfix | 3 +++ pylint/checkers/modified_iterating_checker.py | 12 ++++++++---- tests/functional/m/modified_iterating.py | 12 ++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 doc/whatsnew/fragments/7461.bugfix diff --git a/doc/whatsnew/fragments/7461.bugfix b/doc/whatsnew/fragments/7461.bugfix new file mode 100644 index 0000000000..1fb503c9ab --- /dev/null +++ b/doc/whatsnew/fragments/7461.bugfix @@ -0,0 +1,3 @@ +Fix a crash in the ``modified-iterating-dict`` checker involving instance attributes. + +Closes #7461 diff --git a/pylint/checkers/modified_iterating_checker.py b/pylint/checkers/modified_iterating_checker.py index 62e887a954..d32bb56ef0 100644 --- a/pylint/checkers/modified_iterating_checker.py +++ b/pylint/checkers/modified_iterating_checker.py @@ -128,7 +128,7 @@ def _is_node_assigns_subscript_name(node: nodes.NodeNG) -> bool: ) def _modified_iterating_list_cond( - self, node: nodes.NodeNG, iter_obj: nodes.NodeNG + self, node: nodes.NodeNG, iter_obj: nodes.Name | nodes.Attribute ) -> bool: if not self._is_node_expr_that_calls_attribute_name(node): return False @@ -141,7 +141,7 @@ def _modified_iterating_list_cond( ) def _modified_iterating_dict_cond( - self, node: nodes.NodeNG, iter_obj: nodes.NodeNG + self, node: nodes.NodeNG, iter_obj: nodes.Name | nodes.Attribute ) -> bool: if not self._is_node_assigns_subscript_name(node): return False @@ -159,10 +159,14 @@ def _modified_iterating_dict_cond( return False if infer_val != utils.safe_infer(iter_obj): return False - return node.targets[0].value.name == iter_obj.name + if isinstance(iter_obj, nodes.Attribute): + iter_obj_name = iter_obj.attrname + else: + iter_obj_name = iter_obj.name + return node.targets[0].value.name == iter_obj_name def _modified_iterating_set_cond( - self, node: nodes.NodeNG, iter_obj: nodes.NodeNG + self, node: nodes.NodeNG, iter_obj: nodes.Name | nodes.Attribute ) -> bool: if not self._is_node_expr_that_calls_attribute_name(node): return False diff --git a/tests/functional/m/modified_iterating.py b/tests/functional/m/modified_iterating.py index 527ce358cb..d9aad394ab 100644 --- a/tests/functional/m/modified_iterating.py +++ b/tests/functional/m/modified_iterating.py @@ -105,3 +105,15 @@ def my_method(self): """This should raise as we are deleting.""" for var in self.attribute: del var # [modified-iterating-list] + + +class MyClass2: + """Regression test for https://github.com/PyCQA/pylint/issues/7461""" + def __init__(self) -> None: + self.attribute = {} + + def my_method(self): + """This should not raise, as a copy was made.""" + for key in self.attribute: + tmp = self.attribute.copy() + tmp[key] = None