Skip to content

Commit

Permalink
fix: bug with attributes accessing
Browse files Browse the repository at this point in the history
Fix #306
  • Loading branch information
Bruno Alla authored and browniebroke committed Jan 20, 2021
1 parent 3dcee1d commit 417e630
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
39 changes: 31 additions & 8 deletions django_codemod/visitors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from libcst import (
Arg,
Attribute,
BaseExpression,
BaseSmallStatement,
Call,
Expand Down Expand Up @@ -74,14 +75,6 @@ def ctx_key_imported_as(self):
def entity_imported_as(self):
return self.context.scratch.get(self.ctx_key_imported_as, None)

@property
def ctx_key_is_name_called(self):
return f"{self.rename_from}-is_name_called"

@property
def entity_is_name_called(self):
return self.context.scratch.get(self.ctx_key_is_name_called, False)

@property
def is_imported_with_old_name(self):
is_imported = self.ctx_key_imported_as in self.context.scratch
Expand Down Expand Up @@ -156,6 +149,14 @@ def add_new_import(self, evaluated_name: Optional[str] = None) -> None:
asname=as_name,
)

@property
def ctx_key_is_name_called(self):
return f"{self.rename_from}-is_name_called"

@property
def entity_is_name_called(self):
return self.context.scratch.get(self.ctx_key_is_name_called, False)

def visit_Call(self, node: Call) -> Optional[bool]:
if self.is_imported_with_old_name and m.matches(
node, m.Call(func=m.Name(self.old_name))
Expand All @@ -167,10 +168,32 @@ 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
):
Expand Down
30 changes: 30 additions & 0 deletions tests/visitors/test_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from libcst import matchers as m
from parameterized import parameterized

from django_codemod.visitors.base import (
BaseFuncRenameTransformer,
Expand Down Expand Up @@ -189,6 +190,35 @@ def something():
"""
self.assertCodemod(before, after)

@parameterized.expand(
[
("response.func",),
("response.func.other",),
("response.func.other.one",),
]
)
def test_attribute_access(self, attribute_access) -> None:
"""When accessing an attribute that looks like the imported name."""
before = f"""
from django.dummy.module import func
result = func()
def test_something():
response = get_response()
assert {attribute_access} == 1
"""
after = f"""
from django.dummy.module import better_func
result = better_func()
def test_something():
response = get_response()
assert {attribute_access} == 1
"""
self.assertCodemod(before, after)


class OtherModuleFuncRenameTransformer(BaseFuncRenameTransformer):
"""Transformer with different module."""
Expand Down

0 comments on commit 417e630

Please sign in to comment.