Opened 6 years ago
Closed 6 years ago
#30731 closed Bug (fixed)
simplify_regexp() doesn't replace trailing groups.
| Reported by: | Alan Crosswell | Owned by: | Alan Crosswell |
|---|---|---|---|
| Component: | contrib.admindocs | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | yes | UI/UX: | no |
Description
replace_named_groups() fails to replace the final named group if the urlpattern passed in is missing a trailing '/'.
For example, with input r'entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)' the "related_field" does not get properly replaced. A workaround is to tack on a '/' at the end and then it works.
Code that reproduces this is attached.
This function is used downstream in Django REST Framework. See issue 6888
Attachments (1)
Change History (8)
by , 6 years ago
comment:1 by , 6 years ago
comment:2 by , 6 years ago
| Summary: | django.contrib.admindocs.utils.replace_named_groups() fails substitution if missing trailing / → simplify_regexp() doesn't replace trailing groups. |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Version: | 2.2 → master |
Thanks for the ticket, trailing slash is not necessary regexp patterns could be also enclosed by $, by I agree that this could be easily fix by:
diff --git a/django/contrib/admindocs/utils.py b/django/contrib/admindocs/utils.py
index 1ce4594501..db27f82deb 100644
--- a/django/contrib/admindocs/utils.py
+++ b/django/contrib/admindocs/utils.py
@@ -167,12 +167,6 @@ def replace_named_groups(pattern):
# Handle nested parentheses, e.g. '^(?P<a>(x|y))/b'.
unmatched_open_brackets, prev_char = 1, None
for idx, val in enumerate(pattern[end:]):
- # If brackets are balanced, the end of the string for the current
- # named capture group pattern has been reached.
- if unmatched_open_brackets == 0:
- group_pattern_and_name.append((pattern[start:end + idx], group_name))
- break
-
# Check for unescaped `(` and `)`. They mark the start and end of a
# nested group.
if val == '(' and prev_char != '\\':
@@ -180,6 +174,11 @@ def replace_named_groups(pattern):
elif val == ')' and prev_char != '\\':
unmatched_open_brackets -= 1
prev_char = val
+ # If brackets are balanced, the end of the string for the current
+ # named capture group pattern has been reached.
+ if unmatched_open_brackets == 0:
+ group_pattern_and_name.append((pattern[start:end + idx + 1], group_name))
+ break
# Replace the string for named capture groups with their group names.
for group_pattern, group_name in group_pattern_and_name:
Similar change should be made in replace_unnamed_groups(). Please add testcases to admin_docs.test_views.AdminDocViewFunctionsTests.test_simplify_regex.
comment:3 by , 6 years ago
| Easy pickings: | set |
|---|
comment:4 by , 6 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:6 by , 6 years ago
| Has patch: | set |
|---|
Here's execution of the example code:
(env) django-example$ python demo.py path: entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+) expected: entries/<pk>/relationships/<related_field> got: entries/<pk>/relationships/(?P<related_field>\w+) path_trailing: entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)/ expected: entries/<pk>/relationships/<related_field>/ got: entries/<pk>/relationships/<related_field>/ Traceback (most recent call last): File "demo.py", line 21, in <module> assert path == expected_path, "path without trailing slash didn't match expected" AssertionError: path without trailing slash didn't match expected (env) django-example$