mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 16:07:38 +03:00 
			
		
		
		
	Drop all compat support to Django < 2 urls (#7337)
This commit is contained in:
		
							parent
							
								
									65add6679d
								
							
						
					
					
						commit
						bb795674f8
					
				|  | @ -5,65 +5,6 @@ versions of Django/Python, and compatibility wrappers around optional packages. | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.views.generic import View | from django.views.generic import View | ||||||
| 
 | 
 | ||||||
| try: |  | ||||||
|     from django.urls import (  # noqa |  | ||||||
|         URLPattern, |  | ||||||
|         URLResolver, |  | ||||||
|     ) |  | ||||||
| except ImportError: |  | ||||||
|     # Will be removed in Django 2.0 |  | ||||||
|     from django.urls import (  # noqa |  | ||||||
|         RegexURLPattern as URLPattern, |  | ||||||
|         RegexURLResolver as URLResolver, |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_original_route(urlpattern): |  | ||||||
|     """ |  | ||||||
|     Get the original route/regex that was typed in by the user into the path(), re_path() or url() directive. This |  | ||||||
|     is in contrast with get_regex_pattern below, which for RoutePattern returns the raw regex generated from the path(). |  | ||||||
|     """ |  | ||||||
|     if hasattr(urlpattern, 'pattern'): |  | ||||||
|         # Django 2.0 |  | ||||||
|         return str(urlpattern.pattern) |  | ||||||
|     else: |  | ||||||
|         # Django < 2.0 |  | ||||||
|         return urlpattern.regex.pattern |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_regex_pattern(urlpattern): |  | ||||||
|     """ |  | ||||||
|     Get the raw regex out of the urlpattern's RegexPattern or RoutePattern. This is always a regular expression, |  | ||||||
|     unlike get_original_route above. |  | ||||||
|     """ |  | ||||||
|     if hasattr(urlpattern, 'pattern'): |  | ||||||
|         # Django 2.0 |  | ||||||
|         return urlpattern.pattern.regex.pattern |  | ||||||
|     else: |  | ||||||
|         # Django < 2.0 |  | ||||||
|         return urlpattern.regex.pattern |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def is_route_pattern(urlpattern): |  | ||||||
|     if hasattr(urlpattern, 'pattern'): |  | ||||||
|         # Django 2.0 |  | ||||||
|         from django.urls.resolvers import RoutePattern |  | ||||||
|         return isinstance(urlpattern.pattern, RoutePattern) |  | ||||||
|     else: |  | ||||||
|         # Django < 2.0 |  | ||||||
|         return False |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_url_resolver(regex, urlpatterns): |  | ||||||
|     try: |  | ||||||
|         # Django 2.0 |  | ||||||
|         from django.urls.resolvers import RegexPattern |  | ||||||
|         return URLResolver(RegexPattern(regex), urlpatterns) |  | ||||||
| 
 |  | ||||||
|     except ImportError: |  | ||||||
|         # Django < 2.0 |  | ||||||
|         return URLResolver(regex, urlpatterns) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| def unicode_http_header(value): | def unicode_http_header(value): | ||||||
|     # Coerce HTTP header value to unicode. |     # Coerce HTTP header value to unicode. | ||||||
|  |  | ||||||
|  | @ -10,9 +10,9 @@ from django.conf import settings | ||||||
| from django.contrib.admindocs.views import simplify_regex | from django.contrib.admindocs.views import simplify_regex | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| from django.http import Http404 | from django.http import Http404 | ||||||
|  | from django.urls import URLPattern, URLResolver | ||||||
| 
 | 
 | ||||||
| from rest_framework import exceptions | from rest_framework import exceptions | ||||||
| from rest_framework.compat import URLPattern, URLResolver, get_original_route |  | ||||||
| from rest_framework.request import clone_request | from rest_framework.request import clone_request | ||||||
| from rest_framework.settings import api_settings | from rest_framework.settings import api_settings | ||||||
| from rest_framework.utils.model_meta import _get_pk | from rest_framework.utils.model_meta import _get_pk | ||||||
|  | @ -79,7 +79,7 @@ class EndpointEnumerator: | ||||||
|         api_endpoints = [] |         api_endpoints = [] | ||||||
| 
 | 
 | ||||||
|         for pattern in patterns: |         for pattern in patterns: | ||||||
|             path_regex = prefix + get_original_route(pattern) |             path_regex = prefix + str(pattern.pattern) | ||||||
|             if isinstance(pattern, URLPattern): |             if isinstance(pattern, URLPattern): | ||||||
|                 path = self.get_path_from_regex(path_regex) |                 path = self.get_path_from_regex(path_regex) | ||||||
|                 callback = pattern.callback |                 callback = pattern.callback | ||||||
|  |  | ||||||
|  | @ -1,9 +1,7 @@ | ||||||
| from django.conf.urls import include, url | from django.conf.urls import include, url | ||||||
| from django.urls import path, register_converter | from django.urls import URLResolver, path, register_converter | ||||||
|  | from django.urls.resolvers import RoutePattern | ||||||
| 
 | 
 | ||||||
| from rest_framework.compat import ( |  | ||||||
|     URLResolver, get_regex_pattern, is_route_pattern |  | ||||||
| ) |  | ||||||
| from rest_framework.settings import api_settings | from rest_framework.settings import api_settings | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +36,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r | ||||||
|     for urlpattern in urlpatterns: |     for urlpattern in urlpatterns: | ||||||
|         if isinstance(urlpattern, URLResolver): |         if isinstance(urlpattern, URLResolver): | ||||||
|             # Set of included URL patterns |             # Set of included URL patterns | ||||||
|             regex = get_regex_pattern(urlpattern) |             regex = urlpattern.pattern.regex.pattern | ||||||
|             namespace = urlpattern.namespace |             namespace = urlpattern.namespace | ||||||
|             app_name = urlpattern.app_name |             app_name = urlpattern.app_name | ||||||
|             kwargs = urlpattern.default_kwargs |             kwargs = urlpattern.default_kwargs | ||||||
|  | @ -49,7 +47,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r | ||||||
|                                              suffix_route) |                                              suffix_route) | ||||||
| 
 | 
 | ||||||
|             # if the original pattern was a RoutePattern we need to preserve it |             # if the original pattern was a RoutePattern we need to preserve it | ||||||
|             if is_route_pattern(urlpattern): |             if isinstance(urlpattern.pattern, RoutePattern): | ||||||
|                 assert path is not None |                 assert path is not None | ||||||
|                 route = str(urlpattern.pattern) |                 route = str(urlpattern.pattern) | ||||||
|                 new_pattern = path(route, include((patterns, app_name), namespace), kwargs) |                 new_pattern = path(route, include((patterns, app_name), namespace), kwargs) | ||||||
|  | @ -59,7 +57,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r | ||||||
|             ret.append(new_pattern) |             ret.append(new_pattern) | ||||||
|         else: |         else: | ||||||
|             # Regular URL pattern |             # Regular URL pattern | ||||||
|             regex = get_regex_pattern(urlpattern).rstrip('$').rstrip('/') + suffix_pattern |             regex = urlpattern.pattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern | ||||||
|             view = urlpattern.callback |             view = urlpattern.callback | ||||||
|             kwargs = urlpattern.default_args |             kwargs = urlpattern.default_args | ||||||
|             name = urlpattern.name |             name = urlpattern.name | ||||||
|  | @ -68,7 +66,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_r | ||||||
|                 ret.append(urlpattern) |                 ret.append(urlpattern) | ||||||
| 
 | 
 | ||||||
|             # if the original pattern was a RoutePattern we need to preserve it |             # if the original pattern was a RoutePattern we need to preserve it | ||||||
|             if is_route_pattern(urlpattern): |             if isinstance(urlpattern.pattern, RoutePattern): | ||||||
|                 assert path is not None |                 assert path is not None | ||||||
|                 assert suffix_route is not None |                 assert suffix_route is not None | ||||||
|                 route = str(urlpattern.pattern).rstrip('$').rstrip('/') + suffix_route |                 route = str(urlpattern.pattern).rstrip('$').rstrip('/') + suffix_route | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ from django.urls import path | ||||||
| from rest_framework import ( | from rest_framework import ( | ||||||
|     filters, generics, pagination, permissions, serializers |     filters, generics, pagination, permissions, serializers | ||||||
| ) | ) | ||||||
| from rest_framework.compat import coreapi, coreschema, get_regex_pattern | from rest_framework.compat import coreapi, coreschema | ||||||
| from rest_framework.decorators import action, api_view, schema | from rest_framework.decorators import action, api_view, schema | ||||||
| from rest_framework.request import Request | from rest_framework.request import Request | ||||||
| from rest_framework.routers import DefaultRouter, SimpleRouter | from rest_framework.routers import DefaultRouter, SimpleRouter | ||||||
|  | @ -1079,7 +1079,7 @@ class SchemaGenerationExclusionTests(TestCase): | ||||||
|         inspector = EndpointEnumerator(self.patterns) |         inspector = EndpointEnumerator(self.patterns) | ||||||
| 
 | 
 | ||||||
|         # Not pretty. Mimics internals of EndpointEnumerator to put should_include_endpoint under test |         # Not pretty. Mimics internals of EndpointEnumerator to put should_include_endpoint under test | ||||||
|         pairs = [(inspector.get_path_from_regex(get_regex_pattern(pattern)), pattern.callback) |         pairs = [(inspector.get_path_from_regex(pattern.pattern.regex.pattern), pattern.callback) | ||||||
|                  for pattern in self.patterns] |                  for pattern in self.patterns] | ||||||
| 
 | 
 | ||||||
|         should_include = [ |         should_include = [ | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import datetime | import datetime | ||||||
| from importlib import reload as reload_module | from importlib import reload as reload_module | ||||||
| 
 | 
 | ||||||
| import django |  | ||||||
| import pytest | import pytest | ||||||
| from django.core.exceptions import ImproperlyConfigured | from django.core.exceptions import ImproperlyConfigured | ||||||
| from django.db import models | from django.db import models | ||||||
|  | @ -191,7 +190,6 @@ class SearchFilterTests(TestCase): | ||||||
| 
 | 
 | ||||||
|         assert terms == ['asdf'] |         assert terms == ['asdf'] | ||||||
| 
 | 
 | ||||||
|     @pytest.mark.skipif(django.VERSION[:2] < (2, 2), reason="requires django 2.2 or higher") |  | ||||||
|     def test_search_field_with_additional_transforms(self): |     def test_search_field_with_additional_transforms(self): | ||||||
|         from django.test.utils import register_lookup |         from django.test.utils import register_lookup | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,7 +8,6 @@ from django.test import TestCase, override_settings | ||||||
| from django.urls import resolve, reverse | from django.urls import resolve, reverse | ||||||
| 
 | 
 | ||||||
| from rest_framework import permissions, serializers, viewsets | from rest_framework import permissions, serializers, viewsets | ||||||
| from rest_framework.compat import get_regex_pattern |  | ||||||
| from rest_framework.decorators import action | from rest_framework.decorators import action | ||||||
| from rest_framework.response import Response | from rest_framework.response import Response | ||||||
| from rest_framework.routers import DefaultRouter, SimpleRouter | from rest_framework.routers import DefaultRouter, SimpleRouter | ||||||
|  | @ -192,8 +191,7 @@ class TestCustomLookupFields(URLPatternsTestCase, TestCase): | ||||||
| 
 | 
 | ||||||
|     def test_custom_lookup_field_route(self): |     def test_custom_lookup_field_route(self): | ||||||
|         detail_route = notes_router.urls[-1] |         detail_route = notes_router.urls[-1] | ||||||
|         detail_url_pattern = get_regex_pattern(detail_route) |         assert '<uuid>' in detail_route.pattern.regex.pattern | ||||||
|         assert '<uuid>' in detail_url_pattern |  | ||||||
| 
 | 
 | ||||||
|     def test_retrieve_lookup_field_list_view(self): |     def test_retrieve_lookup_field_list_view(self): | ||||||
|         response = self.client.get('/example/notes/') |         response = self.client.get('/example/notes/') | ||||||
|  | @ -229,7 +227,7 @@ class TestLookupValueRegex(TestCase): | ||||||
|     def test_urls_limited_by_lookup_value_regex(self): |     def test_urls_limited_by_lookup_value_regex(self): | ||||||
|         expected = ['^notes/$', '^notes/(?P<uuid>[0-9a-f]{32})/$'] |         expected = ['^notes/$', '^notes/(?P<uuid>[0-9a-f]{32})/$'] | ||||||
|         for idx in range(len(expected)): |         for idx in range(len(expected)): | ||||||
|             assert expected[idx] == get_regex_pattern(self.urls[idx]) |             assert expected[idx] == self.urls[idx].pattern.regex.pattern | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @override_settings(ROOT_URLCONF='tests.test_routers') | @override_settings(ROOT_URLCONF='tests.test_routers') | ||||||
|  | @ -249,8 +247,7 @@ class TestLookupUrlKwargs(URLPatternsTestCase, TestCase): | ||||||
| 
 | 
 | ||||||
|     def test_custom_lookup_url_kwarg_route(self): |     def test_custom_lookup_url_kwarg_route(self): | ||||||
|         detail_route = kwarged_notes_router.urls[-1] |         detail_route = kwarged_notes_router.urls[-1] | ||||||
|         detail_url_pattern = get_regex_pattern(detail_route) |         assert '^notes/(?P<text>' in detail_route.pattern.regex.pattern | ||||||
|         assert '^notes/(?P<text>' in detail_url_pattern |  | ||||||
| 
 | 
 | ||||||
|     def test_retrieve_lookup_url_kwarg_detail_view(self): |     def test_retrieve_lookup_url_kwarg_detail_view(self): | ||||||
|         response = self.client.get('/example2/notes/fo/') |         response = self.client.get('/example2/notes/fo/') | ||||||
|  | @ -273,7 +270,7 @@ class TestTrailingSlashIncluded(TestCase): | ||||||
|     def test_urls_have_trailing_slash_by_default(self): |     def test_urls_have_trailing_slash_by_default(self): | ||||||
|         expected = ['^notes/$', '^notes/(?P<pk>[^/.]+)/$'] |         expected = ['^notes/$', '^notes/(?P<pk>[^/.]+)/$'] | ||||||
|         for idx in range(len(expected)): |         for idx in range(len(expected)): | ||||||
|             assert expected[idx] == get_regex_pattern(self.urls[idx]) |             assert expected[idx] == self.urls[idx].pattern.regex.pattern | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestTrailingSlashRemoved(TestCase): | class TestTrailingSlashRemoved(TestCase): | ||||||
|  | @ -288,7 +285,7 @@ class TestTrailingSlashRemoved(TestCase): | ||||||
|     def test_urls_can_have_trailing_slash_removed(self): |     def test_urls_can_have_trailing_slash_removed(self): | ||||||
|         expected = ['^notes$', '^notes/(?P<pk>[^/.]+)$'] |         expected = ['^notes$', '^notes/(?P<pk>[^/.]+)$'] | ||||||
|         for idx in range(len(expected)): |         for idx in range(len(expected)): | ||||||
|             assert expected[idx] == get_regex_pattern(self.urls[idx]) |             assert expected[idx] == self.urls[idx].pattern.regex.pattern | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestNameableRoot(TestCase): | class TestNameableRoot(TestCase): | ||||||
|  |  | ||||||
|  | @ -3,9 +3,9 @@ from collections import namedtuple | ||||||
| 
 | 
 | ||||||
| from django.conf.urls import include, url | from django.conf.urls import include, url | ||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
| from django.urls import Resolver404, path, re_path | from django.urls import Resolver404, URLResolver, path, re_path | ||||||
|  | from django.urls.resolvers import RegexPattern | ||||||
| 
 | 
 | ||||||
| from rest_framework.compat import make_url_resolver |  | ||||||
| from rest_framework.test import APIRequestFactory | from rest_framework.test import APIRequestFactory | ||||||
| from rest_framework.urlpatterns import format_suffix_patterns | from rest_framework.urlpatterns import format_suffix_patterns | ||||||
| 
 | 
 | ||||||
|  | @ -28,7 +28,7 @@ class FormatSuffixTests(TestCase): | ||||||
|             urlpatterns = format_suffix_patterns(urlpatterns, allowed=allowed) |             urlpatterns = format_suffix_patterns(urlpatterns, allowed=allowed) | ||||||
|         except Exception: |         except Exception: | ||||||
|             self.fail("Failed to apply `format_suffix_patterns` on  the supplied urlpatterns") |             self.fail("Failed to apply `format_suffix_patterns` on  the supplied urlpatterns") | ||||||
|         resolver = make_url_resolver(r'^/', urlpatterns) |         resolver = URLResolver(RegexPattern(r'^/'), urlpatterns) | ||||||
|         for test_path in test_paths: |         for test_path in test_paths: | ||||||
|             try: |             try: | ||||||
|                 test_path, expected_resolved = test_path |                 test_path, expected_resolved = test_path | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user