Loading django/conf/urls/__init__.py +3 −1 Original line number Diff line number Diff line Loading @@ -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().') django/core/urlresolvers.py +40 −86 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ from __future__ import unicode_literals import functools import re import warnings from importlib import import_module from threading import local Loading @@ -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 Loading Loading @@ -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. 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). 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, 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 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)) (lookup_view, mod_name) ) else: 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)) (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 Loading Loading @@ -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 Loading @@ -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): Loading Loading @@ -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:] Loading Loading @@ -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()!") Loading @@ -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: Loading Loading @@ -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: Loading docs/ref/templates/builtins.txt +0 −7 Original line number Diff line number Diff line Loading @@ -1051,13 +1051,6 @@ This will follow the normal :ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`, including using any hints provided by the context as to the current application. .. deprecated:: 1.8 You can also pass a dotted Python path to a view function, but this syntax is deprecated and will be removed in Django 1.10:: {% url 'path.to.some_view' v1 v2 %} .. warning:: Don't forget to put quotes around the :func:`~django.conf.urls.url` Loading docs/ref/urlresolvers.txt +2 −21 Original line number Diff line number Diff line Loading @@ -12,9 +12,8 @@ your code, Django provides the following function: .. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None) ``viewname`` can be a string containing the Python path to the view object, a :ref:`URL pattern name <naming-url-patterns>`, or the callable view object. For example, given the following ``url``:: ``viewname`` can be a :ref:`URL pattern name <naming-url-patterns>` or the callable view object. For example, given the following ``url``:: from news import views Loading Loading @@ -63,24 +62,6 @@ namespaces into URLs on specific application instances, according to the The ``urlconf`` argument is the URLconf module containing the url patterns to use for reversing. By default, the root URLconf for the current thread is used. .. deprecated:: 1.8 The ability to reverse using the Python path, e.g. ``reverse('news.views.archive')``, has been deprecated. .. admonition:: Make sure your views are all correct. As part of working out which URL names map to which patterns, the ``reverse()`` function has to import all of your URLconf files and examine the name of each view. This involves importing each view function. If there are *any* errors whilst importing any of your view functions, it will cause ``reverse()`` to raise an error, even if that view function is not the one you are trying to reverse. Make sure that any views you reference in your URLconf files exist and can be imported correctly. Do not include lines that reference views you haven't written yet, because those views will not be importable. .. note:: The string returned by ``reverse()`` is already Loading tests/gis_tests/geoapp/test_sitemaps.py +1 −11 Original line number Diff line number Diff line Loading @@ -7,10 +7,8 @@ from xml.dom import minidom from django.conf import settings from django.contrib.sites.models import Site from django.test import ( TestCase, ignore_warnings, modify_settings, override_settings, skipUnlessDBFeature, TestCase, modify_settings, override_settings, skipUnlessDBFeature, ) from django.utils.deprecation import RemovedInDjango110Warning from .models import City, Country Loading @@ -30,17 +28,9 @@ class GeoSitemapTest(TestCase): expected = set(expected) self.assertEqual(actual, expected) @ignore_warnings(category=RemovedInDjango110Warning) def test_geositemap_kml(self): "Tests KML/KMZ geographic sitemaps." for kml_type in ('kml', 'kmz'): # The URL for the sitemaps in urls.py have been updated # with a name but since reversing by Python path is tried first # before reversing by name and works since we're giving # name='django.contrib.gis.sitemaps.views.(kml|kmz)', we need # to silence the erroneous warning until reversing by dotted # path is removed. The test will work without modification when # it's removed. doc = minidom.parseString(self.client.get('/sitemaps/%s.xml' % kml_type).content) # Ensuring the right sitemaps namespace is present. Loading Loading
django/conf/urls/__init__.py +3 −1 Original line number Diff line number Diff line Loading @@ -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().')
django/core/urlresolvers.py +40 −86 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ from __future__ import unicode_literals import functools import re import warnings from importlib import import_module from threading import local Loading @@ -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 Loading Loading @@ -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. 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). 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, 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 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)) (lookup_view, mod_name) ) else: 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)) (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 Loading Loading @@ -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 Loading @@ -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): Loading Loading @@ -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:] Loading Loading @@ -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()!") Loading @@ -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: Loading Loading @@ -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: Loading
docs/ref/templates/builtins.txt +0 −7 Original line number Diff line number Diff line Loading @@ -1051,13 +1051,6 @@ This will follow the normal :ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`, including using any hints provided by the context as to the current application. .. deprecated:: 1.8 You can also pass a dotted Python path to a view function, but this syntax is deprecated and will be removed in Django 1.10:: {% url 'path.to.some_view' v1 v2 %} .. warning:: Don't forget to put quotes around the :func:`~django.conf.urls.url` Loading
docs/ref/urlresolvers.txt +2 −21 Original line number Diff line number Diff line Loading @@ -12,9 +12,8 @@ your code, Django provides the following function: .. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None) ``viewname`` can be a string containing the Python path to the view object, a :ref:`URL pattern name <naming-url-patterns>`, or the callable view object. For example, given the following ``url``:: ``viewname`` can be a :ref:`URL pattern name <naming-url-patterns>` or the callable view object. For example, given the following ``url``:: from news import views Loading Loading @@ -63,24 +62,6 @@ namespaces into URLs on specific application instances, according to the The ``urlconf`` argument is the URLconf module containing the url patterns to use for reversing. By default, the root URLconf for the current thread is used. .. deprecated:: 1.8 The ability to reverse using the Python path, e.g. ``reverse('news.views.archive')``, has been deprecated. .. admonition:: Make sure your views are all correct. As part of working out which URL names map to which patterns, the ``reverse()`` function has to import all of your URLconf files and examine the name of each view. This involves importing each view function. If there are *any* errors whilst importing any of your view functions, it will cause ``reverse()`` to raise an error, even if that view function is not the one you are trying to reverse. Make sure that any views you reference in your URLconf files exist and can be imported correctly. Do not include lines that reference views you haven't written yet, because those views will not be importable. .. note:: The string returned by ``reverse()`` is already Loading
tests/gis_tests/geoapp/test_sitemaps.py +1 −11 Original line number Diff line number Diff line Loading @@ -7,10 +7,8 @@ from xml.dom import minidom from django.conf import settings from django.contrib.sites.models import Site from django.test import ( TestCase, ignore_warnings, modify_settings, override_settings, skipUnlessDBFeature, TestCase, modify_settings, override_settings, skipUnlessDBFeature, ) from django.utils.deprecation import RemovedInDjango110Warning from .models import City, Country Loading @@ -30,17 +28,9 @@ class GeoSitemapTest(TestCase): expected = set(expected) self.assertEqual(actual, expected) @ignore_warnings(category=RemovedInDjango110Warning) def test_geositemap_kml(self): "Tests KML/KMZ geographic sitemaps." for kml_type in ('kml', 'kmz'): # The URL for the sitemaps in urls.py have been updated # with a name but since reversing by Python path is tried first # before reversing by name and works since we're giving # name='django.contrib.gis.sitemaps.views.(kml|kmz)', we need # to silence the erroneous warning until reversing by dotted # path is removed. The test will work without modification when # it's removed. doc = minidom.parseString(self.client.get('/sitemaps/%s.xml' % kml_type).content) # Ensuring the right sitemaps namespace is present. Loading