1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Refs #22384 -- Removed the ability to reverse URLs by dotted path per deprecation timeline.

This commit is contained in:
Tim Graham 2015-08-17 13:45:07 -04:00
parent d79122f40b
commit 785cc71d5b
15 changed files with 93 additions and 298 deletions

View File

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

View File

@ -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
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
@ -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:

View File

@ -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`

View File

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

View File

@ -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
@ -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.

View File

@ -3,9 +3,8 @@ from __future__ import unicode_literals
from django.contrib.auth.views import logout
from django.core.urlresolvers import NoReverseMatch, reverse_lazy
from django.shortcuts import resolve_url
from django.test import SimpleTestCase, ignore_warnings, override_settings
from django.test import SimpleTestCase, override_settings
from django.utils import six
from django.utils.deprecation import RemovedInDjango110Warning
from .models import UnimportantThing
@ -51,8 +50,8 @@ class ResolveUrlTests(SimpleTestCase):
def test_view_function(self):
"""
Tests that passing a view name to ``resolve_url`` will result in the
URL path mapping to that view name.
Tests that passing a view function to ``resolve_url`` will result in
the URL path mapping to that view name.
"""
resolved_url = resolve_url(logout)
self.assertEqual('/accounts/logout/', resolved_url)
@ -66,13 +65,12 @@ class ResolveUrlTests(SimpleTestCase):
self.assertIsInstance(resolved_url, six.text_type)
self.assertEqual('/accounts/logout/', resolved_url)
@ignore_warnings(category=RemovedInDjango110Warning)
def test_valid_view_name(self):
"""
Tests that passing a view function to ``resolve_url`` will result in
the URL path mapping to that view.
Tests that passing a view name to ``resolve_url`` will result in the
URL path mapping to that view.
"""
resolved_url = resolve_url('django.contrib.auth.views.logout')
resolved_url = resolve_url('logout')
self.assertEqual('/accounts/logout/', resolved_url)
def test_domain(self):

View File

@ -9,9 +9,8 @@ from django.conf import settings
from django.contrib.sitemaps import GenericSitemap, Sitemap
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.test import ignore_warnings, modify_settings, override_settings
from django.test import modify_settings, override_settings
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango110Warning
from django.utils.formats import localize
from django.utils.translation import activate, deactivate
@ -21,15 +20,8 @@ from .models import TestModel
class HTTPSitemapTests(SitemapTestsBase):
@ignore_warnings(category=RemovedInDjango110Warning)
def test_simple_sitemap_index(self):
"A simple sitemap index can be rendered"
# The URL for views.sitemap in tests/urls/http.py has 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.sitemaps.views.sitemap', we need to silence
# the erroneous warning until reversing by dotted path is removed.
# The test will work without modification when it's removed.
response = self.client.get('/simple/index.xml')
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@ -38,19 +30,12 @@ class HTTPSitemapTests(SitemapTestsBase):
""" % self.base_url
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
@ignore_warnings(category=RemovedInDjango110Warning)
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(upath(__file__)), 'templates')],
}])
def test_simple_sitemap_custom_index(self):
"A simple sitemap index can be rendered with a custom template"
# The URL for views.sitemap in tests/urls/http.py has 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.sitemaps.views.sitemap', we need to silence
# the erroneous warning until reversing by dotted path is removed.
# The test will work without modification when it's removed.
response = self.client.get('/simple/custom-index.xml')
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a customised template -->
@ -194,14 +179,7 @@ class HTTPSitemapTests(SitemapTestsBase):
""" % self.base_url
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
@ignore_warnings(category=RemovedInDjango110Warning)
def test_x_robots_sitemap(self):
# The URL for views.sitemap in tests/urls/http.py has 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.sitemaps.views.sitemap', we need to silence
# the erroneous warning until reversing by dotted path is removed.
# The test will work without modification when it's removed.
response = self.client.get('/simple/index.xml')
self.assertEqual(response['X-Robots-Tag'], 'noindex, noodp, noarchive')

View File

@ -2,8 +2,7 @@ from __future__ import unicode_literals
from datetime import date
from django.test import ignore_warnings, override_settings
from django.utils.deprecation import RemovedInDjango110Warning
from django.test import override_settings
from .base import SitemapTestsBase
@ -12,15 +11,8 @@ from .base import SitemapTestsBase
class HTTPSSitemapTests(SitemapTestsBase):
protocol = 'https'
@ignore_warnings(category=RemovedInDjango110Warning)
def test_secure_sitemap_index(self):
"A secure sitemap index can be rendered"
# The URL for views.sitemap in tests/urls/https.py has 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.sitemaps.views.sitemap', we need to silence
# the erroneous warning until reversing by dotted path is removed.
# The test will work without modification when it's removed.
response = self.client.get('/secure/index.xml')
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@ -44,15 +36,8 @@ class HTTPSSitemapTests(SitemapTestsBase):
class HTTPSDetectionSitemapTests(SitemapTestsBase):
extra = {'wsgi.url_scheme': 'https'}
@ignore_warnings(category=RemovedInDjango110Warning)
def test_sitemap_index_with_https_request(self):
"A sitemap index requested in HTTPS is rendered with HTTPS links"
# The URL for views.sitemap in tests/urls/https.py has 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.sitemaps.views.sitemap', we need to silence
# the erroneous warning until reversing by dotted path is removed.
# The test will work without modification when it's removed.
response = self.client.get('/simple/index.xml', **self.extra)
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

View File

@ -1,10 +1,7 @@
# coding: utf-8
from django.core.urlresolvers import NoReverseMatch, resolve
from django.template import RequestContext, TemplateSyntaxError
from django.test import (
RequestFactory, SimpleTestCase, ignore_warnings, override_settings,
)
from django.utils.deprecation import RemovedInDjango110Warning
from django.test import RequestFactory, SimpleTestCase, override_settings
from ..utils import setup
@ -13,38 +10,32 @@ from ..utils import setup
class UrlTagTests(SimpleTestCase):
# Successes
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url01': '{% url "template_tests.views.client" client.id %}'})
@setup({'url01': '{% url "client" client.id %}'})
def test_url01(self):
output = self.engine.render_to_string('url01', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url02': '{% url "template_tests.views.client_action" id=client.id action="update" %}'})
@setup({'url02': '{% url "client_action" id=client.id action="update" %}'})
def test_url02(self):
output = self.engine.render_to_string('url02', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/update/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url02a': '{% url "template_tests.views.client_action" client.id "update" %}'})
@setup({'url02a': '{% url "client_action" client.id "update" %}'})
def test_url02a(self):
output = self.engine.render_to_string('url02a', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/update/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url02b': "{% url 'template_tests.views.client_action' id=client.id action='update' %}"})
@setup({'url02b': "{% url 'client_action' id=client.id action='update' %}"})
def test_url02b(self):
output = self.engine.render_to_string('url02b', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/update/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url02c': "{% url 'template_tests.views.client_action' client.id 'update' %}"})
@setup({'url02c': "{% url 'client_action' client.id 'update' %}"})
def test_url02c(self):
output = self.engine.render_to_string('url02c', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/update/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url03': '{% url "template_tests.views.index" %}'})
@setup({'url03': '{% url "index" %}'})
def test_url03(self):
output = self.engine.render_to_string('url03')
self.assertEqual(output, '/')
@ -64,12 +55,6 @@ class UrlTagTests(SimpleTestCase):
output = self.engine.render_to_string('url06', {'v': 'Ω'})
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url07': '{% url "template_tests.views.client2" tag=v %}'})
def test_url07(self):
output = self.engine.render_to_string('url07', {'v': 'Ω'})
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
@setup({'url08': '{% url "метка_оператора" v %}'})
def test_url08(self):
output = self.engine.render_to_string('url08', {'v': 'Ω'})
@ -80,55 +65,45 @@ class UrlTagTests(SimpleTestCase):
output = self.engine.render_to_string('url09', {'v': 'Ω'})
self.assertEqual(output, '/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url10': '{% url "template_tests.views.client_action" id=client.id action="two words" %}'})
@setup({'url10': '{% url "client_action" id=client.id action="two words" %}'})
def test_url10(self):
output = self.engine.render_to_string('url10', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/two%20words/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url11': '{% url "template_tests.views.client_action" id=client.id action="==" %}'})
@setup({'url11': '{% url "client_action" id=client.id action="==" %}'})
def test_url11(self):
output = self.engine.render_to_string('url11', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/==/')
@setup({'url12': '{% url "template_tests.views.client_action" '
'id=client.id action="!$&\'()*+,;=~:@," %}'})
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url12': '{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'})
def test_url12(self):
output = self.engine.render_to_string('url12', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/!$&amp;&#39;()*+,;=~:@,/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url13': '{% url "template_tests.views.client_action" '
'id=client.id action=arg|join:"-" %}'})
@setup({'url13': '{% url "client_action" id=client.id action=arg|join:"-" %}'})
def test_url13(self):
output = self.engine.render_to_string('url13', {'client': {'id': 1}, 'arg': ['a', 'b']})
self.assertEqual(output, '/client/1/a-b/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url14': '{% url "template_tests.views.client_action" client.id arg|join:"-" %}'})
@setup({'url14': '{% url "client_action" client.id arg|join:"-" %}'})
def test_url14(self):
output = self.engine.render_to_string('url14', {'client': {'id': 1}, 'arg': ['a', 'b']})
self.assertEqual(output, '/client/1/a-b/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url15': '{% url "template_tests.views.client_action" 12 "test" %}'})
@setup({'url15': '{% url "client_action" 12 "test" %}'})
def test_url15(self):
output = self.engine.render_to_string('url15')
self.assertEqual(output, '/client/12/test/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url18': '{% url "template_tests.views.client" "1,2" %}'})
@setup({'url18': '{% url "client" "1,2" %}'})
def test_url18(self):
output = self.engine.render_to_string('url18')
self.assertEqual(output, '/client/1,2/')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url19': '{% url named_url client.id %}'})
def test_url19(self):
output = self.engine.render_to_string(
'url19', {'client': {'id': 1}, 'named_url': 'template_tests.views.client'}
'url19', {'client': {'id': 1}, 'named_url': 'client'}
)
self.assertEqual(output, '/client/1/')
@ -138,10 +113,8 @@ class UrlTagTests(SimpleTestCase):
self.assertEqual(output, '/named-client/1/')
@setup({'url21': '{% autoescape off %}'
'{% url "template_tests.views.client_action" '
'id=client.id action="!$&\'()*+,;=~:@," %}'
'{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'
'{% endautoescape %}'})
@ignore_warnings(category=RemovedInDjango110Warning)
def test_url21(self):
output = self.engine.render_to_string('url21', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/!$&\'()*+,;=~:@,/')
@ -157,8 +130,7 @@ class UrlTagTests(SimpleTestCase):
with self.assertRaises(NoReverseMatch):
self.engine.render_to_string('url-fail02')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url-fail03': '{% url "template_tests.views.client" %}'})
@setup({'url-fail03': '{% url "client" %}'})
def test_url_fail03(self):
with self.assertRaises(NoReverseMatch):
self.engine.render_to_string('url-fail03')
@ -203,7 +175,6 @@ class UrlTagTests(SimpleTestCase):
with self.assertRaises(NoReverseMatch):
self.engine.render_to_string('url-fail12', {'named_url': 'no_such_view'})
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url-fail13': '{% url named_url %}'})
def test_url_fail13(self):
with self.assertRaises(NoReverseMatch):
@ -240,14 +211,12 @@ class UrlTagTests(SimpleTestCase):
self.engine.render_to_string('url-fail19', {'named_url': 'view'})
# {% url ... as var %}
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url-asvar01': '{% url "template_tests.views.index" as url %}'})
@setup({'url-asvar01': '{% url "index" as url %}'})
def test_url_asvar01(self):
output = self.engine.render_to_string('url-asvar01')
self.assertEqual(output, '')
@ignore_warnings(category=RemovedInDjango110Warning)
@setup({'url-asvar02': '{% url "template_tests.views.index" as url %}{{ url }}'})
@setup({'url-asvar02': '{% url "index" as url %}{{ url }}'})
def test_url_asvar02(self):
output = self.engine.render_to_string('url-asvar02')
self.assertEqual(output, '/')

View File

@ -7,10 +7,10 @@ from . import views
ns_patterns = [
# Test urls for testing reverse lookups
url(r'^$', views.index),
url(r'^client/([0-9,]+)/$', views.client),
url(r'^client/(?P<id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action),
url(r'^client/(?P<client_id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action),
url(r'^$', views.index, name='index'),
url(r'^client/([0-9,]+)/$', views.client, name='client'),
url(r'^client/(?P<id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action, name='client_action'),
url(r'^client/(?P<client_id>[0-9]+)/(?P<action>[^/]+)/$', views.client_action, name='client_action'),
url(r'^named-client/([0-9]+)/$', views.client2, name="named.client"),
]

View File

@ -1,30 +1,7 @@
import warnings
from django.conf.urls import url
from django.utils.deprecation import RemovedInDjango110Warning
from . import views
# Test deprecated behavior of passing strings as view to url().
# Some of these can be removed in Django 1.10 as they aren't convertable to
# callables.
with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=RemovedInDjango110Warning)
urlpatterns = [
# View has erroneous import
url(r'erroneous_inner/$', views.erroneous_view),
# Module has erroneous import
url(r'erroneous_outer/$', 'urlpatterns_reverse.erroneous_views_module.erroneous_view'),
# Module is an unqualified string
url(r'erroneous_unqualified/$', 'unqualified_view'),
# View does not exist
url(r'missing_inner/$', 'urlpatterns_reverse.views.missing_view'),
# View is not a callable (string import; arbitrary Python object)
url(r'uncallable-dotted/$', 'urlpatterns_reverse.views.uncallable'),
# View is not a callable (explicit import; arbitrary Python object)
url(r'uncallable-object/$', views.uncallable),
# Module does not exist
url(r'missing_outer/$', 'urlpatterns_reverse.missing_module.missing_view'),
# Regex contains an error (refs #6170)
url(r'(regex_error/$', views.empty_view),
]

View File

@ -1,5 +0,0 @@
import non_existent # NOQA
def erroneous_view(request):
pass

View File

@ -26,9 +26,7 @@ from django.test import (
)
from django.test.utils import override_script_prefix
from django.utils import six
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango110Warning,
)
from django.utils.deprecation import RemovedInDjango20Warning
from . import middleware, urlconf_outer, views
from .views import empty_view
@ -231,13 +229,6 @@ test_data = (
('nested-namedcapture', NoReverseMatch, [], {'outer': 'opt/', 'inner': 'opt'}),
('nested-namedcapture', NoReverseMatch, [], {'inner': 'opt'}),
# Regression for #9038
# These views are resolved by method name. Each method is deployed twice -
# once with an explicit argument, and once using the default value on
# the method. This is potentially ambiguous, as you have to pick the
# correct view for the arguments provided.
('urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/', [], {}),
('urlpatterns_reverse.views.absolute_kwargs_view', '/absolute_arg_view/10/', [], {'arg1': 10}),
('non_path_include', '/includes/non_path_include/', [], {}),
# Tests for #13154
@ -292,7 +283,6 @@ class NoURLPatternsTests(SimpleTestCase):
@override_settings(ROOT_URLCONF='urlpatterns_reverse.urls')
class URLPatternReverse(SimpleTestCase):
@ignore_warnings(category=RemovedInDjango110Warning)
def test_urlpattern_reverse(self):
for name, expected, args, kwargs in test_data:
try:
@ -544,11 +534,10 @@ class ReverseShortcutTests(SimpleTestCase):
redirect("urlpatterns_reverse.nonimported_module.view")
self.assertNotIn("urlpatterns_reverse.nonimported_module", sys.modules)
@ignore_warnings(category=RemovedInDjango110Warning)
def test_reverse_by_path_nested(self):
# Views that are added to urlpatterns using include() should be
# reversible by dotted path.
self.assertEqual(reverse('urlpatterns_reverse.views.nested_view'), '/includes/nested_path/')
# Views added to urlpatterns using include() should be reversible.
from .views import nested_view
self.assertEqual(reverse(nested_view), '/includes/nested_path/')
def test_redirect_view_object(self):
from .views import absolute_kwargs_view
@ -982,24 +971,16 @@ class ResolverMatchTests(SimpleTestCase):
@override_settings(ROOT_URLCONF='urlpatterns_reverse.erroneous_urls')
class ErroneousViewTests(SimpleTestCase):
def test_erroneous_resolve(self):
self.assertRaises(ImportError, self.client.get, '/erroneous_inner/')
self.assertRaises(ImportError, self.client.get, '/erroneous_outer/')
self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_inner/')
self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_outer/')
self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable-dotted/')
self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable-object/')
def test_noncallable_view(self):
# View is not a callable (explicit import; arbitrary Python object)
with self.assertRaisesMessage(TypeError, 'view must be a callable'):
url(r'uncallable-object/$', views.uncallable)
# Regression test for #21157
self.assertRaises(ImportError, self.client.get, '/erroneous_unqualified/')
def test_erroneous_reverse(self):
"""
Ensure that a useful exception is raised when a regex is invalid in the
URLConf (#6170).
"""
# The regex error will be hit before NoReverseMatch can be raised
self.assertRaises(ImproperlyConfigured, reverse, 'whatever blah blah')
def test_invalid_regex(self):
# Regex contains an error (refs #6170)
msg = '(regex_error/$" is not a valid regular expression'
with self.assertRaisesMessage(ImproperlyConfigured, msg):
reverse(views.empty_view)
class ViewLoadingTests(SimpleTestCase):

View File

@ -2,7 +2,7 @@ from django.conf.urls import include, url
from .views import (
absolute_kwargs_view, defaults_view, empty_view, empty_view_partial,
empty_view_wrapped, kwargs_view, nested_view,
empty_view_wrapped, nested_view,
)
other_patterns = [
@ -67,10 +67,6 @@ urlpatterns = [
# This is non-reversible, but we shouldn't blow up when parsing it.
url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"),
# Regression views for #9038. See tests for more details
url(r'arg_view/$', kwargs_view),
url(r'arg_view/(?P<arg1>[0-9]+)/$', kwargs_view),
url(r'absolute_arg_view/(?P<arg1>[0-9]+)/$', absolute_kwargs_view),
url(r'absolute_arg_view/$', absolute_kwargs_view),
# Tests for #13154. Mixed syntax to test both ways of defining URLs.

View File

@ -10,10 +10,6 @@ def empty_view(request, *args, **kwargs):
return HttpResponse('')
def kwargs_view(request, arg1=1, arg2=2):
return HttpResponse('')
def absolute_kwargs_view(request, arg1=1, arg2=2):
return HttpResponse('')