From 1358a67bf95cde86b09b689b4f10f2eeb642de31 Mon Sep 17 00:00:00 2001 From: Marten Kenbeek Date: Thu, 12 Jan 2017 03:40:18 +0100 Subject: [PATCH] Fixed #27713 -- Clarified NoReverseMatch error message when no view is found. --- django/urls/resolvers.py | 22 +++++++++++++++++----- tests/urlpatterns_reverse/tests.py | 27 +++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index 0bb5645dc1..1de59a8763 100644 --- a/django/urls/resolvers.py +++ b/django/urls/resolvers.py @@ -478,11 +478,23 @@ class RegexURLResolver(LocaleRegexProvider): lookup_view_s = lookup_view patterns = [pattern for (possibility, pattern, defaults) in possibilities] - raise NoReverseMatch( - "Reverse for '%s' with arguments '%s' and keyword " - "arguments '%s' not found. %d pattern(s) tried: %s" % - (lookup_view_s, args, kwargs, len(patterns), patterns) - ) + if patterns: + if args: + arg_msg = "arguments '%s'" % (args,) + elif kwargs: + arg_msg = "keyword arguments '%s'" % (kwargs,) + else: + arg_msg = "no arguments" + msg = ( + "Reverse for '%s' with %s not found. %d pattern(s) tried: %s" % + (lookup_view_s, arg_msg, len(patterns), patterns) + ) + else: + msg = ( + "Reverse for '%(view)s' not found. '%(view)s' is not " + "a valid view function or pattern name." % {'view': lookup_view_s} + ) + raise NoReverseMatch(msg) class LocaleRegexURLResolver(RegexURLResolver): diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py index b02898e345..b332ac4f7e 100644 --- a/tests/urlpatterns_reverse/tests.py +++ b/tests/urlpatterns_reverse/tests.py @@ -330,6 +330,29 @@ class URLPatternReverse(SimpleTestCase): six.text_type ) + def test_view_not_found_message(self): + msg = ( + "Reverse for 'non-existent-view' not found. 'non-existent-view' " + "is not a valid view function or pattern name." + ) + with self.assertRaisesMessage(NoReverseMatch, msg): + reverse('non-existent-view') + + def test_no_args_message(self): + msg = "Reverse for 'places' with no arguments not found. 1 pattern(s) tried:" + with self.assertRaisesMessage(NoReverseMatch, msg): + reverse('places') + + def test_illegal_args_message(self): + msg = "Reverse for 'places' with arguments '(1, 2)' not found. 1 pattern(s) tried:" + with self.assertRaisesMessage(NoReverseMatch, msg): + reverse('places', args=(1, 2)) + + def test_illegal_kwargs_message(self): + msg = "Reverse for 'places' with keyword arguments '{'arg1': 2}' not found. 1 pattern(s) tried:" + with self.assertRaisesMessage(NoReverseMatch, msg): + reverse('places', kwargs={str('arg1'): 2}) + class ResolverTests(SimpleTestCase): @ignore_warnings(category=RemovedInDjango20Warning) @@ -860,7 +883,7 @@ class RequestURLconfTests(SimpleTestCase): Test reversing an URL from the *default* URLconf from inside a response middleware. """ - message = "Reverse for 'outer' with arguments '()' and keyword arguments '{}' not found." + message = "Reverse for 'outer' not found." with self.assertRaisesMessage(NoReverseMatch, message): self.client.get('/second_test/') @@ -890,7 +913,7 @@ class RequestURLconfTests(SimpleTestCase): Test reversing an URL from the *default* URLconf from inside a streaming response. """ - message = "Reverse for 'outer' with arguments '()' and keyword arguments '{}' not found." + message = "Reverse for 'outer' not found." with self.assertRaisesMessage(NoReverseMatch, message): self.client.get('/second_test/') b''.join(self.client.get('/second_test/'))