diff -r 41ee28cb9212 django/core/urlresolvers.py
a
|
b
|
|
16 | 16 | from django.utils.encoding import iri_to_uri, force_unicode, smart_str |
17 | 17 | from django.utils.functional import memoize, lazy |
18 | 18 | from django.utils.importlib import import_module |
| 19 | from django.utils.module_loading import module_has_submodule |
19 | 20 | from django.utils.regex_helper import normalize |
20 | 21 | from django.utils.translation import get_language |
21 | 22 | |
… |
… |
|
84 | 85 | during the import fail and the string is returned. |
85 | 86 | """ |
86 | 87 | if not callable(lookup_view): |
| 88 | mod_name, func_name = get_mod_func(lookup_view) |
87 | 89 | try: |
88 | | # Bail early for non-ASCII strings (they can't be functions). |
89 | | lookup_view = lookup_view.encode('ascii') |
90 | | mod_name, func_name = get_mod_func(lookup_view) |
91 | 90 | if func_name != '': |
92 | 91 | lookup_view = getattr(import_module(mod_name), func_name) |
93 | 92 | if not callable(lookup_view): |
94 | | raise AttributeError("'%s.%s' is not a callable." % (mod_name, func_name)) |
95 | | except (ImportError, AttributeError): |
| 93 | raise ViewDoesNotExist("Could not import %s.%s. View is not callable." % (mod_name, func_name)) |
| 94 | except AttributeError: |
| 95 | if not can_fail: |
| 96 | raise ViewDoesNotExist("Could not import %s. View does not exist in module %s." % (lookup_view, mod_name)) |
| 97 | except ImportError: |
| 98 | ownermod, submod = get_mod_func(mod_name) |
| 99 | if not can_fail and submod != '' and not module_has_submodule(import_module(ownermod), submod): |
| 100 | raise ViewDoesNotExist("Could not import %s. Owning module %s does not exist." % (lookup_view, mod_name)) |
96 | 101 | if not can_fail: |
97 | 102 | raise |
98 | | except UnicodeEncodeError: |
99 | | pass |
100 | 103 | return lookup_view |
101 | 104 | get_callable = memoize(get_callable, _callable_cache, 1) |
102 | 105 | |
… |
… |
|
192 | 195 | def callback(self): |
193 | 196 | if self._callback is not None: |
194 | 197 | return self._callback |
195 | | try: |
196 | | self._callback = get_callable(self._callback_str) |
197 | | except ImportError, e: |
198 | | mod_name, _ = get_mod_func(self._callback_str) |
199 | | raise ViewDoesNotExist("Could not import %s. Error was: %s" % (mod_name, str(e))) |
200 | | except AttributeError, e: |
201 | | mod_name, func_name = get_mod_func(self._callback_str) |
202 | | raise ViewDoesNotExist("Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))) |
| 198 | |
| 199 | self._callback = get_callable(self._callback_str) |
203 | 200 | return self._callback |
204 | 201 | |
205 | 202 | class RegexURLResolver(LocaleRegexProvider): |
… |
… |
|
325 | 322 | # Lazy import, since urls.defaults imports this file |
326 | 323 | from django.conf.urls import defaults |
327 | 324 | callback = getattr(defaults, 'handler%s' % view_type) |
328 | | try: |
329 | | return get_callable(callback), {} |
330 | | except (ImportError, AttributeError), e: |
331 | | raise ViewDoesNotExist("Tried %s. Error was: %s" % (callback, str(e))) |
| 325 | return get_callable(callback), {} |
332 | 326 | |
333 | 327 | def resolve404(self): |
334 | 328 | return self._resolve_special('404') |
diff -r 41ee28cb9212 tests/regressiontests/urlpatterns_reverse/erroneous_urls.py
-
|
+
|
|
| 1 | |
| 2 | from django.conf.urls.defaults import * |
| 3 | |
| 4 | urlpatterns = patterns('', |
| 5 | # View has erroneous import |
| 6 | url(r'erroneous_inner/$', 'regressiontests.urlpatterns_reverse.views.erroneous_view'), |
| 7 | # Module has erroneous import |
| 8 | url(r'erroneous_outer/$', 'regressiontests.urlpatterns_reverse.erroneous_views_module.erroneous_view'), |
| 9 | # View does not exist |
| 10 | url(r'missing_inner/$', 'regressiontests.urlpatterns_reverse.views.missing_view'), |
| 11 | # View is not callable |
| 12 | url(r'uncallable/$', 'regressiontests.urlpatterns_reverse.views.uncallable'), |
| 13 | # Module does not exist |
| 14 | url(r'missing_outer/$', 'regressiontests.urlpatterns_reverse.missing_module.missing_view'), |
| 15 | ) |
diff -r 41ee28cb9212 tests/regressiontests/urlpatterns_reverse/erroneous_views_module.py
-
|
+
|
|
| 1 | import non_existent |
| 2 | |
| 3 | def erroneous_view(request): |
| 4 | pass |
diff -r 41ee28cb9212 tests/regressiontests/urlpatterns_reverse/tests.py
a
|
b
|
|
2 | 2 | Unit tests for reverse URL lookups. |
3 | 3 | """ |
4 | 4 | from django.conf import settings |
5 | | from django.core.exceptions import ImproperlyConfigured |
| 5 | from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist |
6 | 6 | from django.core.urlresolvers import reverse, resolve, NoReverseMatch,\ |
7 | 7 | Resolver404, ResolverMatch,\ |
8 | 8 | RegexURLResolver, RegexURLPattern |
… |
… |
|
470 | 470 | self.assertEqual(match[0], func) |
471 | 471 | self.assertEqual(match[1], args) |
472 | 472 | self.assertEqual(match[2], kwargs) |
| 473 | |
| 474 | class ErroneousViewTests(TestCase): |
| 475 | urls = 'regressiontests.urlpatterns_reverse.erroneous_urls' |
| 476 | |
| 477 | def test_erroneous_resolve(self): |
| 478 | self.assertRaises(ImportError, self.client.get, '/erroneous_inner/') |
| 479 | self.assertRaises(ImportError, self.client.get, '/erroneous_outer/') |
| 480 | self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_inner/') |
| 481 | self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_outer/') |
| 482 | self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable/') |
| 483 | |
diff -r 41ee28cb9212 tests/regressiontests/urlpatterns_reverse/views.py
a
|
b
|
|
16 | 16 | def defaults_view(request, arg1, arg2): |
17 | 17 | pass |
18 | 18 | |
| 19 | def erroneous_view(request): |
| 20 | import non_existent |
| 21 | |
| 22 | uncallable = "Can I be a view? Pleeeease?" |
| 23 | |
19 | 24 | class ViewClass(object): |
20 | 25 | def __call__(self, request, *args, **kwargs): |
21 | 26 | return HttpResponse('') |