Skip to content

Commit

Permalink
Adds fixer: gis_admin_deprecations for Django 5.0
Browse files Browse the repository at this point in the history
Allows replacement of OSMGeoAdmin and GeoModelAdmin with GISModelAdmin
from the same module, those classe were removed on Django 5.0:
https://docs.djangoproject.com/en/5.0/releases/5.0/#django-contrib-gis
  • Loading branch information
fitoria committed Aug 19, 2024
1 parent 2eb9dea commit 22c4435
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,32 @@ Such use cases are why calling ``format_html()`` without any arguments or keywor
-format_html("<marquee>{name}</marquee>".format(name=name))
+format_html("<marquee>{name}</marquee>", name=name)
Replace deprecated ``OSMGeoAdmin`` and ``GeoModelAdmin`` classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Name:** ``gis_admin_deprecations``

Rewrites imports and calls for ``OSMGeoAdmin`` and ``GeoModelAdmin`` on imports and admin base classes.
The new GISModelAdmin class allows customizing the widget used for GeometryField. This is encouraged instead of deprecated GeoModelAdmin and OSMGeoAdmin.
This was deprecated in `Ticket #34609 <https://code.djangoproject.com/ticket/27674>`__.

.. code-block:: diff
-from django.contrib.gis.admin.options import OSMGeoAdmin
+from django.contrib.gis.admin.options import GISModelAdmin
-class MyAdminClass(OSMGeoAdmin):
+class MyAdminClass(GISModelAdmin):
.. code-block:: diff
-from django.contrib.gis.admin.options import GeoModelAdmin
+from django.contrib.gis.admin.options import GISModelAdmin
-class MyAdminClass(GeoModelAdmin):
+class MyAdminClass(GISModelAdmin):
Django 4.2
----------

Expand Down
65 changes: 65 additions & 0 deletions src/django_upgrade/fixers/gis_admin_deprecations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Rename OSMGeoAdmin to GISModelAdmin in django.contrib.gis.admin.options
due to deprecation on Django 5.0:
https://docs.djangoproject.com/en/5.0/releases/5.0/#features-removed-in-5-0
"""

from __future__ import annotations

import ast
from functools import partial
from typing import Iterable

from tokenize_rt import Offset

from django_upgrade.ast import ast_start_offset
from django_upgrade.ast import is_rewritable_import_from
from django_upgrade.data import Fixer
from django_upgrade.data import State
from django_upgrade.data import TokenFunc
from django_upgrade.tokens import find_and_replace_name
from django_upgrade.tokens import update_import_names

fixer = Fixer(
__name__,
min_version=(5, 0),
)

MODULE = "django.contrib.gis.admin.options"
RENAMES = {
"OSMGeoAdmin": "GISModelAdmin",
"GeoModelAdmin": "GISModelAdmin",
}


@fixer.register(ast.ImportFrom)
def visit_ImportFrom(
state: State,
node: ast.ImportFrom,
parents: tuple[ast.AST, ...],
) -> Iterable[tuple[Offset, TokenFunc]]:
if node.module == MODULE and is_rewritable_import_from(node):
name_map = {}
for alias in node.names:
if alias.name in RENAMES:
name_map[alias.name] = RENAMES[alias.name]

if name_map:
yield ast_start_offset(node), partial(
update_import_names,
node=node,
name_map=name_map,
)


@fixer.register(ast.Name)
def visit_Name(
state: State,
node: ast.Name,
parents: tuple[ast.AST, ...],
) -> Iterable[tuple[Offset, TokenFunc]]:
if (name := node.id) in RENAMES and name in state.from_imports[MODULE]:
new_name = RENAMES[name]
yield ast_start_offset(node), partial(
find_and_replace_name, name=name, new=new_name
)
83 changes: 83 additions & 0 deletions tests/fixers/test_gis_admin_deprecations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from __future__ import annotations

from functools import partial

from django_upgrade.data import Settings
from tests.fixers import tools

settings = Settings(target_version=(5, 0))
check_noop = partial(tools.check_noop, settings=settings)
check_transformed = partial(tools.check_transformed, settings=settings)


def test_no_deprecated_alias():
check_noop(
"""\
from django.contrib.gis.admin.options import GeoAdmin
GeoAdmin
""",
)


def test_one_local_name():
check_transformed(
"""\
from django.contrib.gis.admin.options import OSMGeoAdmin
class MyModelAdmin(OSMGeoAdmin):
pass
""",
"""\
from django.contrib.gis.admin.options import GISModelAdmin
class MyModelAdmin(GISModelAdmin):
pass
""",
)
check_transformed(
"""\
from django.contrib.gis.admin.options import GeoModelAdmin
class MyModelAdmin(GeoModelAdmin):
pass
""",
"""\
from django.contrib.gis.admin.options import GISModelAdmin
class MyModelAdmin(GISModelAdmin):
pass
""",
)


def test_with_alias():
check_transformed(
"""\
from django.contrib.gis.admin.options import OSMGeoAdmin as GeoAdmin
class MyModelAdmin(GeoAdmin):
pass
""",
"""\
from django.contrib.gis.admin.options import GISModelAdmin as GeoAdmin
class MyModelAdmin(GeoAdmin):
pass
""",
)

check_transformed(
"""\
from django.contrib.gis.admin.options import GeoModelAdmin as GeoAdmin
class MyModelAdmin(GeoAdmin):
pass
""",
"""\
from django.contrib.gis.admin.options import GISModelAdmin as GeoAdmin
class MyModelAdmin(GeoAdmin):
pass
""",
)

0 comments on commit 22c4435

Please sign in to comment.