format_suffix_patterns is applied before the trailing slash.

This commit is contained in:
Xavier Ordoquy 2015-06-11 00:32:05 +02:00
parent ca0a7ee1de
commit e7e5946c2e
2 changed files with 40 additions and 16 deletions

View File

@ -21,7 +21,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
else: else:
# Regular URL pattern # Regular URL pattern
regex = urlpattern.regex.pattern.rstrip('$') + suffix_pattern regex = urlpattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern
view = urlpattern._callback or urlpattern._callback_str view = urlpattern._callback or urlpattern._callback_str
kwargs = urlpattern.default_args kwargs = urlpattern.default_args
name = urlpattern.name name = urlpattern.name
@ -55,8 +55,8 @@ def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
allowed_pattern = allowed[0] allowed_pattern = allowed[0]
else: else:
allowed_pattern = '(%s)' % '|'.join(allowed) allowed_pattern = '(%s)' % '|'.join(allowed)
suffix_pattern = r'\.(?P<%s>%s)$' % (suffix_kwarg, allowed_pattern) suffix_pattern = r'\.(?P<%s>%s)/?$' % (suffix_kwarg, allowed_pattern)
else: else:
suffix_pattern = r'\.(?P<%s>[a-z0-9]+)$' % suffix_kwarg suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg
return apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required) return apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required)

View File

@ -17,7 +17,8 @@ def dummy_view(request, *args, **kwargs):
class FormatSuffixTests(TestCase): class FormatSuffixTests(TestCase):
""" """
Tests `format_suffix_patterns` against different URLPatterns to ensure the URLs still resolve properly, including any captured parameters. Tests `format_suffix_patterns` against different URLPatterns to ensure the
URLs still resolve properly, including any captured parameters.
""" """
def _resolve_urlpatterns(self, urlpatterns, test_paths): def _resolve_urlpatterns(self, urlpatterns, test_paths):
factory = APIRequestFactory() factory = APIRequestFactory()
@ -35,11 +36,37 @@ class FormatSuffixTests(TestCase):
self.assertEqual(callback_args, test_path.args) self.assertEqual(callback_args, test_path.args)
self.assertEqual(callback_kwargs, test_path.kwargs) self.assertEqual(callback_kwargs, test_path.kwargs)
def test_trailing_slash(self):
factory = APIRequestFactory()
urlpatterns = format_suffix_patterns([
url(r'^test/$', dummy_view),
])
resolver = urlresolvers.RegexURLResolver(r'^/', urlpatterns)
test_paths = [
(URLTestPath('/test.api', (), {'format': 'api'}), True),
(URLTestPath('/test/.api', (), {'format': 'api'}), False),
(URLTestPath('/test.api/', (), {'format': 'api'}), True),
]
for test_path, expected_resolved in test_paths:
request = factory.get(test_path.path)
try:
callback, callback_args, callback_kwargs = resolver.resolve(request.path_info)
except urlresolvers.Resolver404:
callback, callback_args, callback_kwargs = (None, None, None)
if not expected_resolved:
assert callback is None
continue
print(test_path, callback, callback_args, callback_kwargs)
assert callback_args == test_path.args
assert callback_kwargs == test_path.kwargs
def test_format_suffix(self): def test_format_suffix(self):
urlpatterns = patterns( urlpatterns = [
'',
url(r'^test$', dummy_view), url(r'^test$', dummy_view),
) ]
test_paths = [ test_paths = [
URLTestPath('/test', (), {}), URLTestPath('/test', (), {}),
URLTestPath('/test.api', (), {'format': 'api'}), URLTestPath('/test.api', (), {'format': 'api'}),
@ -48,10 +75,9 @@ class FormatSuffixTests(TestCase):
self._resolve_urlpatterns(urlpatterns, test_paths) self._resolve_urlpatterns(urlpatterns, test_paths)
def test_default_args(self): def test_default_args(self):
urlpatterns = patterns( urlpatterns = [
'',
url(r'^test$', dummy_view, {'foo': 'bar'}), url(r'^test$', dummy_view, {'foo': 'bar'}),
) ]
test_paths = [ test_paths = [
URLTestPath('/test', (), {'foo': 'bar', }), URLTestPath('/test', (), {'foo': 'bar', }),
URLTestPath('/test.api', (), {'foo': 'bar', 'format': 'api'}), URLTestPath('/test.api', (), {'foo': 'bar', 'format': 'api'}),
@ -60,14 +86,12 @@ class FormatSuffixTests(TestCase):
self._resolve_urlpatterns(urlpatterns, test_paths) self._resolve_urlpatterns(urlpatterns, test_paths)
def test_included_urls(self): def test_included_urls(self):
nested_patterns = patterns( nested_patterns = [
'',
url(r'^path$', dummy_view) url(r'^path$', dummy_view)
) ]
urlpatterns = patterns( urlpatterns = [
'',
url(r'^test/', include(nested_patterns), {'foo': 'bar'}), url(r'^test/', include(nested_patterns), {'foo': 'bar'}),
) ]
test_paths = [ test_paths = [
URLTestPath('/test/path', (), {'foo': 'bar', }), URLTestPath('/test/path', (), {'foo': 'bar', }),
URLTestPath('/test/path.api', (), {'foo': 'bar', 'format': 'api'}), URLTestPath('/test/path.api', (), {'foo': 'bar', 'format': 'api'}),