Browse Source

Fixed #35090 -- Deprecated registering URL converters with the same name.

Salvo Polizzi 1 year ago
parent
commit
6e1ece7ed5

+ 12 - 0
django/urls/converters.py

@@ -1,5 +1,8 @@
 import functools
 import uuid
+import warnings
+
+from django.utils.deprecation import RemovedInDjango60Warning
 
 
 class IntConverter:
@@ -53,6 +56,15 @@ REGISTERED_CONVERTERS = {}
 
 
 def register_converter(converter, type_name):
+    if type_name in REGISTERED_CONVERTERS or type_name in DEFAULT_CONVERTERS:
+        # RemovedInDjango60Warning: when the deprecation ends, replace with
+        # raise ValueError(f"Converter {type_name} is already registered.")
+        warnings.warn(
+            f"Converter {type_name!r} is already registered. Support for overriding "
+            "registered converters is deprecated and will be removed in Django 6.0.",
+            RemovedInDjango60Warning,
+            stacklevel=2,
+        )
     REGISTERED_CONVERTERS[type_name] = converter()
     get_converters.cache_clear()
 

+ 3 - 0
docs/internals/deprecation.txt

@@ -74,6 +74,9 @@ details on these changes.
 * The setter for ``django.contrib.gis.gdal.OGRGeometry.coord_dim`` will be
   removed.
 
+* ``django.urls.register_converter()`` will no longer allow overriding existing
+  converters.
+
 .. _deprecation-removed-in-5.1:
 
 5.1

+ 4 - 0
docs/ref/urls.txt

@@ -120,6 +120,10 @@ The ``converter`` argument is a converter class, and ``type_name`` is the
 converter name to use in path patterns. See
 :ref:`registering-custom-path-converters` for an example.
 
+.. deprecated:: 5.1
+
+    Overriding existing converters is deprecated.
+
 ==================================================
 ``django.conf.urls`` functions for use in URLconfs
 ==================================================

+ 3 - 0
docs/releases/5.1.txt

@@ -419,6 +419,9 @@ Miscellaneous
 * Setting ``django.contrib.gis.gdal.OGRGeometry.coord_dim`` is deprecated. Use
   :meth:`~django.contrib.gis.gdal.OGRGeometry.set_3d` instead.
 
+* Overriding existing converters with ``django.urls.register_converter()`` is
+  deprecated.
+
 Features removed in 5.1
 =======================
 

+ 5 - 0
docs/topics/http/urls.txt

@@ -183,6 +183,11 @@ Register custom converter classes in your URLconf using
         ...,
     ]
 
+.. deprecated:: 5.1
+
+    Overriding existing converters with ``django.urls.register_converter()`` is
+    deprecated.
+
 Using regular expressions
 =========================
 

+ 34 - 2
tests/urlpatterns/tests.py

@@ -4,10 +4,20 @@ import uuid
 from django.core.exceptions import ImproperlyConfigured
 from django.test import SimpleTestCase
 from django.test.utils import override_settings
-from django.urls import NoReverseMatch, Resolver404, path, re_path, resolve, reverse
+from django.urls import (
+    NoReverseMatch,
+    Resolver404,
+    path,
+    re_path,
+    register_converter,
+    resolve,
+    reverse,
+)
+from django.urls.converters import IntConverter
+from django.utils.deprecation import RemovedInDjango60Warning
 from django.views import View
 
-from .converters import DynamicConverter
+from .converters import Base64Converter, DynamicConverter
 from .views import empty_view
 
 included_kwargs = {"base": b"hello", "value": b"world"}
@@ -193,6 +203,28 @@ class SimplifiedURLTests(SimpleTestCase):
         with self.assertRaisesMessage(ImproperlyConfigured, msg):
             path("foo/<nonexistent:var>/", empty_view)
 
+    def test_warning_override_default_converter(self):
+        # RemovedInDjango60Warning: when the deprecation ends, replace with
+        # msg = "Converter 'int' is already registered."
+        # with self.assertRaisesMessage(ValueError, msg):
+        msg = (
+            "Converter 'int' is already registered. Support for overriding registered "
+            "converters is deprecated and will be removed in Django 6.0."
+        )
+        with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
+            register_converter(IntConverter, "int")
+
+    def test_warning_override_converter(self):
+        # RemovedInDjango60Warning: when the deprecation ends, replace with
+        # msg = "Converter 'base64' is already registered."
+        # with self.assertRaisesMessage(ValueError, msg):
+        msg = (
+            "Converter 'base64' is already registered. Support for overriding "
+            "registered converters is deprecated and will be removed in Django 6.0."
+        )
+        with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
+            register_converter(Base64Converter, "base64")
+
     def test_invalid_view(self):
         msg = "view must be a callable or a list/tuple in the case of include()."
         with self.assertRaisesMessage(TypeError, msg):