mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 19:14:01 +03:00
Introduce RemovedInDRF…Warning classes to simplify deprecations. (#6480)
Closes #6290.
This commit is contained in:
parent
a216d02ce0
commit
94593b3a50
|
@ -18,9 +18,9 @@ REST framework releases follow a formal deprecation policy, which is in line wit
|
|||
|
||||
The timeline for deprecation of a feature present in version 1.0 would work as follows:
|
||||
|
||||
* Version 1.1 would remain **fully backwards compatible** with 1.0, but would raise `PendingDeprecationWarning` warnings if you use the feature that are due to be deprecated. These warnings are **silent by default**, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using `python -Wd manage.py test`, you'll be warned of any API changes you need to make.
|
||||
* Version 1.1 would remain **fully backwards compatible** with 1.0, but would raise `RemovedInDRF13Warning` warnings, subclassing `PendingDeprecationWarning`, if you use the feature that are due to be deprecated. These warnings are **silent by default**, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using `python -Wd manage.py test`, you'll be warned of any API changes you need to make.
|
||||
|
||||
* Version 1.2 would escalate these warnings to `DeprecationWarning`, which is loud by default.
|
||||
* Version 1.2 would escalate these warnings to subclass `DeprecationWarning`, which is loud by default.
|
||||
|
||||
* Version 1.3 would remove the deprecated bits of API entirely.
|
||||
|
||||
|
|
|
@ -23,3 +23,11 @@ HTTP_HEADER_ENCODING = 'iso-8859-1'
|
|||
ISO_8601 = 'iso-8601'
|
||||
|
||||
default_app_config = 'rest_framework.apps.RestFrameworkConfig'
|
||||
|
||||
|
||||
class RemovedInDRF310Warning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInDRF311Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
|
|
@ -14,6 +14,7 @@ import warnings
|
|||
from django.forms.utils import pretty_name
|
||||
from django.utils import six
|
||||
|
||||
from rest_framework import RemovedInDRF310Warning
|
||||
from rest_framework.views import APIView
|
||||
|
||||
|
||||
|
@ -225,7 +226,7 @@ def detail_route(methods=None, **kwargs):
|
|||
warnings.warn(
|
||||
"`detail_route` is deprecated and will be removed in 3.10 in favor of "
|
||||
"`action`, which accepts a `detail` bool. Use `@action(detail=True)` instead.",
|
||||
DeprecationWarning, stacklevel=2
|
||||
RemovedInDRF310Warning, stacklevel=2
|
||||
)
|
||||
|
||||
def decorator(func):
|
||||
|
@ -243,7 +244,7 @@ def list_route(methods=None, **kwargs):
|
|||
warnings.warn(
|
||||
"`list_route` is deprecated and will be removed in 3.10 in favor of "
|
||||
"`action`, which accepts a `detail` bool. Use `@action(detail=False)` instead.",
|
||||
DeprecationWarning, stacklevel=2
|
||||
RemovedInDRF310Warning, stacklevel=2
|
||||
)
|
||||
|
||||
def decorator(func):
|
||||
|
|
|
@ -17,6 +17,7 @@ from django.utils import six
|
|||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import RemovedInDRF310Warning
|
||||
from rest_framework.compat import (
|
||||
coreapi, coreschema, distinct, is_guardian_installed
|
||||
)
|
||||
|
@ -299,7 +300,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
|
|||
warnings.warn(
|
||||
"`DjangoObjectPermissionsFilter` has been deprecated and moved to "
|
||||
"the 3rd-party django-rest-framework-guardian package.",
|
||||
DeprecationWarning, stacklevel=2
|
||||
RemovedInDRF310Warning, stacklevel=2
|
||||
)
|
||||
assert is_guardian_installed(), 'Using DjangoObjectPermissionsFilter, but django-guardian is not installed'
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ from django.urls import NoReverseMatch
|
|||
from django.utils import six
|
||||
from django.utils.deprecation import RenameMethodsBase
|
||||
|
||||
from rest_framework import views
|
||||
from rest_framework import (
|
||||
RemovedInDRF310Warning, RemovedInDRF311Warning, views
|
||||
)
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.schemas import SchemaGenerator
|
||||
|
@ -43,7 +45,7 @@ class DynamicDetailRoute(object):
|
|||
"`DynamicDetailRoute` is deprecated and will be removed in 3.10 "
|
||||
"in favor of `DynamicRoute`, which accepts a `detail` boolean. Use "
|
||||
"`DynamicRoute(url, name, True, initkwargs)` instead.",
|
||||
DeprecationWarning, stacklevel=2
|
||||
RemovedInDRF310Warning, stacklevel=2
|
||||
)
|
||||
return DynamicRoute(url, name, True, initkwargs)
|
||||
|
||||
|
@ -54,7 +56,7 @@ class DynamicListRoute(object):
|
|||
"`DynamicListRoute` is deprecated and will be removed in 3.10 in "
|
||||
"favor of `DynamicRoute`, which accepts a `detail` boolean. Use "
|
||||
"`DynamicRoute(url, name, False, initkwargs)` instead.",
|
||||
DeprecationWarning, stacklevel=2
|
||||
RemovedInDRF310Warning, stacklevel=2
|
||||
)
|
||||
return DynamicRoute(url, name, False, initkwargs)
|
||||
|
||||
|
@ -77,7 +79,7 @@ def flatten(list_of_lists):
|
|||
|
||||
class RenameRouterMethods(RenameMethodsBase):
|
||||
renamed_methods = (
|
||||
('get_default_base_name', 'get_default_basename', PendingDeprecationWarning),
|
||||
('get_default_base_name', 'get_default_basename', RemovedInDRF311Warning),
|
||||
)
|
||||
|
||||
|
||||
|
@ -88,7 +90,7 @@ class BaseRouter(six.with_metaclass(RenameRouterMethods)):
|
|||
def register(self, prefix, viewset, basename=None, base_name=None):
|
||||
if base_name is not None:
|
||||
msg = "The `base_name` argument is pending deprecation in favor of `basename`."
|
||||
warnings.warn(msg, PendingDeprecationWarning, 2)
|
||||
warnings.warn(msg, RemovedInDRF311Warning, 2)
|
||||
|
||||
assert not (basename and base_name), (
|
||||
"Do not provide both the `basename` and `base_name` arguments.")
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||
import pytest
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework import RemovedInDRF310Warning, status
|
||||
from rest_framework.authentication import BasicAuthentication
|
||||
from rest_framework.decorators import (
|
||||
action, api_view, authentication_classes, detail_route, list_route,
|
||||
|
@ -290,7 +290,7 @@ class ActionDecoratorTestCase(TestCase):
|
|||
raise NotImplementedError
|
||||
|
||||
def test_detail_route_deprecation(self):
|
||||
with pytest.warns(DeprecationWarning) as record:
|
||||
with pytest.warns(RemovedInDRF310Warning) as record:
|
||||
@detail_route()
|
||||
def view(request):
|
||||
raise NotImplementedError
|
||||
|
@ -303,7 +303,7 @@ class ActionDecoratorTestCase(TestCase):
|
|||
)
|
||||
|
||||
def test_list_route_deprecation(self):
|
||||
with pytest.warns(DeprecationWarning) as record:
|
||||
with pytest.warns(RemovedInDRF310Warning) as record:
|
||||
@list_route()
|
||||
def view(request):
|
||||
raise NotImplementedError
|
||||
|
@ -317,7 +317,7 @@ class ActionDecoratorTestCase(TestCase):
|
|||
|
||||
def test_route_url_name_from_path(self):
|
||||
# pre-3.8 behavior was to base the `url_name` off of the `url_path`
|
||||
with pytest.warns(DeprecationWarning):
|
||||
with pytest.warns(RemovedInDRF310Warning):
|
||||
@list_route(url_path='foo_bar')
|
||||
def view(request):
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -12,8 +12,8 @@ from django.test import TestCase
|
|||
from django.urls import ResolverMatch
|
||||
|
||||
from rest_framework import (
|
||||
HTTP_HEADER_ENCODING, authentication, generics, permissions, serializers,
|
||||
status, views
|
||||
HTTP_HEADER_ENCODING, RemovedInDRF310Warning, authentication, generics,
|
||||
permissions, serializers, status, views
|
||||
)
|
||||
from rest_framework.compat import PY36, is_guardian_installed, mock
|
||||
from rest_framework.filters import DjangoObjectPermissionsFilter
|
||||
|
@ -427,7 +427,7 @@ class ObjectPermissionsIntegrationTests(TestCase):
|
|||
message = ("`DjangoObjectPermissionsFilter` has been deprecated and moved "
|
||||
"to the 3rd-party django-rest-framework-guardian package.")
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertIs(w[-1].category, DeprecationWarning)
|
||||
self.assertIs(w[-1].category, RemovedInDRF310Warning)
|
||||
self.assertEqual(str(w[-1].message), message)
|
||||
|
||||
def test_can_read_list_permissions(self):
|
||||
|
|
|
@ -10,7 +10,9 @@ from django.db import models
|
|||
from django.test import TestCase, override_settings
|
||||
from django.urls import resolve, reverse
|
||||
|
||||
from rest_framework import permissions, serializers, viewsets
|
||||
from rest_framework import (
|
||||
RemovedInDRF311Warning, permissions, serializers, viewsets
|
||||
)
|
||||
from rest_framework.compat import get_regex_pattern
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
@ -508,7 +510,7 @@ class TestBaseNameRename(TestCase):
|
|||
def test_base_name_argument_deprecation(self):
|
||||
router = SimpleRouter()
|
||||
|
||||
with pytest.warns(PendingDeprecationWarning) as w:
|
||||
with pytest.warns(RemovedInDRF311Warning) as w:
|
||||
warnings.simplefilter('always')
|
||||
router.register('mock', MockViewSet, base_name='mock')
|
||||
|
||||
|
@ -535,7 +537,7 @@ class TestBaseNameRename(TestCase):
|
|||
msg = "`CustomRouter.get_default_base_name` method should be renamed `get_default_basename`."
|
||||
|
||||
# Class definition should raise a warning
|
||||
with pytest.warns(PendingDeprecationWarning) as w:
|
||||
with pytest.warns(RemovedInDRF311Warning) as w:
|
||||
warnings.simplefilter('always')
|
||||
|
||||
class CustomRouter(SimpleRouter):
|
||||
|
|
Loading…
Reference in New Issue
Block a user