Browse Source

Fixed #34691 -- Added system check for unmatched angle brackets in path().

Amir Karimi 1 year ago
parent
commit
d1855c4847

+ 1 - 0
AUTHORS

@@ -62,6 +62,7 @@ answer newbie questions, and generally made Django that much better:
     Aljaž Košir <aljazkosir5@gmail.com>
     Aljosa Mohorovic <aljosa.mohorovic@gmail.com>
     Alokik Vijay <alokik.roe@gmail.com>
+    Amir Karimi <amk9978@gmail.com>
     Amit Chakradeo <https://amit.chakradeo.net/>
     Amit Ramon <amit.ramon@gmail.com>
     Amit Upadhyay <http://www.amitu.com/blog/>

+ 32 - 1
django/urls/resolvers.py

@@ -318,7 +318,10 @@ class RoutePattern(CheckURLMixin):
         return None
 
     def check(self):
-        warnings = self._check_pattern_startswith_slash()
+        warnings = [
+            *self._check_pattern_startswith_slash(),
+            *self._check_pattern_unmatched_angle_brackets(),
+        ]
         route = self._route
         if "(?P<" in route or route.startswith("^") or route.endswith("$"):
             warnings.append(
@@ -331,6 +334,34 @@ class RoutePattern(CheckURLMixin):
             )
         return warnings
 
+    def _check_pattern_unmatched_angle_brackets(self):
+        warnings = []
+        segments = self._route.split("/")
+        for segment in segments:
+            open_bracket_counter = 0
+            unmatched_angle_bracket = None
+            for char in segment:
+                if char == "<":
+                    open_bracket_counter += 1
+                elif char == ">":
+                    open_bracket_counter -= 1
+                    if open_bracket_counter < 0:
+                        unmatched_angle_bracket = ">"
+                        break
+            else:
+                if open_bracket_counter > 0:
+                    unmatched_angle_bracket = "<"
+
+            if unmatched_angle_bracket is not None:
+                warnings.append(
+                    Warning(
+                        "Your URL pattern %s has an unmatched '%s' bracket."
+                        % (self.describe(), unmatched_angle_bracket),
+                        id="urls.W010",
+                    )
+                )
+        return warnings
+
     def _compile(self, route):
         return re.compile(_route_to_regex(route, self._is_endpoint)[0])
 

+ 2 - 0
docs/ref/checks.txt

@@ -609,6 +609,8 @@ The following checks are performed on your URL configuration:
   imported.
 * **urls.E009**: Your URL pattern ``<pattern>`` has an invalid view, pass
   ``<view>.as_view()`` instead of ``<view>``.
+* **urls.W010**: Your URL pattern ``<pattern>` has an unmatched
+  ``<angle bracket>``.
 
 ``contrib`` app checks
 ======================

+ 41 - 0
tests/check_framework/test_urls.py

@@ -161,6 +161,47 @@ class CheckUrlConfigTests(SimpleTestCase):
             ],
         )
 
+    @override_settings(
+        ROOT_URLCONF="check_framework.urls.path_compatibility.matched_angle_brackets"
+    )
+    def test_no_warnings_matched_angle_brackets(self):
+        self.assertEqual(check_url_config(None), [])
+
+    @override_settings(
+        ROOT_URLCONF="check_framework.urls.path_compatibility.unmatched_angle_brackets"
+    )
+    def test_warning_unmatched_angle_brackets(self):
+        self.assertEqual(
+            check_url_config(None),
+            [
+                Warning(
+                    "Your URL pattern 'beginning-with/<angle_bracket' has an unmatched "
+                    "'<' bracket.",
+                    id="urls.W010",
+                ),
+                Warning(
+                    "Your URL pattern 'ending-with/angle_bracket>' has an unmatched "
+                    "'>' bracket.",
+                    id="urls.W010",
+                ),
+                Warning(
+                    "Your URL pattern 'closed_angle>/x/<opened_angle' has an unmatched "
+                    "'>' bracket.",
+                    id="urls.W010",
+                ),
+                Warning(
+                    "Your URL pattern 'closed_angle>/x/<opened_angle' has an unmatched "
+                    "'<' bracket.",
+                    id="urls.W010",
+                ),
+                Warning(
+                    "Your URL pattern '<mixed>angle_bracket>' has an unmatched '>' "
+                    "bracket.",
+                    id="urls.W010",
+                ),
+            ],
+        )
+
 
 class UpdatedToPathTests(SimpleTestCase):
     @override_settings(

+ 5 - 0
tests/check_framework/urls/path_compatibility/matched_angle_brackets.py

@@ -0,0 +1,5 @@
+from django.urls import path
+
+urlpatterns = [
+    path("<int:angle_bracket>", lambda x: x),
+]

+ 8 - 0
tests/check_framework/urls/path_compatibility/unmatched_angle_brackets.py

@@ -0,0 +1,8 @@
+from django.urls import path
+
+urlpatterns = [
+    path("beginning-with/<angle_bracket", lambda x: x),
+    path("ending-with/angle_bracket>", lambda x: x),
+    path("closed_angle>/x/<opened_angle", lambda x: x),
+    path("<mixed>angle_bracket>", lambda x: x),
+]