Don't swallow AttributeError in core.urlresolvers.get_callable.

This commit is contained in:
Florian Apolloner 2012-08-14 21:12:08 +02:00
parent 37c9318748
commit 367bfaa522
3 changed files with 34 additions and 13 deletions

View File

@ -89,18 +89,11 @@ def get_callable(lookup_view, can_fail=False):
""" """
if not callable(lookup_view): if not callable(lookup_view):
mod_name, func_name = get_mod_func(lookup_view) mod_name, func_name = get_mod_func(lookup_view)
if func_name == '':
return lookup_view
try: try:
if func_name != '': mod = import_module(mod_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))
except ImportError: except ImportError:
parentmod, submod = get_mod_func(mod_name) parentmod, submod = get_mod_func(mod_name)
if (not can_fail and submod != '' and if (not can_fail and submod != '' and
@ -110,6 +103,18 @@ def get_callable(lookup_view, can_fail=False):
(lookup_view, mod_name)) (lookup_view, mod_name))
if not can_fail: if not can_fail:
raise 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 return lookup_view
get_callable = memoize(get_callable, _callable_cache, 1) get_callable = memoize(get_callable, _callable_cache, 1)

View File

@ -5,8 +5,9 @@ from __future__ import absolute_import, unicode_literals
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
from django.core.urlresolvers import (reverse, resolve, NoReverseMatch, from django.core.urlresolvers import (reverse, resolve, get_callable,
Resolver404, ResolverMatch, RegexURLResolver, RegexURLPattern) NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver,
RegexURLPattern)
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.test import TestCase from django.test import TestCase
@ -519,3 +520,16 @@ class ErroneousViewTests(TestCase):
""" """
# The regex error will be hit before NoReverseMatch can be raised # The regex error will be hit before NoReverseMatch can be raised
self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah') 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')

View File

@ -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')