From f576347a4e387a7e478142e29a1a3e189ee38cd9 Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Thu, 21 Jan 2021 12:38:36 +0000 Subject: [PATCH] fix: don't confuse kwargs with symbol to codemod --- django_codemod/visitors/base.py | 37 +++++++++++---------------------- tests/visitors/test_base.py | 16 ++++++++++++++ 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/django_codemod/visitors/base.py b/django_codemod/visitors/base.py index e849eef1..9303c323 100644 --- a/django_codemod/visitors/base.py +++ b/django_codemod/visitors/base.py @@ -4,7 +4,6 @@ from libcst import ( Arg, - Attribute, BaseExpression, BaseSmallStatement, Call, @@ -168,36 +167,24 @@ def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression: self.context.scratch.pop(self.ctx_key_is_name_called, None) return super().leave_Call(original_node, updated_node) - @property - def ctx_key_is_name_in_attribute(self): - return f"{self.rename_from}-is_in_attribute" - - @property - def entity_is_in_attribute(self): - return self.context.scratch.get(self.ctx_key_is_name_in_attribute, False) - - def visit_Attribute(self, node: Attribute) -> Optional[bool]: - if self.is_imported_with_old_name and m.matches( - node, m.Attribute(attr=m.Name(self.old_name)) - ): - self.context.scratch[self.ctx_key_is_name_in_attribute] = True - return super().visit_Attribute(node) - - def leave_Attribute( - self, original_node: Attribute, updated_node: Attribute - ) -> BaseExpression: - self.context.scratch.pop(self.ctx_key_is_name_in_attribute, None) - return super().leave_Attribute(original_node, updated_node) - def leave_Name(self, original_node: Name, updated_node: Name) -> BaseExpression: if ( self.is_imported_with_old_name and not self.entity_is_name_called - and not self.entity_is_in_attribute and m.matches(updated_node, m.Name(value=self.old_name)) - and self.resolve_scope(original_node) == self.import_scope ): - return updated_node.with_changes(value=self.new_name) + try: + scope = self.resolve_scope(original_node) + except KeyError: + # Can't resolve scope of original_node, ignore it + # Might be because of one of these reasons: + # - It's the same name in another scope + # - It's a attribute with the same name + # - It's a keyword argument + pass + else: + if scope == self.import_scope: + return updated_node.with_changes(value=self.new_name) return super().leave_Name(original_node, updated_node) diff --git a/tests/visitors/test_base.py b/tests/visitors/test_base.py index 22a9d29d..ecea4f59 100644 --- a/tests/visitors/test_base.py +++ b/tests/visitors/test_base.py @@ -219,6 +219,22 @@ def test_something(): """ self.assertCodemod(before, after) + def test_kwargs(self) -> None: + """When function is called with a kwargs bearing the same name.""" + before = """ + from django.dummy.module import func + + func() + something(func="test") + """ + after = """ + from django.dummy.module import better_func + + better_func() + something(func="test") + """ + self.assertCodemod(before, after) + class OtherModuleFuncRenameTransformer(BaseFuncRenameTransformer): """Transformer with different module."""