diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index fe2eab04b..4bd5bdbda 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -7,8 +7,6 @@ ______ _____ _____ _____ __ \_| \_\____/\____/ \_/ |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_| """ -import django - __title__ = 'Django REST framework' __version__ = '3.15.1' __author__ = 'Tom Christie' @@ -25,10 +23,6 @@ HTTP_HEADER_ENCODING = 'iso-8859-1' ISO_8601 = 'iso-8601' -if django.VERSION < (3, 2): - default_app_config = 'rest_framework.apps.RestFrameworkConfig' - - class RemovedInDRF315Warning(DeprecationWarning): pass diff --git a/rest_framework/authtoken/__init__.py b/rest_framework/authtoken/__init__.py index 285fe15c6..e69de29bb 100644 --- a/rest_framework/authtoken/__init__.py +++ b/rest_framework/authtoken/__init__.py @@ -1,4 +0,0 @@ -import django - -if django.VERSION < (3, 2): - default_app_config = 'rest_framework.authtoken.apps.AuthTokenConfig' diff --git a/rest_framework/compat.py b/rest_framework/compat.py index afc06b6cb..27c5632be 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -151,30 +151,6 @@ else: return False -if django.VERSION >= (4, 2): - # Django 4.2+: use the stock parse_header_parameters function - # Note: Django 4.1 also has an implementation of parse_header_parameters - # which is slightly different from the one in 4.2, it needs - # 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): # Django 5.1+: use the stock ip_address_validators function # Note: Before Django 5.1, ip_address_validators returns a tuple containing diff --git a/rest_framework/filters.py b/rest_framework/filters.py index 435c30c88..3f4730da8 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -114,10 +114,6 @@ class SearchFilter(BaseFilterBackend): if hasattr(field, "path_infos"): # Update opts to follow the relation. opts = field.path_infos[-1].to_opts - # django < 4.1 - elif hasattr(field, 'get_path_info'): - # Update opts to follow the relation. - opts = field.get_path_info()[-1].to_opts # Otherwise, use the field with icontains. lookup = 'icontains' return LOOKUP_SEP.join([field_name, lookup]) diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index f0fd2b884..0e8e4bcb8 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -15,9 +15,9 @@ from django.http.multipartparser import ChunkIter from django.http.multipartparser import \ MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParserError +from django.utils.http import parse_header_parameters from rest_framework import renderers -from rest_framework.compat import parse_header_parameters from rest_framework.exceptions import ParseError from rest_framework.settings import api_settings from rest_framework.utils import json diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index db1fdd128..ea73c6657 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -19,12 +19,13 @@ from django.core.paginator import Page from django.template import engines, loader from django.urls import NoReverseMatch from django.utils.html import mark_safe +from django.utils.http import parse_header_parameters from django.utils.safestring import SafeString from rest_framework import VERSION, exceptions, serializers, status from rest_framework.compat import ( INDENT_SEPARATORS, LONG_SEPARATORS, SHORT_SEPARATORS, coreapi, coreschema, - parse_header_parameters, pygments_css, yaml + pygments_css, yaml ) from rest_framework.exceptions import ParseError from rest_framework.request import is_form_media_type, override_method diff --git a/rest_framework/request.py b/rest_framework/request.py index 93109226d..f30578fa2 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -16,9 +16,9 @@ from django.conf import settings from django.http import HttpRequest, QueryDict from django.http.request import RawPostDataException from django.utils.datastructures import MultiValueDict +from django.utils.http import parse_header_parameters from rest_framework import exceptions -from rest_framework.compat import parse_header_parameters from rest_framework.settings import api_settings diff --git a/rest_framework/test.py b/rest_framework/test.py index 04409f962..e939adcd7 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -3,7 +3,6 @@ import io from importlib import import_module -import django from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.handlers.wsgi import WSGIHandler @@ -394,19 +393,7 @@ class URLPatternsTestCase(testcases.SimpleTestCase): cls._override.enable() - if django.VERSION > (4, 0): - cls.addClassCleanup(cls._override.disable) - cls.addClassCleanup(cleanup_url_patterns, cls) + cls.addClassCleanup(cls._override.disable) + cls.addClassCleanup(cleanup_url_patterns, cls) 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 diff --git a/rest_framework/utils/mediatypes.py b/rest_framework/utils/mediatypes.py index b9004d496..8641732f0 100644 --- a/rest_framework/utils/mediatypes.py +++ b/rest_framework/utils/mediatypes.py @@ -3,7 +3,7 @@ Handling of media types, as found in HTTP Content-Type and Accept headers. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 """ -from rest_framework.compat import parse_header_parameters +from django.utils.http import parse_header_parameters def media_type_matches(lhs, rhs): diff --git a/tests/authentication/test_authentication.py b/tests/authentication/test_authentication.py index 22e837ef4..2f05ce7d1 100644 --- a/tests/authentication/test_authentication.py +++ b/tests/authentication/test_authentication.py @@ -1,6 +1,5 @@ import base64 -import django import pytest from django.conf import settings from django.contrib.auth.models import User @@ -235,21 +234,13 @@ class SessionAuthTests(TestCase): Ensure POSTing form over session authentication with CSRF token succeeds. Regression test for #6088 """ - # Remove this shim when dropping support for Django 3.0. - if django.VERSION < (3, 1): - from django.middleware.csrf import _get_new_csrf_token - else: - from django.middleware.csrf import ( - _get_new_csrf_string, _mask_cipher_secret - ) - - def _get_new_csrf_token(): - return _mask_cipher_secret(_get_new_csrf_string()) - self.csrf_client.login(username=self.username, password=self.password) # Set the csrf_token cookie so that CsrfViewMiddleware._get_token() works - token = _get_new_csrf_token() + from django.middleware.csrf import ( + _get_new_csrf_string, _mask_cipher_secret + ) + token = _mask_cipher_secret(_get_new_csrf_string()) self.csrf_client.cookies[settings.CSRF_COOKIE_NAME] = token # Post the token matching the cookie value diff --git a/tests/conftest.py b/tests/conftest.py index b67475d8a..01914ae77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,8 +13,6 @@ def pytest_addoption(parser): def pytest_configure(config): from django.conf import settings - # USE_L10N is deprecated, and will be removed in Django 5.0. - use_l10n = {"USE_L10N": True} if django.VERSION < (4, 0) else {} settings.configure( DEBUG_PROPAGATE_EXCEPTIONS=True, DATABASES={ @@ -64,7 +62,6 @@ def pytest_configure(config): PASSWORD_HASHERS=( 'django.contrib.auth.hashers.MD5PasswordHasher', ), - **use_l10n, ) # guardian is optional @@ -87,10 +84,7 @@ def pytest_configure(config): import rest_framework settings.STATIC_ROOT = os.path.join(os.path.dirname(rest_framework.__file__), 'static-root') backend = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' - if django.VERSION < (4, 2): - settings.STATICFILES_STORAGE = backend - else: - settings.STORAGES['staticfiles']['BACKEND'] = backend + settings.STORAGES['staticfiles']['BACKEND'] = backend django.setup() diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index d69f1652d..ae1a2b0fa 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -12,7 +12,6 @@ import re import sys import tempfile -import django import pytest from django.core.exceptions import ImproperlyConfigured from django.core.serializers.json import DjangoJSONEncoder @@ -453,14 +452,11 @@ class TestPosgresFieldsMapping(TestCase): model = ArrayFieldModel fields = ['array_field', 'array_field_with_blank'] - validators = "" - if django.VERSION < (4, 1): - validators = ", validators=[]" expected = dedent(""" TestSerializer(): - array_field = ListField(allow_empty=False, child=CharField(label='Array field'%s)) - array_field_with_blank = ListField(child=CharField(label='Array field with blank'%s), required=False) - """ % (validators, validators)) + array_field = ListField(allow_empty=False, child=CharField(label='Array field')) + array_field_with_blank = ListField(child=CharField(label='Array field with blank'), required=False) + """) self.assertEqual(repr(TestSerializer()), expected) @pytest.mark.skipif(hasattr(models, 'JSONField'), reason='has models.JSONField') diff --git a/tests/test_testing.py b/tests/test_testing.py index 196319a29..7c2a09fae 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -2,7 +2,6 @@ import itertools from io import BytesIO from unittest.mock import patch -import django from django.contrib.auth.models import User from django.http import HttpResponseRedirect from django.shortcuts import redirect @@ -334,18 +333,10 @@ class TestUrlPatternTestCase(URLPatternsTestCase): super().setUpClass() assert urlpatterns is cls.urlpatterns - if django.VERSION > (4, 0): - cls.addClassCleanup( - check_urlpatterns, - cls - ) - - if django.VERSION < (4, 0): - @classmethod - def tearDownClass(cls): - assert urlpatterns is cls.urlpatterns - super().tearDownClass() - assert urlpatterns is not cls.urlpatterns + cls.addClassCleanup( + check_urlpatterns, + cls + ) def test_urlpatterns(self): assert self.client.get('/').status_code == 200