From 4d95e8c3498c1618a2fcdb75d47d446ace2d3966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janek=20Nouvertn=C3=A9?= Date: Mon, 15 Apr 2024 09:04:39 +0200 Subject: [PATCH] refactor!: Remove deprecated `app` param of `Response.to_asgi_response` (#3393) * Remove 'app' parameter from `.to_asgi_response` --- docs/release-notes/whats-new-3.rst | 8 ++++ litestar/handlers/http_handlers/_utils.py | 6 +-- litestar/handlers/http_handlers/base.py | 7 ++-- litestar/response/base.py | 12 ------ litestar/response/file.py | 11 ------ litestar/response/redirect.py | 12 ------ litestar/response/streaming.py | 12 ------ litestar/response/template.py | 12 ------ litestar/routes/http.py | 2 +- .../test_response_to_asgi_response.py | 37 +++++-------------- 10 files changed, 23 insertions(+), 96 deletions(-) diff --git a/docs/release-notes/whats-new-3.rst b/docs/release-notes/whats-new-3.rst index dd0c85a16e..54b6270f4b 100644 --- a/docs/release-notes/whats-new-3.rst +++ b/docs/release-notes/whats-new-3.rst @@ -105,3 +105,11 @@ the root path (``/``), in which case that plugin will be used. For those previously using the ``root_schema_site`` attribute, the migration involves ensuring that the UI intended to be served at the ``/schema`` endpoint is the first plugin listed in the :attr:`OpenAPIConfig.render_plugins`. + + +Deprecated ``app`` parameter for ``Response.to_asgi_response`` has been removed +------------------------------------------------------------------------------- + +The parameter ``app`` for :meth:`~response.Response.to_asgi_response` has been removed. +If you need access to the app instance inside a custom ``to_asgi_response`` method, +replace the usages of ``app`` with ``request.app``. diff --git a/litestar/handlers/http_handlers/_utils.py b/litestar/handlers/http_handlers/_utils.py index ec95145ab8..86c59556b2 100644 --- a/litestar/handlers/http_handlers/_utils.py +++ b/litestar/handlers/http_handlers/_utils.py @@ -11,7 +11,6 @@ from litestar.types.builtin_types import NoneType if TYPE_CHECKING: - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.datastructures import Cookie, ResponseHeader @@ -59,7 +58,6 @@ def create_data_handler( async def handler( data: Any, request: Request[Any, Any, Any], - app: Litestar, **kwargs: Any, ) -> ASGIApp: if isawaitable(data): @@ -76,7 +74,7 @@ async def handler( if after_request: response = await after_request(response) # type: ignore[arg-type,misc] - return response.to_asgi_response(app=None, request=request, headers=normalize_headers(headers), cookies=cookies) # pyright: ignore + return response.to_asgi_response(request=request, headers=normalize_headers(headers), cookies=cookies) # pyright: ignore return handler @@ -144,13 +142,11 @@ def create_response_handler( async def handler( data: Response, - app: Litestar, request: Request, **kwargs: Any, # kwargs is for return dto ) -> ASGIApp: response = await after_request(data) if after_request else data # type:ignore[arg-type,misc] return response.to_asgi_response( # type: ignore[no-any-return] - app=None, background=background, cookies=cookie_list, headers=normalized_headers, diff --git a/litestar/handlers/http_handlers/base.py b/litestar/handlers/http_handlers/base.py index 2d5d8322ff..ff30e3a778 100644 --- a/litestar/handlers/http_handlers/base.py +++ b/litestar/handlers/http_handlers/base.py @@ -472,7 +472,7 @@ def resolve_tags(self) -> list[str]: return self._resolved_tags - def get_response_handler(self, is_response_type_data: bool = False) -> Callable[[Any], Awaitable[ASGIApp]]: + def get_response_handler(self, is_response_type_data: bool = False) -> Callable[..., Awaitable[ASGIApp]]: """Resolve the response_handler function for the route handler. This method is memoized so the computation occurs only once. @@ -538,11 +538,10 @@ def get_response_handler(self, is_response_type_data: bool = False) -> Callable[ else self._response_handler_mapping["default_handler"], ) - async def to_response(self, app: Litestar, data: Any, request: Request) -> ASGIApp: + async def to_response(self, data: Any, request: Request) -> ASGIApp: """Return a :class:`Response <.response.Response>` from the handler by resolving and calling it. Args: - app: The :class:`Litestar ` app instance data: Either an instance of a :class:`Response <.response.Response>`, a Response instance or an arbitrary value. request: A :class:`Request <.connection.Request>` instance @@ -554,7 +553,7 @@ async def to_response(self, app: Litestar, data: Any, request: Request) -> ASGIA data = return_dto_type(request).data_to_encodable_type(data) response_handler = self.get_response_handler(is_response_type_data=isinstance(data, Response)) - return await response_handler(app=app, data=data, request=request) # type: ignore[call-arg] + return await response_handler(data=data, request=request) def on_registration(self, app: Litestar) -> None: super().on_registration(app) diff --git a/litestar/response/base.py b/litestar/response/base.py index 67eec09159..9cc0ae3122 100644 --- a/litestar/response/base.py +++ b/litestar/response/base.py @@ -17,7 +17,6 @@ if TYPE_CHECKING: from typing import Optional - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.types import ( @@ -397,7 +396,6 @@ def render(self, content: Any, media_type: str, enc_hook: Serializer = default_s def to_asgi_response( self, - app: Litestar | None, request: Request, *, background: BackgroundTask | BackgroundTasks | None = None, @@ -412,7 +410,6 @@ def to_asgi_response( """Create an ASGIResponse from a Response instance. Args: - app: The :class:`Litestar <.app.Litestar>` application instance. background: Background task(s) to be executed after the response is sent. cookies: A list of cookies to be set on the response. encoded_headers: A list of already encoded headers. @@ -427,15 +424,6 @@ def to_asgi_response( An ASGIResponse instance. """ - if app is not None: - warn_deprecation( - version="2.1", - deprecated_name="app", - kind="parameter", - removal_in="3.0.0", - alternative="request.app", - ) - headers = {**headers, **self.headers} if headers is not None else self.headers cookies = self.cookies if cookies is None else itertools.chain(self.cookies, cookies) diff --git a/litestar/response/file.py b/litestar/response/file.py index 1fc6f8632d..9a99482d4c 100644 --- a/litestar/response/file.py +++ b/litestar/response/file.py @@ -13,7 +13,6 @@ from litestar.file_system import BaseLocalFileSystem, FileSystemAdapter from litestar.response.base import Response from litestar.response.streaming import ASGIStreamingResponse -from litestar.utils.deprecation import warn_deprecation from litestar.utils.helpers import get_enum_string_value if TYPE_CHECKING: @@ -22,7 +21,6 @@ from anyio import Path - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.datastructures.cookie import Cookie @@ -319,7 +317,6 @@ def __init__( def to_asgi_response( self, - app: Litestar | None, request: Request, *, background: BackgroundTask | BackgroundTasks | None = None, @@ -348,14 +345,6 @@ def to_asgi_response( Returns: A low-level ASGI file response. """ - if app is not None: - warn_deprecation( - version="2.1", - deprecated_name="app", - kind="parameter", - removal_in="3.0.0", - alternative="request.app", - ) headers = {**headers, **self.headers} if headers is not None else self.headers cookies = self.cookies if cookies is None else itertools.chain(self.cookies, cookies) diff --git a/litestar/response/redirect.py b/litestar/response/redirect.py index 6a070769e9..bd60bb16a8 100644 --- a/litestar/response/redirect.py +++ b/litestar/response/redirect.py @@ -9,11 +9,9 @@ from litestar.response.base import ASGIResponse, Response from litestar.status_codes import HTTP_302_FOUND from litestar.utils import url_quote -from litestar.utils.deprecation import warn_deprecation from litestar.utils.helpers import get_enum_string_value if TYPE_CHECKING: - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.datastructures import Cookie @@ -129,7 +127,6 @@ def __init__( def to_asgi_response( self, - app: Litestar | None, request: Request, *, background: BackgroundTask | BackgroundTasks | None = None, @@ -145,15 +142,6 @@ def to_asgi_response( cookies = self.cookies if cookies is None else itertools.chain(self.cookies, cookies) media_type = get_enum_string_value(self.media_type or media_type or MediaType.TEXT) - if app is not None: - warn_deprecation( - version="2.1", - deprecated_name="app", - kind="parameter", - removal_in="3.0.0", - alternative="request.app", - ) - return ASGIRedirectResponse( path=self.url, background=self.background or background, diff --git a/litestar/response/streaming.py b/litestar/response/streaming.py index fc76522416..5643d8e3ca 100644 --- a/litestar/response/streaming.py +++ b/litestar/response/streaming.py @@ -9,12 +9,10 @@ from litestar.enums import MediaType from litestar.response.base import ASGIResponse, Response from litestar.types.helper_types import StreamType -from litestar.utils.deprecation import warn_deprecation from litestar.utils.helpers import get_enum_string_value from litestar.utils.sync import AsyncIteratorWrapper if TYPE_CHECKING: - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.datastructures.cookie import Cookie @@ -177,7 +175,6 @@ def __init__( def to_asgi_response( self, - app: Litestar | None, request: Request, *, background: BackgroundTask | BackgroundTasks | None = None, @@ -192,7 +189,6 @@ def to_asgi_response( """Create an ASGIStreamingResponse from a StremaingResponse instance. Args: - app: The :class:`Litestar <.app.Litestar>` application instance. background: Background task(s) to be executed after the response is sent. cookies: A list of cookies to be set on the response. encoded_headers: A list of already encoded headers. @@ -206,14 +202,6 @@ def to_asgi_response( Returns: An ASGIStreamingResponse instance. """ - if app is not None: - warn_deprecation( - version="2.1", - deprecated_name="app", - kind="parameter", - removal_in="3.0.0", - alternative="request.app", - ) headers = {**headers, **self.headers} if headers is not None else self.headers cookies = self.cookies if cookies is None else itertools.chain(self.cookies, cookies) diff --git a/litestar/response/template.py b/litestar/response/template.py index 6499aaec01..660a511bc2 100644 --- a/litestar/response/template.py +++ b/litestar/response/template.py @@ -9,12 +9,10 @@ from litestar.exceptions import ImproperlyConfiguredException from litestar.response.base import ASGIResponse, Response from litestar.status_codes import HTTP_200_OK -from litestar.utils.deprecation import warn_deprecation from litestar.utils.empty import value_or_default from litestar.utils.scope.state import ScopeState if TYPE_CHECKING: - from litestar.app import Litestar from litestar.background_tasks import BackgroundTask, BackgroundTasks from litestar.connection import Request from litestar.datastructures import Cookie @@ -99,7 +97,6 @@ def create_template_context(self, request: Request) -> dict[str, Any]: def to_asgi_response( self, - app: Litestar | None, request: Request, *, background: BackgroundTask | BackgroundTasks | None = None, @@ -111,15 +108,6 @@ def to_asgi_response( status_code: int | None = None, type_encoders: TypeEncodersMap | None = None, ) -> ASGIResponse: - if app is not None: - warn_deprecation( - version="2.1", - deprecated_name="app", - kind="parameter", - removal_in="3.0.0", - alternative="request.app", - ) - if not (template_engine := request.app.template_engine): raise ImproperlyConfiguredException("Template engine is not configured") diff --git a/litestar/routes/http.py b/litestar/routes/http.py index 95595edc1a..acd8048cf8 100644 --- a/litestar/routes/http.py +++ b/litestar/routes/http.py @@ -153,7 +153,7 @@ async def _call_handler_function( route_handler=route_handler, parameter_model=parameter_model, request=request ) - response: ASGIApp = await route_handler.to_response(app=scope["app"], data=response_data, request=request) + response: ASGIApp = await route_handler.to_response(data=response_data, request=request) if cleanup_group: await cleanup_group.cleanup() diff --git a/tests/unit/test_response/test_response_to_asgi_response.py b/tests/unit/test_response/test_response_to_asgi_response.py index 3caf6136a5..b3bf33e2f6 100644 --- a/tests/unit/test_response/test_response_to_asgi_response.py +++ b/tests/unit/test_response/test_response_to_asgi_response.py @@ -89,8 +89,7 @@ async def handler(data: DataclassPerson) -> DataclassPerson: response = await handler.to_response( data=handler.fn(data=person_instance), - app=Litestar(route_handlers=[handler]), - request=RequestFactory().get(route_handler=handler), + request=RequestFactory(app=Litestar(route_handlers=[handler])).get(route_handler=handler), ) assert loads(response.body) == msgspec.to_builtins(person_instance) # type: ignore[attr-defined] @@ -103,9 +102,7 @@ def handler() -> Response: with create_test_client(handler) as client: http_route: HTTPRoute = client.app.routes[0] route_handler = http_route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) assert isinstance(response, ASGIResponse) @@ -128,9 +125,7 @@ def handler() -> StarletteResponse: with create_test_client(handler) as client: http_route: HTTPRoute = client.app.routes[0] route_handler = http_route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) assert isinstance(response, StarletteResponse) assert response is expected_response # type: ignore[unreachable] @@ -155,9 +150,7 @@ def handler() -> Redirect: with create_test_client(handler) as client: route: HTTPRoute = client.app.routes[0] route_handler = route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) encoded_headers = response.encode_headers() # type: ignore[attr-defined] assert isinstance(response, ASGIResponse) @@ -209,9 +202,7 @@ def handler() -> File: with create_test_client(handler) as client: route: HTTPRoute = client.app.routes[0] route_handler = route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) assert isinstance(response, ASGIFileResponse) assert response.file_info if iscoroutine(response.file_info): @@ -267,11 +258,9 @@ def handler() -> Stream: route_handler = route.route_handlers[0] if should_raise: with pytest.raises(TypeError): - await route_handler.to_response(data=route_handler.fn(), app=client.app, request=RequestFactory().get()) + await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) else: - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) assert isinstance(response, ASGIStreamingResponse) encoded_headers = response.encode_headers() assert (b"local-header", b"123") in encoded_headers @@ -315,9 +304,7 @@ def handler() -> Template: ) as client: route: HTTPRoute = client.app.routes[0] route_handler = route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory(app=app).get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory(app=app).get()) assert isinstance(response, ASGIResponse) encoded_headers = response.encode_headers() @@ -366,9 +353,7 @@ def handler() -> ServerSentEvent: with create_test_client(handler) as client: route: HTTPRoute = client.app.routes[0] route_handler = route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) encoded_headers = response.encode_headers() # type: ignore[attr-defined] assert isinstance(response, ASGIStreamingResponse) @@ -411,9 +396,7 @@ def handler() -> ServerSentEvent: with create_test_client(handler) as client: route: HTTPRoute = client.app.routes[0] route_handler = route.route_handlers[0] - response = await route_handler.to_response( - data=route_handler.fn(), app=client.app, request=RequestFactory().get() - ) + response = await route_handler.to_response(data=route_handler.fn(), request=RequestFactory().get()) assert isinstance(response, ASGIStreamingResponse) async for value in response.iterator: events.append(cast("bytes", value))