2
0
Эх сурвалжийг харах

Fixed #28135 -- Made simplify_regex() handle non-capturing groups.

Ayush Joshi 3 жил өмнө
parent
commit
0a17666045

+ 17 - 1
django/contrib/admindocs/utils.py

@@ -137,9 +137,10 @@ if docutils_is_available:
     for name, urlbase in ROLES.items():
         create_reference_role(name, urlbase)
 
-# Match the beginning of a named or unnamed group.
+# Match the beginning of a named, unnamed, or non-capturing groups.
 named_group_matcher = _lazy_re_compile(r'\(\?P(<\w+>)')
 unnamed_group_matcher = _lazy_re_compile(r'\(')
+non_capturing_group_matcher = _lazy_re_compile(r'\(\?\:')
 
 
 def replace_metacharacters(pattern):
@@ -210,3 +211,18 @@ def replace_unnamed_groups(pattern):
         final_pattern += pattern[:start] + '<var>'
         prev_end = end
     return final_pattern + pattern[prev_end:]
+
+
+def remove_non_capturing_groups(pattern):
+    r"""
+    Find non-capturing groups in the given `pattern` and remove them, e.g.
+    1. (?P<a>\w+)/b/(?:\w+)c(?:\w+) => (?P<a>\\w+)/b/c
+    2. ^(?:\w+(?:\w+))a => ^a
+    3. ^a(?:\w+)/b(?:\w+) => ^a/b
+    """
+    group_start_end_indices = _find_groups(pattern, non_capturing_group_matcher)
+    final_pattern, prev_end = '', None
+    for start, end, _ in group_start_end_indices:
+        final_pattern += pattern[prev_end:start]
+        prev_end = end
+    return final_pattern + pattern[prev_end:]

+ 3 - 1
django/contrib/admindocs/views.py

@@ -8,7 +8,8 @@ from django.contrib import admin
 from django.contrib.admin.views.decorators import staff_member_required
 from django.contrib.admindocs import utils
 from django.contrib.admindocs.utils import (
-    replace_metacharacters, replace_named_groups, replace_unnamed_groups,
+    remove_non_capturing_groups, replace_metacharacters, replace_named_groups,
+    replace_unnamed_groups,
 )
 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
 from django.db import models
@@ -410,6 +411,7 @@ def simplify_regex(pattern):
     example, turn "^(?P<sport_slug>\w+)/athletes/(?P<athlete_slug>\w+)/$"
     into "/<sport_slug>/athletes/<athlete_slug>/".
     """
+    pattern = remove_non_capturing_groups(pattern)
     pattern = replace_named_groups(pattern)
     pattern = replace_unnamed_groups(pattern)
     pattern = replace_metacharacters(pattern)

+ 7 - 0
tests/admin_docs/test_views.py

@@ -397,6 +397,13 @@ class AdminDocViewFunctionsTests(SimpleTestCase):
             (r'^(?P<a>(x|y))/b/(?P<c>\w+)', '/<a>/b/<c>'),
             (r'^(?P<a>(x|y))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
             (r'^(?P<a>(x|y)(\(|\)))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
+            # Non-capturing groups.
+            (r'^a(?:\w+)b', '/ab'),
+            (r'^a(?:(x|y))', '/a'),
+            (r'^(?:\w+(?:\w+))a', '/a'),
+            (r'^a(?:\w+)/b(?:\w+)', '/a/b'),
+            (r'(?P<a>\w+)/b/(?:\w+)c(?:\w+)', '/<a>/b/c'),
+            (r'(?P<a>\w+)/b/(\w+)/(?:\w+)c(?:\w+)', '/<a>/b/<var>/c'),
             # Single and repeated metacharacters.
             (r'^a', '/a'),
             (r'^^a', '/a'),