Skip to content

Commit

Permalink
feat(DTO): Enable codegen backend by default (#3215)
Browse files Browse the repository at this point in the history
* Enable DTO codegen backend by default
* Update docs
  • Loading branch information
provinzkraut authored and JacobCoffee committed Mar 22, 2024
1 parent dceb050 commit 7f9a81a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 21 deletions.
9 changes: 5 additions & 4 deletions docs/usage/dto/0-basic-use.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ DTOs can similarly be defined on :class:`Routers <litestar.router.Router>` and
Improving performance with the codegen backend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. admonition:: Experimental feature
:class: danger
.. note::

This is an experimental feature and should be approached with caution. It may
behave unexpectedly, contain bugs and may disappear again in a future version.
This feature was introduced in ``2.2.0`` and hidden behind the ``DTO_CODEGEN``
feature flag. As of ``2.8.0`` it is considered stable and enabled by default. It can
still be disabled selectively by using the
``DTOConfig(experimental_codegen_backend=True)`` override.


The DTO backend is the part that does the heavy lifting for all the DTO features. It
Expand Down
15 changes: 13 additions & 2 deletions litestar/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import inspect
import logging
import os
import warnings
from contextlib import (
AbstractAsyncContextManager,
AsyncExitStack,
Expand All @@ -20,12 +21,13 @@
from litestar._openapi.plugin import OpenAPIPlugin
from litestar._openapi.schema_generation import openapi_schema_plugins
from litestar.config.allowed_hosts import AllowedHostsConfig
from litestar.config.app import AppConfig
from litestar.config.app import AppConfig, ExperimentalFeatures
from litestar.config.response_cache import ResponseCacheConfig
from litestar.connection import Request, WebSocket
from litestar.datastructures.state import State
from litestar.events.emitter import BaseEventEmitterBackend, SimpleEventEmitter
from litestar.exceptions import (
LitestarWarning,
MissingDependencyException,
NoRouteMatchFoundException,
)
Expand Down Expand Up @@ -55,7 +57,6 @@
if TYPE_CHECKING:
from typing_extensions import Self

from litestar.config.app import ExperimentalFeatures
from litestar.config.compression import CompressionConfig
from litestar.config.cors import CORSConfig
from litestar.config.csrf import CSRFConfig
Expand Down Expand Up @@ -396,6 +397,16 @@ def __init__(
self._lifespan_managers.append(store)
self._server_lifespan_managers = [p.server_lifespan for p in config.plugins or [] if isinstance(p, CLIPlugin)]
self.experimental_features = frozenset(config.experimental_features or [])
if ExperimentalFeatures.DTO_CODEGEN in self.experimental_features:
warnings.warn(
"Use of redundant experimental feature flag DTO_CODEGEN. "
"DTO codegen backend is enabled by default since Litestar 2.8. The "
"DTO_CODEGEN feature flag can be safely removed from the configuration "
"and will be removed in version 3.0.",
category=LitestarWarning,
stacklevel=2,
)

self.get_logger: GetLogger = get_logger_placeholder
self.logger: Logger | None = None
self.routes: list[HTTPRoute | ASGIRoute | WebSocketRoute] = []
Expand Down
4 changes: 1 addition & 3 deletions litestar/dto/base_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,7 @@ def create_for_field_definition(
)

if backend_cls is None:
backend_cls = DTOCodegenBackend if cls.config.experimental_codegen_backend else DTOBackend
elif backend_cls is DTOCodegenBackend and cls.config.experimental_codegen_backend is False:
backend_cls = DTOBackend
backend_cls = DTOCodegenBackend if cls.config.experimental_codegen_backend is not False else DTOBackend

backend_context[key] = backend_cls( # type: ignore[literal-required]
dto_factory=cls,
Expand Down
11 changes: 0 additions & 11 deletions litestar/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from typing import TYPE_CHECKING, Any, Callable, Mapping, Sequence, cast

from litestar._signature import SignatureModel
from litestar.config.app import ExperimentalFeatures
from litestar.di import Provide
from litestar.dto import DTOData
from litestar.exceptions import ImproperlyConfiguredException
Expand All @@ -32,7 +31,6 @@
from litestar.connection import ASGIConnection
from litestar.controller import Controller
from litestar.dto import AbstractDTO
from litestar.dto._backend import DTOBackend
from litestar.params import ParameterKwarg
from litestar.router import Router
from litestar.types import AnyCallable, AsyncAnyCallable, ExceptionHandler
Expand Down Expand Up @@ -442,13 +440,6 @@ def resolve_signature_namespace(self) -> dict[str, Any]:
self._resolved_signature_namespace = ns
return cast("dict[str, Any]", self._resolved_signature_namespace)

def _get_dto_backend_cls(self) -> type[DTOBackend] | None:
if ExperimentalFeatures.DTO_CODEGEN in self.app.experimental_features:
from litestar.dto._codegen_backend import DTOCodegenBackend

return DTOCodegenBackend
return None

def resolve_data_dto(self) -> type[AbstractDTO] | None:
"""Resolve the data_dto by starting from the route handler and moving up.
If a handler is found it is returned, otherwise None is set.
Expand Down Expand Up @@ -478,7 +469,6 @@ def resolve_data_dto(self) -> type[AbstractDTO] | None:
data_dto.create_for_field_definition(
field_definition=self.parsed_data_field,
handler_id=self.handler_id,
backend_cls=self._get_dto_backend_cls(),
)

self._resolved_data_dto = data_dto
Expand Down Expand Up @@ -512,7 +502,6 @@ def resolve_return_dto(self) -> type[AbstractDTO] | None:
return_dto.create_for_field_definition(
field_definition=self.parsed_return_field,
handler_id=self.handler_id,
backend_cls=self._get_dto_backend_cls(),
)
self._resolved_return_dto = return_dto
else:
Expand Down
7 changes: 6 additions & 1 deletion tests/unit/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pytest import MonkeyPatch

from litestar import Litestar, MediaType, Request, Response, get
from litestar.config.app import AppConfig
from litestar.config.app import AppConfig, ExperimentalFeatures
from litestar.config.response_cache import ResponseCacheConfig
from litestar.contrib.sqlalchemy.plugins import SQLAlchemySerializationPlugin
from litestar.datastructures import MutableScopeHeaders, State
Expand Down Expand Up @@ -445,3 +445,8 @@ async def hook_b(app: Litestar) -> None:
assert events[1] == "ctx_1"
assert events[2] == "hook_a"
assert events[3] == "hook_b"


def test_use_dto_codegen_feature_flag_warns() -> None:
with pytest.warns(LitestarWarning, match="Use of redundant experimental feature flag DTO_CODEGEN"):
Litestar(experimental_features=[ExperimentalFeatures.DTO_CODEGEN])
13 changes: 13 additions & 0 deletions tests/unit/test_dto/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,16 @@ def handler(data: Model) -> Model:

backend = handler.resolve_data_dto()._dto_backends[handler.handler_id]["data_backend"] # type: ignore[union-attr]
assert isinstance(backend, DTOBackend)


def test_use_codegen_backend_by_default(ModelDataDTO: type[AbstractDTO]) -> None:
ModelDataDTO.config = DTOConfig()

@post(dto=ModelDataDTO, signature_types=[Model])
def handler(data: Model) -> Model:
return data

Litestar(route_handlers=[handler])

backend = handler.resolve_data_dto()._dto_backends[handler.handler_id]["data_backend"] # type: ignore[union-attr]
assert isinstance(backend, DTOBackend)

0 comments on commit 7f9a81a

Please sign in to comment.