浏览代码

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

Tim Graham 9 年之前
父节点
当前提交
785cc71d5b

+ 3 - 1
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().')

+ 40 - 86
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.
-
-    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
+        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:

+ 0 - 7
docs/ref/templates/builtins.txt

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

+ 2 - 21
docs/ref/urlresolvers.txt

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

+ 1 - 11
tests/gis_tests/geoapp/test_sitemaps.py

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

+ 6 - 8
tests/resolve_url/tests.py

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

+ 1 - 23
tests/sitemaps_tests/test_http.py

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

+ 1 - 16
tests/sitemaps_tests/test_https.py

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

+ 19 - 50
tests/template_tests/syntax_tests/test_url.py

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

+ 4 - 4
tests/template_tests/urls.py

@@ -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"),
 ]
 

+ 3 - 26
tests/urlpatterns_reverse/erroneous_urls.py

@@ -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),
-    ]
+urlpatterns = [
+    url(r'(regex_error/$', views.empty_view),
+]

+ 0 - 5
tests/urlpatterns_reverse/erroneous_views_module.py

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

+ 13 - 32
tests/urlpatterns_reverse/tests.py

@@ -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/')
-
-        # Regression test for #21157
-        self.assertRaises(ImportError, self.client.get, '/erroneous_unqualified/')
+    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)
 
-    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):

+ 1 - 5
tests/urlpatterns_reverse/urls.py

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

+ 0 - 4
tests/urlpatterns_reverse/views.py

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