diff options
| author | Tim Graham <timograham@gmail.com> | 2015-08-17 13:45:07 -0400 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-09-23 19:31:09 -0400 |
| commit | 785cc71d5b3300e2702b0b2fc7316e58ca70b563 (patch) | |
| tree | dc526b6b3df79c0da82694f0879713f33c0dee3c /django | |
| parent | d79122f40ba2016b1a943e2e1ba46984b2ef99ad (diff) | |
Refs #22384 -- Removed the ability to reverse URLs by dotted path per deprecation timeline.
Diffstat (limited to 'django')
| -rw-r--r-- | django/conf/urls/__init__.py | 4 | ||||
| -rw-r--r-- | django/core/urlresolvers.py | 124 |
2 files changed, 42 insertions, 86 deletions
diff --git a/django/conf/urls/__init__.py b/django/conf/urls/__init__.py index f9cd305ece..512d6f79e0 100644 --- a/django/conf/urls/__init__.py +++ b/django/conf/urls/__init__.py @@ -79,5 +79,7 @@ def url(regex, view, kwargs=None, name=None): # For include(...) processing. urlconf_module, app_name, namespace = view return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace) - else: + elif callable(view): return RegexURLPattern(regex, view, kwargs, name) + else: + raise TypeError('view must be a callable or a list/tuple in the case of include().') diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index 81aa9bb7ca..303901048a 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -9,7 +9,6 @@ from __future__ import unicode_literals import functools import re -import warnings from importlib import import_module from threading import local @@ -17,7 +16,6 @@ from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist from django.http import Http404 from django.utils import lru_cache, six from django.utils.datastructures import MultiValueDict -from django.utils.deprecation import RemovedInDjango110Warning from django.utils.encoding import force_str, force_text, iri_to_uri from django.utils.functional import cached_property, lazy from django.utils.http import RFC3986_SUBDELIMS, urlquote @@ -80,67 +78,50 @@ class NoReverseMatch(Exception): @lru_cache.lru_cache(maxsize=None) -def get_callable(lookup_view, can_fail=False): +def get_callable(lookup_view): """ - Return a callable corresponding to lookup_view. This function is used - by both resolve() and reverse(), so can_fail allows the caller to choose - between returning the input as is and raising an exception when the input - string can't be interpreted as an import path. + Return a callable corresponding to lookup_view. - If lookup_view is already a callable, return it. - If lookup_view is a string import path that can be resolved to a callable, - import that callable and return it. - If lookup_view is some other kind of string and can_fail is True, the string - is returned as is. If can_fail is False, an exception is raised (either - ImportError or ViewDoesNotExist). + * If lookup_view is already a callable, return it. + * If lookup_view is a string import path that can be resolved to a callable, + import that callable and return it, otherwise raise an exception + (ImportError or ViewDoesNotExist). """ if callable(lookup_view): return lookup_view if not isinstance(lookup_view, six.string_types): - raise ViewDoesNotExist( - "'%s' is not a callable or a dot-notation path" % lookup_view - ) + raise ViewDoesNotExist("'%s' is not a callable or a dot-notation path" % lookup_view) mod_name, func_name = get_mod_func(lookup_view) if not func_name: # No '.' in lookup_view - if can_fail: - return lookup_view - else: - raise ImportError( - "Could not import '%s'. The path must be fully qualified." % - lookup_view) + raise ImportError("Could not import '%s'. The path must be fully qualified." % lookup_view) try: mod = import_module(mod_name) except ImportError: - if can_fail: - return lookup_view + parentmod, submod = get_mod_func(mod_name) + if submod and not module_has_submodule(import_module(parentmod), submod): + raise ViewDoesNotExist( + "Could not import '%s'. Parent module %s does not exist." % + (lookup_view, mod_name) + ) else: - parentmod, submod = get_mod_func(mod_name) - if submod and not module_has_submodule(import_module(parentmod), submod): - raise ViewDoesNotExist( - "Could not import '%s'. Parent module %s does not exist." % - (lookup_view, mod_name)) - else: - raise + raise else: try: view_func = getattr(mod, func_name) except AttributeError: - if can_fail: - return lookup_view - else: - raise ViewDoesNotExist( - "Could not import '%s'. View does not exist in module %s." % - (lookup_view, mod_name)) + raise ViewDoesNotExist( + "Could not import '%s'. View does not exist in module %s." % + (lookup_view, mod_name) + ) else: if not callable(view_func): - # For backwards compatibility this is raised regardless of can_fail raise ViewDoesNotExist( "Could not import '%s.%s'. View is not callable." % - (mod_name, func_name)) - + (mod_name, func_name) + ) return view_func @@ -209,14 +190,7 @@ class LocaleRegexProvider(object): class RegexURLPattern(LocaleRegexProvider): def __init__(self, regex, callback, default_args=None, name=None): LocaleRegexProvider.__init__(self, regex) - # callback is either a string like 'foo.views.news.stories.story_detail' - # which represents the path to a module and a view function name, or a - # callable object (view). - if callable(callback): - self._callback = callback - else: - self._callback = None - self._callback_str = callback + self.callback = callback # the view self.default_args = default_args or {} self.name = name @@ -239,13 +213,19 @@ class RegexURLPattern(LocaleRegexProvider): return ResolverMatch(self.callback, args, kwargs, self.name) - @property - def callback(self): - if self._callback is not None: - return self._callback - - self._callback = get_callable(self._callback_str) - return self._callback + @cached_property + def lookup_str(self): + """ + A string that identifies the view (e.g. 'path.to.view_function' or + 'path.to.ClassBasedView'). + """ + callback = self.callback + if isinstance(callback, functools.partial): + callback = callback.func + if not hasattr(callback, '__name__'): + return callback.__module__ + "." + callback.__class__.__name__ + else: + return callback.__module__ + "." + callback.__name__ class RegexURLResolver(LocaleRegexProvider): @@ -283,18 +263,8 @@ class RegexURLResolver(LocaleRegexProvider): apps = {} language_code = get_language() for pattern in reversed(self.url_patterns): - if hasattr(pattern, '_callback_str'): - self._callback_strs.add(pattern._callback_str) - elif hasattr(pattern, '_callback'): - callback = pattern._callback - if isinstance(callback, functools.partial): - callback = callback.func - - if not hasattr(callback, '__name__'): - lookup_str = callback.__module__ + "." + callback.__class__.__name__ - else: - lookup_str = callback.__module__ + "." + callback.__name__ - self._callback_strs.add(lookup_str) + if isinstance(pattern, RegexURLPattern): + self._callback_strs.add(pattern.lookup_str) p_pattern = pattern.regex.pattern if p_pattern.startswith('^'): p_pattern = p_pattern[1:] @@ -427,9 +397,6 @@ class RegexURLResolver(LocaleRegexProvider): callback = getattr(urls, 'handler%s' % view_type) return get_callable(callback), {} - def reverse(self, lookup_view, *args, **kwargs): - return self._reverse_with_prefix(lookup_view, '', *args, **kwargs) - def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs): if args and kwargs: raise ValueError("Don't mix *args and **kwargs in call to reverse()!") @@ -439,18 +406,6 @@ class RegexURLResolver(LocaleRegexProvider): if not self._populated: self._populate() - original_lookup = lookup_view - try: - if self._is_callback(lookup_view): - lookup_view = get_callable(lookup_view, True) - except (ImportError, AttributeError) as e: - raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) - else: - if not callable(original_lookup) and callable(lookup_view): - warnings.warn( - 'Reversing by dotted path is deprecated (%s).' % original_lookup, - RemovedInDjango110Warning, stacklevel=3 - ) possibilities = self.reverse_dict.getlist(lookup_view) for possibility, pattern, defaults in possibilities: @@ -484,9 +439,8 @@ class RegexURLResolver(LocaleRegexProvider): if url.startswith('//'): url = '/%%2F%s' % url[2:] return url - # lookup_view can be URL label, or dotted path, or callable, Any of - # these can be passed in at the top, but callables are not friendly in - # error messages. + # lookup_view can be URL name or callable, but callables are not + # friendly in error messages. m = getattr(lookup_view, '__module__', None) n = getattr(lookup_view, '__name__', None) if m is not None and n is not None: |
