diff --git a/CHANGES.rst b/CHANGES.rst index 3481fd210..63fa124e4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,11 @@ Version 2.1.0 Unreleased +- Remove previously deprecated code. :pr:`2276` + + - Request and response mixins have all been merged into the + ``Request`` and ``Response`` classes. + - Default values passed to ``Headers`` are validated the same way values added later are. :issue:`1608` - Setting ``CacheControl`` int properties, such as ``max_age``, will diff --git a/src/werkzeug/wrappers/__init__.py b/src/werkzeug/wrappers/__init__.py index eb69a9949..b8c45d71c 100644 --- a/src/werkzeug/wrappers/__init__.py +++ b/src/werkzeug/wrappers/__init__.py @@ -1,16 +1,3 @@ -from .accept import AcceptMixin -from .auth import AuthorizationMixin -from .auth import WWWAuthenticateMixin -from .base_request import BaseRequest -from .base_response import BaseResponse -from .common_descriptors import CommonRequestDescriptorsMixin -from .common_descriptors import CommonResponseDescriptorsMixin -from .etag import ETagRequestMixin -from .etag import ETagResponseMixin -from .request import PlainRequest from .request import Request as Request -from .request import StreamOnlyMixin from .response import Response as Response from .response import ResponseStream -from .response import ResponseStreamMixin -from .user_agent import UserAgentMixin diff --git a/src/werkzeug/wrappers/accept.py b/src/werkzeug/wrappers/accept.py deleted file mode 100644 index 9605e637d..000000000 --- a/src/werkzeug/wrappers/accept.py +++ /dev/null @@ -1,14 +0,0 @@ -import typing as t -import warnings - - -class AcceptMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'AcceptMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/auth.py b/src/werkzeug/wrappers/auth.py deleted file mode 100644 index da31b7cf7..000000000 --- a/src/werkzeug/wrappers/auth.py +++ /dev/null @@ -1,26 +0,0 @@ -import typing as t -import warnings - - -class AuthorizationMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'AuthorizationMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore - - -class WWWAuthenticateMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'WWWAuthenticateMixin' is deprecated and will be removed" - " in Werkzeug 2.1. 'Response' now includes the" - " functionality directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/base_request.py b/src/werkzeug/wrappers/base_request.py deleted file mode 100644 index 451989fd7..000000000 --- a/src/werkzeug/wrappers/base_request.py +++ /dev/null @@ -1,36 +0,0 @@ -import typing as t -import warnings - -from .request import Request - - -class _FakeSubclassCheck(type): - def __subclasscheck__(cls, subclass: t.Type) -> bool: - warnings.warn( - "'BaseRequest' is deprecated and will be removed in" - " Werkzeug 2.1. Use 'issubclass(cls, Request)' instead.", - DeprecationWarning, - stacklevel=2, - ) - return issubclass(subclass, Request) - - def __instancecheck__(cls, instance: t.Any) -> bool: - warnings.warn( - "'BaseRequest' is deprecated and will be removed in" - " Werkzeug 2.1. Use 'isinstance(obj, Request)' instead.", - DeprecationWarning, - stacklevel=2, - ) - return isinstance(instance, Request) - - -class BaseRequest(Request, metaclass=_FakeSubclassCheck): - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'BaseRequest' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) diff --git a/src/werkzeug/wrappers/base_response.py b/src/werkzeug/wrappers/base_response.py deleted file mode 100644 index 3e0dc6766..000000000 --- a/src/werkzeug/wrappers/base_response.py +++ /dev/null @@ -1,36 +0,0 @@ -import typing as t -import warnings - -from .response import Response - - -class _FakeSubclassCheck(type): - def __subclasscheck__(cls, subclass: t.Type) -> bool: - warnings.warn( - "'BaseResponse' is deprecated and will be removed in" - " Werkzeug 2.1. Use 'issubclass(cls, Response)' instead.", - DeprecationWarning, - stacklevel=2, - ) - return issubclass(subclass, Response) - - def __instancecheck__(cls, instance: t.Any) -> bool: - warnings.warn( - "'BaseResponse' is deprecated and will be removed in" - " Werkzeug 2.1. Use 'isinstance(obj, Response)' instead.", - DeprecationWarning, - stacklevel=2, - ) - return isinstance(instance, Response) - - -class BaseResponse(Response, metaclass=_FakeSubclassCheck): - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'BaseResponse' is deprecated and will be removed in" - " Werkzeug 2.1. 'Response' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) diff --git a/src/werkzeug/wrappers/common_descriptors.py b/src/werkzeug/wrappers/common_descriptors.py deleted file mode 100644 index db87ea5fa..000000000 --- a/src/werkzeug/wrappers/common_descriptors.py +++ /dev/null @@ -1,26 +0,0 @@ -import typing as t -import warnings - - -class CommonRequestDescriptorsMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'CommonRequestDescriptorsMixin' is deprecated and will be" - " removed in Werkzeug 2.1. 'Request' now includes the" - " functionality directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore - - -class CommonResponseDescriptorsMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'CommonResponseDescriptorsMixin' is deprecated and will be" - " removed in Werkzeug 2.1. 'Response' now includes the" - " functionality directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/cors.py b/src/werkzeug/wrappers/cors.py deleted file mode 100644 index 89cf83ef8..000000000 --- a/src/werkzeug/wrappers/cors.py +++ /dev/null @@ -1,26 +0,0 @@ -import typing as t -import warnings - - -class CORSRequestMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'CORSRequestMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore - - -class CORSResponseMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'CORSResponseMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Response' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/etag.py b/src/werkzeug/wrappers/etag.py deleted file mode 100644 index 2e9015a58..000000000 --- a/src/werkzeug/wrappers/etag.py +++ /dev/null @@ -1,26 +0,0 @@ -import typing as t -import warnings - - -class ETagRequestMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'ETagRequestMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore - - -class ETagResponseMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'ETagResponseMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Response' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/json.py b/src/werkzeug/wrappers/json.py deleted file mode 100644 index ab6ed7ba9..000000000 --- a/src/werkzeug/wrappers/json.py +++ /dev/null @@ -1,13 +0,0 @@ -import typing as t -import warnings - - -class JSONMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'JSONMixin' is deprecated and will be removed in Werkzeug" - " 2.1. 'Request' now includes the functionality directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/request.py b/src/werkzeug/wrappers/request.py index 700cda04c..5ccfb0c1a 100644 --- a/src/werkzeug/wrappers/request.py +++ b/src/werkzeug/wrappers/request.py @@ -610,51 +610,3 @@ def on_json_loading_failed(self, e: ValueError) -> t.Any: :exc:`~werkzeug.exceptions.BadRequest`. """ raise BadRequest(f"Failed to decode JSON object: {e}") - - -class StreamOnlyMixin: - """Mixin to create a ``Request`` that disables the ``data``, - ``form``, and ``files`` properties. Only ``stream`` is available. - - .. deprecated:: 2.0 - Will be removed in Werkzeug 2.1. Create the request with - ``shallow=True`` instead. - - .. versionadded:: 0.9 - """ - - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'StreamOnlyMixin' is deprecated and will be removed in" - " Werkzeug 2.1. Create the request with 'shallow=True'" - " instead.", - DeprecationWarning, - stacklevel=2, - ) - kwargs["shallow"] = True - super().__init__(*args, **kwargs) # type: ignore - - -class PlainRequest(StreamOnlyMixin, Request): - """A request object without ``data``, ``form``, and ``files``. - - .. deprecated:: 2.0 - Will be removed in Werkzeug 2.1. Create the request with - ``shallow=True`` instead. - - .. versionadded:: 0.9 - """ - - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'PlainRequest' is deprecated and will be removed in" - " Werkzeug 2.1. Create the request with 'shallow=True'" - " instead.", - DeprecationWarning, - stacklevel=2, - ) - - # Don't show the DeprecationWarning for StreamOnlyMixin. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - super().__init__(*args, **kwargs) diff --git a/src/werkzeug/wrappers/response.py b/src/werkzeug/wrappers/response.py index d365c4e09..5602cd61e 100644 --- a/src/werkzeug/wrappers/response.py +++ b/src/werkzeug/wrappers/response.py @@ -834,9 +834,9 @@ def add_etag(self, overwrite: bool = False, weak: bool = False) -> None: class ResponseStream: - """A file descriptor like object used by the :class:`ResponseStreamMixin` to - represent the body of the stream. It directly pushes into the response - iterable of the response object. + """A file descriptor like object used by :meth:`Response.stream` to + represent the body of the stream. It directly pushes into the + response iterable of the response object. """ mode = "wb+" @@ -876,15 +876,3 @@ def tell(self) -> int: @property def encoding(self) -> str: return self.response.charset - - -class ResponseStreamMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'ResponseStreamMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Response' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/src/werkzeug/wrappers/user_agent.py b/src/werkzeug/wrappers/user_agent.py deleted file mode 100644 index 184ffd023..000000000 --- a/src/werkzeug/wrappers/user_agent.py +++ /dev/null @@ -1,14 +0,0 @@ -import typing as t -import warnings - - -class UserAgentMixin: - def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: - warnings.warn( - "'UserAgentMixin' is deprecated and will be removed in" - " Werkzeug 2.1. 'Request' now includes the functionality" - " directly.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(*args, **kwargs) # type: ignore diff --git a/tests/test_wrappers.py b/tests/test_wrappers.py index 913033070..5ed4a56d4 100644 --- a/tests/test_wrappers.py +++ b/tests/test_wrappers.py @@ -29,9 +29,6 @@ from werkzeug.test import Client from werkzeug.test import create_environ from werkzeug.test import run_wsgi_app -from werkzeug.wrappers.cors import CORSRequestMixin -from werkzeug.wrappers.cors import CORSResponseMixin -from werkzeug.wrappers.json import JSONMixin from werkzeug.wsgi import LimitedStream from werkzeug.wsgi import wrap_file @@ -1608,66 +1605,6 @@ def test_cache_disabled(self): request.get_json() -@pytest.mark.parametrize( - "cls", - [ - wrappers.BaseRequest, - wrappers.CommonRequestDescriptorsMixin, - wrappers.AcceptMixin, - wrappers.ETagRequestMixin, - wrappers.UserAgentMixin, - wrappers.AuthorizationMixin, - wrappers.StreamOnlyMixin, - wrappers.PlainRequest, - CORSRequestMixin, - JSONMixin, - ], -) -def test_request_mixins_deprecated(cls): - class CheckRequest(cls, wrappers.Request): - pass - - with pytest.deprecated_call(match=cls.__name__): - CheckRequest({"SERVER_NAME": "example.org", "SERVER_PORT": "80"}) - - -@pytest.mark.parametrize( - "cls", - [ - wrappers.BaseResponse, - wrappers.CommonResponseDescriptorsMixin, - wrappers.ResponseStreamMixin, - wrappers.ETagResponseMixin, - wrappers.WWWAuthenticateMixin, - CORSResponseMixin, - JSONMixin, - ], -) -def test_response_mixins_deprecated(cls): - class CheckResponse(cls, wrappers.Response): - pass - - with pytest.deprecated_call(match=cls.__name__): - CheckResponse() - - -def test_check_base_deprecated(): - with pytest.deprecated_call(match=r"issubclass\(cls, Request\)"): - assert issubclass(wrappers.Request, wrappers.BaseRequest) - - with pytest.deprecated_call(match=r"isinstance\(obj, Request\)"): - assert isinstance( - wrappers.Request({"SERVER_NAME": "example.org", "SERVER_PORT": "80"}), - wrappers.BaseRequest, - ) - - with pytest.deprecated_call(match=r"issubclass\(cls, Response\)"): - assert issubclass(wrappers.Response, wrappers.BaseResponse) - - with pytest.deprecated_call(match=r"isinstance\(obj, Response\)"): - assert isinstance(wrappers.Response(), wrappers.BaseResponse) - - def test_response_freeze_no_etag_deprecated(): with pytest.deprecated_call(match="no_etag"): Response("Hello, World!").freeze(no_etag=True)