Loading django/core/urlresolvers.py +16 −11 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading tests/regressiontests/urlpatterns_reverse/tests.py +16 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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') tests/regressiontests/urlpatterns_reverse/views_broken.py 0 → 100644 +2 −0 Original line number Diff line number Diff line # I just raise an AttributeError to confuse the view loading mechanism raise AttributeError('I am here to confuse django.core.urlresolvers.get_callable') Loading
django/core/urlresolvers.py +16 −11 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading
tests/regressiontests/urlpatterns_reverse/tests.py +16 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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')
tests/regressiontests/urlpatterns_reverse/views_broken.py 0 → 100644 +2 −0 Original line number Diff line number Diff line # I just raise an AttributeError to confuse the view loading mechanism raise AttributeError('I am here to confuse django.core.urlresolvers.get_callable')