From a25d3ce007b90a0516aed54fc1c5a16510a290e4 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Mon, 17 Aug 2015 10:45:00 -0400 Subject: [PATCH] Refs #22218 -- Removed conf.urls.patterns() per deprecation timeline. --- django/conf/urls/__init__.py | 19 +-- django/conf/urls/i18n.py | 23 +-- django/core/urlresolvers.py | 8 - docs/internals/deprecation.txt | 2 +- docs/ref/urls.txt | 71 --------- docs/releases/1.4.txt | 2 +- docs/topics/i18n/translation.txt | 8 +- tests/i18n/urls.py | 13 +- .../included_namespace_urls.py | 35 ++--- tests/urlpatterns_reverse/urls.py | 143 +++++++++--------- 10 files changed, 94 insertions(+), 230 deletions(-) diff --git a/django/conf/urls/__init__.py b/django/conf/urls/__init__.py index ab67fd30a5..d63dbe9213 100644 --- a/django/conf/urls/__init__.py +++ b/django/conf/urls/__init__.py @@ -10,7 +10,7 @@ from django.utils.deprecation import ( RemovedInDjango20Warning, RemovedInDjango110Warning, ) -__all__ = ['handler400', 'handler403', 'handler404', 'handler500', 'include', 'patterns', 'url'] +__all__ = ['handler400', 'handler403', 'handler404', 'handler500', 'include', 'url'] handler400 = 'django.views.defaults.bad_request' handler403 = 'django.views.defaults.permission_denied' @@ -76,23 +76,6 @@ def include(arg, namespace=None, app_name=None): return (urlconf_module, app_name, namespace) -def patterns(prefix, *args): - warnings.warn( - 'django.conf.urls.patterns() is deprecated and will be removed in ' - 'Django 1.10. Update your urlpatterns to be a list of ' - 'django.conf.urls.url() instances instead.', - RemovedInDjango110Warning, stacklevel=2 - ) - pattern_list = [] - for t in args: - if isinstance(t, (list, tuple)): - t = url(prefix=prefix, *t) - elif isinstance(t, RegexURLPattern): - t.add_prefix(prefix) - pattern_list.append(t) - return pattern_list - - def url(regex, view, kwargs=None, name=None, prefix=''): if isinstance(view, (list, tuple)): # For include(...) processing. diff --git a/django/conf/urls/i18n.py b/django/conf/urls/i18n.py index 44e05b357d..056b957ee0 100644 --- a/django/conf/urls/i18n.py +++ b/django/conf/urls/i18n.py @@ -1,33 +1,18 @@ -import warnings - from django.conf import settings -from django.conf.urls import patterns, url +from django.conf.urls import url from django.core.urlresolvers import LocaleRegexURLResolver -from django.utils import six -from django.utils.deprecation import RemovedInDjango110Warning from django.views.i18n import set_language -def i18n_patterns(prefix, *args): +def i18n_patterns(*urls): """ Adds the language code prefix to every URL pattern within this function. This may only be used in the root URLconf, not in an included URLconf. """ - if isinstance(prefix, six.string_types): - warnings.warn( - "Calling i18n_patterns() with the `prefix` argument and with tuples " - "instead of django.conf.urls.url() instances is deprecated and " - "will no longer work in Django 1.10. Use a list of " - "django.conf.urls.url() instances instead.", - RemovedInDjango110Warning, stacklevel=2 - ) - pattern_list = patterns(prefix, *args) - else: - pattern_list = [prefix] + list(args) if not settings.USE_I18N: - return pattern_list - return [LocaleRegexURLResolver(pattern_list)] + return urls + return [LocaleRegexURLResolver(list(urls))] urlpatterns = [ diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index 1355f29f3c..81aa9bb7ca 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -223,14 +223,6 @@ class RegexURLPattern(LocaleRegexProvider): def __repr__(self): return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern)) - def add_prefix(self, prefix): - """ - Adds the prefix string to a string-based callback. - """ - if not prefix or not hasattr(self, '_callback_str'): - return - self._callback_str = prefix + '.' + self._callback_str - def resolve(self, path): match = self.regex.search(path) if match: diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 10bced6dea..99e293d9a9 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -626,7 +626,7 @@ details on these changes. :mod:`django.contrib.gis.utils` will be removed. * ``django.conf.urls.defaults`` will be removed. The functions - :func:`~django.conf.urls.include`, :func:`~django.conf.urls.patterns` and + :func:`~django.conf.urls.include`, ``patterns()`` and :func:`~django.conf.urls.url` plus :data:`~django.conf.urls.handler404`, :data:`~django.conf.urls.handler500`, are now available through :mod:`django.conf.urls` . diff --git a/docs/ref/urls.txt b/docs/ref/urls.txt index 1fb9375b79..2b40c9eaf6 100644 --- a/docs/ref/urls.txt +++ b/docs/ref/urls.txt @@ -4,77 +4,6 @@ .. module:: django.conf.urls -patterns() ----------- - -.. function:: patterns(prefix, pattern_description, ...) - -.. deprecated:: 1.8 - - ``urlpatterns`` should be a plain list of :func:`django.conf.urls.url` - instances instead. - -A function that takes a prefix, and an arbitrary number of URL patterns, and -returns a list of URL patterns in the format Django needs. - -The first argument to ``patterns()`` is a string ``prefix``. Here's the example -URLconf from the :doc:`Django overview `:: - - from django.conf.urls import patterns, url - - urlpatterns = patterns('', - url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'), - url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'), - url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'), - ) - -In this example, each view has a common prefix -- ``'news.views'``. -Instead of typing that out for each entry in ``urlpatterns``, you can use the -first argument to the ``patterns()`` function to specify a prefix to apply to -each view function. - -With this in mind, the above example can be written more concisely as:: - - from django.conf.urls import patterns, url - - urlpatterns = patterns('news.views', - url(r'^articles/([0-9]{4})/$', 'year_archive'), - url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'month_archive'), - url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'article_detail'), - ) - -Note that you don't put a trailing dot (``"."``) in the prefix. Django puts -that in automatically. - -The remaining arguments should be tuples in this format:: - - (regular expression, Python callback function [, optional_dictionary [, optional_name]]) - -The ``optional_dictionary`` and ``optional_name`` parameters are described in -:ref:`Passing extra options to view functions `. - -.. note:: - Because ``patterns()`` is a function call, it accepts a maximum of 255 - arguments (URL patterns, in this case). This is a limit for all Python - function calls. This is rarely a problem in practice, because you'll - typically structure your URL patterns modularly by using ``include()`` - sections. However, on the off-chance you do hit the 255-argument limit, - realize that ``patterns()`` returns a Python list, so you can split up the - construction of the list. - - :: - - urlpatterns = patterns('', - ... - ) - urlpatterns += patterns('', - ... - ) - - Python lists have unlimited size, so there's no limit to how many URL - patterns you can construct. The only limit is that you can only create 254 - at a time (the 255th argument is the initial prefix argument). - static() -------- diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 5b63758bbb..cf0f9a64fb 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -1233,7 +1233,7 @@ disable this backward-compatibility shim and deprecation warning. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Until Django 1.3, the functions :func:`~django.conf.urls.include`, -:func:`~django.conf.urls.patterns` and :func:`~django.conf.urls.url` plus +``patterns()`` and :func:`~django.conf.urls.url` plus :data:`~django.conf.urls.handler404`, :data:`~django.conf.urls.handler500` were located in a ``django.conf.urls.defaults`` module. diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index 9b46dfe830..d78862c82c 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -1332,13 +1332,7 @@ Django provides two mechanisms to internationalize URL patterns: Language prefix in URL patterns ------------------------------- -.. function:: i18n_patterns(prefix, pattern_description, ...) - -.. deprecated:: 1.8 - - The ``prefix`` argument to ``i18n_patterns()`` has been deprecated and will - not be supported in Django 1.10. Simply pass a list of - :func:`django.conf.urls.url` instances instead. +.. function:: i18n_patterns(*pattern_list) This function can be used in your root URLconf and Django will automatically prepend the current active language code to all url patterns defined within diff --git a/tests/i18n/urls.py b/tests/i18n/urls.py index 2485d1d11a..af2abb9fb8 100644 --- a/tests/i18n/urls.py +++ b/tests/i18n/urls.py @@ -1,16 +1,11 @@ from __future__ import unicode_literals +from django.conf.urls import url from django.conf.urls.i18n import i18n_patterns from django.http import HttpResponse, StreamingHttpResponse -from django.test import ignore_warnings -from django.utils.deprecation import RemovedInDjango110Warning from django.utils.translation import ugettext_lazy as _ -# test deprecated version of i18n_patterns() function (with prefix). Remove it -# and convert to list of urls() in Django 1.10 -i18n_patterns = ignore_warnings(category=RemovedInDjango110Warning)(i18n_patterns) - -urlpatterns = i18n_patterns('', - (r'^simple/$', lambda r: HttpResponse()), - (r'^streaming/$', lambda r: StreamingHttpResponse([_("Yes"), "/", _("No")])), +urlpatterns = i18n_patterns( + url(r'^simple/$', lambda r: HttpResponse()), + url(r'^streaming/$', lambda r: StreamingHttpResponse([_("Yes"), "/", _("No")])), ) diff --git a/tests/urlpatterns_reverse/included_namespace_urls.py b/tests/urlpatterns_reverse/included_namespace_urls.py index 93aa007716..8b2e9dbda1 100644 --- a/tests/urlpatterns_reverse/included_namespace_urls.py +++ b/tests/urlpatterns_reverse/included_namespace_urls.py @@ -1,31 +1,24 @@ -import warnings - -from django.conf.urls import include, patterns, url -from django.utils.deprecation import RemovedInDjango110Warning +from django.conf.urls import include, url from .namespace_urls import URLObject -from .views import view_class_instance +from .views import empty_view, view_class_instance testobj3 = URLObject('testapp', 'test-ns3') testobj4 = URLObject('testapp', 'test-ns4') -# test deprecated patterns() function. convert to list of urls() in Django 1.10 -with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=RemovedInDjango110Warning) +urlpatterns = [ + url(r'^normal/$', empty_view, name='inc-normal-view'), + url(r'^normal/(?P[0-9]+)/(?P[0-9]+)/$', empty_view, name='inc-normal-view'), - urlpatterns = patterns('urlpatterns_reverse.views', - url(r'^normal/$', 'empty_view', name='inc-normal-view'), - url(r'^normal/(?P[0-9]+)/(?P[0-9]+)/$', 'empty_view', name='inc-normal-view'), + url(r'^\+\\\$\*/$', empty_view, name='inc-special-view'), - url(r'^\+\\\$\*/$', 'empty_view', name='inc-special-view'), + url(r'^mixed_args/([0-9]+)/(?P[0-9]+)/$', empty_view, name='inc-mixed-args'), + url(r'^no_kwargs/([0-9]+)/([0-9]+)/$', empty_view, name='inc-no-kwargs'), - url(r'^mixed_args/([0-9]+)/(?P[0-9]+)/$', 'empty_view', name='inc-mixed-args'), - url(r'^no_kwargs/([0-9]+)/([0-9]+)/$', 'empty_view', name='inc-no-kwargs'), + url(r'^view_class/(?P[0-9]+)/(?P[0-9]+)/$', view_class_instance, name='inc-view-class'), - url(r'^view_class/(?P[0-9]+)/(?P[0-9]+)/$', view_class_instance, name='inc-view-class'), - - (r'^test3/', include(testobj3.urls)), - (r'^test4/', include(testobj4.urls)), - (r'^ns-included3/', include('urlpatterns_reverse.included_urls', namespace='inc-ns3')), - (r'^ns-included4/', include('urlpatterns_reverse.namespace_urls', namespace='inc-ns4')), - ) + url(r'^test3/', include(testobj3.urls)), + url(r'^test4/', include(testobj4.urls)), + url(r'^ns-included3/', include('urlpatterns_reverse.included_urls', namespace='inc-ns3')), + url(r'^ns-included4/', include('urlpatterns_reverse.namespace_urls', namespace='inc-ns4')), +] diff --git a/tests/urlpatterns_reverse/urls.py b/tests/urlpatterns_reverse/urls.py index 98a00f803f..4672f1800d 100644 --- a/tests/urlpatterns_reverse/urls.py +++ b/tests/urlpatterns_reverse/urls.py @@ -1,11 +1,8 @@ -import warnings - -from django.conf.urls import include, patterns, url -from django.utils.deprecation import RemovedInDjango110Warning +from django.conf.urls import include, url from .views import ( absolute_kwargs_view, defaults_view, empty_view, empty_view_partial, - empty_view_wrapped, nested_view, + empty_view_wrapped, kwargs_view, nested_view, ) other_patterns = [ @@ -13,79 +10,75 @@ other_patterns = [ url(r'nested_path/$', nested_view), ] -# test deprecated patterns() function. convert to list of urls() in Django 1.10 -with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=RemovedInDjango110Warning) +urlpatterns = [ + url(r'^places/([0-9]+)/$', empty_view, name='places'), + url(r'^places?/$', empty_view, name="places?"), + url(r'^places+/$', empty_view, name="places+"), + url(r'^places*/$', empty_view, name="places*"), + url(r'^(?:places/)?$', empty_view, name="places2?"), + url(r'^(?:places/)+$', empty_view, name="places2+"), + url(r'^(?:places/)*$', empty_view, name="places2*"), + url(r'^places/([0-9]+|[a-z_]+)/', empty_view, name="places3"), + url(r'^places/(?P[0-9]+)/$', empty_view, name="places4"), + url(r'^people/(?P\w+)/$', empty_view, name="people"), + url(r'^people/(?:name/)', empty_view, name="people2"), + url(r'^people/(?:name/(\w+)/)?', empty_view, name="people2a"), + url(r'^people/(?P\w+)-(?P=name)/$', empty_view, name="people_backref"), + url(r'^optional/(?P.*)/(?:.+/)?', empty_view, name="optional"), + url(r'^optional/(?P\d+)/(?:(?P\d+)/)?', absolute_kwargs_view, name="named_optional"), + url(r'^optional/(?P\d+)/(?:(?P\d+)/)?$', absolute_kwargs_view, name="named_optional_terminated"), + url(r'^nested/noncapture/(?:(?P

\w+))$', empty_view, name='nested-noncapture'), + url(r'^nested/capture/((\w+)/)?$', empty_view, name='nested-capture'), + url(r'^nested/capture/mixed/((?P

\w+))$', empty_view, name='nested-mixedcapture'), + url(r'^nested/capture/named/(?P(?P\w+)/)?$', empty_view, name='nested-namedcapture'), + url(r'^hardcoded/$', empty_view, name="hardcoded"), + url(r'^hardcoded/doc\.pdf$', empty_view, name="hardcoded2"), + url(r'^people/(?P\w\w)/(?P\w+)/$', empty_view, name="people3"), + url(r'^people/(?P\w\w)/(?P[0-9])/$', empty_view, name="people4"), + url(r'^people/((?P\w\w)/test)?/(\w+)/$', empty_view, name="people6"), + url(r'^character_set/[abcdef0-9]/$', empty_view, name="range"), + url(r'^character_set/[\w]/$', empty_view, name="range2"), + url(r'^price/\$([0-9]+)/$', empty_view, name="price"), + url(r'^price/[$]([0-9]+)/$', empty_view, name="price2"), + url(r'^price/[\$]([0-9]+)/$', empty_view, name="price3"), + url(r'^product/(?P\w+)\+\(\$(?P[0-9]+(\.[0-9]+)?)\)/$', empty_view, name="product"), + url(r'^headlines/(?P[0-9]+)\.(?P[0-9]+)\.(?P[0-9]+)/$', empty_view, name="headlines"), + url(r'^windows_path/(?P[A-Z]):\\(?P.+)/$', empty_view, name="windows"), + url(r'^special_chars/(?P.+)/$', empty_view, name="special"), + url(r'^(?P.+)/[0-9]+/$', empty_view, name="mixed"), + url(r'^repeats/a{1,2}/$', empty_view, name="repeats"), + url(r'^repeats/a{2,4}/$', empty_view, name="repeats2"), + url(r'^repeats/a{2}/$', empty_view, name="repeats3"), + url(r'^(?i)CaseInsensitive/(\w+)', empty_view, name="insensitive"), + url(r'^test/1/?', empty_view, name="test"), + url(r'^(?i)test/2/?$', empty_view, name="test2"), + url(r'^outer/(?P[0-9]+)/', include('urlpatterns_reverse.included_urls')), + url(r'^outer-no-kwargs/([0-9]+)/', include('urlpatterns_reverse.included_no_kwargs_urls')), + url('', include('urlpatterns_reverse.extra_urls')), + url(r'^lookahead-/(?!not-a-city)(?P[^/]+)/$', empty_view, name='lookahead-negative'), + url(r'^lookahead\+/(?=a-city)(?P[^/]+)/$', empty_view, name='lookahead-positive'), + url(r'^lookbehind-/(?P[^/]+)(?[^/]+)(?<=a-city)/$', empty_view, name='lookbehind-positive'), - urlpatterns = patterns('', - url(r'^places/([0-9]+)/$', empty_view, name='places'), - url(r'^places?/$', empty_view, name="places?"), - url(r'^places+/$', empty_view, name="places+"), - url(r'^places*/$', empty_view, name="places*"), - url(r'^(?:places/)?$', empty_view, name="places2?"), - url(r'^(?:places/)+$', empty_view, name="places2+"), - url(r'^(?:places/)*$', empty_view, name="places2*"), - url(r'^places/([0-9]+|[a-z_]+)/', empty_view, name="places3"), - url(r'^places/(?P[0-9]+)/$', empty_view, name="places4"), - url(r'^people/(?P\w+)/$', empty_view, name="people"), - url(r'^people/(?:name/)', empty_view, name="people2"), - url(r'^people/(?:name/(\w+)/)?', empty_view, name="people2a"), - url(r'^people/(?P\w+)-(?P=name)/$', empty_view, name="people_backref"), - url(r'^optional/(?P.*)/(?:.+/)?', empty_view, name="optional"), - url(r'^optional/(?P\d+)/(?:(?P\d+)/)?', absolute_kwargs_view, name="named_optional"), - url(r'^optional/(?P\d+)/(?:(?P\d+)/)?$', absolute_kwargs_view, name="named_optional_terminated"), - url(r'^nested/noncapture/(?:(?P

\w+))$', empty_view, name='nested-noncapture'), - url(r'^nested/capture/((\w+)/)?$', empty_view, name='nested-capture'), - url(r'^nested/capture/mixed/((?P

\w+))$', empty_view, name='nested-mixedcapture'), - url(r'^nested/capture/named/(?P(?P\w+)/)?$', empty_view, name='nested-namedcapture'), - url(r'^hardcoded/$', empty_view, name="hardcoded"), - url(r'^hardcoded/doc\.pdf$', empty_view, name="hardcoded2"), - url(r'^people/(?P\w\w)/(?P\w+)/$', empty_view, name="people3"), - url(r'^people/(?P\w\w)/(?P[0-9])/$', empty_view, name="people4"), - url(r'^people/((?P\w\w)/test)?/(\w+)/$', empty_view, name="people6"), - url(r'^character_set/[abcdef0-9]/$', empty_view, name="range"), - url(r'^character_set/[\w]/$', empty_view, name="range2"), - url(r'^price/\$([0-9]+)/$', empty_view, name="price"), - url(r'^price/[$]([0-9]+)/$', empty_view, name="price2"), - url(r'^price/[\$]([0-9]+)/$', empty_view, name="price3"), - url(r'^product/(?P\w+)\+\(\$(?P[0-9]+(\.[0-9]+)?)\)/$', empty_view, name="product"), - url(r'^headlines/(?P[0-9]+)\.(?P[0-9]+)\.(?P[0-9]+)/$', empty_view, name="headlines"), - url(r'^windows_path/(?P[A-Z]):\\(?P.+)/$', empty_view, name="windows"), - url(r'^special_chars/(?P.+)/$', empty_view, name="special"), - url(r'^(?P.+)/[0-9]+/$', empty_view, name="mixed"), - url(r'^repeats/a{1,2}/$', empty_view, name="repeats"), - url(r'^repeats/a{2,4}/$', empty_view, name="repeats2"), - url(r'^repeats/a{2}/$', empty_view, name="repeats3"), - url(r'^(?i)CaseInsensitive/(\w+)', empty_view, name="insensitive"), - url(r'^test/1/?', empty_view, name="test"), - url(r'^(?i)test/2/?$', empty_view, name="test2"), - url(r'^outer/(?P[0-9]+)/', include('urlpatterns_reverse.included_urls')), - url(r'^outer-no-kwargs/([0-9]+)/', include('urlpatterns_reverse.included_no_kwargs_urls')), - url('', include('urlpatterns_reverse.extra_urls')), - url(r'^lookahead-/(?!not-a-city)(?P[^/]+)/$', empty_view, name='lookahead-negative'), - url(r'^lookahead\+/(?=a-city)(?P[^/]+)/$', empty_view, name='lookahead-positive'), - url(r'^lookbehind-/(?P[^/]+)(?[^/]+)(?<=a-city)/$', empty_view, name='lookbehind-positive'), + # Partials should be fine. + url(r'^partial/', empty_view_partial, name="partial"), + url(r'^partial_wrapped/', empty_view_wrapped, name="partial_wrapped"), - # Partials should be fine. - url(r'^partial/', empty_view_partial, name="partial"), - url(r'^partial_wrapped/', empty_view_wrapped, name="partial_wrapped"), + # This is non-reversible, but we shouldn't blow up when parsing it. + url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"), - # 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[0-9]+)/$', kwargs_view), + url(r'absolute_arg_view/(?P[0-9]+)/$', absolute_kwargs_view), + url(r'absolute_arg_view/$', absolute_kwargs_view), - # Regression views for #9038. See tests for more details - url(r'arg_view/$', 'urlpatterns_reverse.views.kwargs_view'), - url(r'arg_view/(?P[0-9]+)/$', 'urlpatterns_reverse.views.kwargs_view'), - url(r'absolute_arg_view/(?P[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. + url(r'defaults_view1/(?P[0-9]+)/', defaults_view, {'arg2': 1}, name='defaults'), + url(r'defaults_view2/(?P[0-9]+)/', defaults_view, {'arg2': 2}, 'defaults'), - # Tests for #13154. Mixed syntax to test both ways of defining URLs. - url(r'defaults_view1/(?P[0-9]+)/', defaults_view, {'arg2': 1}, name='defaults'), - (r'defaults_view2/(?P[0-9]+)/', defaults_view, {'arg2': 2}, 'defaults'), + url('^includes/', include(other_patterns)), - url('^includes/', include(other_patterns)), - - # Security tests - url('(.+)/security/$', empty_view, name='security'), - ) + # Security tests + url('(.+)/security/$', empty_view, name='security'), +]