summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/core/urlresolvers.py27
-rw-r--r--tests/regressiontests/urlpatterns_reverse/tests.py18
-rw-r--r--tests/regressiontests/urlpatterns_reverse/views_broken.py2
3 files changed, 34 insertions, 13 deletions
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index 1498c9989d..b83f2f51b0 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -89,18 +89,11 @@ def get_callable(lookup_view, can_fail=False):
"""
if not callable(lookup_view):
mod_name, func_name = get_mod_func(lookup_view)
+ if func_name == '':
+ return lookup_view
+
try:
- if func_name != '':
- lookup_view = getattr(import_module(mod_name), func_name)
- if not callable(lookup_view):
- raise ViewDoesNotExist(
- "Could not import %s.%s. View is not callable." %
- (mod_name, func_name))
- except AttributeError:
- if not can_fail:
- raise ViewDoesNotExist(
- "Could not import %s. View does not exist in module %s." %
- (lookup_view, mod_name))
+ mod = import_module(mod_name)
except ImportError:
parentmod, submod = get_mod_func(mod_name)
if (not can_fail and submod != '' and
@@ -110,6 +103,18 @@ def get_callable(lookup_view, can_fail=False):
(lookup_view, mod_name))
if not can_fail:
raise
+ else:
+ try:
+ lookup_view = getattr(mod, func_name)
+ if not callable(lookup_view):
+ raise ViewDoesNotExist(
+ "Could not import %s.%s. View is not callable." %
+ (mod_name, func_name))
+ except AttributeError:
+ if not can_fail:
+ raise ViewDoesNotExist(
+ "Could not import %s. View does not exist in module %s." %
+ (lookup_view, mod_name))
return lookup_view
get_callable = memoize(get_callable, _callable_cache, 1)
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
index 207cc56488..b9c64183e5 100644
--- a/tests/regressiontests/urlpatterns_reverse/tests.py
+++ b/tests/regressiontests/urlpatterns_reverse/tests.py
@@ -5,8 +5,9 @@ from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
-from django.core.urlresolvers import (reverse, resolve, NoReverseMatch,
- Resolver404, ResolverMatch, RegexURLResolver, RegexURLPattern)
+from django.core.urlresolvers import (reverse, resolve, get_callable,
+ NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver,
+ RegexURLPattern)
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect
from django.test import TestCase
@@ -519,3 +520,16 @@ class ErroneousViewTests(TestCase):
"""
# The regex error will be hit before NoReverseMatch can be raised
self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah')
+
+class ViewLoadingTests(TestCase):
+ def test_view_loading(self):
+ # A missing view (identified by an AttributeError) should raise
+ # ViewDoesNotExist, ...
+ self.assertRaisesRegexp(ViewDoesNotExist, ".*View does not exist in.*",
+ get_callable,
+ 'regressiontests.urlpatterns_reverse.views.i_should_not_exist')
+ # ... but if the AttributeError is caused by something else don't
+ # swallow it.
+ self.assertRaises(AttributeError, get_callable,
+ 'regressiontests.urlpatterns_reverse.views_broken.i_am_broken')
+
diff --git a/tests/regressiontests/urlpatterns_reverse/views_broken.py b/tests/regressiontests/urlpatterns_reverse/views_broken.py
new file mode 100644
index 0000000000..4953aab239
--- /dev/null
+++ b/tests/regressiontests/urlpatterns_reverse/views_broken.py
@@ -0,0 +1,2 @@
+# I just raise an AttributeError to confuse the view loading mechanism
+raise AttributeError('I am here to confuse django.core.urlresolvers.get_callable')