Skip to content

Commit 58b0efe

Browse files
committed
feat!: static handler configuration (#3900)
1 parent cf60ebf commit 58b0efe

File tree

78 files changed

+1447
-1258
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1447
-1258
lines changed

docs/release-notes/whats-new-3.rst

+21
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,24 @@ Change the media type of :attr:`~enums.MediaType.MESSAGEPACK` and
204204
newly introduced official ``application/vnd.msgpack``.
205205

206206
https://www.iana.org/assignments/media-types/application/vnd.msgpack
207+
208+
209+
Deprecated ``resolve_`` methods on route handlers
210+
-------------------------------------------------
211+
212+
All ``resolve_`` methods on the route handlers
213+
(e.g. :meth:`~litestar.handlers.HTTPRouteHandler.resolve_response_headers`) have been
214+
deprecated and will be removed in ``4.0``. The attributes can now safely be accessed
215+
directly (e.g. `HTTPRouteHandlers.response_headers`).
216+
217+
218+
Moved routing related methods from ``Router`` to ``Litestar``
219+
-------------------------------------------------------------
220+
221+
:class:`~litestar.router.Router` now only holds route handlers and configuration, while
222+
the actual routing is done in :class:`~litestar.app.Litestar`. With this, several
223+
methods and properties have been moved from ``Router`` to ``Litestar``:
224+
225+
- ``route_handler_method_map``
226+
- ``get_route_handler_map``
227+
- ``routes``

litestar/_asgi/asgi_router.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class ASGIRouter:
5252
"_plain_routes",
5353
"_registered_routes",
5454
"_static_routes",
55+
"_trie_initialized",
5556
"app",
5657
"root_route_map_node",
5758
"route_handler_index",
@@ -69,6 +70,7 @@ def __init__(self, app: Litestar) -> None:
6970
self._mount_routes: dict[str, RouteTrieNode] = {}
7071
self._plain_routes: set[str] = set()
7172
self._registered_routes: set[HTTPRoute | WebSocketRoute | ASGIRoute] = set()
73+
self._trie_initialized = False
7274
self.app = app
7375
self.root_route_map_node: RouteTrieNode = create_node()
7476
self.route_handler_index: dict[str, RouteHandlerType] = {}
@@ -94,7 +96,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
9496
ScopeState.from_scope(scope).exception_handlers = self._app_exception_handlers
9597
raise
9698
else:
97-
ScopeState.from_scope(scope).exception_handlers = route_handler.resolve_exception_handlers()
99+
ScopeState.from_scope(scope).exception_handlers = route_handler.exception_handlers
98100
scope["route_handler"] = route_handler
99101
scope["path_template"] = path_template
100102
await asgi_app(scope, receive, send)
@@ -145,8 +147,16 @@ def construct_routing_trie(self) -> None:
145147
146148
This map is used in the asgi router to route requests.
147149
"""
148-
new_routes = [route for route in self.app.routes if route not in self._registered_routes]
149-
for route in new_routes:
150+
if self._trie_initialized: # pragma: no cover
151+
self._mount_paths_regex = None
152+
self._mount_routes = {}
153+
self._plain_routes = set()
154+
self._registered_routes = set()
155+
self.root_route_map_node = create_node()
156+
self.route_handler_index = {}
157+
self.route_mapping = defaultdict(list)
158+
159+
for route in self.app.routes:
150160
add_route_to_trie(
151161
app=self.app,
152162
mount_routes=self._mount_routes,

litestar/_asgi/routing_trie/mapping.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def build_route_middleware_stack(
189189
from litestar.routes import HTTPRoute
190190

191191
asgi_handler: ASGIApp = route.handle # type: ignore[assignment]
192-
handler_middleware = route_handler.resolve_middleware()
192+
handler_middleware = route_handler.middleware
193193
has_cached_route = isinstance(route, HTTPRoute) and any(r.cache for r in route.route_handlers)
194194
has_middleware = (
195195
app.csrf_config or app.compression_config or has_cached_route or app.allowed_hosts or handler_middleware

litestar/_kwargs/extractors.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ async def _extract_multipart(
343343
stream=connection.stream(),
344344
boundary=connection.content_type[-1].get("boundary", "").encode(),
345345
multipart_form_part_limit=multipart_form_part_limit,
346-
type_decoders=connection.route_handler.resolve_type_decoders(),
346+
type_decoders=connection.route_handler.type_decoders,
347347
)
348348
else:
349349
form_values = scope_state.form

litestar/_layers/utils.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@
1212
from litestar.types.composite_types import ResponseCookies, ResponseHeaders
1313

1414

15-
def narrow_response_headers(headers: ResponseHeaders | None) -> Sequence[ResponseHeader] | None:
16-
"""Given :class:`.types.ResponseHeaders` as a :class:`typing.Mapping`, create a list of
15+
def narrow_response_headers(headers: ResponseHeaders | None) -> Sequence[ResponseHeader]:
16+
"""Given :class:`.types.ResponseHeaders` as a :class:`typing.Mapping`, create a tuple of
1717
:class:`.datastructures.response_header.ResponseHeader` from it, otherwise return ``headers`` unchanged
1818
"""
1919
return (
2020
tuple(ResponseHeader(name=name, value=value) for name, value in headers.items())
2121
if isinstance(headers, Mapping)
2222
else headers
23-
)
23+
) or ()
2424

2525

26-
def narrow_response_cookies(cookies: ResponseCookies | None) -> Sequence[Cookie] | None:
26+
def narrow_response_cookies(cookies: ResponseCookies | None) -> Sequence[Cookie]:
2727
"""Given :class:`.types.ResponseCookies` as a :class:`typing.Mapping`, create a list of
2828
:class:`.datastructures.cookie.Cookie` from it, otherwise return ``cookies`` unchanged
2929
"""
3030
return (
3131
tuple(Cookie(key=key, value=value) for key, value in cookies.items())
3232
if isinstance(cookies, Mapping)
3333
else cookies
34-
)
34+
) or ()

litestar/_openapi/datastructures.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,6 @@ def add_operation_id(self, operation_id: str) -> None:
243243
if operation_id in self.operation_ids:
244244
raise ImproperlyConfiguredException(
245245
"operation_ids must be unique, "
246-
f"please ensure the value of 'operation_id' is either not set or unique for {operation_id}"
246+
f"please ensure the value of 'operation_id' is either not set or unique for {operation_id!r}"
247247
)
248248
self.operation_ids.add(operation_id)

litestar/_openapi/parameters.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ def __init__(
9494
self.schema_creator = SchemaCreator.from_openapi_context(self.context, prefer_alias=True)
9595
self.route_handler = route_handler
9696
self.parameters = ParameterCollection(route_handler)
97-
self.dependency_providers = route_handler.resolve_dependencies()
98-
self.layered_parameters = route_handler.resolve_layered_parameters()
97+
self.dependency_providers = route_handler.dependencies
98+
self.layered_parameters = route_handler.parameter_field_definitions
9999
self.path_parameters = path_parameters
100100

101101
def create_parameter(self, field_definition: FieldDefinition, parameter_name: str) -> Parameter:

litestar/_openapi/path_item.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def create_path_item(self) -> PathItem:
3636
A PathItem instance.
3737
"""
3838
for http_method, route_handler in self.route.route_handler_map.items():
39-
if not route_handler.resolve_include_in_schema():
39+
if not route_handler.include_in_schema:
4040
continue
4141

4242
operation = self.create_operation_for_handler_method(route_handler, HttpMethod(http_method))
@@ -64,7 +64,7 @@ def create_operation_for_handler_method(
6464
request_body = None
6565
if data_field := signature_fields.get("data"):
6666
request_body = create_request_body(
67-
self.context, route_handler.handler_id, route_handler.resolve_data_dto(), data_field
67+
self.context, route_handler.handler_id, route_handler.data_dto, data_field
6868
)
6969

7070
raises_validation_error = bool(data_field or self._path_item.parameters or parameters)
@@ -74,14 +74,14 @@ def create_operation_for_handler_method(
7474

7575
return route_handler.operation_class(
7676
operation_id=operation_id,
77-
tags=route_handler.resolve_tags() or None,
77+
tags=sorted(route_handler.tags) if route_handler.tags else None,
7878
summary=route_handler.summary or SEPARATORS_CLEANUP_PATTERN.sub("", route_handler.handler_name.title()),
7979
description=self.create_description_for_handler(route_handler),
8080
deprecated=route_handler.deprecated,
8181
responses=responses,
8282
request_body=request_body,
8383
parameters=parameters or None, # type: ignore[arg-type]
84-
security=route_handler.resolve_security() or None,
84+
security=list(route_handler.security) if route_handler.security else None,
8585
)
8686

8787
def create_operation_id(self, route_handler: HTTPRouteHandler, http_method: HttpMethod) -> str:

litestar/_openapi/plugin.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def receive_route(self, route: BaseRoute) -> None:
198198
if not isinstance(route, HTTPRoute):
199199
return
200200

201-
if any(route_handler.resolve_include_in_schema() for route_handler in route.route_handler_map.values()):
201+
if any(route_handler.include_in_schema for route_handler in route.route_handler_map.values()):
202202
# Force recompute the schema if a new route is added
203203
self._openapi = None
204204
self.included_routes[route.path] = route

litestar/_openapi/responses.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def create_success_response(self) -> OpenAPIResponse:
127127
else:
128128
media_type = self.route_handler.media_type
129129

130-
if dto := self.route_handler.resolve_return_dto():
130+
if dto := self.route_handler.return_dto:
131131
result = dto.create_openapi_schema(
132132
field_definition=self.field_definition,
133133
handler_id=self.route_handler.handler_id,
@@ -209,7 +209,7 @@ def set_success_response_headers(self, response: OpenAPIResponse) -> None:
209209
else:
210210
schema_creator = SchemaCreator.from_openapi_context(self.context, generate_examples=False)
211211

212-
for response_header in self.route_handler.resolve_response_headers():
212+
for response_header in self.route_handler.response_headers:
213213
header = OpenAPIHeader()
214214
for attribute_name, attribute_value in (
215215
(k, v) for k, v in asdict(response_header).items() if v is not None
@@ -223,7 +223,7 @@ def set_success_response_headers(self, response: OpenAPIResponse) -> None:
223223

224224
response.headers[response_header.name] = header
225225

226-
if cookies := self.route_handler.resolve_response_cookies():
226+
if cookies := self.route_handler.response_cookies:
227227
response.headers["Set-Cookie"] = OpenAPIHeader(
228228
schema=Schema(
229229
all_of=[create_cookie_schema(cookie=cookie) for cookie in sorted(cookies, key=attrgetter("key"))]

0 commit comments

Comments
 (0)