From 998c9dd599cd907bb38f440fff13a808571589f8 Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Tue, 7 Nov 2017 16:39:59 +0000 Subject: [PATCH] Fixed #28663 -- Add a check for likely incorrectly migrated django.urls.path() routes. --- django/urls/resolvers.py | 11 ++++++- docs/ref/checks.txt | 4 ++- tests/check_framework/test_urls.py | 30 +++++++++++++++++++ .../urls/path_compatibility/__init__.py | 0 .../beginning_with_caret.py | 5 ++++ .../contains_re_named_group.py | 5 ++++ .../path_compatibility/ending_with_dollar.py | 5 ++++ 7 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/check_framework/urls/path_compatibility/__init__.py create mode 100644 tests/check_framework/urls/path_compatibility/beginning_with_caret.py create mode 100644 tests/check_framework/urls/path_compatibility/contains_re_named_group.py create mode 100644 tests/check_framework/urls/path_compatibility/ending_with_dollar.py diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index 412b7458be..7e8187d95c 100644 --- a/django/urls/resolvers.py +++ b/django/urls/resolvers.py @@ -255,7 +255,16 @@ class RoutePattern(CheckURLMixin): return None def check(self): - return self._check_pattern_startswith_slash() + warnings = self._check_pattern_startswith_slash() + route = self._route + if '(?P<' in route or route.startswith('^') or route.endswith('$'): + warnings.append(Warning( + "Your URL pattern {} has a route that contains '(?P<', begins " + "with a '^', or ends with a '$'. This was likely an oversight " + "when migrating to django.urls.path().".format(self.describe()), + id='2_0.W001', + )) + return warnings def _compile(self, route): return re.compile(_route_to_regex(route, self._is_endpoint)[0]) diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 62c8204def..9b3f1be356 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -98,7 +98,9 @@ Backwards compatibility Compatibility checks warn of potential problems that might occur after upgrading Django. -Currently, there aren't any of these checks. +* **2_0.W001**: Your URL pattern ```` has a ``route`` that contains + ``(?P<``, begins with a ``^``, or ends with a ``$``. This was likely an + oversight when migrating from ``url()`` to :func:`~django.urls.path`. Caches ------ diff --git a/tests/check_framework/test_urls.py b/tests/check_framework/test_urls.py index 5a0d811433..aa53af930e 100644 --- a/tests/check_framework/test_urls.py +++ b/tests/check_framework/test_urls.py @@ -135,6 +135,36 @@ class CheckUrlConfigTests(SimpleTestCase): self.assertEqual(result, []) +class UpdatedToPathTests(SimpleTestCase): + + @override_settings(ROOT_URLCONF='check_framework.urls.path_compatibility.contains_re_named_group') + def test_contains_re_named_group(self): + result = check_url_config(None) + self.assertEqual(len(result), 1) + warning = result[0] + self.assertEqual(warning.id, '2_0.W001') + expected_msg = "Your URL pattern '(?P\\d+)' has a route" + self.assertIn(expected_msg, warning.msg) + + @override_settings(ROOT_URLCONF='check_framework.urls.path_compatibility.beginning_with_caret') + def test_beginning_with_caret(self): + result = check_url_config(None) + self.assertEqual(len(result), 1) + warning = result[0] + self.assertEqual(warning.id, '2_0.W001') + expected_msg = "Your URL pattern '^beginning-with-caret' has a route" + self.assertIn(expected_msg, warning.msg) + + @override_settings(ROOT_URLCONF='check_framework.urls.path_compatibility.ending_with_dollar') + def test_ending_with_dollar(self): + result = check_url_config(None) + self.assertEqual(len(result), 1) + warning = result[0] + self.assertEqual(warning.id, '2_0.W001') + expected_msg = "Your URL pattern 'ending-with-dollar$' has a route" + self.assertIn(expected_msg, warning.msg) + + class CheckURLSettingsTests(SimpleTestCase): @override_settings(STATIC_URL='a/', MEDIA_URL='b/') diff --git a/tests/check_framework/urls/path_compatibility/__init__.py b/tests/check_framework/urls/path_compatibility/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/urls/path_compatibility/beginning_with_caret.py b/tests/check_framework/urls/path_compatibility/beginning_with_caret.py new file mode 100644 index 0000000000..7e3e9c8707 --- /dev/null +++ b/tests/check_framework/urls/path_compatibility/beginning_with_caret.py @@ -0,0 +1,5 @@ +from django.urls import path + +urlpatterns = [ + path('^beginning-with-caret', lambda x: x), +] diff --git a/tests/check_framework/urls/path_compatibility/contains_re_named_group.py b/tests/check_framework/urls/path_compatibility/contains_re_named_group.py new file mode 100644 index 0000000000..76c4939f3f --- /dev/null +++ b/tests/check_framework/urls/path_compatibility/contains_re_named_group.py @@ -0,0 +1,5 @@ +from django.urls import path + +urlpatterns = [ + path('(?P\d+)', lambda x: x), +] diff --git a/tests/check_framework/urls/path_compatibility/ending_with_dollar.py b/tests/check_framework/urls/path_compatibility/ending_with_dollar.py new file mode 100644 index 0000000000..0ea82a1ba6 --- /dev/null +++ b/tests/check_framework/urls/path_compatibility/ending_with_dollar.py @@ -0,0 +1,5 @@ +from django.urls import path + +urlpatterns = [ + path('ending-with-dollar$', lambda x: x), +]