Litestar 2.16.0

9 hours ago 1

2.16.0#

Released: 2025-05-04

Features#

Logging: Selectively disable logging for status codes or exception types#

Add support for disabling stack traces for specific status codes or exception types when in debug mode or running with log_exceptions="always"

Disable tracebacks for ‘404 - Not Found’ exceptions#

from litestar import Litestar from litestar.logging import LoggingConfig app = Litestar( route_handlers=[index, value_error, name_error], logging_config=LoggingConfig( disable_stack_trace={404}, log_exceptions="always", ), )

References: litestar-org/litestar#4081, litestar-org/litestar#4086

Reference route handler in error message for return value / status code mismatch# DTO: Improve inspection and tracebacks for generated functions#

Generated transfer functions now populate linecache to improve tracebacks and support introspection of the generated functions e.g. via inspect.getsource()

Before:

File "<string>", line 18, in func TypeError: <something's wrong>

After:

File "dto_transfer_function_0971e01f653c", line 18, in func TypeError: <something's wrong>

References: litestar-org/litestar#4159

DTO: Add custom attribute accessor callable# OpenAPI: Add custom example ids support# OpenAPI: Allow passing scalar configuration options#

Add an options parameter to ScalarRenderPlugin, that can be used to pass options directly to scalar.

from litestar import Litestar from litestar.openapi.config import OpenAPIConfig from litestar.openapi.plugins import ScalarRenderPlugin scalar_plugin = ScalarRenderPlugin(version="1.19.5", options={"showSidebar": False}) app = Litestar( route_handlers=[hello_world], openapi_config=OpenAPIConfig( title="Litestar Example", description="Example of Litestar with Scalar OpenAPI docs", version="0.0.1", render_plugins=[scalar_plugin], path="/docs", ), )

References: litestar-org/litestar#3951, litestar-org/litestar#4162

Bugfixes#

Typing: remove usage of private _AnnotatedAlias#

Remove deprecated usage of _AnnotatedAlias, which is no longer needed for backwards compatibility.

References: litestar-org/litestar#4126

DI: Ensure generator dependencies always handle error during clean up#

Fix issue where dependency cleanup could be skipped during exception handling, if another exception happened during the cleanup itself.

  • Ensure all dependencies are cleaned up, even if exceptions occur.

  • Group exceptions using ExceptionGroup during cleanup phase.

References: litestar-org/litestar#4148

CLI: Improve error message on ImportError# CLI: Ensure dynamically added commands / groups are always visible# Testing: Ensure subprocess client does not swallow startup failure# OpenAPI: Use prefixItems for fixed-length tuples#

2.15.2#

Released: 2025-04-06

Bugfixes#

Events: Fix error handling for synchronous handlers#

Fix a bug where exceptions weren’t handled correctly on synchronous event handlers, and would result in another exception.

@listener("raise_exception") def raise_exception_if_odd(value) -> None: if value is not None and value % 2 != 0: raise ValueError(f"{value} is odd")

Would raise an AttributeError: 'AsyncCallable' object has no attribute '__name__'. Did you mean: '__ne__'?

References: litestar-org/litestar#4045

Fix wrong order of arguments in FileSystemAdapter passed to open fsspec file system#

The order of arguments of various fsspec implementations varies, causing FileSystemAdapter.open to fail in different ways. This was fixed by always passing arguments as keywords to the file system.

References: litestar-org/litestar#4049

Correctly handle typing_extensions.TypeAliasType on typing-extensions>4.13.0#

2.15.1#

Released: 2025-02-27

Bugfixes#

Warn about using streaming responses with a body#

Issue a warning if the body parameter of a streaming response is used, as setting this has no effect

References: litestar-org/litestar#4033

Fix incorrect deprecation warning issued when subclassing middlewares#

2.15.0#

Released: 2025-02-26

Features#

JWT: Revoked token handler# Allow route_reverse params of type uuid to be passed as str# CLI: Better error message for invalid --app string# DTO: Support @property fields for msgspec and dataclass# Add new ASGIMiddleware# Add SerializationPlugin and InitPlugin to replace their respective protocols# Allow passing a debugger_module to the application#

A new debugger_module parameter has been added to Litestar, which can receive any debugger module that implements a pdb.post_mortem() function with the same signature as the stdlib. This function will be called when an exception occurs and pdb_on_exception is set to True.

References: litestar-org/litestar#3967

Bugfixes#

Prevent accidental scope key overrides by mounted ASGI apps#

When mounting ASGI apps, there’s no guarantee they won’t overwrite some key in the scope that we rely on, e.g. scope["app"], which is what caused litestar-org/litestar#3934.

To prevent this, two thing shave been changed:

  1. We do not store the Litestar instance under the generic app key anymore, but the more specific litestar_app key. In addition the from_scope() method has been added, which can be used to safely access the current app from the scope

  2. A new parameter copy_scope has been added to the ASGI route handler, which, when set to True will copy the scope before calling into the mounted ASGI app, aiming to make things behave more as expected, by giving the called app its own environment without causing any side-effects. Since this change might break some things, It’s been left it with a default of None, which does not copy the scope, but will issue a warning if the mounted app modified it, enabling users to decide how to deal with that situation

References: litestar-org/litestar#3934, litestar-org/litestar#3945

Fix deprecated attrs import#

2.14.0#

Released: 2025-02-12

Features#

Deprecate litestar.contrib.prometheus in favour of litestar.plugins.prometheus#

The module litestar.contrib.prometheus has been moved to litestar.plugins.prometheus. litestar.contrib.prometheus will be deprecated in the next major version

References: litestar-org/litestar#3863

Deprecate litestar.contrib.attrs in favour of litestar.plugins.attrs#

The module litestar.contrib.attrs has been moved to litestar.plugins.attrs. litestar.contrib.attrs will be deprecated in the next major version

References: litestar-org/litestar#3862

Add a streaming multipart parser#

Add a streaming multipart parser via the multipart library

This provides

  • Ability to stream large / larger-than-memory file uploads

  • Better / more correct edge case handling

  • Still good performance

References: litestar-org/litestar#3872

Add WebSocket send stream#

Add a new websocket_stream() route handler that supports streaming data to a WebSocket via an async generator.

@websocket_stream("/") async def handler() -> AsyncGenerator[str, None]: yield str(time.time()) await asyncio.sleep(.1)

This is roughly equivalent to (with some edge case handling omitted):

@websocket("/") async def handler(socket: WebSocket) -> None: await socket.accept() try: async with anyio.task_group() as tg: # 'receive' in the background to catch client disconnects tg.start_soon(socket.receive) while True: socket.send_text(str(time.time())) await asyncio.sleep(.1) finally: await socket.close()

Just like the WebSocket listeners, it also supports dependency injection and serialization:

@dataclass class Event: time: float data: str async def provide_client_info(socket: WebSocket) -> str: return f"{socket.client.host}:{socket.client.port}" @websocket_stream("/", dependencies={"client_info": provide_client_info}) async def handler(client_info: str) -> AsyncGenerator[Event, None]: yield Event(time=time.time(), data="hello, world!") await asyncio.sleep(.1)

References: litestar-org/litestar#3894

Add query params to Redirect# Add Valkey as a native store#

Add a new ValkeyStore, which provides the same functionality as the RedisStore but using valkey instead.

The necessary dependencies can be installed with the litestar[valkey] extra, which includes valkey as well as libvalkey as an optimisation layer.

References: litestar-org/litestar#3892

Correctly specify "path" as an error message source for validation errors# Add subprocess test client# Support for Python 3.13#

Support Python 3.13

Important

  • There are no Python 3.13 prebuilt wheels for psycopg[binary]. If you rely on this for development, you’ll need to have the postgres development libraries installed

  • picologging does not currently support Python 3.13

References: litestar-org/litestar#3850

Bugfixes#

OpenAPI: Always generate refs for enums# Support varying mtime semantics across different fsspec implementations#

Change the implementation of File to be able to handle most fsspec implementation’s mtime equivalent.

This is necessary because fsspec implementations do not have a standardised way to retrieve an mtime equivalent; Some report an mtime, while some may use a different key (e.g. Last-Modified) and others do not report this value at all.

References: litestar-org/litestar#3899, litestar-org/litestar#3902

OpenAPI: Ensure query-only properties are only included in queries# Channels: Use SQL function for in psycopg backend#

2.13.0#

Released: 2024-11-20

Features#

Add request_max_body_size layered parameter#

Add a new request_max_body_size layered parameter, which limits the maximum size of a request body before returning a 413 - Request Entity Too Large.

References:

Send CSRF request header in OpenAPI plugins#

Supported OpenAPI UI clients will extract the CSRF cookie value and attach it to the request headers if CSRF is enabled on the application.

References: litestar-org/litestar#3754

deprecate litestar.contrib.sqlalchemy# implement HTMX plugin using litestar-htmx#

This plugin migrates the HTMX integration to litestar.plugins.htmx.

This logic has been moved to it’s own repository named litestar-htmx

References: litestar-org/litestar#3837

Pydantic: honor hide_input_in_errors in throwing validation exceptions# deprecate``litestar.contrib.pydantic``#

Bugfixes#

Fix sign bug in rate limit middelware#

Fix a bug in the rate limit middleware, that would cause the response header fields RateLimit-Remaining and RateLimit-Reset to have negative values.

References: litestar-org/litestar#3776

OpenAPI: map JSONSchema spec naming convention to snake_case when names from schema_extra are not found# Use correct path template for routes without path parameters#

Fix a but where, when using PrometheusConfig.group_path=True, the metrics exporter response content would ignore all paths with no path parameters.

References: litestar-org/litestar#3784

Fix a dangling anyio stream in TestClient# Fix bug in handling of missing more_body key in ASGI response#

Some frameworks do not include the more_body key in the “http.response.body” ASGI event. According to the ASGI specification, this key should be set to False when there is no additional body content. Litestar expects more_body to be explicitly defined, but others might not.

This leads to failures when an ASGI framework mounted on Litestar throws error if this key is missing.

References: litestar-org/litestar#3845

Fix duplicate RateLimit-* headers with caching#

2.12.1#

Released: 2024-09-21

Bugfixes#

Fix base package requiring annotated_types dependency#

2.12.0#

Released: 2024-09-21

Features#

Support strings in media_type for ResponseSpec# OpenAPI: Allow customizing schema component keys#

Allow customizing the schema key used for a component in the OpenAPI schema. The supplied keys are enforced to be unique, and it is checked that they won’t be reused across different types.

The keys can be set with the newly introduced schema_component_key parameter, which is available on KwargDefinition, Body() and Parameter().

Two components will be generated: Data and not_data#

@dataclass class Data: pass @post("/") def handler( data: Annotated[Data, Parameter(schema_component_key="not_data")], ) -> Data: return Data() @get("/") def handler_2() -> Annotated[Data, Parameter(schema_component_key="not_data")]: return Data()

References: litestar-org/litestar#3738

Raise exception when body parameter is annotated with non-bytes type#

Add an informative error message to help avoid the common mistake of attempting to use the body parameter to receive validated / structured data by annotating it with a type such as list[str], instead of bytes.

References: litestar-org/litestar#3740

OpenAPI: Default to latest scalar version#

Bugfixes#

Fix overzealous warning for greedy middleware exclude pattern# Fix dangling coroutines in request extraction handling cleanup#

Fix a bug where, when a required header parameter was defined for a request that also expects a request body, failing to provide the header resulted in a RuntimeWarning.

@post() async def handler(data: str, secret: Annotated[str, Parameter(header="x-secret")]) -> None: return None

If the x-secret header was not provided, warning like this would be seen:

RuntimeWarning: coroutine 'json_extractor' was never awaited

References: litestar-org/litestar#3734, litestar-org/litestar#3735

OpenAPI: Correctly handle type keyword# OpenAPI: Ensure valid schema keys# OpenAPI: Correctly handle msgspec.Struct tagged unions# OpenAPI: Fix Pydantic 1 constrained string with default factory# OpenAPI/DTO: Fix missing Pydantic 2 computed fields#

Fix a bug that would lead to Pydantic computed fields to be ignored during schema generation when the model was using a PydanticDTO.

Only the foo field would be included in the schema#

class MyModel(BaseModel): foo: int @computed_field def bar(self) -> int: return 123 @get(path="/", return_dto=PydanticDTO[MyModel]) async def test() -> MyModel: return MyModel.model_validate({"foo": 1})

References: litestar-org/litestar#3656, litestar-org/litestar#3721

OpenAPI: Fix Pydantic json_schema_extra overrides only being merged partially#

Fix a bug where json_schema_extra were not reliably extracted from Pydantic models and included in the OpenAPI schema.

Only the title set directly on the field would be used for the schema#

class Model(pydantic.BaseModel): with_title: str = pydantic.Field(title="new_title") with_extra_title: str = pydantic.Field(json_schema_extra={"title": "more_new_title"}) @get("/example") async def example_route() -> Model: return Model(with_title="1", with_extra_title="2")

References: litestar-org/litestar#3656, litestar-org/litestar#3721

2.11.0#

Released: 2024-08-27

Features#

Use PyJWT instead of python-jose# DTO: Introduce forbid_unknown_fields config# DTO: Support extra="forbid" model config for PydanticDTO#

For Pydantic models with extra=”forbid” in their configuration:

Pydantic 2

class User(BaseModel): model_config = ConfigDict(extra='ignore') name: str

Pydantic 1

class User(BaseModel): class Config: extra = "ignore" name: str

forbid_unknown_fields will be set to True by default.

Note

It’s still possible to override this configuration at the DTO level

To facilitate this feature, get_config_for_model_type() has been added to AbstractDTO, allowing the customization of the base config defined on the DTO factory for a specific model type. It will be called on DTO factory initialization, and receives the concrete DTO model type along side the DTOConfig defined on the base DTO, which it can alter and return a new version to be used within the DTO instance.

References: litestar-org/litestar#3691

Custom JWT payload classes#

Support extending the default Token class used by the JWT backends decode the payload into.

  • Add new token_cls field on the JWT auth config classes

  • Add new token_cls parameter to JWT auth middlewares

  • Switch to using msgspec to convert the JWT payload into instances of the token class

Python 3.8+

import dataclasses import secrets from typing import Any, Dict from litestar import Request, get from litestar.connection import ASGIConnection from litestar.security.jwt import JWTAuth, Token @dataclasses.dataclass class CustomToken(Token): token_flag: bool = False @dataclasses.dataclass class User: id: str async def retrieve_user_handler(token: CustomToken, connection: ASGIConnection) -> User: return User(id=token.sub) TOKEN_SECRET = secrets.token_hex() jwt_auth = JWTAuth[User]( token_secret=TOKEN_SECRET, retrieve_user_handler=retrieve_user_handler, token_cls=CustomToken, ) @get("/") def handler(request: Request[User, CustomToken, Any]) -> Dict[str, Any]: return {"id": request.user.id, "token_flag": request.auth.token_flag}

Python 3.9+

import dataclasses import secrets from typing import Any from litestar import Request, get from litestar.connection import ASGIConnection from litestar.security.jwt import JWTAuth, Token @dataclasses.dataclass class CustomToken(Token): token_flag: bool = False @dataclasses.dataclass class User: id: str async def retrieve_user_handler(token: CustomToken, connection: ASGIConnection) -> User: return User(id=token.sub) TOKEN_SECRET = secrets.token_hex() jwt_auth = JWTAuth[User]( token_secret=TOKEN_SECRET, retrieve_user_handler=retrieve_user_handler, token_cls=CustomToken, ) @get("/") def handler(request: Request[User, CustomToken, Any]) -> dict[str, Any]: return {"id": request.user.id, "token_flag": request.auth.token_flag}

References: litestar-org/litestar#3692

Extended JWT configuration options# Warn about greedy exclude patterns in middlewares#

Raise a warning when a middlewares exclude pattern greedily matches all paths.

from litestar.middlewares class MyMiddleware(AbstractMiddleware): exclude = ["/", "/home"] async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: await self.app(scope, receive, send)

Middleware like this would silently be disabled for every route, since the exclude pattern / matches all paths. If a configuration like this is detected, a warning will now be raised at application startup.

References: litestar-org/litestar#3700

RFC 9457 Problem Details plugin#

Bugfixes#

Fix creation of FormMultiDict in Request.form to properly handle multi-keys#

Fix litestar-org/litestar#3627 by properly handling the creation of FormMultiDict where multiple values are given for a single key, to make form() match the behaviour of receiving form data via the data kwarg inside a route handler.

Before

@post("/") async def handler(request: Request) -> Any: return (await request.form()).getall("foo") with create_test_client(handler) as client: print(client.post("/", data={"foo": ["1", "2"]}).json()) # [["1", "2"]]

After

@post("/") async def handler(request: Request) -> Any: return (await request.form()).getall("foo") with create_test_client(handler) as client: print(client.post("/", data={"foo": ["1", "2"]}).json()) # ["1", "2"]

References: litestar-org/litestar#3627, litestar-org/litestar#3639

DTO: Fix inconsistent use of strict decoding mode#

Fix inconsistent usage of msgspec’s strict mode in the base DTO backend.

strict=False was being used when transferring from builtins, while strict=True was used transferring from raw data, causing an unwanted discrepancy in behaviour.

References: litestar-org/litestar#3685

Use path template for prometheus metrics#

Changed previous 1-by-1 replacement logic for PrometheusMiddleware.group_path=true with a more robust and slightly faster solution.

References: litestar-org/litestar#3687

Ensure OpenTelemetry captures exceptions in the outermost application layers# Fix CSRFMiddleware sometimes setting cookies for excluded paths# Make override behaviour consistent between signature_namespace and signature_types#

Ensure that adding signature types to signature_namespace and signature_types behaves the same way when a name was already present in the namespace.

Both will now issue a warning if a name is being overwritten with a different type. If a name is registered again for the same type, no warning will be given.

Note

You can disable this warning globally by setting LITESTAR_WARN_SIGNATURE_NAMESPACE_OVERRIDE=0 in your environment

References: litestar-org/litestar#3681, litestar-org/litestar#3696

2.10.0#

Released: 2024-07-26

Features#

Allow creating parent directories for a file store# Add logging_module parameter to LoggingConfig# Add handler name to exceptions in handler validation# Add strict validation support for Pydantic plugin#

Bugfixes#

Fix signature model signatures clash# Correctly handle Annotated NewType# Use ASGIConnection instead of Request for flash#

Currently, the FlashPlugin expects the request parameter to be a type of Request. However, there’s no reason it can’t use the parent class ASGIConnection.

Doing this, allows for flash to be called in guards that expect an ASGIConnection instead of Request:

def requires_active_user(connection: ASGIConnection, _: BaseRouteHandler) -> None: if connection.user.is_active: return msg = "Your user account is inactive." flash(connection, msg, category="error") raise PermissionDeniedException(msg)

References: litestar-org/litestar#3626

Allow returning Response[None] from head route handlers#

2.9.1#

Released: 2024-06-21

Bugfixes#

Add OPTIONS to the default safe methods for CSRFConfig# Prometheus: Capture templated route name for metrics# Respect base_url in .websocket_connect#

Fix a bug that caused websocket_connect() / websocket_connect() to not respect the base_url set in the client’s constructor, and instead would use the static ws://testerver URL as a base.

Also removes most of the test client code as it was unneeded and in the way of this fix :)

Explanation for the last part: All the extra code we had was just proxying method calls to the httpx.Client / httpx.AsyncClient, while altering the base URL. Since we already set the base URL on the httpx Client’s superclass instance, which in turn does this merging internally, this step isn’t needed at all.

References: litestar-org/litestar#3567

Fix deprecation warning for subclassing route handler decorators#

Fix an issue where there was a deprecation warning emitted by all route handler decorators. This warning was introduced in 2.9.0 to warn about the upcoming deprecation, but should have only applied to user subclasses of the handler classes, and not the built-in ones (get, post, etc.)

References: litestar-org/litestar#3552, litestar-org/litestar#3569

CLI: Don’t call rich_click.patch if rich_click is installed#

Don’t call rich_click.patch if rich_click is installed. As this monkey patches click globally, it can introduce unwanted side effects. Instead, use conditional imports to refer to the correct library.

External libraries will still be able to make use of rich_click implicitly when it’s installed by inheriting from LitestarGroup / LitestarExtensionGroup, which they will by default.

References: litestar-org/litestar#3534, litestar-org/litestar#3570

Correctly handle typing.NewType#

When encountering a typing.NewType during OpenAPI schema generation, we currently treat it as an opaque type. This PR changes the behaviour such that :class`typing.NewType`s are always unwrapped during schema generation.

References: litestar-org/litestar#3580

Encode response content object returned from an exception handler.#

When an handler raises an exception and exception handler returns a Response with a model (e.g. pydantic) object, ensure that object can be encoded as when returning data from a regular handler.

References: litestar-org/litestar#3585

2.9.0#

Released: 2024-06-02

Features#

Add async websocket_connect to AsyncTestClient# add SecretString and SecretBytes datastructures# Deprecate subclassing route handler decorators#

Deprecation for the 2.x release line of the semantic route handler classes removed in #3436.

References: litestar-org/litestar#3439

Bugfixes#

asgi lifespan msg after lifespan context exception#

An exception raised within an asgi lifespan context manager would result in a “lifespan.startup.failed” message being sent after we’ve already sent a “lifespan.startup.complete” message. This would cause uvicorn to raise a STATE_TRANSITION_ERROR assertion error due to their check for that condition , if asgi lifespan is forced (i.e., with $ uvicorn test_apps.test_app:app --lifespan on).

E.g.,

During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/peter/.local/share/pdm/venvs/litestar-dj-FOhMr-3.8/lib/python3.8/site-packages/uvicorn/lifespan/on.py", line 86, in main await app(scope, self.receive, self.send) File "/home/peter/.local/share/pdm/venvs/litestar-dj-FOhMr-3.8/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__ return await self.app(scope, receive, send) File "/home/peter/PycharmProjects/litestar/litestar/app.py", line 568, in __call__ await self.asgi_router.lifespan(receive=receive, send=send) # type: ignore[arg-type] File "/home/peter/PycharmProjects/litestar/litestar/_asgi/asgi_router.py", line 180, in lifespan await send(failure_message) File "/home/peter/.local/share/pdm/venvs/litestar-dj-FOhMr-3.8/lib/python3.8/site-packages/uvicorn/lifespan/on.py", line 116, in send assert not self.startup_event.is_set(), STATE_TRANSITION_ERROR AssertionError: Got invalid state transition on lifespan protocol.

This PR modifies ASGIRouter.lifespan() so that it sends a shutdown failure message if we’ve already confirmed startup.

References: litestar-org/litestar#3315

bug when pydantic==1.10 is installed# OpenAPI router and controller on same app.#

Fixes an :exc`ImproperlyConfiguredException` where an app that explicitly registers an OpenAPIController on the application, and implicitly uses the OpenAPI router via the OpenAPIConfig object. This was caused by the two different handlers being given the same name as defined in litestar.constants.

PR adds a distinct name for use by the handler that serves openapi.json on the controller.

References: litestar-org/litestar#3337, litestar-org/litestar#3338

pydantic v2 import tests for pydantic v1.10.15#

Fixes bug with Pydantic V1 environment test where the test was run against v2. Adds assertion for version to the test.

Fixes a bug exposed by above that relied on pydantic not having v1 in the package namespace if v1 is installed. This doesn’t hold true after pydantic’s 1.10.15 release.

References: litestar-org/litestar#3348, litestar-org/litestar#3347

schema for generic wrapped return types with DTO#

Fix schema generated for DTOs where the supported type is wrapped in a generic outer type.

Prior behavior of using the backend.annotation as the basis for generating the openapi schema for the represented type is not applicable for the case where the DTO supported type is wrapped in a generic outer object. In that case backend.annotation only represents the type of the attribute on the generic type that holds the DTO supported type annotation.

This change detects the case where we unwrap an outer generic type, and rebuilds the generic annotation in a manner appropriate for schema generation, before generating the schema for the annotation. It does this by substituting the DTOs transfer model for the original model in the original annotations type arguments.

References: litestar-org/litestar#2929, litestar-org/litestar#3371

Ambiguous default warning for no signature default# Path param consumed by dependency treated as unconsumed#

Consider parameters defined in handler dependencies in order to determine if a path parameter has been consumed for openapi generation purposes.

Fixes an issue where path parameters not consumed by the handler, but consumed by dependencies would cause an :exc`ImproperlyConfiguredException`.

References: litestar-org/litestar#3369, litestar-org/litestar#3380

“name” and “in” should not be included in openapi headers#

Exclude the “name” and “in” fields from openapi schema generated for headers.

Add BaseSchemaObject._iter_fields() method that allows schema types to define the fields that should be included in their openapi schema representation and override that method for OpenAPIHeader.

References: litestar-org/litestar#3416, litestar-org/litestar#3417

top-level import of optional package# regular handler under mounted app#

Fix an issue where a regular handler under a mounted asgi app would prevent a request from routing through the mounted application if the request path contained the path of the regular handler as a substring.

References: litestar-org/litestar#3429, litestar-org/litestar#3430

logging to file with structlog#

Fix and issue with converting StructLoggingConfig to dict during call to configure() when the config object has a custom logger factory that references a TextIO object, which cannot be pickled.

References: litestar-org/litestar#3425

clear session cookie if new session exceeds CHUNK_SIZE# flash messages were not displayed on Redirect# Validation of optional sequence in multipart data with one value# field not optional if default value# prevent starting multiple responses#

Prevent the app’s exception handler middleware from starting a response after one has already started.

When something in the middleware stack raises an exception after a “http.response.start” message has already been sent, we end up with long exception chains that obfuscate the original exception.

This change implements tracking of when a response has started, and if so, we immediately raise the exception instead of sending it through the usual exception handling code path.

References: litestar-org/litestar#3479

logging middleware with multi-body response# handle dto type nested in mapping#

Added handling for transferring data from a transfer model, to a DTO supported instance when the DTO supported type is nested in a mapping.

I.e, handles this case:

@dataclass class NestedDC: a: int b: str @dataclass class DC: nested_mapping: Dict[str, NestedDC]

References: litestar-org/litestar#3463, litestar-org/litestar#3486

examples omitted in schema produced by dto# fix handling validation of subscribed generics#

Fix a bug that would lead to a TypeError when subscribed generics were used in a route handler signature and subject to validation.

from typing import Generic, TypeVar from litestar import get from litestar.testing import create_test_client T = TypeVar("T") class Foo(Generic[T]): pass async def provide_foo() -> Foo[str]: return Foo() @get("/", dependencies={"foo": provide_foo}) async def something(foo: Foo[str]) -> None: return None with create_test_client([something]) as client: client.get("/")

References: litestar-org/litestar#3519

exclude static file from schema# use re.match instead of re.search for mounted app path (#3501)# do not log exceptions twice, deprecate traceback_line_limit and fix pretty_print_tty#
  • The wording of the log message, when logging an exception, has been updated.

  • For structlog, the traceback field in the log message (which contained a truncated stacktrace) has been removed. The exception field is still around and contains the full stacktrace.

  • The option traceback_line_limit has been deprecated. The value is now ignored, the full stacktrace will be logged.

References: litestar-org/litestar#3228, litestar-org/litestar#3507

YAML schema dump#

Fix an issue in the OpenAPI YAML schema dump logic of OpenAPIController where the endpoint for the OpenAPI YAML schema file returns an empty response if a request has been made to the OpenAPI JSON schema previously due to an incorrect variable check.

References: litestar-org/litestar#3537

2.8.3#

Released: 2024-05-06

Bugfixes#

Fix improper limitation of a pathname to a restricted directory# Remove use of asserts for control flow.#

#3347 introduced a new pattern to differentiate between Pydantic v1 and v2 installs, however it relies on using assert which is an issue as can optimised away.

This PR changes the approach to manually throw an ImportError instead.

References: litestar-org/litestar#3354, litestar-org/litestar#3359

schema for generic wrapped return types with DTO# Ambiguous default warning for no signature default# Path param consumed by dependency treated as unconsumed#

Consider parameters defined in handler dependencies in order to determine if a path parameter has been consumed for openapi generation purposes.

Fixes an issue where path parameters not consumed by the handler, but consumed by dependencies would cause an ImproperlyConfiguredException.

References: litestar-org/litestar#3369, litestar-org/litestar#3380

Solve a caching issue in CacheControlHeader# “name” and “in” should not be included in openapi headers# top-level import of optional package# regular handler under mounted app#

Fix an issue where a regular handler under a mounted asgi app would prevent a request from routing through the mounted application if the request path contained the path of the regular handler as a substring.

References: litestar-org/litestar#3429, litestar-org/litestar#3430

logging to file with structlog#

PR fixes issue with converting StructLoggingConfig to dict during call to configure() when the config object has a custom logger factory that references a TextIO object, which cannot be pickled.

References: litestar-org/litestar#3425

clear session cookie if new session gt CHUNK_SIZE# flash messages were not displayed on Redirect# Validation of optional sequence in multipart data with one value#

2.8.2#

Released: 2024-04-09

Bugfixes#

pydantic v2 import tests for pydantic v1.10.15#

Fixes bug with Pydantic v1 environment test causing the test to run against v2. Adds assertion for version to the test.

Fixes a bug exposed by above that relied on Pydantic not having v1 in the package namespace if v1 is installed. This doesn’t hold true after Pydantic’s 1.10.15 release.

Moves application environment tests from the release job into the normal CI run.

References: litestar-org/litestar#3348, litestar-org/litestar#3347

2.8.1#

Released: 2024-04-08

Bugfixes#

ASGI lifespan msg after lifespan context exception#

An exception raised within an asgi lifespan context manager would result in a “lifespan.startup.failed” message

This PR modifies ASGIRouter.lifespan() so that it sends a shutdown failure message if we’ve already confirmed startup.

References: litestar-org/litestar#3315

Fix when pydantic==1.10 is installed# OpenAPI router and controller on same app.#

Fixes an ImproperlyConfiguredException where an app that explicitly registers an OpenAPIController on the application, and implicitly uses the OpenAPI router via the OpenAPIConfig object. This was caused by the two different handlers being given the same name as defined in litestar.constants.

PR adds a distinct name for use by the handler that serves openapi.json on the controller.

References: litestar-org/litestar#3337, litestar-org/litestar#3338

2.8.0#

Released: 2024-04-05

Features#

Add path parameter to Litestar application class# Allow for console output to be silenced#

Introduces optional environment variables that allow customizing the “Application” name displayed in the console output and suppressing the initial from_env or the Rich info table at startup.

Provides flexibility in tailoring the console output to better integrate Litestar into larger applications or CLIs.

References: litestar-org/litestar#3180

Add flash plugin# Use memoized request_class and response_class values# Enable codegen backend by default# Added precedence of CLI parameters over envs#

Adds precedence of CLI parameters over environment variables. Before this change, environment variables would take precedence over CLI parameters.

Since CLI parameters are more explicit and are set by the user, they should take precedence over environment variables.

References: litestar-org/litestar#3188, litestar-org/litestar#3190

Only print when terminal is TTY enabled#

Sets LITESTAR_QUIET_CONSOLE and LITESTAR_APP_NAME in the autodiscovery function. Also prevents the tabular console output from printing when the terminal is not TTY

References: litestar-org/litestar#3219

Support schema_extra in Parameter and Body#

Introduces a way to modify the generated OpenAPI spec by adding a schema_extra parameter to the Parameter and Body classes. The schema_extra parameter accepts a dict[str, Any] where the keys correspond to the keyword parameter names in Schema, and the values are used to override items in the generated Schema object.

Provides a convenient way to customize the OpenAPI documentation for inbound parameters.

References: litestar-org/litestar#3204

Add typing.TypeVar expansion#

Adds a method for TypeVar expansion on registration This allows the use of generic route handler and generic controller without relying on forward references.

References: litestar-org/litestar#3242

Add LITESTAR_ prefix before WEB_CONCURRENCY env option# Warn about ambiguous default values in parameter specifications#

As discussed in litestar-org/litestar#3280, we want to warn about, and eventually disallow specifying parameter defaults in two places.

To achieve this, 2 warnings are added:

  • A deprecation warning if a default is specified when using Annotated: param: Annotated[int, Parameter(..., default=1)] instead of param: Annotated[int, Parameter(...)] = 1

  • An additional warning in the above case if two default values are specified which do not match in value: param: Annotated[int, Parameter(..., default=1)] = 2

In a future version, the first one should result in an exception at startup, preventing both of these scenarios.

References: litestar-org/litestar#3283

Support declaring DTOField via Annotated# Add “TRACE” to HttpMethod enum# Pydantic DTO non-instantiable types#

Simplifies the type that is applied to DTO transfer models for certain Pydantic field types. It addresses JsonValue, EmailStr, IPvAnyAddress/IPvAnyNetwork/IPvAnyInterface types by using appropriate type annotations on the transfer models to ensure compatibility with msgspec serialization and deserialization.

References: litestar-org/litestar#3296

Bugfixes#

Unique schema names for nested models (#3134)#

Fixes an issue where nested models beyond the max_nested_depth would not have unique schema names in the OpenAPI documentation. The fix appends the nested model’s name to the unique_name to differentiate it from the parent model.

References: litestar-org/litestar#3134, litestar-org/litestar#3136

Remove duplicate rich-click config options# Fix Pydantic json_schema_extra examples.# Set default on schema from FieldDefinition#

Consider the following:

def get_foo(foo_id: int = 10) -> None: ...

In such cases, no KwargDefinition is created since there is no metadata provided via Annotated. The default is still parsed, and set on the generated FieldDefinition, however the SchemaCreator currently only considers defaults that are set on KwargDefinition.

So in such cases, we should fallback to the default set on the FieldDefinition if there is a valid default value.

References: litestar-org/litestar#3278, litestar-org/litestar#3280

Custom types cause serialisation error in exception response with non-JSON media-type# Ensure default values are always represented in schema for dataclasses and msgspec.Structs# Pydantic v2 error handling/serialization when for non-Pydantic exceptions# Fix OpenAPI schema generation for paths with path parameters of different types on the same path#

Fixes a bug that would cause no OpenAPI schema to be generated for paths with path parameters that only differ on the path parameter type, such as /{param:int} and /{param:str}. This was caused by an internal representation issue in Litestar’s routing system.

References: litestar-org/litestar#2700, litestar-org/litestar#3293

Document unconsumed path parameters#

Fixes a bug where path parameters not consumed by route handlers would not be included in the OpenAPI schema.

This could/would not include the {param} in the schema, yet it is still required to be passed when calling the path.

References: litestar-org/litestar#3290, litestar-org/litestar#3295

2.7.1#

Released: 2024-03-22

Bugfixes#

replace TestClient.__enter__ return type with Self#

TestClient.__enter__ and AsyncTestClient.__enter__ return Self. If you inherit TestClient, its __enter__ method should return derived class’s instance unless override the method. Self is a more flexible return type.

References: litestar-org/litestar#3194

use the full path for fetching openapi.json#

This specifies the spec-url and apiDescriptionUrl of Rapidoc, and Stoplight Elements as absolute paths relative to the root of the site.

This ensures that both of the send the request for the JSON of the OpenAPI schema to the right endpoint.

References: litestar-org/litestar#3047, litestar-org/litestar#3196

JSON schema examples were OpenAPI formatted#

The generated examples in JSON schema objects were formatted as:

"examples": { "some-id": { "description": "Lorem ipsum", "value": "the real beef" } }

However, above is OpenAPI example format, and must not be used in JSON schema objects. Schema objects follow different formatting:

"examples": [ "the real beef" ]

This is referenced at least from parameters, media types and components.

The technical change here is to define Schema.examples as list[Any] instead of list[Example]. Examples can and must still be defined as list[Example] for OpenAPI objects (e.g. Parameter, Body) but for JSON schema examples the code now internally generates/converts list[Any] format instead.

Extra confusion here comes from the OpenAPI 3.0 vs OpenAPI 3.1 difference. OpenAPI 3.0 only allowed example (singular) field in schema objects. OpenAPI 3.1 supports the full JSON schema 2020-12 spec and so examples array in schema objects.

Both example and examples seem to be supported, though the former is marked as deprecated in the latest specs.

This can be tested over at https://editor-next.swagger.io by loading up the OpenAPI 3.1 Pet store example. Then add examples in components.schemas.Pet using the both ways and see the Swagger UI only render the example once it’s properly formatted (it ignores is otherwise).

References: litestar-org/litestar#2849, litestar-org/litestar#3224

queue_listener handler for Python >= 3.12#
  • Fix the queue_listener handler for Python 3.12

Python 3.12 introduced a new way to configure QueueHandler and QueueListener via logging.config.dictConfig(). As described in the logging documentation.

The listener still needs to be started & stopped, as previously. To do so, we’ve introduced LoggingQueueListener.

And as stated in the doc: * Any custom queue handler and listener classes will need to be defined with the same initialization signatures as QueueHandler and QueueListener.

References: litestar-org/litestar#2954, litestar-org/litestar#3185

extend openapi meta collected from domain models#

FieldDefinition s pack any OpenAPI metadata onto a KwargDefinition instance when types are parsed from domain models.

When we produce a DTO type, we transfer this meta from the KwargDefinition to a msgspec.Meta instance, however so far this has only included constraints, not attributes such as descriptions, examples and title.

This change ensures that we transfer the openapi meta for the complete intersection of fields that exist on b oth KwargDefinition and Meta.

References: litestar-org/litestar#3232, litestar-org/litestar#3237

kwarg ambiguity exc msg for path params#

Fixes the way we construct the exception message when there is a kwarg ambiguity detected for path parameters.

References: litestar-org/litestar#3261

2.7.0#

Released: 2024-03-10

Features#

Support ResponseSpec(..., examples=[...])#

Allow defining custom examples for the responses via ResponseSpec. The examples set this way are always generated locally, for each response: Examples that go within the schema definition cannot be set by this.

{ "paths": { "/": { "get": { "responses": { "200": { "content": { "application/json": { "schema": {}, "examples": "..."}} }} }} } }

References: litestar-org/litestar#3068, litestar-org/litestar#3100

support “+json”-suffixed response media types# Allow reusable Router instances#

It was not possible to re-attach a router instance once it was attached. This makes that possible.

The router instance now gets deepcopied when it’s registered to another router.

The application startup performance gets a hit here, but the same approach is already used for controllers and handlers, so this only harmonizes the implementation.

References: litestar-org/litestar#3012, litestar-org/litestar#3103

only display path in ValidationExceptions# expose request_class to other layers# expose websocket_class# Add type_decoders to Router and route handlers#

Add type_decoders to __init__ method for handler, routers and decorators to keep consistency with type_encoders parameter

References: litestar-org/litestar#3153

Pass type_decoders in WebsocketListenerRouteHandler#

Pass type_decoders to parent’s __init__ in WebsocketListenerRouteHandler init, otherwise type_decoders will be None replace params order in docs, __init__ (decoders before encoders)

References: litestar-org/litestar#3162

3116 enhancement session middleware#

For server side sessions, the session id is now generated before the route handler. Thus, on first visit, a session id will be available inside the route handler’s scope instead of afterwards A new abstract method get_session_id was added to BaseSessionBackend since this method will be called for both ClientSideSessions and ServerSideSessions. Only for ServerSideSessions it will return an actual id. Using request.set_session(...) will return the session id for ServerSideSessions and None for ClientSideSessions The session auth MiddlewareWrapper now refers to the Session Middleware via the configured backend, instead of it being hardcoded

References: litestar-org/litestar#3116, litestar-org/litestar#3127

make random seed for openapi example generation configurable#

Allow random seed used for generating the examples in the OpenAPI schema (when create_examples is set to True) to be configured by the user. This is related to litestar-org/litestar#3059 however whether this change is enough to close that issue or not is not confirmed.

References: litestar-org/litestar#3166

generate openapi components schemas in a deterministic order#

Ensure that the insertion into the Components.schemas dictionary of the OpenAPI spec will be in alphabetical order (based on the normalized name of the Schema).

References: litestar-org/litestar#3172

Bugfixes#

missing cors headers in response# sending empty data in sse in js client#

Fix an issue with SSE where JavaScript clients fail to receive an event without data. The spec is not clear in whether or not an event without data is ok. Considering the EventSource “client” is not ok with it, and that it’s so easy DX-wise to make the mistake not explicitly sending it, this change fixes it by defaulting to the empty-string

References: litestar-org/litestar#3176

2.6.3#

Released: 2024-03-04

Bugfixes#

Pydantic V1 schema generation for PrivateAttr in GenericModel#

2.6.2#

Released: 2024/03/02

Bugfixes#

DTO msgspec meta constraints not being included in transfer model#

Fix an issue where msgspec constraints set in msgspec.Meta would not be honoured by the DTO.

In the given example, the min_length=3 constraint would be ignored by the model generated by MsgspecDTO.

from typing import Annotated import msgspec from litestar import post from litestar.dto import MsgspecDTO class Request(msgspec.Struct): foo: Annotated[str, msgspec.Meta(min_length=3)] @post("/example/", dto=MsgspecDTO[Request]) async def example(data: Request) -> Request: return data

Constraints like these are now transferred.

Two things to note are:

  • For DTOs with DTOConfig(partial=True) we cannot transfer the length constraints as they are only supported on fields that as subtypes of str, bytes or a collection type, but partial=True sets all fields as T | UNSET

  • For the PiccoloDTO, fields which are not required will also drop the length constraints. A warning about this will be raised here.

References: litestar-org/litestar#3026, litestar-org/litestar#3113

Missing control header for static files# Fix OpenAPI schema generation for Pydantic v2 constrained Secret types#

Fix schema generation for pydantic.SecretStr and pydantic.SecretBytes which, when constrained, would not be recognised as such with Pydantic V2 since they’re not subtypes of their respective bases anymore.

References: litestar-org/litestar#3148, litestar-org/litestar#3149

Fix OpenAPI schema generation for Pydantic private attributes#

Fix a bug that caused a NameError when trying to resolve forward references in Pydantic private fields.

Although private fields were respected excluded from the schema, it was still attempted to extract their type annotation. This was fixed by not relying on typing.get_type_hints to get the type information, but instead using Pydantic’s own APIs, allowing us to only extract information about the types of relevant fields.

References: litestar-org/litestar#3150, litestar-org/litestar#3151

OpenAPI description not set for UUID based path parameters in OpenAPI# Fix RedisStore client created with with_client unclosed#

2.6.1#

Released: 2024/02/14

Bugfixes#

SQLAlchemy: Use IntegrityError instead of deprecated ConflictError#

Updated the repository to return IntegrityError instead of the now deprecated ConflictError

References: litestar-org/litestar#3094

Remove usage of deprecated static_files property# Sessions: Fix cookie naming for short cookies#

Previously, cookie names always had a suffix of the form "-{i}" appended to them. With this change, the suffix is omitted if the cookie is short enough (< 4 KB) to not be split into multiple chunks.

References: litestar-org/litestar#3090, litestar-org/litestar#3095

Static files: Fix path resolution for windows# Fix logging middleware with structlog causes application to return a 500 when request body is malformed# OpenAPI: Generate correct response schema for ResponseSpec(None)# Prevent exception handlers from extracting details from non-Litestar exceptions#

2.6.0#

Released: 2024/02/06

Features#

Enable disabling configuring root logger within LoggingConfig# Simplified static file handling and enhancements#

Static file serving has been implemented with regular route handlers instead of a specialised ASGI app. At the moment, this is complementary to the usage of StaticFilesConfig to maintain backwards compatibility.

This achieves a few things:

  • Fixes litestar-org/litestar#2629

  • Circumvents special casing needed in the routing logic for the static files app

  • Removes the need for a static_files_config attribute on the app

  • Removes the need for a special url_for_static_asset() method on the app since route_reverse can be used instead

Additionally:

  • Most router options can now be passed to the create_static_files_router(), allowing further customisation

  • A new resolve_symlinks flag has been added, defaulting to True to keep backwards compatibility

Usage

Instead of

app = Litestar( static_files_config=[StaticFilesConfig(path="/static", directories=["some_dir"])] )

You can now simply use

app = Litestar( route_handlers=[ create_static_files_router(path="/static", directories=["some_dir"]) ] )

References: litestar-org/litestar#2629, litestar-org/litestar#2960

Exclude Piccolo ORM columns with secret=True from PydanticDTO output#

For Piccolo columns with secret=True set, corresponding PydanticDTO attributes will be marked as WRITE_ONLY to prevent the column being included in return_dto

References: litestar-org/litestar#3030

Allow discovering registered plugins by their fully qualified name#

PluginRegistryPluginRegistry` now supports retrieving a plugin by its fully qualified name.

References: litestar-org/litestar#3027

Support externally typed classes as dependency providers#
  • Implement a new DIPlugin class that allows the generation of signatures for arbitrary types where their signature cannot be extracted from the type’s __init__ method

  • Implement DIPlugins for Pydantic and Msgspec to allow using their respective modelled types as dependency providers. These plugins will be registered by default

References: litestar-org/litestar#2979, litestar-org/litestar#3066

Add structlog plugin#

A Structlog plugin to make it easier to configure structlog in a single place.

The plugin:

  • Detects if a logger has setLevel before calling

  • Set even message name to be init-cap

  • Add set_level interface to config

  • Allows structlog printer to detect if console is TTY enabled. If so, a Struglog color formatter with Rich traceback printer is used

  • Auto-configures stdlib logger to use the structlog logger

References: litestar-org/litestar#2943

Add reload-include and reload-exclude to CLI run command#

2.5.5#

Released: 2024/02/04

Bugfixes#

Fix scope state key handling#

Fix a regression introduced in #2751 that would wrongfully assume the state key is always present within the ASGI Scope. This is only the case when the Litestar root application is invoked first, since we enforce such a key there, but the presence of that key is not actually guaranteed by the ASGI spec and some servers, such as hypercorn, do not provide it.

References: litestar-org/litestar#3070

2.5.4#

Released: 2024/01/31

Bugfixes#

Handle KeyError when root_path is not present in ASGI scope#

Nginx Unit ASGI server does not set “root_path” in the ASGI scope, which is expected as part of the changes done in #3039. This PR fixes the assumption that the key is always present and instead tries to optionally retrieve it.

KeyError on GET / 'root_path'

References: litestar-org/litestar#3051

ServerSentEvent typing error#

fixes small typing error:

error: Argument 1 to "ServerSentEvent" has incompatible type "AsyncIterable[ServerSentEventMessage]"; expected "str | bytes | Iterable[str | bytes] | Iterator[str | bytes] | AsyncIterable[str | bytes] | AsyncIterator[str | bytes]" [arg-type]

inside test_sse there was a Any I changed to trigger the test then solved it.

References: litestar-org/litestar#3048

2.5.3#

Released: 2024/01/29

Bugfixes#

Handle diverging ASGI root_path behaviour#

Uvicorn 0.26.0 introduced a breaking change in its handling of the ASGI root_path behaviour, which, while adhering to the spec, diverges from the interpretation of other ASGI servers of this aspect of the spec (e.g. hypercorn and daphne do not follow uvicorn’s interpretation as of today). A fix was introduced that ensures consistent behaviour of applications in any case.

References: litestar-org/litestar#3041, litestar-org/litestar#3039

2.5.2#

Released: 2024/01/27

Bugfixes#

Ensure MultiDict and ImmutableMultiDict copy methods return the instance’s type# Ensure exceptiongroup is installed on Python 3.11#

2.5.1#

Released: 2024/01/18

Bugfixes#

Fix OpenAPI schema generation for Union of multiple msgspec.Structs and None# Fix misleading error message for missing dependencies provide by a package extra#

Ensure that MissingDependencyException includes the correct name of the package to install if the package name differs from the Litestar package extra. (e.g. pip install litestar[jinja] vs pip install jinja2). Previously the exception assumed the same name for both the package and package-extra name.

References: litestar-org/litestar#2921

Fix OpenAPI schema file upload schema types for swagger#
  • Always set format as binary

  • Fix schema for swagger with multiple files, which requires the type of the request body schema to be object with properties instead of a schema of type array and items.

References: litestar-org/litestar#2628, litestar-org/litestar#2745

2.5.0#

Released: 2024/01/06

Features#

Postgres channels backends# Add --schema and --exclude option to litestar route CLI command#

Two new options were added to the litestar route CLI command:

  • --schema, to include the routes serving OpenAPI schema and docs

  • --exclude to exclude routes matching a specified pattern

See also

Read more in the CLI cli section.

References: litestar-org/litestar#2886

Bugfixes#

Fix serialization of custom types in exception responses#

Fix a bug that would lead to a SerializationException when custom types were present in an exception response handled by the built-in exception handlers.

class Foo: pass @get() def handler() -> None: raise ValidationException(extra={"foo": Foo("bar")}) app = Litestar(route_handlers=[handler], type_encoders={Foo: lambda foo: "foo"})

The cause was that, in examples like the one shown above, type_encoders were not resolved properly from all layers by the exception handling middleware, causing the serializer to throw an exception for an unknown type.

References: litestar-org/litestar#2867, litestar-org/litestar#2941

Fix SSE reverting to default event_type after 1st message#

The event_type set within an SSE returned from a handler would revert back to a default after the first message sent:

@get("/stream") async def stream(self) -> ServerSentEvent: async def gen() -> AsyncGenerator[str, None]: c = 0 while True: yield f"<div>{c}</div>\n" c += 1 return ServerSentEvent(gen(), event_type="my_event")

In this example, the event type would only be my_event for the first message, and fall back to a default afterwards. The implementation has been fixed and will now continue sending the set event type for all messages.

References: litestar-org/litestar#2877, litestar-org/litestar#2888

Correctly handle single file upload validation when multiple files are specified#

Uploading a single file when the validation target allowed multiple would cause a ValidationException:

class FileUpload(Struct): files: list[UploadFile] @post(path="/") async def upload_files_object( data: Annotated[FileUpload, Body(media_type=RequestEncodingType.MULTI_PART)] ) -> list[str]: pass

This could would only allow for 2 or more files to be sent, and otherwise throw an exception.

References: litestar-org/litestar#2939, litestar-org/litestar#2950

Fix trailing messages after unsubscribe in channels#

Fix a bug that would allow some channels backend to receive messages from a channel it just unsubscribed from, for a short period of time, due to how the different brokers handle unsubscribes.

await backend.subscribe(["foo", "bar"]) # subscribe to two channels await backend.publish( b"something", ["foo"] ) # publish a message to a channel we're subscribed to # start the stream after publishing. Depending on the backend # the previously published message might be in the stream event_generator = backend.stream_events() # unsubscribe from the channel we previously published to await backend.unsubscribe(["foo"]) # this should block, as we expect messages from channels # we unsubscribed from to not appear in the stream anymore print(anext(event_generator))

Backends affected by this were in-memory, Redis PubSub and asyncpg. The Redis stream and psycopg backends were not affected.

References: litestar-org/litestar#2894

Other changes#

Improve performance of threaded synchronous execution#

Performance of threaded synchronous code was improved by using the async library’s native threading helpers instead of anyio. On asyncio, asyncio.loop.run_in_executor() is now used and on trio trio.to_thread.run_sync().

Beneficiaries of these performance improvements are:

  • Synchronous route handlers making use of sync_to_thread=True

  • Synchronous dependency providers making use of sync_to_thread=True

  • Synchronous SSE generators

  • FileStore

  • Large file uploads where the max_spool_size is exceeded and the spooled temporary file has been rolled to disk

  • File and ASGIFileResponse

References: litestar-org/litestar#2937

2.4.5#

Released: 2023/12/23

Bugfixes#

Fix validation of empty payload data with default values#

Prior to this fix, a handler like:

@post(path="/", sync_to_thread=False) def test(data: str = "abc") -> dict: return {"foo": data}

$ curl localhost:8000 -X POST

would return a client error like:

{"status_code":400,"detail":"Validation failed for POST http://localhost:8000/","extra":[{"message":"Expected `str`, got `null`","key":"data","source":"body"}]}

References: litestar-org/litestar#2902, litestar-org/litestar#2903

Support for returning Response[None] with a 204 status code from a handler# Fix error message of get_logger_placeholder()#

2.4.4#

Released: 2023/12/13

Bugfixes#

Support non-valid identifier as serialization target name# Fix regression signature validation for DTO validated types# Fix regression in OpenAPI schema key names#

Fix a regression introduced in 2.4.0 regarding the naming of OpenAPI schema keys, in which a change was introduced to the way that keys for the OpenAPI components/schemas objects were calculated to address the possibility of name collisions.

This behaviour was reverted for the case where a name has no collision, and now only introduces extended keys for the case where there are multiple objects with the same name, a case which would previously result in an exception.

References: litestar-org/litestar#2804, litestar-org/litestar#2841

Fix regression in OpenAPI handling of routes with multiple handlers#

Fix a regression introduced in 2.4.3 causing two routes registered with the same path, but different methods to break OpenAPI schema generation due to both of them having the same value for operation ID.

References: litestar-org/litestar#2863, litestar-org/litestar#2864

Fix OpenAPI schema generation for recursive models#

2.4.3#

Released: 2023/12/07

Bugfixes#

Fix OpenAPI schema for Literal | None unions#

Fix a bug where an incorrect OpenAPI schema was generated generated when any Literal | None-union was present in an annotation.

For example

type: Literal["sink", "source"] | None

would generate

{ "name": "type", "in": "query", "schema": { "type": "string", "enum": [ "sink", "source", null ] } }

References: litestar-org/litestar#2812, litestar-org/litestar#2818

Fix advanced-alchemy 0.6.0 compatibility issue with touch_updated_timestamp#

Fix an incorrect import for touch_updated_timestamp of Advanced Alchemy, introduced in Advanced-Alchemy version 0.6.0.

References: litestar-org/litestar#2843

2.4.2#

Released: 2023/12/02

Bugfixes#

Fix OpenAPI handling of parameters with duplicated names# Fix late failure where DTOData is used without a DTO#

Fix an issue where a handler would be allowed to be registered with a DTOData annotation without having a DTO defined, which would result in a runtime exception. In cases like these, a configuration error is now raised during startup.

References: litestar-org/litestar#2779, litestar-org/litestar#2789

Correctly propagate camelCase names on OpenAPI schema#

Fix a bug where OpenAPI schema fields would be inappropriately propagated as camelCase where they should have been snake_case

References: litestar-org/litestar#2800

Fix error handling in event handler stream#

Fix a class of errors that could result in the event listener stream being terminated when an exception occurred within an event listener. Errors in event listeners are now not propagated anymore but handled by the backend and logged instead.

References: litestar-org/litestar#2810,, litestar-org/litestar#2814

Fix OpenAPI schema for Pydantic computed fields#

2.4.1#

Released: 2023/11/28

Bugfixes#

Fix circular import when importing from litestar.security.jwt# Raise config error when generator dependencies are cached#

2.4.0#

Released: 2023/11/27

Features#

Add server_lifespan hook#

A new server_lifespan hook is now available on Litestar. This hook works similar to the regular lifespan context manager, with the difference being is that it is only called once for the entire server lifespan, not for each application startup phase. Note that these only differ when running with an ASGI server that’s using multiple worker processes.

References: litestar-org/litestar#2658

Allow rendering templates directly from strings# Support nested DTO field renaming#

Using similar semantics as for exclusion/inclusion, nested DTO fields can now also be renamed:

from dataclasses import dataclass @dataclass class Bar: id: str @dataclass class Foo: id: str bars: list[Bar] FooDTO = DataclassDTO[Annotated[Foo, DTOConfig(rename_fields={"bars.0.id": "bar_id"})]]

References: litestar-org/litestar#2721, litestar-org/litestar#2764

Bugfixes#

Fix HTTPException handling during concurrent dependency resolving# Fix OpenAPI examples format#

Fix the OpenAPI examples format by removing the wrapping object.

Before the change, for a given model

@dataclass class Foo: foo: int

The following example would be generated:

{ "description": "Example value", "value": { "foo": 7906 } }

After the fix, this is now:

References: litestar-org/litestar#2272, litestar-org/litestar#2660

Fix CLI plugin commands not showing up in command list#

Fix a bug where commands registered by CLI plugins were available, but would not show up in the commands list

References: litestar-org/litestar#2441

Fix missing write-only mark in dto_field() signature# Fix OpenAPI schemas incorrectly flagged as duplicates# Fix Pydantic URL type support in OpenAPI and serialization#

Add missing support for Pydantic’s URL types (AnyUrl and its descendants) for both serialization and OpenAPI schema generation. These types were only partially supported previously; Serialization support was lacking for v1 and v2, and OpenAPI support was missing for v2.

References: litestar-org/litestar#2664, litestar-org/litestar#2701

Fix incorrect ValidationException message when multiple errors were encountered# Fix DTO renaming renames all fields of the same name in nested DTOs#

Fix an issue with nested field renaming in DTOs that would lead to all fields with a given name to be renamed in a nested structure.

In the below example, both Foo.id and Bar.id would have been renamed to foo_id

from dataclasses import dataclass @dataclass class Bar: id: str @dataclass class Foo: id: str bar: Bar FooDTO = DataclassDTO[Annotated[Foo, DTOConfig(rename_fields={"id": "foo_id"})]]

References: litestar-org/litestar#2721, litestar-org/litestar#2764

Fix handling of DTO objects nested in mappings# Fix inconsistent sequence union parameter errors# Fix graceful handling of WebSocket disconnect in channels WebSockets handlers#

Fix the behaviour of WebSocket disconnect handling within the WebSocket handlers provided by channels, that would sometimes lead to a RuntimeError: Unexpected ASGI message 'websocket.close', after sending 'websocket.close'. exception being raised upon the closing of a WebSocket connection.

References: litestar-org/litestar#2691

2.3.2#

Released: 2023/11/06

Bugfixes#

Fix recursion error when re-using the path of a route handler for static files#

A regression was fixed that would cause a recursion error when the path of a static files host was reused for a route handler with a different HTTP method.

from litestar import Litestar from litestar import post from litestar.static_files import StaticFilesConfig @post("/uploads") async def handler() -> None: pass app = Litestar( [handler], static_files_config=[ StaticFilesConfig(directories=["uploads"], path="/uploads"), ], )

References: litestar-org/litestar#2629, litestar-org/litestar#2630

2.3.1#

Released: 2023/11/04

Bugfixes#

CLI: Fix not providing SSL certfiles breaks uvicorn command when using reload or multiple workers#

2.3.0#

Released: 2023/11/02

Features#

Python 3.12 support# New layered parameter signature_types#

Types in this collection are added to signature_namespace using the type’s __name__ attribute. This provides a nicer interface when adding names to the signature namespace w ithout modifying the type name, e.g.: signature_namespace={"Model": Model} is equivalent to signature_types=[Model].

The implementation makes it an error to supply a type in signature_types that has a value for __name__ already in the signature namespace.

It will also throw an error if an item in signature_types has no __name__ attribute.

References: litestar-org/litestar#2422

Added RapiDoc for OpenAPI schema visualisation# Support Pydantic 1 & 2 within the same application#

Added support for Pydantic 1 & 2 within the same application by integrating with Pydantic’s backwards compatibility layer:

from litestar import get from pydantic.v1 import BaseModel as BaseModelV1 from pydantic import BaseModel class V1Foo(BaseModelV1): bar: str class V2Foo(BaseModel): bar: str @get("/1") def foo_v1(data: V1Foo) -> V1Foo: return data @get("/2") def foo_v2(data: V2Foo) -> V2Foo: return data

References: litestar-org/litestar#2487

Add ResponseCacheConfig.cache_response_filter to allow filtering responses eligible for caching# SSL support and self-signed certificates for CLI#

Add support for SSL and generating self-signed certificates to the CLI.

For this, three new arguments were added to the CLI’s run command:

  • --ssl-certfile

  • --ssl-keyfile

  • --create-self-signed-cert

The --ssl-certfile and –ssl-keyfile flags are passed to uvicorn when using litestar run. Uvicorn requires both to be passed (or neither) but additional validation was added to generate a more user friendly CLI errors.

The other SSL-related flags (like password or CA) were not added (yet). See uvicorn CLI docs

Generating of a self-signed certificate

One more CLI flag was added (--create-devcert) that uses the cryptography module to generate a self-signed development certificate. Both of the previous flags must be passed when using this flag. Then the following logic is used:

  • If both files already exists, they are used and nothing is generated

  • If neither file exists, the dev cert and key are generated

  • If only one file exists, it is ambiguous what to do so an exception is raised

References: litestar-org/litestar#2335, litestar-org/litestar#2554

Bugfixes#

Use custom request class when given during exception handling# Fix missing OpenAPI schema for generic response type annotations#

OpenAPI schemas are now correctly generated when a response type annotation contains a generic type such as

Python 3.8+

from msgspec import Struct from litestar import get, Response from typing import TypeVar, Generic, Optional T = TypeVar("T") class ResponseStruct(Struct, Generic[T]): code: int data: Optional[T] @get("/") def test_handler() -> Response[ResponseStruct[str]]: return Response( ResponseStruct(code=200, data="Hello World"), )

Python 3.10+

from msgspec import Struct from litestar import get, Response from typing import TypeVar, Generic T = TypeVar("T") class ResponseStruct(Struct, Generic[T]): code: int data: T | None @get("/") def test_handler() -> Response[ResponseStruct[str]]: return Response( ResponseStruct(code=200, data="Hello World"), )

References: litestar-org/litestar#2383, litestar-org/litestar#2463

Fix rendering of OpenAPI examples#

An issue was fixed where OpenAPI examples would be rendered as

{ "parameters": [ { "schema": { "type": "string", "examples": [ { "summary": "example summary", "value": "example value" } ] } } ] }

instead of

{ "parameters": [ { "schema": { "type": "string" }, "examples": { "example1": { "summary": "example summary" "value": "example value" } } } ] }

References: litestar-org/litestar#2494, litestar-org/litestar#2509

Fix non UTF-8 handling when logging requests#

When structlog is not installed, the request body would not get parsed and shown as a byte sequence. Instead, it was serialized into a string with the assumption that it is valid UTF-8. This was fixed by decoding the bytes with backslashreplace before displaying them.

References: litestar-org/litestar#2529, litestar-org/litestar#2530

Fix ExceptionHandler typing to properly support Exception subclasses#

Fix the typing for ExceptionHandler to support subclasses of Exception, such that code like this will type check properly:

from litestar import Request, Response class CustomException(Exception): ... def handle_exc(req: Request, exc: CustomException) -> Response: ...

References: litestar-org/litestar#2520, litestar-org/litestar#2533

Fix OpenAPI schema generation for variable length tuples# Fix channels performance issue when polling with no subscribers in arbitrary_channels_allowed mode#

Fix a bug that would cause high CPU loads while idling when using a ChannelsPlugin with the arbitrary_channels_allowed enabled and while no subscriptions for any channel were active.

References: litestar-org/litestar#2547

Fix CLI schema export for non-serializable types when using create_examples=True#

When trying to export a schema via the litestar schema openapi --output schema.json making use of a non-JSON serializable type, would result in an encoding error because the standard library JSON serializer was used. This has been fixed by using Litestar’s own JSON encoder, enabling the serialization of all types supplied by the schema.

References: litestar-org/litestar#2575, litestar-org/litestar#2581

Fix OpenAPI schema generation for Literal and Enum unions with None#

Existing behavior was to make the schema for every type that is a union with None a "one_of" schema, that includes OpenAPIType.NULL in the "one_of" types.

When a Literal or Enum type is in a union with None, this behavior is not desirable, as we want to have null available in the list of available options on the type’s schema.

This was fixed by modifying Literal and Enum schema generation so that i t can be identified that the types are in a union with None, allowing null to be included in Schema.enum values.

References: litestar-org/litestar#2546, litestar-org/litestar#2550

Fix cache overrides when using same route with different handlers#

2.2.0#

Released: 2023/10/12

Features#

CLI enabled by default#

The CLI and all its dependencies are now included by default, to enable a better and more consistent developer experience out of the box.

The previous litestar[cli] extra is still available for backwards compatibility, but as of 2.2.0 it is without effect.

References: litestar-org/litestar#2318, litestar-org/litestar#2346

Customization of Pydantic integration via PydanticPlugin#

A new PydanticPlugin has been added, which can be used to configure Pydantic behaviour. Currently it supports setting a prefer_alias option, which will pass the by_alias=True flag to Pydantic when exporting models, as well as generate schemas accordingly.

References: litestar-org/litestar#2373, litestar-org/litestar#2404

Add /schema/openapi.yml to the available schema paths#

The YAML version of the OpenAPI schema is now available under /schema/openapi.yml in addition to /schema/openapi.yaml.

References: litestar-org/litestar#2411

Add experimental DTO codegen backend#

A new DTO backend was introduced which speeds up the transfer process by generating optimized Python code ahead of time. Testing shows that the new backend is between 2.5 and 5 times faster depending on the operation and data provided.

The new backend can be enabled globally for all DTOs by passing the appropriate feature flag to the Litestar application:

from litestar import Litestar from litestar.config.app import ExperimentalFeatures app = Litestar(experimental_features=[ExperimentalFeatures.DTO_CODEGEN])

References: litestar-org/litestar#2388

Improved error messages for missing required parameters#

Error messages for missing required parameters will now also contain the source of the expected parameter:

Before:

{ "status_code": 400, "detail": "Missing required parameter foo for url http://testerver.local" }

After:

{ "status_code": 400, "detail": "Missing required header parameter 'foo' for url http://testerver.local" }

References: litestar-org/litestar#2418

Bugfixes#

Fix implicit conversion of objects to bool in debug response# Correctly re-export filters and exceptions from advanced-alchemy#

Some re-exports of filter and exception types from advanced-alchemy were missing, causing various issues when advanced-alchemy was installed, but Litestar would still use its own version of these classes.

References: litestar-org/litestar#2358, litestar-org/litestar#2360

Re-add create_engine method to SQLAlchemy configs#

The create_engine method was removed in an advanced-alchemy releases. This was addresses by re-adding it to the versions provided by Litestar.

References: litestar-org/litestar#2382

Fix before_request modifies route handler signature#

The before_request would modify the return annotation of associated route handlers to conform with its own return type annotation, which would cause issues and unexpected behaviour when that annotation was not compatible with the original one.

This was fixed by not having the before_request handler modify the route handler’s signature. Users are now expected to ensure that values returned from a before_request handler conform to the return type annotation of the route handler.

References: litestar-org/litestar#2368, litestar-org/litestar#2391

Ensure compression is applied before caching when using compression middleware#

A previous limitation was removed that would apply compression from the CompressionMiddleware only after a response was restored from the cache, resulting in unnecessary repeated computation and increased size of the stored response.

This was due to caching being handled on the response layer, where a response object would be pickled, restored upon a cache hit and then re-sent, including all middlewares.

The new implementation now instead applies caching on the ASGI level; Individual messages sent to the send callable are cached, and later re-sent. This process ensures that the compression middleware has been applied before, and will be skipped when re-sending a cached response.

In addition, this increases performance and reduces storage size even in cases where no compression is applied because the slow and inefficient pickle format can be avoided.

References: litestar-org/litestar#1301, litestar-org/litestar#2393

Fix implicit JSON parsing of URL encoded data#

A process was removed where Litestar would implicitly attempt to parse parts of URL encoded data as JSON. This was originally added to provide some performance boosts when that data was in fact meant to be JSON, but turned out to be too fragile.

Regular data conversion / validation is unaffected by this.

References: litestar-org/litestar#2394

2.1.1#

Released: 2023/09/24

Bugfixes#

Fix DeprecationWarning raised by Response.to_asgi_response#

2.1.0#

Released: 2023/09/23

View the full changelog

Features#

Make 302 the default status_code for redirect responses# Add include_in_schema() option for all layers# Deprecate parameter app of Response.to_asgi_response# Authentication: Add parameters to set the JWT extras field# Templating: Add possibility to customize Jinja environment# Add support for minjinja# SQLAlchemy: Exclude implicit fields for SQLAlchemy DTO#

SQLAlchemyDTO (Advanced Alchemy) can now be configured using a separate config object. This can be set using both class inheritance and Annotated:

class MyModelDTO(SQLAlchemyDTO[MyModel]): config = SQLAlchemyDTOConfig()

or

MyModelDTO = SQLAlchemyDTO[Annotated[MyModel, SQLAlchemyDTOConfig()]]

The new configuration currently accepts a single attribute which is include_implicit_fields that has a default value of True. If set to to False, all implicitly mapped columns will be hidden from the DTO. If set to hybrid-only, then hybrid properties will be shown but not other implicit columns.

Finally, implicit columns that are marked with Mark.READ_ONLY or Mark.WRITE_ONLY will always be shown regardless of the value of include_implicit_fields.

References: litestar-org/litestar#2170

SQLAlchemy: Allow repository functions to be filtered by expressions#

Enhances the SQLALchemy repository so that you can more easily pass in complex where expressions into the repository functions.

Tip

Without this, you have to override the statement parameter and it separates the where conditions from the filters and the kwargs.

Allows usage of this syntax:

locations, total_count = await model_service.list_and_count( ST_DWithin(UniqueLocation.location, geog, 1000), account_id=str(account_id) )

instead of the previous method of overriding the statement:

locations, total_count = await model_service.list_and_count( statement=select(Model).where(ST_DWithin(UniqueLocation.location, geog, 1000)), account_id=str(account_id), )

References: litestar-org/litestar#2265

SQLAlchemy: Use lambda_stmt in the repository# SQLAlchemy: Swap to the advanced_alchemy implementations#

Bugfixes#

Remove usages of deprecated ExceptionHandlerMiddleware debug parameter# DTOs: Raise ValidationException when Pydantic validation fails# Set the max width of the console to 80# Handling of optional path parameters# Use os.replace instead of shutil.move for renaming files# Exception detail attribute# Filters not available in exists()# Add Pydantic types to SQLAlchemy registry only if Pydantic is installed# Don’t add content type for responses that don’t have a body# SQLAlchemyPlugin refactored#

Changes the way the SQLAlchemyPlugin to now append the other plugins instead of the inheritance that was previously used. This makes using the plugins.get function work as expected.

References: litestar-org/litestar#2269

Ensure app-dir is appended to path during autodiscovery# Set content length header by default# Incorrect handling of mutable headers in ASGIResponse#

Update ASGIResponse, Response and friends to address a few issues related to headers:

  • If encoded_headers were passed in at any point, they were mutated within responses, leading to a growing list of headers with every response

  • While mutating encoded_headers, the checks performed to assert a value was (not) already present, headers were not treated case-insensitive

  • Unnecessary work was performed while converting cookies / headers into an encoded headers list

This was fixed by:

  • Removing the use of and deprecate encoded_headers

  • Handling headers on ASGIResponse with MutableScopeHeaders, which allows for case-insensitive membership tests, .setdefault operations, etc.

References: litestar-org/litestar#2196, litestar-org/litestar#2308

Adds missing ORM registry export# Discrepancy in attrs, msgspec and Pydantic for multi-part forms# Set proper default for exclude_http_methods in auth middleware#

2.0.0#

Released: 2023/08/19

Bugfixes#

Regression | Missing media_type information to error responses# Regression | Litestar.debug does not propagate to exception handling middleware# Static files not being served if a route handler with the same base path was registered#

Fixed a bug that would result in a 404 - Not Found when requesting a static file where the path was also used by a route handler.

References: litestar-org/litestar#2154

HTMX: Missing default values for receive and send parameters of HTMXRequest# DTO: Excluded attributes accessed during transfer#

Fix the behaviour of DTOs such that they will no longer access fields that have been included. This behaviour would previously cause issues when these attributes were either costly or impossible to access (e.g. lazy loaded relationships of a SQLAlchemy model).

References: litestar-org/litestar#2125, litestar-org/litestar#2127

DTO | Regression: DTOData.create_instance ignores renaming# OpenAPI | Regression: Response schema for files and streams set application/octet-stream as contentEncoding instead of contentMediaType#

Fix a regression that would set application/octet-stream as the contentEncoding instead of contentMediaType in the response schema of File Stream.

References: litestar-org/litestar#2130

OpenAPI | Regression: Response schema diverges from prefer_alias setting for Pydantic models#

Fix a regression that made the response schema use prefer_alias=True, diverging from how Pydantic models are exported by default.

References: litestar-org/litestar#2150

OpenAPI | Regression: Examples not being generated deterministically#

Fix a regression that made generated examples non-deterministic, caused by a misconfiguration of the random seeding.

References: litestar-org/litestar#2161

SQLAlchemy repository: Handling of dialects not supporting JSON# JWT | Regression: OPTIONS and HEAD being authenticated by default#

Fix a regression that would make litestar.contrib.jwt.JWTAuthenticationMiddleware authenticate OPTIONS and HEAD requests by default.

References: litestar-org/litestar#2160

SessionAuth | Regression: OPTIONS and HEAD being authenticated by default#

2.0.0rc1#

Released: 2023/08/05

Features#

Support for server-sent-events#

Support for Server-sent events <https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events> has been added with the ServerSentEvent:

async def my_generator() -> AsyncGenerator[bytes, None]: count = 0 while count < 10: await sleep(0.01) count += 1 yield str(count) @get(path="/count") def sse_handler() -> ServerSentEvent: return ServerSentEvent(my_generator())

References: litestar-org/litestar#1185, litestar-org/litestar#2035

SQLAlchemy repository: allow specifying id_attribute per method#

The following methods now accept an id_attribute argument, allowing to specify an alternative value to the models primary key:

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.delete

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.delete_many

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.get

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.update

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.delete

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.delete_many

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.get

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.update

References: litestar-org/litestar#2052

SQLAlchemy repository: New upsert_many method#

A new method upsert_many has been added to the SQLAlchemy repositories, providing equivalent functionality to the upsert method for multiple model instances.

See also

~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.upsert_many ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.upsert_many

References: litestar-org/litestar#2056

SQLAlchemy repository: New filters: OnBeforeAfter, NotInCollectionFilter and NotInSearchFilter#

The following filters have been added to the SQLAlchemy repositories:

litestar.contrib.repository.filters.OnBeforeAfter

litestar.contrib.repository.filters.NotInCollectionFilter

Allowing to filter using a WHERE ... NOT IN (...) clause

litestar.contrib.repository.filters.NotInSearchFilter

Allowing to filter using a WHERE field_name NOT LIKE ‘%’ || :value || ‘%’` clause

References: litestar-org/litestar#2057

SQLAlchemy repository: Configurable chunk sizing for delete_many#

The repository now accepts a chunk_size parameter, determining the maximum amount of parameters in an IN statement before it gets chunked.

This is currently only used in the delete_many method.

References: litestar-org/litestar#2061

SQLAlchemy repository: Support InstrumentedAttribute for attribute columns#

Support InstrumentedAttribute for in the repository’s id_attribute, and the following methods:

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.delete

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.delete_many

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.get

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.update

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.delete

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.delete_many

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.get

  • ~litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository.update

References: litestar-org/litestar#2054

OpenAPI: Support callable operation_id on route handlers#

Route handlers may be passed a callable to operation_id to create the OpenAPI operation ID.

References: litestar-org/litestar#2078

Run event listeners concurrently# Support extending the CLI with plugins#

Bugfixes#

DTO: Support renamed fields in DTOData and create_instance# SQLAlchemy repository: Fix health_check for oracle# Fix serialization of empty strings in multipart form#

A bug was fixed that would cause a validation error to be raised for empty strings during multipart form decoding.

References: litestar-org/litestar#2044

Other changes#

Use debug mode by default in test clients# Removal of deprecated partial module#breaking Removal of deprecated dto/factory module#breaking Removal of deprecated contrib/msgspec module#breaking

2.0.0beta4#

Released: 2023/07/21

Bugfixes#

Fix extra package dependencies#

2.0.0beta3#

Released: 2023/07/20

Features#

SQLAlchemyDTO (Advanced Alchemy): column/relationship type inference#

If type annotations aren’t available for a given column/relationship, they may be inferred from the mapped object.

For columns, the type‘s python_type will be used as the type of the column, and the nullable property to determine if the field should have a None union.

For relationships, where the RelationshipProperty.direction is ONETOMANY or MANYTOMANY, RelationshipProperty.collection_class and RelationshipProperty.mapper.class_ are used to construct an annotation for the collection.

For one-to-one relationships, RelationshipProperty.mapper.class_ is used to get the type annotation, and will be made a union with None if all of the foreign key columns are nullable.

References: litestar-org/litestar#1853, litestar-org/litestar#1879

DTO: Piccolo ORM# OpenAPI: Allow setting OpenAPIController.path from `OpenAPIConfig# SQLAlchemy repository: auto_commit, auto_expunge and auto_refresh options#

Three new parameters have been added to the repository and various methods:

auto_commit

When this True, the session will commit() instead of flush() before returning.

Available in:

  • ~SQLAlchemyAsyncRepository.add

  • ~SQLAlchemyAsyncRepository.add_many

  • ~SQLAlchemyAsyncRepository.delete

  • ~SQLAlchemyAsyncRepository.delete_many

  • ~SQLAlchemyAsyncRepository.get_or_create

  • ~SQLAlchemyAsyncRepository.update

  • ~SQLAlchemyAsyncRepository.update_many

  • ~SQLAlchemyAsyncRepository.upsert

(and their sync equivalents)

auto_refresh

When True, the session will execute refresh() objects before returning.

Available in:

  • ~SQLAlchemyAsyncRepository.add

  • ~SQLAlchemyAsyncRepository.get_or_create

  • ~SQLAlchemyAsyncRepository.update

  • ~SQLAlchemyAsyncRepository.upsert

(and their sync equivalents)

auto_expunge

When this is True, the session will execute expunge() all objects before returning.

Available in:

  • ~SQLAlchemyAsyncRepository.add

  • ~SQLAlchemyAsyncRepository.add_many

  • ~SQLAlchemyAsyncRepository.delete

  • ~SQLAlchemyAsyncRepository.delete_many

  • ~SQLAlchemyAsyncRepository.get

  • ~SQLAlchemyAsyncRepository.get_one

  • ~SQLAlchemyAsyncRepository.get_one_or_none

  • ~SQLAlchemyAsyncRepository.get_or_create

  • ~SQLAlchemyAsyncRepository.update

  • ~SQLAlchemyAsyncRepository.update_many

  • ~SQLAlchemyAsyncRepository.list

  • ~SQLAlchemyAsyncRepository.upsert

(and their sync equivalents)

References: litestar-org/litestar#1900

Include path name in ImproperlyConfiguredException message for missing param types# DTO: New include parameter added to DTOConfig# Pydantic 2 support#

Bugfixes#

SQLAlchemy repository: Fix audit columns defaulting to app startup time#

A bug was fixed where ~litestar.contrib.sqlalchemy.base.AuditColumns.created_at and ~litestar.contrib.sqlalchemy.base.AuditColumns.updated_at would default to the datetime at initialization time, instead of the time of the update.

References: litestar-org/litestar#1894

SQLAlchemyDTO (Advanced Alchemy): Fix handling of Sequence with defaults#

Fixes handling of columns defined with Sequence default values.

The SQLAlchemy default value for a Column will be ignored when it is a Sequence object. This is because the SQLAlchemy sequence types represent server generated values, and there is no way for us to generate a reasonable default value for that field from it without making a database query, which is not possible deserialization.

References: litestar-org/litestar#1851, litestar-org/litestar#1883

Allow JSON as redirect response# DTO / OpenAPI: Fix detection of required fields for Pydantic and msgspec DTOs#

A bug was fixed that would lead to fields of a Pydantic model or msgspec Structs being marked as “not required” in the generated OpenAPI schema when used with DTOs.

References: litestar-org/litestar#1946

Other changes#

AbstractDTOFactory moved to dto.factory.base#breaking SQLAlchemy repository: Rename _sentinel column to sa_orm_sentinel#breaking

The _sentinel column of ~litestar.contrib.sqlalchemy.base.UUIDPrimaryKey has been renamed to sa_orm_sentinel, to support Spanner, which does not support tables starting with _.

References: litestar-org/litestar#1933

Replace Header, CacheControlHeader and ETag Pydantic models with dataclasses#breaking

As part of the removal of Pydantic as a hard dependency, the header models Header, CacheControlHeader and ETag have been replaced with dataclasses.

Note

Although marked breaking, this change should not affect usage unless you relied on these being Pydantic models in some way.

References: litestar-org/litestar#1917

Pydantic as an optional dependency#breaking

As of this release, Pydantic is no longer a required dependency of Litestar. It is still supported in the same capacity as before, but Litestar itself does not depend on it anymore in its internals.

References: litestar-org/litestar#1963

Deprecation of partial module#

The litestar.partial and litestar.partial.Partial have been deprecated and will be removed in a future release. Users are advised to upgrade to DTOs, making use of the DTOConfig option partial=True.

References: litestar-org/litestar#2002

2.0.0beta2#

Released: 2023/06/24

Features#

Support annotated-types# Increased verbosity of validation error response keys#breaking

The keys in validation error responses now include the full path to the field where the originated.

An optional source key has been added, signifying whether the value is from the body, a cookie, a header, or a query param.

before#

{ "status_code": 400, "detail": "Validation failed for POST http://localhost:8000/some-route", "extra": [ {"key": "int_param", "message": "value is not a valid integer"}, {"key": "int_header", "message": "value is not a valid integer"}, {"key": "int_cookie", "message": "value is not a valid integer"}, {"key": "my_value", "message": "value is not a valid integer"} ] }

after#

{ "status_code": 400, "detail": "Validation failed for POST http://localhost:8000/some-route", "extra": [ {"key": "child.my_value", "message": "value is not a valid integer", "source": "body"}, {"key": "int_param", "message": "value is not a valid integer", "source": "query"}, {"key": "int_header", "message": "value is not a valid integer", "source": "header"}, {"key": "int_cookie", "message": "value is not a valid integer", "source": "cookie"}, ] }

References: litestar-org/litestar#1774

TestClient default timeout#breaking SQLAlchemy DTO: Explicit error messages when type annotations for a column are missing#

Bugfixes#

Remove exception details from Internal Server Error responses# Pydantic v1 regex validation#

2.0.0beta1#

Released: 2023/06/16

Features#

Expose ParsedType as public API# Improved debugging capabilities#
  • A new pdb_on_exception parameter was added to Litestar. When set to True, Litestar will drop into a the Python debugger when an exception occurs. It defaults to None

  • When pdb_on_exception is None, setting the environment variable LITESTAR_PDB=1 can be used to enable this behaviour

  • When using the CLI, passing the --pdb flag to the run command will temporarily set the environment variable LITESTAR_PDB=1

References: litestar-org/litestar#1742

OpenAPI: Add operation_class argument to HTTP route handlers# OpenAPI: Support nested Literal annotations# CLI: Add --reload-dir option to run command#

A new --reload-dir option was added to the litestar run command. When used, --reload is implied, and the server will watch for changes in the given directory.

References: litestar-org/litestar#1689

Allow extra attributes on JWTs via extras attribute#

Add the litestar.contrib.jwt.Token.extras attribute, containing extra attributes found on the JWT.

References: litestar-org/litestar#1695

Add default modes for Websocket.iter_json and WebSocket.iter_data# SQLAlchemy repository: Synchronous repositories#

Add a new synchronous repository base class: litestar.contrib.sqlalchemy.repository.SQLAlchemySyncRepository, which offer the same functionality as its asynchronous counterpart while operating on a synchronous sqlalchemy.orm.Session.

References: litestar-org/litestar#1683

SQLAlchemy repository: Oracle Database support# SQLAlchemy repository: DuckDB support# SQLAlchemy repository: Google Spanner support# SQLAlchemy repository: JSON check constraint for Oracle Database#

When using the litestar.contrib.sqlalchemy.types.JsonB type with an Oracle Database engine, a JSON check constraint will be created for that column.

References: litestar-org/litestar#1780

SQLAlchemy repository: Remove created and updated columns#breaking

The created and updated columns have been superseded by created_at and updated_at respectively, to prevent name clashes.

References: litestar-org/litestar#1816

SQLAlchemy repository: Add timezone aware type#breaking

A new timezone aware type litestar.contrib.sqlalchemy.types.DateTimeUTC has been added, which enforces UTC timestamps stored in the database.

References: litestar-org/litestar#1816

SQLAlchemy repository: Exclude unloaded columns in to_dict#

When exporting models using the ~litestar.contrib.sqlalchemy.base.CommonTableAttributes.to_dict method, unloaded columns will now always be excluded. This prevents implicit I/O via lazy loading, and errors when using an asynchronous session.

References: litestar-org/litestar#1802

DTOs: Nested keyword arguments in .create_instance()# DTOs: Hybrid properties and association proxies in SQLAlchemyDTO (Advanced Alchemy)# DTOs: Transfer to generic collection types# DTOs: Data transfer for non-generic builtin collection annotations#

Non-parametrized generics in annotations (e.g. a: dict) will now be inferred as being parametrized with Any. a: dict is then equivalent to a: dict[Any, Any].

References: litestar-org/litestar#1799

DTOs: Exclude leading underscore fields by default#breaking DTOs: Msgspec and Pydantic DTO factory implementation#

Bugfixes#

Store and reuse state deep_copy directive when copying state#

App state can be created using deep_copy=False, however state would still be deep copied for dependency injection.

This was fixed memoizing the value of deep_copy when state is created, and reusing it on subsequent copies.

References: litestar-org/litestar#1674, litestar-org/litestar#1678

ParsedType.is_subclass_of(X) True for union if all union types are subtypes of X#

When ParsedType was introduced, is_subclass_of() any union was deliberately left to return False with the intention of waiting for some use-cases to arrive.

This behaviour was changed to address an issue where a handler may be typed to return a union of multiple response types; If all response types are Response subtypes then the correct response handler will now be applied.

References: litestar-org/litestar#1652, litestar-org/litestar#1690

Inconsistent template autoescape behavior# Missing ChannelsPlugin in signature namespace population# Gzip middleware not sending small streaming responses# Premature transfer to nested models with DTOData# Incorrect sync_to_thread usage warnings for generator dependencies# Dependency injection custom dependencies in WebSocketListener# OpenAPI schema for Dict[K, V] ignores generic#

An issue with the OpenAPI schema generation was fixed that would lead to generic arguments to dict being ignored.

An type like dict[str, int] now correctly renders as {"type": "object", "additionalProperties": { "type": "integer" }}.

References: litestar-org/litestar#1795, litestar-org/litestar#1828

WebSocketTestSession not timing out without when connection is not accepted# SQLAlchemy repository: Fix alembic migrations generated for models using GUID#

Migrations generated for models with a ~litestar.contrib.sqlalchemy.types.GUID type would erroneously add a length=16 on the input. Since this parameter is not defined in the type’s the __init__ method. This was fixed by adding the appropriate parameter to the type’s signature.

References: litestar-org/litestar#1676

Other changes#

DTOs: Arbitrary generic wrappers#

When a handler returns a type that is not supported by the DTO, but:

  • the return type is generic

  • it has a generic type argument that is supported by the dto

  • the type argument maps to an attribute on the return type

the DTO operations will be performed on the data retrieved from that attribute of the instance returned from the handler, and return the instance.

The constraints are:

  • the type returned from the handler must be a type that litestar can natively encode

  • the annotation of the attribute that holds the data must be a type that DTOs can otherwise manage

Python 3.8+

from dataclasses import dataclass from typing import Generic, List, TypeVar from typing_extensions import Annotated from litestar import Litestar, get from litestar.dto import DTOConfig from litestar.dto.factory.dataclass_factory import DataclassDTO @dataclass class User: name: str age: int T = TypeVar("T") V = TypeVar("V") @dataclass class Wrapped(Generic[T, V]): data: List[T] other: V @get(dto=DataclassDTO[Annotated[User, DTOConfig(exclude={"age"})]]) def handler() -> Wrapped[User, int]: return Wrapped( data=[User(name="John", age=42), User(name="Jane", age=43)], other=2, ) app = Litestar(route_handlers=[handler]) # GET "/": {"data": [{"name": "John"}, {"name": "Jane"}], "other": 2}

Python 3.9+

from dataclasses import dataclass from typing import Generic, TypeVar from typing import Annotated from litestar import Litestar, get from litestar.dto import DTOConfig from litestar.dto.factory.dataclass_factory import DataclassDTO @dataclass class User: name: str age: int T = TypeVar("T") V = TypeVar("V") @dataclass class Wrapped(Generic[T, V]): data: list[T] other: V @get(dto=DataclassDTO[Annotated[User, DTOConfig(exclude={"age"})]]) def handler() -> Wrapped[User, int]: return Wrapped( data=[User(name="John", age=42), User(name="Jane", age=43)], other=2, ) app = Litestar(route_handlers=[handler]) # GET "/": {"data": [{"name": "John"}, {"name": "Jane"}], "other": 2}

References: litestar-org/litestar#1631,, litestar-org/litestar#1798, litestar-org/litestar#1801

Remove state parameter from AfterExceptionHookHandler and BeforeMessageSendHookHandler#breaking

Remove the state parameter from AfterExceptionHookHandler and BeforeMessageSendHookHandler.

AfterExceptionHookHandlers will have to be updated from

async def after_exception_handler( exc: Exception, scope: Scope, state: State ) -> None: ...

to

async def after_exception_handler(exc: Exception, scope: Scope) -> None: ...

The state can still be accessed like so:

async def after_exception_handler(exc: Exception, scope: Scope) -> None: state = scope["app"].state

BeforeMessageSendHookHandlers will have to be updated from

async def before_send_hook_handler( message: Message, state: State, scope: Scope ) -> None: ...

to

async def before_send_hook_handler(message: Message, scope: Scope) -> None: ...

where state can be accessed in the same manner:

async def before_send_hook_handler(message: Message, scope: Scope) -> None: state = scope["app"].state

References: litestar-org/litestar#1739

Removal of dto.exceptions module#breaking

The module dto.exceptions has been removed, since it was not used anymore internally by the DTO implementations, and superseded by standard exceptions.

References: litestar-org/litestar#1773

BaseRouteHandler no longer generic#breaking Deprecation of Litestar parameter preferred_validation_backend#breaking

The following changes have been made regarding the preferred_validation_backend:

  • The preferred_validation_backend parameter of Litestar has been renamed to _preferred_validation_backend and deprecated. It will be removed completely in a future version.

  • The Litestar.preferred_validation_backend attribute has been made private

  • The preferred_validation_backend attribute has been removed from AppConfig

In addition, the logic for selecting a signature validation backend has been simplified as follows: If the preferred backend is set to attrs, or the signature contains attrs types, attrs is selected. In all other cases, Pydantic will be used.

References: litestar-org/litestar#1810

Response.get_serializer moved to serialization.get_serializer#breaking

The Response.get_serializer() method has been removed in favor of the get_serializer() function.

In the previous Response implementation, get_serializer() was called on the response inside the response’s __init__, and the merging of class-level type_encoders with the Response‘s type_encoders occurred inside its get_serializer method.

In the current version of Response, the response body is not encoded until after the response object has been returned from the handler, and it is converted into a low-level ASGIResponse object. Due to this, there is still opportunity for the handler layer resolved type_encoders object to be merged with the Response defined type_encoders, making the merge inside the Response no longer necessary.

In addition, the separate get_serializer function greatly simplifies the interaction between middlewares and serializers, allowing to retrieve one independently from a Response.

References: litestar-org/litestar#1820

Remove response containers and introduce ASGIResponse#breaking

Response Containers were wrapper classes used to indicate the type of response returned by a handler, for example File, Redirect, Template and Stream types. These types abstracted the interface of responses from the underlying response itself.

Response containers have been removed and their functionality largely merged with that of Response. The predefined response containers still exist functionally, as subclasses of Response and are now located within the litestar.response module. In addition to the functionality of Response containers, they now also feature all of the response’s functionality, such as methods to add headers and cookies.

The Response class now only serves as a wrapper and context object, and does not handle the data sending part, which has been delegated to a newly introduced ASGIResponse. This type (and its subclasses) represent the response as an immutable object and are used internally by Litestar to perform the I/O operations of the response. These can be created and returned from handlers like any other ASGI application, however they are low-level, and lack the utility of the higher-level response types.

References: litestar-org/litestar#1790

2.0.0alpha7#

Released: 2023/05/14

Features#

Warn about sync callables in route handlers and dependencies without an explicit sync_to_thread value#

A warning will now be raised when a synchronous callable is being used in an HTTPRouteHandler or Provide, without setting sync_to_thread. This is to ensure that synchronous callables are handled properly, and to prevent accidentally using callables which might block the main thread.

This warning can be turned off globally by setting the environment variable LITESTAR_WARN_IMPLICIT_SYNC_TO_THREAD=0.

References: litestar-org/litestar#1648, litestar-org/litestar#1655

Warn about sync_to_thread with async callables#

A warning will be raised when sync_to_thread is being used in HTTPRouteHandler or Provide with an asynchronous callable, as this will have no effect.

This warning can be turned off globally by setting the environment variable LITESTAR_WARN_SYNC_TO_THREAD_WITH_ASYNC=0.

References: litestar-org/litestar#1664

WebSockets: Dependencies in listener hooks#

Dependencies can now be used in the websocket_listener hooks on_accept, on_disconnect and the connection_lifespan context manager. The socket parameter is therefore also not mandatory anymore in those callables.

References: litestar-org/litestar#1647

Declaring dependencies without Provide# Add DTOData to receive unstructured but validated DTO data#

DTOData is a datastructure for interacting with DTO validated data in its unstructured form.

This utility is to support the case where the amount of data that is available from the client request is not complete enough to instantiate an instance of the model that would otherwise be injected.

References: litestar-org/litestar#1650

Partial DTOs#

Add a partial flag to DTOConfig, making all DTO fields options. Subsequently, any unset values will be filtered when extracting data from transfer models.

This allows for example to use a to handle PATCH requests more easily.

References: litestar-org/litestar#1651

SQLAlchemy repository: psycopg asyncio support# SQLAlchemy repository: BigIntPrimaryKey mixin#

~litestar.contrib.sqlalchemy.base.BigIntPrimaryKey mixin, providing a BigInt primary key column, with a fallback to Integer for sqlite.

References: litestar-org/litestar#1657

SQLAlchemy repository: Store GUIDs as binary on databases that don’t have a native GUID type#

On databases without native support for GUIDs, ~litestar.contrib.sqlalchemy.types.GUID will now fall back to BINARY(16).

References: litestar-org/litestar#1657

Application lifespan context managers#

A new lifespan argument has been added to Litestar, accepting an asynchronous context manager, wrapping the lifespan of the application. It will be entered with the startup phase and exited on shutdown, providing functionality equal to the on_startup and on_shutdown hooks.

References: litestar-org/litestar#1635

Unify application lifespan hooks: Remove before_ and after_#breaking

The following application lifespan hooks have been removed:

  • before_startup

  • after_startup

  • before_shutdown

  • after_shutdown

The remaining hooks on_startup and on_shutdown will now receive as their optional first argument the Litestar application instead of the application’s state.

References: litestar-org/litestar#1663

Trio-compatible event emitter# OpenAPI: Support msgspec.Meta# OpenAPI: Support Pydantic FieldInfo#

Bugfixes#

OpenAPI: Fix name collision in DTO models#

A bug was fixed that would lead to name collisions in the OpenAPI schema when using DTOs with the same class name. DTOs now include a short 8 byte random string in their generated name to prevent this.

References: litestar-org/litestar#1643, litestar-org/litestar#1649

Fix validated attrs model being injected as a dictionary# Validate unknown media types#breaking

2.0.0alpha6#

Released: 2023/05/09

Features#

Add connection_accept_handler to websocket_listener# Testing: Add block and timeout parameters to WebSocketTestSession receive methods# CLI: Add --app-dir option to root command#

The --app-dir option was added to the root CLI command, allowing to set the run applications from a path that’s not the current working directory.

References: litestar-org/litestar#1506

WebSockets: Data iterators# WebSockets: MessagePack support# SQLAlchemy repository: Add support for sentinel column#

This change adds support for sentinel column feature added in sqlalchemy 2.0.10. Without it, there are certain cases where add_many raises an exception.

The _sentinel value added to the declarative base should be excluded from normal select operations automatically and is excluded in the to_dict methods.

References: litestar-org/litestar#1603

DTO: Alias generator for field names#

A new argument rename_strategy has been added to the DTOConfig, allowing to remap field names with strategies such as “camelize”.

References: litestar-org/litestar#1590

DTO: Nested field exclusion# WebSockets: Managing a socket’s lifespan using a context manager in websocket listeners#

Changes the way a socket’s lifespan - accepting the connection and calling the appropriate event hooks - to use a context manager.

The connection_lifespan argument was added to the WebSocketListener, which accepts an asynchronous context manager, which can be used to handle the lifespan of the socket.

References: litestar-org/litestar#1625

New module: Channels#

A new module channels has been added: A general purpose event streaming library, which can for example be used to broadcast messages via WebSockets.

References: litestar-org/litestar#1587

Bugfixes#

Relax typing of **kwargs in ASGIConnection.url_for# Fix: Using websocket_listener in controller causes TypeError#

Other changes#

DTO: Undocumented dto.factory.backends has been made private#breaking

2.0.0alpha5#

Features#

Pass template context to HTMX template response# OpenAPI support for attrs and msgspec classes# SQLAlchemy repository: Add ModelProtocol#

Add a new class contrib.sqlalchemy.base.ModelProtocol, serving as a generic model base type, allowing to specify custom base classes while preserving typing information

References: litestar-org/litestar#1503

SQLAlchemy repository: Support MySQL/MariaDB# SQLAlchemy repository: Support MySQL/MariaDB# SQLAlchemy repository: Add matching logic to get_or_create#

Add a match_fields argument to litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.get_or_create. This lets you lookup a model using a subset of the kwargs you’ve provided. If the remaining kwargs are different from the retrieved model’s stored values, an update is performed.

References: litestar-org/litestar#1345

Repository: Extend filter types#

Add new filters litestar.contrib.repository.filters.OrderBy and litestar.contrib.repository.filters.SearchFilter, providing ORDER BY ... and LIKE ... / ILIKE ... clauses respectively

References: litestar-org/litestar#1345

DTO: Add AbstractDTOFactory and backends#

An all-new DTO implementation was added, using AbstractDTOFactory as a base class, providing Pydantic and msgspec backends to facilitate (de)serialization and validation.

References: litestar-org/litestar#1461

WebSockets: Support DTOs in listeners# DTO based serialization plugin#breaking

SerializationPluginProtocol has been re-implemented, leveraging the new DTOInterface.

If a handler defines a plugin supported type as either the data kwarg type annotation, or as the return annotation for a handler function, and no DTO has otherwise been resolved to handle the type, the protocol creates a DTO implementation to represent that type which is then used to de-serialize into, and serialize from instances of that supported type.

Important

The Piccolo ORM and Tortoise ORM plugins have been removed by this change, but will be re-implemented using the new patterns in a future release leading up to the 2.0 release.

References: litestar-org/litestar#1501

Bugfixes#

Fix inconsistent parsing of unix timestamp between Pydantic and cattrs# Fix: Retrieve type hints from class with no __init__ method causes error# Fix error raised for partially installed attrs dependencies# Remove bool coercion in URL parsing#breaking

When defining a query parameter as param: str, and passing it a string value of "true", the value received by the route handler was the string "True", having been title cased. The same was true for the value of "false".

This has been fixed by removing the coercing of boolean-like values during URL parsing and leaving it up to the parsing utilities of the receiving side (i.e. the handler’s signature model) to handle these values according to the associated type annotations.

References: litestar-org/litestar#1547, litestar-org/litestar#1550

Fix missing content-encoding headers on gzip/brotli compressed files#

Other changes#

SQLAlchemy repository: Rename SQLAlchemyRepository > SQLAlchemyAsyncRepository#breaking

SQLAlchemyRepository has been renamed to litestar.contrib.sqlalchemy.repository.SQLAlchemyAsyncRepository.

References: litestar-org/litestar#1345

DTO: Remove from_connection / extend from_data#breaking

The method DTOInterface.from_connection has been removed and replaced by DTOInterface.from_bytes, which receives both the raw bytes from the connection, and the connection instance. Since from_bytes now does not handle connections anymore, it can also be a synchronous method, improving symmetry with DTOInterface.from_bytes.

The signature of from_data has been changed to also accept the connection, matching from_bytes’ signature.

As a result of these changes, DTOInterface.from_bytes no longer needs to receive the connection instance, so the request parameter has been dropped.

References: litestar-org/litestar#1500

SQLAlchemy 1 contrib module removed#breaking

As a result of the changes introduced in #1501, SQLAlchemy 1 support has been dropped.

Note

If you rely on SQLAlchemy 1, you can stick to Starlite 1.51 for now. In the future, a SQLAlchemy 1 plugin may be released as a standalone package.

References: litestar-org/litestar#1501

Change MissingDependencyException to be a subclass of ImportError# Update standard and full package extras#
  • Add SQLAlchemy, uvicorn, attrs and structlog to the full extra

  • Add uvicorn to the standard extra

  • Add uvicorn[standard] as an optional dependency to be used in the extras

References: litestar-org/litestar#1494

Remove support for declaring DTOs as handler types#breaking

Prior to this, a DTO type could be declared implicitly using type annotations. With the addition of the dto and return_dto parameters, this feature has become superfluous and, in the spirit of offering only one clear way of doing things, has been removed.

References: litestar-org/litestar#1534

DTO: Simplify DTOConfig#breaking
  • The include parameter has been removed, to provide a more accessible interface and avoid overly complex interplay with exclude and its support for dotted attributes

  • field_mapping has been renamed to rename_fields and support to remap field types has been dropped

  • experimental field_definitions has been removed. It may be replaced with a “ComputedField” in a future release that will allow multiple field definitions to be added to the model, and a callable that transforms them into a value for a model field. See

References: litestar-org/litestar#1580

2.0.0alpha4#

Features#

attrs and msgspec support in Partial# Annotated support for route handler and dependency annotations#

Annotated can now be used in route handler and dependencies to specify additional information about the fields.

@get("/") def index(param: int = Parameter(gt=5)) -> dict[str, int]: ...
@get("/") def index(param: Annotated[int, Parameter(gt=5)]) -> dict[str, int]: ...

References: litestar-org/litestar#1462

Bugfixes#

Support text/html Media-Type in Redirect response container# Fix global namespace for type resolution# Add uvicorn to cli extra# Update logging levels when setting Litestar.debug dynamically#

When passing debug=True to Litestar, the litestar logger would be set up in debug mode, but changing the debug attribute after the class had been instantiated did not update the logger accordingly.

This lead to a regression where the --debug flag to the CLI’s run command would no longer have the desired affect, as loggers would still be on the INFO level.

References: litestar-org/litestar#1476, litestar-org/litestar#1482

2.0.0alpha3#

Features#

SQLAlchemy 2.0 Plugin#

A SQLAlchemyInitPlugin was added, providing support for managed synchronous and asynchronous sessions.

References: litestar-org/litestar#1395

Attrs signature modelling# Support setting status codes in Redirect container#

Add support for manually setting status codes in the RedirectResponse response container. This was previously only possible by setting the status_code parameter on the corresponding route handler, making dynamic redirect status codes and conditional redirects using this container hard to implement.

References: litestar-org/litestar#1371, litestar-org/litestar#1412

Sentinel value to support caching responses indefinitely# Accept-header parsing and content negotiation# Enhanced WebSockets support#

Add a new set of features for handling WebSockets, including automatic connection handling, (de)serialization of incoming and outgoing data analogous to route handlers and OOP based event dispatching.

References: litestar-org/litestar#1402

Bugfixes#

SQLAlchemy 1 plugin mutates app state destructively#

When using the SQLAlchemy 1 plugin, repeatedly running through the application lifecycle (as done when testing an application not provided by a factory function), would result in a KeyError on the second pass.

This was caused be the plugin’s on_shutdown handler deleting the engine_app_state_key from the application’s state on application shutdown, but only adding it on application init.

This was fixed by adding performing the necessary setup actions on application startup rather than init.

References: litestar-org/litestar#1368, litestar-org/litestar#1391

Fix SQLAlchemy 1 Plugin - 'Request' object has no attribute 'dict'# Support OpenAPI schema generation with stringized return annotation#

The following code would result in non-specific and incorrect information being generated for the OpenAPI schema:

from __future__ import annotations from starlite import get @get("/") def hello_world() -> dict[str, str]: return {"hello": "world"}

This could be alleviated by removing from __future__ import annotations. Stringized annotations in any form are now fully supported.

References: litestar-org/litestar#1409, litestar-org/litestar#1410

Fix OpenAPI schema generation crashes for models with Annotated type attribute#

When using a model that includes a type annotation with typing.Annotated in a route handler, the interactive documentation would raise an error when accessed. This has been fixed and typing.Annotated is now fully supported.

References: litestar-org/litestar#1372, litestar-org/litestar#1400

Support empty data in RequestFactory#

Other changes#

create_test_client and crate_async_test_client signatures and docstrings to to match Litestar#

2.0.0alpha2#

Features#

Repository contrib & SQLAlchemy repository#

Add a a repository module to contrib, providing abstract base classes to implement the repository pattern. Also added was the contrib.repository.sqlalchemy module, implementing a SQLAlchemy repository, offering hand-tuned abstractions over commonly used tasks, such as handling of object sessions, inserting, updating and upserting individual models or collections.

References: litestar-org/litestar#1254

Data stores & registry#breaking

The starlite.storage module added in the previous version has been renamed starlite.stores to reduce ambiguity, and a new feature, the starlite.stores.registry.StoreRegistry has been introduced; It serves as a central place to manage stores and reduces the amount of configuration needed for various integrations.

  • Add stores kwarg to Starlite and AppConfig to allow seeding of the StoreRegistry

  • Add Starlite.stores attribute, containing a StoreRegistry

  • Change RateLimitMiddleware to use app.stores

  • Change request caching to use app.stores

  • Change server side sessions to use app.stores

  • Move starlite.config.cache.CacheConfig to starlite.config.response_cache.ResponseCacheConfig

  • Rename Starlite.cache_config > Starlite.response_cache_config

  • Rename AppConfig.cache_config > response_cache_config

  • Remove starlite/cache module

  • Remove ASGIConnection.cache property

  • Remove Starlite.cache attribute

Attention

starlite.middleware.rate_limit.RateLimitMiddleware, starlite.config.response_cache.ResponseCacheConfig, and starlite.middleware.session.server_side.ServerSideSessionConfig instead of accepting a storage argument that could be passed a Storage instance now have to be configured via the store attribute, accepting a string key for the store to be used from the registry. The store attribute has a unique default set, guaranteeing a unique starlite.stores.memory.MemoryStore instance is acquired for every one of them from the registry by default

References: litestar-org/litestar#1330

Add starlite.__version__#

Add a __version__ constant to the starlite namespace, containing a NamedTuple, holding information about the currently installed version of Starlite

References: litestar-org/litestar#1277

Add starlite version command to CLI#

Add a new version command to the CLI which displays the currently installed version of Starlite

References: litestar-org/litestar#1322

Enhance CLI autodiscovery logic#breaking

Update the CLI Autodiscovery to only consider canonical modules app and application, but every starlite.app.Starlite instance or application factory able to return a Starlite instance within those or one of their submodules, giving priority to the canonical names app and application for application objects and submodules containing them.

References: litestar-org/litestar#1322

Configurable exception logging and traceback truncation#

Add three new configuration options to starlite.logging.config.BaseLoggingConfig:

starlite.logging.config.LoggingConfig.log_exceptions

Configure when exceptions are logged.

always

Always log exceptions

debug

Log exceptions in debug mode only

never

Never log exception

starlite.logging.config.LoggingConfig.traceback_line_limit

Configure how many lines of tracback are logged

starlite.logging.config.LoggingConfig.exception_logging_handler

A callable that receives three parameters - the app.logger, the connection scope and the traceback list, and should handle logging

See also

starlite.logging.config.LoggingConfig

References: litestar-org/litestar#1296

Bugfixes#

Allow overwriting default OpenAPI response descriptions# Fix regression in path resolution that prevented 404’s being raised for false paths#breaking

Invalid paths within controllers would under specific circumstances not raise a 404. This was a regression compared to v1.51

Note

This has been marked as breaking since one user has reported to rely on this “feature”

References: litestar-org/litestar#1316

Fix after_request hook not being called on responses returned from handlers# Fix SQLAlchemyPlugin raises error when using SQLAlchemy UUID# Fix JSON.parse error in ReDoc and Swagger OpenAPI handlers#

The HTML generated by the ReDoc and Swagger OpenAPI handlers would cause JSON.parse to throw an error. This was fixed by removing the call to JSON.parse.

References: litestar-org/litestar#1363

Fix CLI prints application info twice#

Other changes#

Update SimpleEventEmitter to use worker pattern#

starlite.events.emitter.SimpleEventEmitter was updated to using an async worker, pulling emitted events from a queue and subsequently calling listeners. Previously listeners were called immediately, making the operation effectively “blocking”.

References: litestar-org/litestar#1346

Make BaseEventEmitterBackend.emit synchronous#breaking

starlite.events.emitter.BaseEventEmitterBackend, and subsequently starlite.events.emitter.SimpleEventEmitter and starlite.app.Starlite.emit have been changed to synchronous function, allowing them to easily be used within synchronous route handlers.

References: litestar-org/litestar#1376

Move 3rd party integration plugins to contrib#breaking Remove picologging dependency from the standard package extra#breaking

picologging has been removed form the standard package extra. If you have been previously relying on this, you need to change pip install starlite[standard] to pip install starlite[standard,picologging]

References: litestar-org/litestar#1313

Replace Starlite() initial_state keyword argument with state#breaking

The initial_state argument to starlite.app.Starlite has been replaced with a state keyword argument, accepting an optional starlite.datastructures.state.State instance.

Existing code using this keyword argument will need to be changed from

from starlite import Starlite app = Starlite(..., initial_state={"some": "key"})

to

from starlite import Starlite from starlite.datastructures.state import State app = Starlite(..., state=State({"some": "key"}))

References: litestar-org/litestar#1350

Remove support for 2 argument form of before_send#breaking

before_send hook handlers initially accepted 2 arguments, but support for a 3 argument form was added later on, accepting an additional scope parameter. Support for the 2 argument form has been dropped with this release.

References: litestar-org/litestar#1354

Standardize module exports#breaking

A large refactoring standardising the way submodules make their names available.

The following public modules have changed their location:

  • config.openapi > openapi.config

  • config.logging > logging.config

  • config.template > template.config

  • config.static_files > static_files.config

The following modules have been removed from the public namespace:

  • asgi

  • kwargs

  • middleware.utils

  • cli.utils

  • contrib.htmx.utils

  • handlers.utils

  • openapi.constants

  • openapi.enums

  • openapi.datastructures

  • openapi.parameters

  • openapi.path_item

  • openapi.request_body

  • openapi.responses

  • openapi.schema

  • openapi.typescript_converter

  • openapi.utils

  • multipart

  • parsers

  • signature

References: litestar-org/litestar#1273

2.0.0alpha1#

Features#

Validation of controller route handler methods#

Starlite will now validate that no duplicate handlers (that is, they have the same path and same method) exist.

References: litestar-org/litestar#1144

HTMX support# Alternate constructor Starlite.from_config#

starlite.app.Starlite.from_config was added to the starlite.app.Starlite class which allows to construct an instance from an starlite.config.app.AppConfig instance.

References: litestar-org/litestar#1190

Web concurrency option for CLI run command#

A --wc / –web-concurrency` option was added to the starlite run command, enabling users to specify the amount of worker processes to use. A corresponding environment variable WEB_CONCURRENCY was added as well

References: litestar-org/litestar#1218

Validation of state parameter in handler functions#

Type annotations of the reserved state parameter in handler functions will now be validated such that annotations using an unsupported type will raise a starlite.exceptions.ImproperlyConfiguredException.

References: litestar-org/litestar#1264

Generic application state#

starlite.connection.base.ASGIConnection and its subclasses are now generic on State which allow to to fully type hint a request as Request[UserType, AuthType, StateType].

References: litestar-org/litestar#1030

Dependency injection of classes#

Support using classes (not class instances, which were already supported) as dependency providers. With this, now every callable is supported as a dependency provider.

References: litestar-org/litestar#1143

Event bus#

A simple event bus system for Starlite, supporting synchronous and asynchronous listeners and emitters, providing a similar interface to handlers. It currently features a simple in-memory, process-local backend

References: litestar-org/litestar#1105

Unified storage interfaces#breaking

Storage backends for server-side sessions starlite.cache.Cache` have been unified and replaced by the starlite.storages, which implements generic asynchronous key/values stores backed by memory, the file system or redis.

Important

This is a breaking change and you need to change your session / cache configuration accordingly

References: litestar-org/litestar#1184

Bugfixes#

Fix resolving of relative paths in StaticFilesConfig# Fix --reload flag to starlite run not working correctly#

Passing the --reload flag to the starlite run command did not work correctly in all circumstances due to an issue with uvicorn. This was resolved by invoking uvicorn in a subprocess.

References: litestar-org/litestar#1191

Fix optional types generate incorrect OpenAPI schemas#

An optional query parameter was incorrectly represented as

{ "oneOf": [ { "type": null" }, { "oneOf": [] } ]}

References: litestar-org/litestar#1210

Fix LoggingMiddleware is sending obfuscated session id to client#

LoggingMiddleware would in some cases send obfuscated data to the client, due to a bug in the obfuscation function which obfuscated values in the input dictionary in-place.

References: litestar-org/litestar#1228

Fix missing domain configuration value for JWT cookie auth#

starlite.contrib.jwt.jwt_auth.JWTCookieAuth didn’t set the domain configuration value on the response cookie.

References: litestar-org/litestar#1223

Fix litestar-org/litestar#1201: Can not serve static file in / path# Fix litestar-org/litestar#1149: Middleware not excluding static path#

A middleware’s exclude parameter would sometimes not be honoured if the path was used to serve static files using StaticFilesConfig

References: litestar-org/litestar#1149

Other changes#

Relaxed type annotations#

Type annotations across the library have been relaxed to more generic forms, for example Iterable[str] instead of List[str] or Mapping[str, str] instead of Dict[str, str].

References: litestar-org/litestar#1140

type_encoders support in AbstractSecurityConfig#

type_encoders support has been added to starlite.security.base.AbstractSecurityConfig, enabling support for customized type_encoders for example in starlite.contrib.jwt.jwt_auth.JWTAuth.

References: litestar-org/litestar#1167

Renamed handler module names#breaking

The modules containing route handlers have been renamed to prevent ambiguity between module and handler names.

  • starlite.handlers.asgi > starlite.handlers.asgi_handlers

  • starlite.handlers.http > starlite.handlers.http_handlers

  • starlite.handlers.websocket > starlite.handlers.websocket_handlers

References: litestar-org/litestar#1170

New plugin protocols#breaking

The plugin protocol has been split into three distinct protocols, covering different use cases:

starlite.plugins.InitPluginProtocol

Hook into an application’s initialization process

starlite.plugins.SerializationPluginProtocol

Extend the serialization and deserialization capabilities of an application

starlite.plugins.OpenAPISchemaPluginProtocol

Extend OpenAPI schema generation

References: litestar-org/litestar#1176

Unify response headers and cookies#breaking

response headers and response cookies now have the same interface, along with the headers and cookies keyword arguments to starlite.response.Response. They each allow to pass either a :class:`Mapping[str, str] <typing.Mapping>, e.g. a dictionary, or a Sequence of starlite.datastructures.response_header.ResponseHeader or starlite.datastructures.cookie.Cookie respectively.

References: litestar-org/litestar#1209

Replace Pydantic models with dataclasses#breaking

Several Pydantic models used for configuration have been replaced with dataclasses or plain classes. This change should be mostly non-breaking, unless you relied on those configuration objects being Pydantic models. The changed models are:

  • starlite.config.allowed_hosts.AllowedHostsConfig

  • starlite.config.app.AppConfig

  • starlite.config.response_cache.ResponseCacheConfig

  • starlite.config.compression.CompressionConfig

  • starlite.config.cors.CORSConfig

  • starlite.config.csrf.CSRFConfig

  • starlite.logging.config.LoggingConfig

  • starlite.openapi.OpenAPIConfig

  • starlite.static_files.StaticFilesConfig

  • starlite.template.TemplateConfig

  • starlite.contrib.jwt.jwt_token.Token

  • starlite.contrib.jwt.jwt_auth.JWTAuth

  • starlite.contrib.jwt.jwt_auth.JWTCookieAuth

  • starlite.contrib.jwt.jwt_auth.OAuth2Login

  • starlite.contrib.jwt.jwt_auth.OAuth2PasswordBearerAuth

  • starlite.contrib.opentelemetry.OpenTelemetryConfig

  • starlite.middleware.logging.LoggingMiddlewareConfig

  • starlite.middleware.rate_limit.RateLimitConfig

  • starlite.middleware.session.base.BaseBackendConfig

  • starlite.middleware.session.client_side.CookieBackendConfig

  • starlite.middleware.session.server_side.ServerSideSessionConfig

  • starlite.response_containers.ResponseContainer

  • starlite.response_containers.File

  • starlite.response_containers.Redirect

  • starlite.response_containers.Stream

  • starlite.security.base.AbstractSecurityConfig

  • starlite.security.session_auth.SessionAuth

References: litestar-org/litestar#1242

SQLAlchemy plugin moved to contrib#breaking

The SQLAlchemyPlugin` has moved to ``starlite.contrib.sqlalchemy_1.plugin and will only be compatible with the SQLAlchemy 1.4 release line. The newer SQLAlchemy 2.x releases will be supported by the contrib.sqlalchemy module.

References: litestar-org/litestar#1252

Cleanup of the starlite namespace#breaking

The starlite namespace has been cleared up, removing many names from it, which now have to be imported from their respective submodules individually. This was both done to improve developer experience as well as reduce the time it takes to import starlite.

References: litestar-org/litestar#1135

Read Entire Article