diff -r f7582637764c django/core/urlresolvers.py
a
|
b
|
|
17 | 17 | from django.utils.encoding import iri_to_uri, force_unicode, smart_str |
18 | 18 | from django.utils.functional import memoize, lazy |
19 | 19 | from django.utils.importlib import import_module |
| 20 | from django.utils.module_loading import module_has_submodule |
20 | 21 | from django.utils.regex_helper import normalize |
21 | 22 | |
22 | 23 | _resolver_cache = {} # Maps URLconf modules to RegexURLResolver instances. |
… |
… |
|
83 | 84 | during the import fail and the string is returned. |
84 | 85 | """ |
85 | 86 | if not callable(lookup_view): |
| 87 | mod_name, func_name = get_mod_func(lookup_view) |
86 | 88 | try: |
87 | | # Bail early for non-ASCII strings (they can't be functions). |
88 | | lookup_view = lookup_view.encode('ascii') |
89 | | mod_name, func_name = get_mod_func(lookup_view) |
90 | 89 | if func_name != '': |
91 | 90 | lookup_view = getattr(import_module(mod_name), func_name) |
92 | 91 | if not callable(lookup_view): |
93 | | raise AttributeError("'%s.%s' is not a callable." % (mod_name, func_name)) |
94 | | except (ImportError, AttributeError): |
| 92 | raise ViewDoesNotExist("Could not import %s.%s. View is not callable." % (mod_name, func_name)) |
| 93 | except AttributeError: |
| 94 | if not can_fail: |
| 95 | raise ViewDoesNotExist("Could not import %s. View does not exist in module %s." % (lookup_view, mod_name)) |
| 96 | except ImportError: |
| 97 | ownermod, submod = get_mod_func(mod_name) |
| 98 | if not can_fail and submod != '' and not module_has_submodule(import_module(ownermod), submod): |
| 99 | raise ViewDoesNotExist("Could not import %s. Owning module %s does not exist." % (lookup_view, mod_name)) |
95 | 100 | if not can_fail: |
96 | 101 | raise |
97 | | except UnicodeEncodeError: |
98 | | pass |
99 | 102 | return lookup_view |
100 | 103 | get_callable = memoize(get_callable, _callable_cache, 1) |
101 | 104 | |
… |
… |
|
160 | 163 | def _get_callback(self): |
161 | 164 | if self._callback is not None: |
162 | 165 | return self._callback |
163 | | try: |
164 | | self._callback = get_callable(self._callback_str) |
165 | | except ImportError, e: |
166 | | mod_name, _ = get_mod_func(self._callback_str) |
167 | | raise ViewDoesNotExist("Could not import %s. Error was: %s" % (mod_name, str(e))) |
168 | | except AttributeError, e: |
169 | | mod_name, func_name = get_mod_func(self._callback_str) |
170 | | raise ViewDoesNotExist("Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))) |
| 166 | |
| 167 | self._callback = get_callable(self._callback_str) |
171 | 168 | return self._callback |
172 | 169 | callback = property(_get_callback) |
173 | 170 | |
… |
… |
|
291 | 288 | # Lazy import, since urls.defaults imports this file |
292 | 289 | from django.conf.urls import defaults |
293 | 290 | callback = getattr(defaults, 'handler%s' % view_type) |
294 | | try: |
295 | | return get_callable(callback), {} |
296 | | except (ImportError, AttributeError), e: |
297 | | raise ViewDoesNotExist("Tried %s. Error was: %s" % (callback, str(e))) |
| 291 | return get_callable(callback), {} |
298 | 292 | |
299 | 293 | def resolve404(self): |
300 | 294 | return self._resolve_special('404') |
diff -r f7582637764c 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 f7582637764c tests/regressiontests/urlpatterns_reverse/erroneous_views_module.py
-
|
+
|
|
| 1 | import non_existent |
| 2 | |
| 3 | def erroneous_view(request): |
| 4 | pass |
diff -r f7582637764c 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 f7582637764c 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('') |