Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module rename support and URLResolversTransformer #123

Merged
merged 2 commits into from
Jul 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions django_codemod/visitors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .admin import InlineHasAddPermissionsTransformer
from .core import URLResolversTransformer
from .decorators import AvailableAttrsTransformer, ContextDecoratorTransformer
from .encoding import (
ForceTextTransformer,
Expand Down Expand Up @@ -48,6 +49,7 @@
"UNGetTextLazyTransformer",
"UNGetTextTransformer",
"URLTransformer",
"URLResolversTransformer",
"UnescapeEntitiesTransformer",
"UnicodeCompatibleTransformer",
)
24 changes: 22 additions & 2 deletions django_codemod/visitors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ def leave_ImportFrom(
return super().leave_ImportFrom(original_node, updated_node)
new_names = []
for import_alias in updated_node.names:
if import_alias.evaluated_name == self.old_name:
if not self.old_name or import_alias.evaluated_name == self.old_name:
as_name = (
import_alias.asname.name.value if import_alias.asname else None
)
AddImportsVisitor.add_needed_import(
context=self.context,
module=".".join(self.new_module_parts),
obj=self.new_name,
obj=self.new_name or import_alias.evaluated_name,
asname=as_name,
)
self.context.scratch[self.ctx_key_is_imported] = not import_alias.asname
Expand All @@ -91,6 +91,26 @@ def is_entity_imported(self):
return self.context.scratch.get(self.ctx_key_is_imported, False)


class BaseSimpleModuleRenameTransformer(BaseSimpleRenameTransformer, ABC):
"""Base class to help rename or move a module."""

@property
def old_name(self):
return ""

@property
def old_module_parts(self):
return self.rename_from.split(".")

@property
def new_name(self):
return ""

@property
def new_module_parts(self):
return self.rename_to.split(".")


class BaseSimpleFuncRenameTransformer(BaseSimpleRenameTransformer, ABC):
"""Base class to help rename or move a function."""

Expand Down
11 changes: 11 additions & 0 deletions django_codemod/visitors/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django_codemod.constants import DJANGO_1_10, DJANGO_2_0
from django_codemod.visitors.base import BaseSimpleModuleRenameTransformer


class URLResolversTransformer(BaseSimpleModuleRenameTransformer):
browniebroke marked this conversation as resolved.
Show resolved Hide resolved
"""Resolve deprecation of ``django.core.urlresolvers``."""

deprecated_in = DJANGO_1_10
removed_in = DJANGO_2_0
rename_from = "django.core.urlresolvers"
rename_to = "django.urls"
6 changes: 6 additions & 0 deletions docs/codemods.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ Applied by passing the `--removed-in 2.0` or `--deprecated-in 1.9` option:
- Adds the `on_delete=models.CASCADE` to all `ForeignKey` and `OneToOneField`s
that don’t use a different option.

## Removed in Django 2.0

Applied by passing the `--removed-in 2.0` or `--deprecated-in 1.10` option:

- Replaces module `django.core.urlresolvers` with `django.urls`.

## Removed in Django 2.1

Applied by passing the `--removed-in 2.1` or `--deprecated-in 1.11` option:
Expand Down
3 changes: 2 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def test_deprecated_in_mapping():
"UnicodeCompatibleTransformer",
],
(1, 11): ["ModelsPermalinkTransformer"],
(1, 10): ["URLResolversTransformer"],
(1, 9): ["OnDeleteTransformer"],
}

Expand Down Expand Up @@ -222,5 +223,5 @@ def test_removed_in_mapping():
"UnicodeCompatibleTransformer",
],
(2, 1): ["ModelsPermalinkTransformer"],
(2, 0): ["OnDeleteTransformer"],
(2, 0): ["OnDeleteTransformer", "URLResolversTransformer"],
}
41 changes: 35 additions & 6 deletions tests/visitors/test_base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import pytest
from libcst import matchers as m

from django_codemod.visitors.base import BaseSimpleFuncRenameTransformer, module_matcher
from django_codemod.visitors.base import (
BaseSimpleFuncRenameTransformer,
BaseSimpleModuleRenameTransformer,
module_matcher,
)

from .base import BaseVisitorTest

Expand Down Expand Up @@ -31,7 +35,7 @@ def test_module_matcher(parts, expected_matcher):
assert repr(matcher) == repr(expected_matcher)


class SameModuleRenameTransformer(BaseSimpleFuncRenameTransformer):
class SameModuleFuncRenameTransformer(BaseSimpleFuncRenameTransformer):
"""Simple transformer renaming function from same module."""

rename_from = "django.dummy.module.func"
Expand All @@ -40,7 +44,7 @@ class SameModuleRenameTransformer(BaseSimpleFuncRenameTransformer):

class TestSimpleFuncRenameTransformer(BaseVisitorTest):

transformer = SameModuleRenameTransformer
transformer = SameModuleFuncRenameTransformer

def test_simple_substitution(self) -> None:
before = """
Expand Down Expand Up @@ -150,16 +154,16 @@ def test_lambda_no_value(self) -> None:
self.assertCodemod(before, after)


class OtherModuleRenameTransformer(BaseSimpleFuncRenameTransformer):
class OtherModuleFuncRenameTransformer(BaseSimpleFuncRenameTransformer):
"""Transformer with different module."""

rename_from = "django.dummy.module.func"
rename_to = "django.better.dummy.better_func"


class TestOtherModuleRenameTransformer(BaseVisitorTest):
class TestOtherModuleFuncRenameTransformer(BaseVisitorTest):

transformer = OtherModuleRenameTransformer
transformer = OtherModuleFuncRenameTransformer

def test_simple_substitution(self) -> None:
before = """
Expand Down Expand Up @@ -200,3 +204,28 @@ def test_import_with_alias(self) -> None:
result = aliased_func()
"""
self.assertCodemod(before, after)


class OtherModuleRenameTransformer(BaseSimpleModuleRenameTransformer):
"""Simple transformer renaming function from same module."""

rename_from = "django.dummy.module"
rename_to = "django.dummy.other_module"


class TestSimpleModuleRenameTransformer(BaseVisitorTest):
browniebroke marked this conversation as resolved.
Show resolved Hide resolved

transformer = OtherModuleRenameTransformer

def test_simple_substitution(self) -> None:
before = """
from django.dummy.module import func

result = func()
"""
after = """
from django.dummy.other_module import func

result = func()
"""
self.assertCodemod(before, after)
20 changes: 20 additions & 0 deletions tests/visitors/test_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django_codemod.visitors import URLResolversTransformer
from tests.visitors.base import BaseVisitorTest


class TestURLResolversTransformer(BaseVisitorTest):

transformer = URLResolversTransformer

def test_simple_substitution(self) -> None:
before = """
from django.core.urlresolvers import path

result = path('foo/', ...)
"""
after = """
from django.urls import path

result = path('foo/', ...)
"""
self.assertCodemod(before, after)