Skip to content

Commit

Permalink
Merge pull request #22 from browniebroke/feature/url-to-re-path
Browse files Browse the repository at this point in the history
  • Loading branch information
browniebroke authored May 10, 2020
2 parents 17e4e81 + 5f516ab commit 3f51538
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 21 deletions.
54 changes: 35 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,42 @@ This is based on
implements codemods for it. This is currently very limited but the aim
is to add more for helping with upcoming deprecations.

Currently implemented:

- `django_codemod.commands.django_40.ForceTextToForceStrCommand`:
migrate deprecated `force_text()` function to `force_str()`.
- `django_codemod.commands.django_40.SmartTextToForceStrCommand`:
migrate deprecated `smart_text()` function to `smart_str()`.
- `django_codemod.commands.django_40.UGetTextToGetTextCommand`:
migrate deprecated `ugettext()` function to `gettext()`.
- `django_codemod.commands.django_40.UGetTextLazyToGetTextLazyCommand`:
migrate deprecated `ugettext_lazy()` function to `gettext_lazy()`.
- `django_codemod.commands.django_40.UGetTextNoopToGetTextNoopCommand`:
migrate deprecated `ugettext_noop()` function to `gettext_noop()`.
- `django_codemod.commands.django_40.UNGetTextToNGetTextCommand`:
migrate deprecated `ungettext()` function to `ngettext()`.
- `django_codemod.commands.django_40.UNGetTextLazyToNGetTextLazyCommand`:
migrate deprecated `ungettext_lazy()` function to `ngettext_lazy()`.

Not finding what you need? I\'m open to contributions, please send me a
pull request.
Currently implemented codemodders are listed below and grouped
by the version of Django where deprecations are removed.

Not finding what you need? I'm open to contributions,
please send me a pull request.

### Django 4.0

All these are in the module `django_codemod.commands.django_40`:

- `ForceTextToForceStrCommand`: migrate deprecated `force_text()` function to `force_str()`.
- `SmartTextToForceStrCommand`: migrate deprecated `smart_text()` function to `smart_str()`.
- `UGetTextToGetTextCommand`: migrate deprecated `ugettext()` function to `gettext()`.
- `UGetTextLazyToGetTextLazyCommand`: migrate deprecated `ugettext_lazy()` function to `gettext_lazy()`.
- `UGetTextNoopToGetTextNoopCommand`: migrate deprecated `ugettext_noop()` function to `gettext_noop()`.
- `UNGetTextToNGetTextCommand`: migrate deprecated `ungettext()` function to `ngettext()`.
- `UNGetTextLazyToNGetTextLazyCommand`: migrate deprecated `ungettext_lazy()` function to `ngettext_lazy()`.
- `URLToRePathCommand`: migrate deprecated `url()` function to `re_path()`.

### Django 3.2

All these are in the module `django_codemod.commands.django_32`:

Nothing these yet!

### Django 3.1

All these are in the module `django_codemod.commands.django_31`:

Nothing these yet!

### Django 3.0

All these are in the module `django_codemod.commands.django_30`:

Nothing these yet!

## Contributors ✨

Expand Down
61 changes: 59 additions & 2 deletions django_codemod/commands/django_40.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@
This is expected to cover most of the things listed in this section:
https://docs.djangoproject.com/en/dev/internals/deprecation/#deprecation-removed-in-4-0
"""
from libcst import matchers as m
from libcst._nodes.statement import ImportFrom
from typing import Union

from libcst import (
matchers as m,
RemovalSentinel,
Call,
BaseExpression,
Name,
RemoveFromParent,
)
from libcst._nodes.statement import ImportFrom, BaseSmallStatement
from libcst.codemod import VisitorBasedCodemodCommand
from libcst.codemod.visitors import AddImportsVisitor

from django_codemod.commands.base import BaseSimpleFuncRename

Expand Down Expand Up @@ -90,3 +101,49 @@ class UNGetTextLazyToNGetTextLazyCommand(UGetTextToGetTextCommand):
DESCRIPTION: str = "Replaces ungettext_lazy() by ngettext_lazy()."
old_name = "ungettext_lazy"
new_name = "ngettext_lazy"


class URLToRePathCommand(VisitorBasedCodemodCommand):
"""Resolve deprecation of django.conf.urls.url."""

def _test_import_from(self, node: ImportFrom) -> bool:
return m.matches(
node,
m.ImportFrom(
module=m.Attribute(
value=m.Attribute(
value=m.Name("django"), attr=m.Name(value="conf")
),
attr=m.Name("urls"),
),
),
)

def leave_ImportFrom(
self, original_node: ImportFrom, updated_node: ImportFrom
) -> Union[BaseSmallStatement, RemovalSentinel]:
if self._test_import_from(updated_node):
new_names = []
new_import_missing = True
new_import_alias = None
for import_alias in original_node.names:
if import_alias.evaluated_name == "url":
AddImportsVisitor.add_needed_import(
self.context, "django.urls", "re_path",
)
else:
if import_alias.evaluated_name == "re_path":
new_import_missing = False
new_names.append(import_alias)
if new_import_missing and new_import_alias is not None:
new_names.append(new_import_alias)
if not new_names:
return RemoveFromParent()
new_names = list(sorted(new_names, key=lambda n: n.evaluated_name))
return ImportFrom(module=updated_node.module, names=new_names)
return super().leave_ImportFrom(original_node, updated_node)

def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression:
if m.matches(updated_node, m.Call(func=m.Name("url"))):
return Call(args=updated_node.args, func=Name("re_path"))
return super().leave_Call(original_node, updated_node)
69 changes: 69 additions & 0 deletions tests/commands/test_django_40.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
UGetTextNoopToGetTextNoopCommand,
UNGetTextToNGetTextCommand,
UNGetTextLazyToNGetTextLazyCommand,
URLToRePathCommand,
)


Expand Down Expand Up @@ -379,3 +380,71 @@ def test_already_imported_substitution(self) -> None:
result = ngettext_lazy(content, plural_content, count)
"""
self.assertCodemod(before, after)


class TestURLToRePathCommand(CodemodTest):

TRANSFORM = URLToRePathCommand

def test_noop(self) -> None:
"""Test when nothing should change."""
before = """
from django.urls import include, re_path
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^weblog/', include('blog.urls')),
]
"""
after = """
from django.urls import include, re_path
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^weblog/', include('blog.urls')),
]
"""

self.assertCodemod(before, after)

def test_simple_substitution(self) -> None:
"""Check simple use case."""
before = """
from django.urls import include
from django.conf.urls import url
urlpatterns = [
url(r'^index/$', views.index, name='index'),
url(r'^weblog/', include('blog.urls')),
]
"""
after = """
from django.urls import re_path, include
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^weblog/', include('blog.urls')),
]
"""
self.assertCodemod(before, after)

def test_already_imported_substitution(self) -> None:
"""Test case where re_path is already in the imports."""
before = """
from django.urls import include, re_path
from django.conf.urls import url
urlpatterns = [
url(r'^index/$', views.index, name='index'),
re_path(r'^weblog/', include('blog.urls')),
]
"""
after = """
from django.urls import include, re_path
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^weblog/', include('blog.urls')),
]
"""
self.assertCodemod(before, after)

0 comments on commit 3f51538

Please sign in to comment.