From 49063341941fa895f366f9209e16d056e66bb628 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sun, 5 Jul 2020 09:59:14 +0700 Subject: [PATCH 1/2] Add BaseSimpleModuleRenameTransformer --- django_codemod/visitors/base.py | 24 +++++++++++++++++-- tests/visitors/test_base.py | 41 ++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/django_codemod/visitors/base.py b/django_codemod/visitors/base.py index 42a4f242..54ee4892 100644 --- a/django_codemod/visitors/base.py +++ b/django_codemod/visitors/base.py @@ -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 @@ -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.""" diff --git a/tests/visitors/test_base.py b/tests/visitors/test_base.py index 32d8255a..5376d6f6 100644 --- a/tests/visitors/test_base.py +++ b/tests/visitors/test_base.py @@ -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 @@ -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" @@ -40,7 +44,7 @@ class SameModuleRenameTransformer(BaseSimpleFuncRenameTransformer): class TestSimpleFuncRenameTransformer(BaseVisitorTest): - transformer = SameModuleRenameTransformer + transformer = SameModuleFuncRenameTransformer def test_simple_substitution(self) -> None: before = """ @@ -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 = """ @@ -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): + + 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) From d6c7ea0dd7a92b813dc00457b22383cdd9b2e329 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sat, 4 Jul 2020 21:33:20 +0700 Subject: [PATCH 2/2] Add URLResolversTransformer --- django_codemod/visitors/__init__.py | 2 ++ django_codemod/visitors/core.py | 11 +++++++++++ docs/codemods.md | 6 ++++++ tests/test_cli.py | 3 ++- tests/visitors/test_core.py | 20 ++++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 django_codemod/visitors/core.py create mode 100644 tests/visitors/test_core.py diff --git a/django_codemod/visitors/__init__.py b/django_codemod/visitors/__init__.py index d378c7ae..cfc86707 100644 --- a/django_codemod/visitors/__init__.py +++ b/django_codemod/visitors/__init__.py @@ -1,4 +1,5 @@ from .admin import InlineHasAddPermissionsTransformer +from .core import URLResolversTransformer from .decorators import AvailableAttrsTransformer, ContextDecoratorTransformer from .encoding import ( ForceTextTransformer, @@ -48,6 +49,7 @@ "UNGetTextLazyTransformer", "UNGetTextTransformer", "URLTransformer", + "URLResolversTransformer", "UnescapeEntitiesTransformer", "UnicodeCompatibleTransformer", ) diff --git a/django_codemod/visitors/core.py b/django_codemod/visitors/core.py new file mode 100644 index 00000000..d3c1e13c --- /dev/null +++ b/django_codemod/visitors/core.py @@ -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): + """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" diff --git a/docs/codemods.md b/docs/codemods.md index 78279be4..a64931cc 100644 --- a/docs/codemods.md +++ b/docs/codemods.md @@ -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: diff --git a/tests/test_cli.py b/tests/test_cli.py index dd231e5b..fbdc7d7f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -189,6 +189,7 @@ def test_deprecated_in_mapping(): "UnicodeCompatibleTransformer", ], (1, 11): ["ModelsPermalinkTransformer"], + (1, 10): ["URLResolversTransformer"], (1, 9): ["OnDeleteTransformer"], } @@ -222,5 +223,5 @@ def test_removed_in_mapping(): "UnicodeCompatibleTransformer", ], (2, 1): ["ModelsPermalinkTransformer"], - (2, 0): ["OnDeleteTransformer"], + (2, 0): ["OnDeleteTransformer", "URLResolversTransformer"], } diff --git a/tests/visitors/test_core.py b/tests/visitors/test_core.py new file mode 100644 index 00000000..30d86f1e --- /dev/null +++ b/tests/visitors/test_core.py @@ -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)