django-upgrade --target-version=5.0 **/*.py

This commit is contained in:
Christian Clauss 2024-01-24 23:44:12 +01:00
parent 74689b1f44
commit d4dfcb5690
21 changed files with 53 additions and 111 deletions

View File

@ -7,7 +7,6 @@ ______ _____ _____ _____ __
\_| \_\____/\____/ \_/ |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_| \_| \_\____/\____/ \_/ |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_|
""" """
import django
__title__ = 'Django REST framework' __title__ = 'Django REST framework'
__version__ = '3.14.0' __version__ = '3.14.0'
@ -25,10 +24,6 @@ HTTP_HEADER_ENCODING = 'iso-8859-1'
ISO_8601 = 'iso-8601' ISO_8601 = 'iso-8601'
if django.VERSION < (3, 2):
default_app_config = 'rest_framework.apps.RestFrameworkConfig'
class RemovedInDRF315Warning(DeprecationWarning): class RemovedInDRF315Warning(DeprecationWarning):
pass pass

View File

@ -17,7 +17,7 @@ def get_authorization_header(request):
Hide some test client ickyness where the header can be unicode. Hide some test client ickyness where the header can be unicode.
""" """
auth = request.META.get('HTTP_AUTHORIZATION', b'') auth = request.headers.get('authorization', b'')
if isinstance(auth, str): if isinstance(auth, str):
# Work around django test client oddness # Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING) auth = auth.encode(HTTP_HEADER_ENCODING)

View File

@ -1,4 +0,0 @@
import django
if django.VERSION < (3, 2):
default_app_config = 'rest_framework.authtoken.apps.AuthTokenConfig'

View File

@ -21,6 +21,7 @@ class TokenChangeList(ChangeList):
current_app=self.model_admin.admin_site.name) current_app=self.model_admin.admin_site.name)
@admin.register(TokenProxy)
class TokenAdmin(admin.ModelAdmin): class TokenAdmin(admin.ModelAdmin):
list_display = ('key', 'user', 'created') list_display = ('key', 'user', 'created')
fields = ('user',) fields = ('user',)
@ -50,6 +51,3 @@ class TokenAdmin(admin.ModelAdmin):
# Map back to actual Token, since delete() uses pk. # Map back to actual Token, since delete() uses pk.
token = Token.objects.get(key=obj.key) token = Token.objects.get(key=obj.key)
return super().delete_model(request, token) return super().delete_model(request, token)
admin.site.register(TokenProxy, TokenAdmin)

View File

@ -145,29 +145,10 @@ else:
return False return False
if django.VERSION >= (4, 2): # Django 4.2+: use the stock parse_header_parameters function
# Django 4.2+: use the stock parse_header_parameters function # Note: Django 4.1 also has an implementation of parse_header_parameters
# Note: Django 4.1 also has an implementation of parse_header_parameters # which is slightly different from the one in 4.2, it needs
# which is slightly different from the one in 4.2, it needs # the compatibility shim as well.
# the compatibility shim as well.
from django.utils.http import parse_header_parameters
else:
# Django <= 4.1: create a compatibility shim for parse_header_parameters
from django.http.multipartparser import parse_header
def parse_header_parameters(line):
# parse_header works with bytes, but parse_header_parameters
# works with strings. Call encode to convert the line to bytes.
main_value_pair, params = parse_header(line.encode())
return main_value_pair, {
# parse_header will convert *some* values to string.
# parse_header_parameters converts *all* values to string.
# Make sure all values are converted by calling decode on
# any remaining non-string values.
k: v if isinstance(v, str) else v.decode()
for k, v in params.items()
}
if django.VERSION >= (5, 1): if django.VERSION >= (5, 1):
# Django 5.1+: use the stock ip_address_validators function # Django 5.1+: use the stock ip_address_validators function

View File

@ -93,5 +93,5 @@ class DefaultContentNegotiation(BaseContentNegotiation):
Given the incoming request, return a tokenized list of media Given the incoming request, return a tokenized list of media
type strings. type strings.
""" """
header = request.META.get('HTTP_ACCEPT', '*/*') header = request.headers.get('accept', '*/*')
return [token.strip() for token in header.split(',')] return [token.strip() for token in header.split(',')]

View File

@ -3,7 +3,6 @@
import io import io
from importlib import import_module from importlib import import_module
import django
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.wsgi import WSGIHandler from django.core.handlers.wsgi import WSGIHandler
@ -394,19 +393,7 @@ class URLPatternsTestCase(testcases.SimpleTestCase):
cls._override.enable() cls._override.enable()
if django.VERSION > (4, 0): cls.addClassCleanup(cls._override.disable)
cls.addClassCleanup(cls._override.disable) cls.addClassCleanup(cleanup_url_patterns, cls)
cls.addClassCleanup(cleanup_url_patterns, cls)
super().setUpClass() super().setUpClass()
if django.VERSION < (4, 0):
@classmethod
def tearDownClass(cls):
super().tearDownClass()
cls._override.disable()
if hasattr(cls, '_module_urlpatterns'):
cls._module.urlpatterns = cls._module_urlpatterns
else:
del cls._module.urlpatterns

View File

@ -26,7 +26,7 @@ class BaseThrottle:
if present and number of proxies is > 0. If not use all of if present and number of proxies is > 0. If not use all of
HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
""" """
xff = request.META.get('HTTP_X_FORWARDED_FOR') xff = request.headers.get('x-forwarded-for')
remote_addr = request.META.get('REMOTE_ADDR') remote_addr = request.META.get('REMOTE_ADDR')
num_proxies = api_settings.NUM_PROXIES num_proxies = api_settings.NUM_PROXIES

View File

@ -1,6 +1,5 @@
import base64 import base64
import django
import pytest import pytest
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -236,15 +235,12 @@ class SessionAuthTests(TestCase):
Regression test for #6088 Regression test for #6088
""" """
# Remove this shim when dropping support for Django 3.0. # Remove this shim when dropping support for Django 3.0.
if django.VERSION < (3, 1): from django.middleware.csrf import (
from django.middleware.csrf import _get_new_csrf_token _get_new_csrf_string, _mask_cipher_secret
else: )
from django.middleware.csrf import (
_get_new_csrf_string, _mask_cipher_secret
)
def _get_new_csrf_token(): def _get_new_csrf_token():
return _mask_cipher_secret(_get_new_csrf_string()) return _mask_cipher_secret(_get_new_csrf_string())
self.csrf_client.login(username=self.username, password=self.password) self.csrf_client.login(username=self.username, password=self.password)

View File

@ -87,10 +87,7 @@ def pytest_configure(config):
import rest_framework import rest_framework
settings.STATIC_ROOT = os.path.join(os.path.dirname(rest_framework.__file__), 'static-root') settings.STATIC_ROOT = os.path.join(os.path.dirname(rest_framework.__file__), 'static-root')
backend = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' backend = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
if django.VERSION < (4, 2): settings.STORAGES['staticfiles']['BACKEND'] = backend
settings.STATICFILES_STORAGE = backend
else:
settings.STORAGES['staticfiles']['BACKEND'] = backend
django.setup() django.setup()

View File

@ -4,7 +4,7 @@ import unittest
from django.http import HttpResponse from django.http import HttpResponse
from django.test import override_settings from django.test import override_settings
from django.urls import path, re_path from django.urls import path
from rest_framework.compat import coreapi, coreschema from rest_framework.compat import coreapi, coreschema
from rest_framework.parsers import FileUploadParser from rest_framework.parsers import FileUploadParser
@ -180,7 +180,7 @@ class HeadersView(APIView):
urlpatterns = [ urlpatterns = [
path('', SchemaView.as_view()), path('', SchemaView.as_view()),
path('example/', ListView.as_view()), path('example/', ListView.as_view()),
re_path(r'^example/(?P<id>[0-9]+)/$', DetailView.as_view()), path('example/<int:id>/', DetailView.as_view()),
path('upload/', UploadView.as_view()), path('upload/', UploadView.as_view()),
path('download/', DownloadView.as_view()), path('download/', DownloadView.as_view()),
path('text/', TextView.as_view()), path('text/', TextView.as_view()),

View File

@ -65,7 +65,7 @@ class TestMiddleware(APITestCase):
key = 'abcd1234' key = 'abcd1234'
Token.objects.create(key=key, user=user) Token.objects.create(key=key, user=user)
self.client.get('/auth', HTTP_AUTHORIZATION='Token %s' % key) self.client.get('/auth', headers={"authorization": 'Token %s' % key})
@override_settings(MIDDLEWARE=('tests.test_middleware.RequestPOSTMiddleware',)) @override_settings(MIDDLEWARE=('tests.test_middleware.RequestPOSTMiddleware',))
def test_middleware_can_access_request_post_when_processing_response(self): def test_middleware_can_access_request_post_when_processing_response(self):

View File

@ -11,7 +11,6 @@ import json # noqa
import sys import sys
import tempfile import tempfile
import django
import pytest import pytest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
@ -454,8 +453,6 @@ class TestPosgresFieldsMapping(TestCase):
fields = ['array_field', 'array_field_with_blank'] fields = ['array_field', 'array_field_with_blank']
validators = "" validators = ""
if django.VERSION < (4, 1):
validators = ", validators=[<django.core.validators.MaxLengthValidator object>]"
expected = dedent(""" expected = dedent("""
TestSerializer(): TestSerializer():
array_field = ListField(allow_empty=False, child=CharField(label='Array field'%s)) array_field = ListField(allow_empty=False, child=CharField(label='Array field'%s))

View File

@ -4,7 +4,7 @@ import pytest
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.test import override_settings from django.test import override_settings
from django.urls import re_path from django.urls import path
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from rest_framework import relations, serializers from rest_framework import relations, serializers
@ -152,7 +152,7 @@ class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
urlpatterns = [ urlpatterns = [
re_path(r'^example/(?P<name>.+)/$', lambda: None, name='example'), path('example/<path:name>/', lambda: None, name='example'),
] ]

View File

@ -174,7 +174,7 @@ class RendererEndToEndTests(TestCase):
def test_default_renderer_serializes_content_on_accept_any(self): def test_default_renderer_serializes_content_on_accept_any(self):
"""If the Accept header is set to */* the default renderer should serialize the response.""" """If the Accept header is set to */* the default renderer should serialize the response."""
resp = self.client.get('/', HTTP_ACCEPT='*/*') resp = self.client.get('/', headers={"accept": '*/*'})
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@ -182,7 +182,7 @@ class RendererEndToEndTests(TestCase):
def test_specified_renderer_serializes_content_default_case(self): def test_specified_renderer_serializes_content_default_case(self):
"""If the Accept header is set the specified renderer should serialize the response. """If the Accept header is set the specified renderer should serialize the response.
(In this case we check that works for the default renderer)""" (In this case we check that works for the default renderer)"""
resp = self.client.get('/', HTTP_ACCEPT=RendererA.media_type) resp = self.client.get('/', headers={"accept": RendererA.media_type})
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@ -190,14 +190,14 @@ class RendererEndToEndTests(TestCase):
def test_specified_renderer_serializes_content_non_default_case(self): def test_specified_renderer_serializes_content_non_default_case(self):
"""If the Accept header is set the specified renderer should serialize the response. """If the Accept header is set the specified renderer should serialize the response.
(In this case we check that works for a non-default renderer)""" (In this case we check that works for a non-default renderer)"""
resp = self.client.get('/', HTTP_ACCEPT=RendererB.media_type) resp = self.client.get('/', headers={"accept": RendererB.media_type})
self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
def test_unsatisfiable_accept_header_on_request_returns_406_status(self): def test_unsatisfiable_accept_header_on_request_returns_406_status(self):
"""If the Accept header is unsatisfiable we should return a 406 Not Acceptable response.""" """If the Accept header is unsatisfiable we should return a 406 Not Acceptable response."""
resp = self.client.get('/', HTTP_ACCEPT='foo/bar') resp = self.client.get('/', headers={"accept": 'foo/bar'})
self.assertEqual(resp.status_code, status.HTTP_406_NOT_ACCEPTABLE) self.assertEqual(resp.status_code, status.HTTP_406_NOT_ACCEPTABLE)
def test_specified_renderer_serializes_content_on_format_query(self): def test_specified_renderer_serializes_content_on_format_query(self):
@ -228,14 +228,14 @@ class RendererEndToEndTests(TestCase):
RendererB.format RendererB.format
) )
resp = self.client.get('/' + param, resp = self.client.get('/' + param,
HTTP_ACCEPT=RendererB.media_type) headers={"accept": RendererB.media_type})
self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
def test_parse_error_renderers_browsable_api(self): def test_parse_error_renderers_browsable_api(self):
"""Invalid data should still render the browsable API correctly.""" """Invalid data should still render the browsable API correctly."""
resp = self.client.post('/parseerror', data='foobar', content_type='application/json', HTTP_ACCEPT='text/html') resp = self.client.post('/parseerror', data='foobar', content_type='application/json', headers={"accept": 'text/html'})
self.assertEqual(resp['Content-Type'], 'text/html; charset=utf-8') self.assertEqual(resp['Content-Type'], 'text/html; charset=utf-8')
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
@ -714,13 +714,13 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
assert result is None assert result is None
def test_extra_actions_dropdown(self): def test_extra_actions_dropdown(self):
resp = self.client.get('/api/examples/', HTTP_ACCEPT='text/html') resp = self.client.get('/api/examples/', headers={"accept": 'text/html'})
assert 'id="extra-actions-menu"' in resp.content.decode() assert 'id="extra-actions-menu"' in resp.content.decode()
assert '/api/examples/list_action/' in resp.content.decode() assert '/api/examples/list_action/' in resp.content.decode()
assert '>Extra list action<' in resp.content.decode() assert '>Extra list action<' in resp.content.decode()
def test_extra_actions_dropdown_not_authed(self): def test_extra_actions_dropdown_not_authed(self):
resp = self.client.get('/api/unauth-examples/', HTTP_ACCEPT='text/html') resp = self.client.get('/api/unauth-examples/', headers={"accept": 'text/html'})
assert 'id="extra-actions-menu"' not in resp.content.decode() assert 'id="extra-actions-menu"' not in resp.content.decode()
assert '/api/examples/list_action/' not in resp.content.decode() assert '/api/examples/list_action/' not in resp.content.decode()
assert '>Extra list action<' not in resp.content.decode() assert '>Extra list action<' not in resp.content.decode()

View File

@ -28,7 +28,7 @@ class Root(APIView):
} }
post = request.POST post = request.POST
json = None json = None
if request.META.get('CONTENT_TYPE') == 'application/json': if request.headers.get('content-type') == 'application/json':
json = request.data json = request.data
return Response({ return Response({

View File

@ -154,7 +154,7 @@ class RendererIntegrationTests(TestCase):
def test_default_renderer_serializes_content_on_accept_any(self): def test_default_renderer_serializes_content_on_accept_any(self):
"""If the Accept header is set to */* the default renderer should serialize the response.""" """If the Accept header is set to */* the default renderer should serialize the response."""
resp = self.client.get('/', HTTP_ACCEPT='*/*') resp = self.client.get('/', headers={"accept": '*/*'})
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@ -162,7 +162,7 @@ class RendererIntegrationTests(TestCase):
def test_specified_renderer_serializes_content_default_case(self): def test_specified_renderer_serializes_content_default_case(self):
"""If the Accept header is set the specified renderer should serialize the response. """If the Accept header is set the specified renderer should serialize the response.
(In this case we check that works for the default renderer)""" (In this case we check that works for the default renderer)"""
resp = self.client.get('/', HTTP_ACCEPT=RendererA.media_type) resp = self.client.get('/', headers={"accept": RendererA.media_type})
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@ -170,7 +170,7 @@ class RendererIntegrationTests(TestCase):
def test_specified_renderer_serializes_content_non_default_case(self): def test_specified_renderer_serializes_content_non_default_case(self):
"""If the Accept header is set the specified renderer should serialize the response. """If the Accept header is set the specified renderer should serialize the response.
(In this case we check that works for a non-default renderer)""" (In this case we check that works for a non-default renderer)"""
resp = self.client.get('/', HTTP_ACCEPT=RendererB.media_type) resp = self.client.get('/', headers={"accept": RendererB.media_type})
self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@ -195,7 +195,7 @@ class RendererIntegrationTests(TestCase):
"""If both a 'format' query and a matching Accept header specified, """If both a 'format' query and a matching Accept header specified,
the renderer with the matching format attribute should serialize the response.""" the renderer with the matching format attribute should serialize the response."""
resp = self.client.get('/?format=%s' % RendererB.format, resp = self.client.get('/?format=%s' % RendererB.format,
HTTP_ACCEPT=RendererB.media_type) headers={"accept": RendererB.media_type})
self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8') self.assertEqual(resp['Content-Type'], RendererB.media_type + '; charset=utf-8')
self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) self.assertEqual(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT))
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)

View File

@ -2,7 +2,6 @@ import itertools
from io import BytesIO from io import BytesIO
from unittest.mock import patch from unittest.mock import patch
import django
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
@ -20,7 +19,7 @@ from rest_framework.test import (
@api_view(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']) @api_view(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'])
def view(request): def view(request):
data = {'auth': request.META.get('HTTP_AUTHORIZATION', b'')} data = {'auth': request.headers.get('authorization', b'')}
if request.user: if request.user:
data['user'] = request.user.username data['user'] = request.user.username
if request.auth: if request.auth:
@ -316,7 +315,7 @@ class TestAPIRequestFactory(TestCase):
data=None, data=None,
content_type='application/json', content_type='application/json',
) )
assert request.META['CONTENT_TYPE'] == 'application/json' assert request.headers['content-type'] == 'application/json'
def check_urlpatterns(cls): def check_urlpatterns(cls):
@ -334,18 +333,10 @@ class TestUrlPatternTestCase(URLPatternsTestCase):
super().setUpClass() super().setUpClass()
assert urlpatterns is cls.urlpatterns assert urlpatterns is cls.urlpatterns
if django.VERSION > (4, 0): cls.addClassCleanup(
cls.addClassCleanup( check_urlpatterns,
check_urlpatterns, cls
cls )
)
if django.VERSION < (4, 0):
@classmethod
def tearDownClass(cls):
assert urlpatterns is cls.urlpatterns
super().tearDownClass()
assert urlpatterns is not cls.urlpatterns
def test_urlpatterns(self): def test_urlpatterns(self):
assert self.client.get('/').status_code == 200 assert self.client.get('/').status_code == 200

View File

@ -1,7 +1,7 @@
from collections import namedtuple from collections import namedtuple
from django.test import TestCase from django.test import TestCase
from django.urls import Resolver404, URLResolver, include, path, re_path from django.urls import Resolver404, URLResolver, include, path
from django.urls.resolvers import RegexPattern from django.urls.resolvers import RegexPattern
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
@ -93,7 +93,7 @@ class FormatSuffixTests(TestCase):
def test_format_suffix_django2_args(self): def test_format_suffix_django2_args(self):
urlpatterns = [ urlpatterns = [
path('convtest/<int:pk>', dummy_view), path('convtest/<int:pk>', dummy_view),
re_path(r'^retest/(?P<pk>[0-9]+)$', dummy_view), path('retest/<int:pk>', dummy_view),
] ]
test_paths = [ test_paths = [
URLTestPath('/convtest/42', (), {'pk': 42}), URLTestPath('/convtest/42', (), {'pk': 42}),
@ -145,10 +145,10 @@ class FormatSuffixTests(TestCase):
def test_included_urls_mixed(self): def test_included_urls_mixed(self):
nested_patterns = [ nested_patterns = [
path('path/<int:child>', dummy_view), path('path/<int:child>', dummy_view),
re_path(r'^re_path/(?P<child>[0-9]+)$', dummy_view) path('re_path/<int:child>', dummy_view)
] ]
urlpatterns = [ urlpatterns = [
re_path(r'^pre_path/(?P<parent>[0-9]+)/', include(nested_patterns), {'foo': 'bar'}), path('pre_path/<int:parent>/', include(nested_patterns), {'foo': 'bar'}),
path('ppath/<int:parent>/', include(nested_patterns), {'foo': 'bar'}), path('ppath/<int:parent>/', include(nested_patterns), {'foo': 'bar'}),
] ]
test_paths = [ test_paths = [
@ -185,7 +185,7 @@ class FormatSuffixTests(TestCase):
def test_allowed_formats_re_path(self): def test_allowed_formats_re_path(self):
urlpatterns = [ urlpatterns = [
re_path(r'^test$', dummy_view), path('test', dummy_view),
] ]
self._test_allowed_formats(urlpatterns) self._test_allowed_formats(urlpatterns)

View File

@ -152,7 +152,7 @@ class TestURLReversing(URLPatternsTestCase, APITestCase):
path('v1/', include((included, 'v1'), namespace='v1')), path('v1/', include((included, 'v1'), namespace='v1')),
path('another/', dummy_view, name='another'), path('another/', dummy_view, name='another'),
re_path(r'^(?P<version>[v1|v2]+)/another/$', dummy_view, name='another'), re_path(r'^(?P<version>[v1|v2]+)/another/$', dummy_view, name='another'),
re_path(r'^(?P<foo>.+)/unversioned/$', dummy_view, name='unversioned'), path('<path:foo>/unversioned/', dummy_view, name='unversioned'),
] ]

10
tox.ini
View File

@ -1,10 +1,13 @@
[tox] [tox]
; https://docs.djangoproject.com/en/stable/faq/install/#what-python-version-can-i-use-with-django
envlist = envlist =
{py36,py37,py38,py39}-django30 {py36,py37,py38,py39}-django30
{py36,py37,py38,py39}-django31 {py36,py37,py38,py39}-django31
{py36,py37,py38,py39,py310}-django32 {py36,py37,py38,py39}-django32
{py38,py39,py310}-{django40,django41,django42,djangomain} {py38,py39}-{django40,django41,django42}
{py311}-{django41,django42,djangomain} {py310}-{django32,django42,django50,djangomain}
{py311}-{django42,django50,djangomain}
{py312}-{django42,django50,djangomain}
base base
dist dist
docs docs
@ -22,6 +25,7 @@ deps =
django40: Django>=4.0,<4.1 django40: Django>=4.0,<4.1
django41: Django>=4.1,<4.2 django41: Django>=4.1,<4.2
django42: Django>=4.2,<5.0 django42: Django>=4.2,<5.0
django50: Django>=5.0,<5.1
djangomain: https://github.com/django/django/archive/main.tar.gz djangomain: https://github.com/django/django/archive/main.tar.gz
-rrequirements/requirements-testing.txt -rrequirements/requirements-testing.txt
-rrequirements/requirements-optionals.txt -rrequirements/requirements-optionals.txt