From 19c490bbea0faf6ec25fba46603c26088c39ce96 Mon Sep 17 00:00:00 2001 From: cofin Date: Sun, 5 Jan 2025 01:14:13 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20litestar?= =?UTF-8?q?-org/litestar@da30d9f1e2e256d7d194f60c1db0d492d7e70d4b=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3803/.buildinfo | 2 +- .../admonitions/sync-to-thread-info.rst.txt | 7 +- 3803/_sources/index.rst.txt | 6 - 3803/_sources/reference/plugins/attrs.rst.txt | 5 + 3803/_sources/reference/plugins/htmx.rst.txt | 7 + 3803/_sources/reference/plugins/index.rst.txt | 4 + .../reference/plugins/prometheus.rst.txt | 5 + .../reference/plugins/pydantic.rst.txt | 5 + 3803/_sources/reference/stores/index.rst.txt | 1 + 3803/_sources/reference/stores/valkey.rst.txt | 5 + 3803/_sources/reference/testing.rst.txt | 2 +- 3803/_sources/reference/types.rst.txt | 12 +- 3803/_sources/release-notes/changelog.rst.txt | 110 + 3803/_sources/topics/sync-vs-async.rst.txt | 2 +- .../01-modeling-and-features.rst.txt | 1 + .../4-final-touches-and-recap.rst.txt | 2 +- .../plugins/sqlalchemy_init_plugin.rst.txt | 28 +- .../plugins/sqlalchemy_plugin.rst.txt | 10 +- 3803/_sources/usage/dto/0-basic-use.rst.txt | 87 +- .../_sources/usage/dto/1-abstract-dto.rst.txt | 36 +- 3803/_sources/usage/exceptions.rst.txt | 49 +- 3803/_sources/usage/htmx.rst.txt | 90 +- 3803/_sources/usage/lifecycle-hooks.rst.txt | 10 +- 3803/_sources/usage/logging.rst.txt | 2 + .../_sources/usage/metrics/prometheus.rst.txt | 6 +- .../middleware/builtin-middleware.rst.txt | 83 +- .../middleware/creating-middleware.rst.txt | 62 +- .../usage/middleware/using-middleware.rst.txt | 2 + 3803/_sources/usage/openapi/index.rst.txt | 12 +- 3803/_sources/usage/plugins/index.rst.txt | 6 +- 3803/_sources/usage/requests.rst.txt | 49 + 3803/_sources/usage/routing/handlers.rst.txt | 2 +- 3803/_sources/usage/routing/overview.rst.txt | 2 +- ...abstract-authentication-middleware.rst.txt | 2 +- 3803/_sources/usage/security/jwt.rst.txt | 2 +- 3803/_sources/usage/stores.rst.txt | 6 + 3803/_sources/usage/testing.rst.txt | 33 + 3803/_sources/usage/websockets.rst.txt | 192 +- 3803/admonitions/sync-to-thread-info.html | 11 +- 3803/benchmarks.html | 5 + 3803/contribution-guide.html | 154 +- 3803/genindex.html | 681 ++++-- 3803/index.html | 11 +- 3803/migration/fastapi.html | 5 + 3803/migration/flask.html | 5 + 3803/migration/index.html | 5 + 3803/objects.inv | Bin 58512 -> 60377 bytes 3803/py-modindex.html | 45 +- 3803/reference/app.html | 25 +- 3803/reference/background_tasks.html | 7 +- 3803/reference/channels/backends/asyncpg.html | 5 + 3803/reference/channels/backends/base.html | 5 + 3803/reference/channels/backends/index.html | 5 + 3803/reference/channels/backends/memory.html | 5 + 3803/reference/channels/backends/psycopg.html | 5 + 3803/reference/channels/backends/redis.html | 5 + 3803/reference/channels/index.html | 5 + 3803/reference/channels/plugin.html | 5 + 3803/reference/channels/subscriber.html | 5 + 3803/reference/cli.html | 5 + 3803/reference/concurrency.html | 57 +- 3803/reference/config.html | 57 +- 3803/reference/connection.html | 5 + 3803/reference/contrib/htmx.html | 306 +-- 3803/reference/contrib/index.html | 5 + 3803/reference/contrib/jinja.html | 5 + 3803/reference/contrib/jwt.html | 5 + 3803/reference/contrib/mako.html | 5 + 3803/reference/contrib/opentelemetry.html | 5 + 3803/reference/contrib/piccolo.html | 7 +- 3803/reference/contrib/pydantic.html | 307 +-- 3803/reference/contrib/repository/abc.html | 5 + .../contrib/repository/exceptions.html | 5 + .../reference/contrib/repository/filters.html | 5 + .../contrib/repository/handlers.html | 5 + .../reference/contrib/repository/testing.html | 5 + 3803/reference/contrib/sqlalchemy/base.html | 5 + 3803/reference/contrib/sqlalchemy/dto.html | 5 + 3803/reference/contrib/sqlalchemy/index.html | 5 + .../reference/contrib/sqlalchemy/plugins.html | 5 + .../contrib/sqlalchemy/repository.html | 5 + 3803/reference/contrib/sqlalchemy/types.html | 5 + 3803/reference/controller.html | 13 + 3803/reference/data_extractors.html | 5 + 3803/reference/datastructures/index.html | 360 +-- .../datastructures/secret_values.html | 5 + 3803/reference/di.html | 5 + 3803/reference/dto/base_dto.html | 5 + 3803/reference/dto/config.html | 5 + 3803/reference/dto/data_structures.html | 5 + 3803/reference/dto/dataclass_dto.html | 5 + 3803/reference/dto/field.html | 5 + 3803/reference/dto/index.html | 5 + 3803/reference/dto/msgspec_dto.html | 5 + 3803/reference/dto/types.html | 5 + 3803/reference/enums.html | 5 + 3803/reference/events.html | 87 +- 3803/reference/exceptions.html | 47 +- 3803/reference/handlers.html | 247 +- 3803/reference/index.html | 5 + 3803/reference/logging/config.html | 5 + 3803/reference/logging/index.html | 5 + 3803/reference/logging/picologging.html | 5 + 3803/reference/logging/standard.html | 5 + 3803/reference/middleware/allowed_hosts.html | 5 + 3803/reference/middleware/authentication.html | 11 +- 3803/reference/middleware/compression.html | 95 +- 3803/reference/middleware/cors.html | 5 + 3803/reference/middleware/csrf.html | 5 + 3803/reference/middleware/index.html | 9 +- 3803/reference/middleware/logging.html | 11 +- 3803/reference/middleware/rate_limit.html | 5 + 3803/reference/middleware/session/base.html | 5 + .../middleware/session/client_side.html | 5 + 3803/reference/middleware/session/index.html | 5 + .../middleware/session/server_side.html | 5 + 3803/reference/openapi/index.html | 5 + 3803/reference/openapi/openapi.html | 471 ++-- 3803/reference/openapi/plugins.html | 7 +- 3803/reference/openapi/spec.html | 143 +- 3803/reference/pagination.html | 5 + 3803/reference/params.html | 5 + 3803/reference/plugins/attrs.html | 1711 ++++++++++++++ 3803/reference/plugins/flash_messages.html | 17 +- 3803/reference/plugins/htmx.html | 2047 +++++++++++++++++ 3803/reference/plugins/index.html | 241 +- 3803/reference/plugins/problem_details.html | 17 +- 3803/reference/plugins/prometheus.html | 2021 ++++++++++++++++ 3803/reference/plugins/pydantic.html | 1938 ++++++++++++++++ 3803/reference/plugins/sqlalchemy.html | 5 + 3803/reference/plugins/structlog.html | 11 +- 3803/reference/repository/abc.html | 5 + 3803/reference/repository/exceptions.html | 5 + 3803/reference/repository/filters.html | 5 + 3803/reference/repository/handlers.html | 5 + 3803/reference/repository/index.html | 5 + 3803/reference/repository/testing.html | 5 + 3803/reference/response/base.html | 5 + 3803/reference/response/file.html | 7 +- 3803/reference/response/index.html | 8 +- 3803/reference/response/redirect.html | 8 +- 3803/reference/response/sse.html | 5 + 3803/reference/response/streaming.html | 5 + 3803/reference/response/template.html | 5 + 3803/reference/router.html | 9 +- 3803/reference/routes.html | 133 +- 3803/reference/security/index.html | 9 +- 3803/reference/security/jwt.html | 13 +- 3803/reference/security/session_auth.html | 11 +- 3803/reference/serialization.html | 43 +- 3803/reference/static_files.html | 7 +- 3803/reference/status_codes.html | 5 + 3803/reference/stores/base.html | 133 +- 3803/reference/stores/file.html | 5 + 3803/reference/stores/index.html | 38 +- 3803/reference/stores/memory.html | 5 + 3803/reference/stores/redis.html | 5 + 3803/reference/stores/registry.html | 11 +- 3803/reference/stores/valkey.html | 1792 +++++++++++++++ 3803/reference/template.html | 145 +- 3803/reference/testing.html | 855 +++---- 3803/reference/types.html | 48 +- 3803/reference/typing.html | 17 +- 3803/release-notes/changelog.html | 115 +- 3803/release-notes/index.html | 5 + 3803/release-notes/whats-new-2.html | 15 +- 3803/search.html | 15 +- 3803/searchindex.js | 2 +- 3803/topics/deployment/docker.html | 5 + 3803/topics/deployment/index.html | 5 + .../deployment/manually-with-asgi-server.html | 5 + 3803/topics/deployment/nginx-unit.html | 5 + 3803/topics/deployment/supervisor.html | 5 + 3803/topics/index.html | 5 + 3803/topics/sync-vs-async.html | 9 +- .../dto-tutorial/01-simple-dto-exclude.html | 5 + .../dto-tutorial/02-nested-exclude.html | 5 + .../03-nested-collection-exclude.html | 5 + .../dto-tutorial/04-max-nested-depth.html | 5 + .../dto-tutorial/05-renaming-fields.html | 5 + .../dto-tutorial/06-receiving-data.html | 5 + .../dto-tutorial/07-read-only-fields.html | 5 + 3803/tutorials/dto-tutorial/08-dto-data.html | 5 + 3803/tutorials/dto-tutorial/09-updating.html | 5 + .../10-layered-dto-declarations.html | 5 + 3803/tutorials/dto-tutorial/index.html | 5 + 3803/tutorials/index.html | 5 + .../01-modeling-and-features.html | 97 +- .../02-repository-introduction.html | 7 +- .../03-repository-controller.html | 5 + .../04-repository-other.html | 5 + 3803/tutorials/repository-tutorial/index.html | 5 + 3803/tutorials/sqlalchemy/0-introduction.html | 5 + .../sqlalchemy/1-provide-session-with-di.html | 5 + .../sqlalchemy/2-serialization-plugin.html | 5 + 3803/tutorials/sqlalchemy/3-init-plugin.html | 5 + .../sqlalchemy/4-final-touches-and-recap.html | 393 ++-- 3803/tutorials/sqlalchemy/index.html | 5 + .../todo-app/0-application-basics.html | 5 + .../todo-app/1-accessing-the-list.html | 5 + .../todo-app/2-interacting-with-the-list.html | 5 + .../todo-app/3-assembling-the-app.html | 5 + 3803/tutorials/todo-app/index.html | 5 + 3803/usage/applications.html | 27 +- 3803/usage/caching.html | 5 + 3803/usage/channels.html | 27 +- 3803/usage/cli.html | 9 +- 3803/usage/custom-types.html | 5 + 3803/usage/databases/index.html | 5 + 3803/usage/databases/piccolo.html | 5 + 3803/usage/databases/sqlalchemy/index.html | 5 + .../sqlalchemy/models_and_repository.html | 20 +- .../databases/sqlalchemy/plugins/index.html | 5 + .../plugins/sqlalchemy_init_plugin.html | 33 +- .../sqlalchemy/plugins/sqlalchemy_plugin.html | 15 +- .../sqlalchemy_serialization_plugin.html | 5 + 3803/usage/debugging.html | 5 + 3803/usage/dependency-injection.html | 11 +- 3803/usage/dto/0-basic-use.html | 57 +- 3803/usage/dto/1-abstract-dto.html | 131 +- .../dto/2-creating-custom-dto-classes.html | 5 + 3803/usage/dto/index.html | 22 +- 3803/usage/events.html | 5 + 3803/usage/exceptions.html | 80 +- 3803/usage/htmx.html | 103 +- 3803/usage/index.html | 5 + 3803/usage/lifecycle-hooks.html | 9 +- 3803/usage/logging.html | 7 +- 3803/usage/metrics/index.html | 5 + 3803/usage/metrics/open-telemetry.html | 5 + 3803/usage/metrics/prometheus.html | 17 +- 3803/usage/middleware/builtin-middleware.html | 54 +- .../usage/middleware/creating-middleware.html | 118 +- 3803/usage/middleware/index.html | 5 + 3803/usage/middleware/using-middleware.html | 23 +- 3803/usage/openapi/index.html | 17 +- 3803/usage/openapi/schema_generation.html | 5 + 3803/usage/openapi/ui_plugins.html | 7 +- 3803/usage/plugins/flash_messages.html | 5 + 3803/usage/plugins/index.html | 43 +- 3803/usage/plugins/problem_details.html | 5 + 3803/usage/requests.html | 54 + 3803/usage/responses.html | 5 + 3803/usage/routing/handlers.html | 13 +- 3803/usage/routing/index.html | 5 + 3803/usage/routing/overview.html | 7 +- 3803/usage/routing/parameters.html | 5 + .../abstract-authentication-middleware.html | 13 +- .../excluding-and-including-endpoints.html | 5 + 3803/usage/security/guards.html | 5 + 3803/usage/security/index.html | 5 + 3803/usage/security/jwt.html | 7 +- .../usage/security/secret-datastructures.html | 5 + 3803/usage/security/security-backends.html | 5 + 3803/usage/static-files.html | 5 + 3803/usage/stores.html | 10 + 3803/usage/templating.html | 5 + 3803/usage/testing.html | 220 +- 3803/usage/websockets.html | 552 ++++- 259 files changed, 15104 insertions(+), 3326 deletions(-) create mode 100644 3803/_sources/reference/plugins/attrs.rst.txt create mode 100644 3803/_sources/reference/plugins/htmx.rst.txt create mode 100644 3803/_sources/reference/plugins/prometheus.rst.txt create mode 100644 3803/_sources/reference/plugins/pydantic.rst.txt create mode 100644 3803/_sources/reference/stores/valkey.rst.txt create mode 100644 3803/reference/plugins/attrs.html create mode 100644 3803/reference/plugins/htmx.html create mode 100644 3803/reference/plugins/prometheus.html create mode 100644 3803/reference/plugins/pydantic.html create mode 100644 3803/reference/stores/valkey.html diff --git a/3803/.buildinfo b/3803/.buildinfo index 2f5557654..ef367cbf1 100644 --- a/3803/.buildinfo +++ b/3803/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: ab56542bf2c95d177c2041da7acd3746 +config: c4c876f80fdbc557678f6722246a88fc tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/3803/_sources/admonitions/sync-to-thread-info.rst.txt b/3803/_sources/admonitions/sync-to-thread-info.rst.txt index 6b13a0b06..fe9329aa5 100644 --- a/3803/_sources/admonitions/sync-to-thread-info.rst.txt +++ b/3803/_sources/admonitions/sync-to-thread-info.rst.txt @@ -7,8 +7,11 @@ running the event loop, and in turn block the whole application. To mitigate this, the ``sync_to_thread`` parameter can be set to ``True``, which - will result in the function being run in a thread pool. Should the function be - non-blocking, ``sync_to_thread`` should be set to ``False`` instead. + will result in the function being run in a thread pool. + + If a synchronous function is non-blocking, setting ``sync_to_thread`` to ``False`` + will tell Litestar that the user is sure about its behavior + and the function can be treated as non-blocking. If a synchronous function is passed, without setting an explicit ``sync_to_thread`` value, a warning will be raised. diff --git a/3803/_sources/index.rst.txt b/3803/_sources/index.rst.txt index 5fde378c9..5bea2e7dd 100644 --- a/3803/_sources/index.rst.txt +++ b/3803/_sources/index.rst.txt @@ -155,12 +155,6 @@ A huge thank you to our current sponsors:

Telemetry Sports

-
- - Stok - -

Stok

-
We invite organizations and individuals to join our sponsorship program. diff --git a/3803/_sources/reference/plugins/attrs.rst.txt b/3803/_sources/reference/plugins/attrs.rst.txt new file mode 100644 index 000000000..e3bcbb96c --- /dev/null +++ b/3803/_sources/reference/plugins/attrs.rst.txt @@ -0,0 +1,5 @@ +attrs +===== + +.. automodule:: litestar.plugins.attrs + :members: diff --git a/3803/_sources/reference/plugins/htmx.rst.txt b/3803/_sources/reference/plugins/htmx.rst.txt new file mode 100644 index 000000000..d13083ec7 --- /dev/null +++ b/3803/_sources/reference/plugins/htmx.rst.txt @@ -0,0 +1,7 @@ +==== +htmx +==== + + +.. automodule:: litestar.plugins.htmx + :members: diff --git a/3803/_sources/reference/plugins/index.rst.txt b/3803/_sources/reference/plugins/index.rst.txt index d3bdcecc5..69b006394 100644 --- a/3803/_sources/reference/plugins/index.rst.txt +++ b/3803/_sources/reference/plugins/index.rst.txt @@ -9,7 +9,11 @@ plugins :maxdepth: 1 :hidden: + attrs flash_messages + htmx problem_details + prometheus + pydantic structlog sqlalchemy diff --git a/3803/_sources/reference/plugins/prometheus.rst.txt b/3803/_sources/reference/plugins/prometheus.rst.txt new file mode 100644 index 000000000..c45052a9f --- /dev/null +++ b/3803/_sources/reference/plugins/prometheus.rst.txt @@ -0,0 +1,5 @@ +prometheus +========== + +.. automodule:: litestar.plugins.prometheus + :members: diff --git a/3803/_sources/reference/plugins/pydantic.rst.txt b/3803/_sources/reference/plugins/pydantic.rst.txt new file mode 100644 index 000000000..104e9ace7 --- /dev/null +++ b/3803/_sources/reference/plugins/pydantic.rst.txt @@ -0,0 +1,5 @@ +pydantic +======== + +.. automodule:: litestar.plugins.pydantic + :members: diff --git a/3803/_sources/reference/stores/index.rst.txt b/3803/_sources/reference/stores/index.rst.txt index 8123ba1da..23095869c 100644 --- a/3803/_sources/reference/stores/index.rst.txt +++ b/3803/_sources/reference/stores/index.rst.txt @@ -8,3 +8,4 @@ stores memory redis registry + valkey diff --git a/3803/_sources/reference/stores/valkey.rst.txt b/3803/_sources/reference/stores/valkey.rst.txt new file mode 100644 index 000000000..288118c2e --- /dev/null +++ b/3803/_sources/reference/stores/valkey.rst.txt @@ -0,0 +1,5 @@ +valkey +====== + +.. automodule:: litestar.stores.valkey + :members: diff --git a/3803/_sources/reference/testing.rst.txt b/3803/_sources/reference/testing.rst.txt index 85767df5b..ebc9bc104 100644 --- a/3803/_sources/reference/testing.rst.txt +++ b/3803/_sources/reference/testing.rst.txt @@ -3,7 +3,7 @@ testing .. automodule:: litestar.testing - :members: RequestFactory, BaseTestClient, TestClient, AsyncTestClient, create_async_test_client, create_test_client + :members: RequestFactory, BaseTestClient, TestClient, AsyncTestClient, create_async_test_client, create_test_client, subprocess_sync_client, subprocess_async_client :undoc-members: WebSocketTestSession diff --git a/3803/_sources/reference/types.rst.txt b/3803/_sources/reference/types.rst.txt index 52767a5d0..2cd000f64 100644 --- a/3803/_sources/reference/types.rst.txt +++ b/3803/_sources/reference/types.rst.txt @@ -1,7 +1,7 @@ types ===== -.. py:currentmodule:: litestar.types +.. module:: litestar.types @@ -58,15 +58,15 @@ ASGI Application Parameters ASGI Scopes ~~~~~~~~~~~~ -.. autodata:: litestar.types.ASGIVersion +.. autoclass:: litestar.types.ASGIVersion -.. autodata:: litestar.types.BaseScope +.. autoclass:: litestar.types.BaseScope -.. autodata:: litestar.types.HTTPScope +.. autoclass:: litestar.types.HTTPScope -.. autodata:: litestar.types.LifeSpanScope +.. autoclass:: litestar.types.LifeSpanScope -.. autodata:: litestar.types.WebSocketScope +.. autoclass:: litestar.types.WebSocketScope ASGI Events diff --git a/3803/_sources/release-notes/changelog.rst.txt b/3803/_sources/release-notes/changelog.rst.txt index 8a22693cb..5257fd1f3 100644 --- a/3803/_sources/release-notes/changelog.rst.txt +++ b/3803/_sources/release-notes/changelog.rst.txt @@ -4,6 +4,116 @@ ============= +.. changelog:: 2.13.0 + :date: 2024-11-20 + + .. change:: Add ``request_max_body_size`` layered parameter + :type: feature + + 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``. + + .. seealso:: + :ref:`usage/requests:limits` + + + .. change:: Send CSRF request header in OpenAPI plugins + :type: feature + :pr: 3754 + + Supported OpenAPI UI clients will extract the CSRF cookie value and attach it to + the request headers if CSRF is enabled on the application. + + .. change:: deprecate `litestar.contrib.sqlalchemy` + :type: feature + :pr: 3755 + + Deprecate the ``litestar.contrib.sqlalchemy`` module in favor of ``litestar.plugins.sqlalchemy`` + + + .. change:: implement `HTMX` plugin using `litestar-htmx` + :type: feature + :pr: 3837 + + This plugin migrates the HTMX integration to ``litestar.plugins.htmx``. + + This logic has been moved to it's own repository named ``litestar-htmx`` + + .. change:: Pydantic: honor ``hide_input_in_errors`` in throwing validation exceptions + :type: feature + :pr: 3843 + + Pydantic's ``BaseModel`` supports configuration to hide data values when + throwing exceptions, via setting ``hide_input_in_errors`` -- see + https://docs.pydantic.dev/2.0/api/config/#pydantic.config.ConfigDict.hide_input_in_errors + and https://docs.pydantic.dev/latest/usage/model_config/#hide-input-in-errors + + Litestar will now honour this setting + + .. change:: deprecate``litestar.contrib.pydantic`` + :type: feature + :pr: 3852 + :issue: 3787 + + ## Description + + Deprecate ``litestar.contrib.pydantic`` in favor of ``litestar.plugins.pydantic`` + + + .. change:: Fix sign bug in rate limit middelware + :type: bugfix + :pr: 3776 + + Fix a bug in the rate limit middleware, that would cause the response header + fields ``RateLimit-Remaining`` and ``RateLimit-Reset`` to have negative values. + + + .. change:: OpenAPI: map JSONSchema spec naming convention to snake_case when names from ``schema_extra`` are not found + :type: bugfix + :pr: 3767 + :issue: 3766 + + Address rejection of ``schema_extra`` values using JSONSchema spec-compliant + key names by mapping between the relevant naming conventions. + + .. change:: Use correct path template for routes without path parameters + :type: bugfix + :pr: 3784 + + Fix a but where, when using ``PrometheusConfig.group_path=True``, the metrics + exporter response content would ignore all paths with no path parameters. + + .. change:: Fix a dangling anyio stream in ``TestClient`` + :type: bugfix + :pr: 3836 + :issue: 3834 + + Fix a dangling anyio stream in ``TestClient`` that would cause a resource warning + + Closes #3834. + + .. change:: Fix bug in handling of missing ``more_body`` key in ASGI response + :type: bugfix + :pr: 3845 + + 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. + + + .. change:: Fix duplicate ``RateLimit-*`` headers with caching + :type: bugfix + :pr: 3855 + :issue: 3625 + + Fix a bug where ``RateLimitMiddleware`` duplicate all ``RateLimit-*`` headers + when handler cache is enabled. + + .. changelog:: 2.12.1 :date: 2024-09-21 diff --git a/3803/_sources/topics/sync-vs-async.rst.txt b/3803/_sources/topics/sync-vs-async.rst.txt index 9df304dc0..e7550f051 100644 --- a/3803/_sources/topics/sync-vs-async.rst.txt +++ b/3803/_sources/topics/sync-vs-async.rst.txt @@ -101,7 +101,7 @@ When to use a synchronous function ---------------------------------- As an inverse of the previous paragraph, it follows that synchronous functions should -be used for non-blocking, non-computationally intensive tasks. The synchronous execution +be used for non-io intensive tasks. The synchronous execution model allows for the smallest amount of overhead and should therefore be preferred in such situations where no asynchronous functionality is made use of. diff --git a/3803/_sources/tutorials/repository-tutorial/01-modeling-and-features.rst.txt b/3803/_sources/tutorials/repository-tutorial/01-modeling-and-features.rst.txt index ce66ea297..849d7cc4f 100644 --- a/3803/_sources/tutorials/repository-tutorial/01-modeling-and-features.rst.txt +++ b/3803/_sources/tutorials/repository-tutorial/01-modeling-and-features.rst.txt @@ -74,6 +74,7 @@ Additional features provided by the built-in base models include: reverts to an ``Integer`` for unsupported variants. - A custom :class:`JsonB ` type that uses native ``JSONB`` where possible and ``Binary`` or ``Blob`` as an alternative. +- A custom :class:`EncryptedString ` encrypted string that supports multiple cryptography backends. Let's build on this as we look at the repository classes. diff --git a/3803/_sources/tutorials/sqlalchemy/4-final-touches-and-recap.rst.txt b/3803/_sources/tutorials/sqlalchemy/4-final-touches-and-recap.rst.txt index 9b70b8f77..a619dff11 100644 --- a/3803/_sources/tutorials/sqlalchemy/4-final-touches-and-recap.rst.txt +++ b/3803/_sources/tutorials/sqlalchemy/4-final-touches-and-recap.rst.txt @@ -59,7 +59,7 @@ engine and session lifecycle, and register our ``transaction`` dependency. .. literalinclude:: /examples/contrib/sqlalchemy/plugins/tutorial/full_app_with_plugin.py :language: python :linenos: - :lines: 80-84 + :lines: 80-83 .. seealso:: diff --git a/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_init_plugin.rst.txt b/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_init_plugin.rst.txt index 2ebd069f6..581e39fe5 100644 --- a/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_init_plugin.rst.txt +++ b/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_init_plugin.rst.txt @@ -1,7 +1,7 @@ SQLAlchemy Init Plugin ---------------------- -The :class:`SQLAlchemyInitPlugin ` adds functionality to the +The :class:`SQLAlchemyInitPlugin ` adds functionality to the application that supports using Litestar with `SQLAlchemy `_. The plugin: @@ -39,8 +39,8 @@ Renaming the dependencies ######################### You can change the name that the engine and session are bound to by setting the -:attr:`engine_dependency_key ` -and :attr:`session_dependency_key ` +:attr:`engine_dependency_key ` +and :attr:`session_dependency_key ` attributes on the plugin configuration. Configuring the before send handler @@ -50,7 +50,7 @@ The plugin configures a ``before_send`` handler that is called before sending a session and removes it from the connection scope. You can change the handler by setting the -:attr:`before_send_handler ` +:attr:`before_send_handler ` attribute on the configuration object. For example, an alternate handler is available that will also commit the session on success and rollback upon failure. @@ -73,21 +73,21 @@ on success and rollback upon failure. Configuring the plugins ####################### -Both the :class:`SQLAlchemyAsyncConfig ` and the -:class:`SQLAlchemySyncConfig ` have an ``engine_config`` +Both the :class:`SQLAlchemyAsyncConfig ` and the +:class:`SQLAlchemySyncConfig ` have an ``engine_config`` attribute that is used to configure the engine. The ``engine_config`` attribute is an instance of -:class:`EngineConfig ` and exposes all of the configuration options +:class:`EngineConfig ` and exposes all of the configuration options available to the SQLAlchemy engine. -The :class:`SQLAlchemyAsyncConfig ` class and the -:class:`SQLAlchemySyncConfig ` class also have a +The :class:`SQLAlchemyAsyncConfig ` class and the +:class:`SQLAlchemySyncConfig ` class also have a ``session_config`` attribute that is used to configure the session. This is either an instance of -:class:`AsyncSessionConfig ` or -:class:`SyncSessionConfig ` depending on the type of config +:class:`AsyncSessionConfig ` or +:class:`SyncSessionConfig ` depending on the type of config object. These classes expose all of the configuration options available to the SQLAlchemy session. -Finally, the :class:`SQLAlchemyAsyncConfig ` class and the -:class:`SQLAlchemySyncConfig ` class expose configuration +Finally, the :class:`SQLAlchemyAsyncConfig ` class and the +:class:`SQLAlchemySyncConfig ` class expose configuration options to control their behavior. Consult the reference documentation for more information. @@ -98,7 +98,7 @@ Example The below example is a complete demonstration of use of the init plugin. Readers who are familiar with the prior section may note the additional complexity involved in managing the conversion to and from SQLAlchemy objects within the handlers. Read on to see how this increased complexity is efficiently handled by the -:class:`SQLAlchemySerializationPlugin `. +:class:`SQLAlchemySerializationPlugin `. .. tab-set:: diff --git a/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_plugin.rst.txt b/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_plugin.rst.txt index 8b0a702a8..c28b5e654 100644 --- a/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_plugin.rst.txt +++ b/3803/_sources/usage/databases/sqlalchemy/plugins/sqlalchemy_plugin.rst.txt @@ -1,18 +1,18 @@ SQLAlchemy Plugin ----------------- -The :class:`SQLAlchemyPlugin ` provides complete support for +The :class:`SQLAlchemyPlugin ` provides complete support for working with `SQLAlchemy `_ in Litestar applications. .. note:: This plugin is only compatible with SQLAlchemy 2.0+. -The :class:`SQLAlchemyPlugin ` combines the functionality of -:class:`SQLAlchemyInitPlugin ` and -:class:`SQLAlchemySerializationPlugin `, each of +The :class:`SQLAlchemyPlugin ` combines the functionality of +:class:`SQLAlchemyInitPlugin ` and +:class:`SQLAlchemySerializationPlugin `, each of which are examined in detail in the following sections. As such, this section describes a complete example of using the -:class:`SQLAlchemyPlugin ` with a Litestar application and a +:class:`SQLAlchemyPlugin ` with a Litestar application and a SQLite database. Or, skip ahead to :doc:`/usage/databases/sqlalchemy/plugins/sqlalchemy_init_plugin` or diff --git a/3803/_sources/usage/dto/0-basic-use.rst.txt b/3803/_sources/usage/dto/0-basic-use.rst.txt index 46693489e..621e655df 100644 --- a/3803/_sources/usage/dto/0-basic-use.rst.txt +++ b/3803/_sources/usage/dto/0-basic-use.rst.txt @@ -76,15 +76,14 @@ DTOs can similarly be defined on :class:`Routers ` and Improving performance with the codegen backend -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: - This feature was introduced in ``2.2.0`` and hidden behind the ``DTO_CODEGEN`` - feature flag. As of ``2.8.0`` it is considered stable and enabled by default. It can - still be disabled selectively by using the - ``DTOConfig(experimental_codegen_backend=True)`` override. - + This feature was introduced in ``2.2.0`` and was hidden behind the ``DTO_CODEGEN`` + feature flag. As of ``2.8.0`` it is considered stable and is enabled by default. + It can still be disabled selectively by using the + ``DTOConfig(experimental_codegen_backend=False)`` override. The DTO backend is the part that does the heavy lifting for all the DTO features. It is responsible for the transforming, validation and parsing. Because of this, @@ -93,21 +92,11 @@ introduced by the DTOs, the DTO codegen backend was introduced; A DTO backend th increases efficiency by generating optimized Python code at runtime to perform all the necessary operations. -Enabling the backend --------------------- - -You can enable this backend globally for all DTOs by passing the appropriate feature -flag to your Litestar application: - -.. code-block:: python - - from litestar import Litestar - from litestar.config.app import ExperimentalFeatures - - app = Litestar(experimental_features=[ExperimentalFeatures.DTO_CODEGEN]) - +Disabling the backend +--------------------- -or selectively for individual DTOs: +You can use ``experimental_codegen_backend=False`` +to disable the codegen backend selectively: .. code-block:: python @@ -121,23 +110,61 @@ or selectively for individual DTOs: class FooDTO(DataclassDTO[Foo]): - config = DTOConfig(experimental_codegen_backend=True) + config = DTOConfig(experimental_codegen_backend=False) -The same flag can be used to disable the backend selectively: +Enabling the backend +-------------------- -.. code-block:: python +.. note:: This is a historical document meant for Litestar versions prior to 2.8.0 + This backend was enabled by default since 2.8.0 - from dataclasses import dataclass - from litestar.dto import DTOConfig, DataclassDTO +.. warning:: ``ExperimentalFeatures.DTO_CODEGEN`` is deprecated and will be removed in 3.0.0 +.. dropdown:: Enabling DTO codegen backend + :icon: git-pull-request-closed - @dataclass - class Foo: - name: str + You can enable this backend globally for all DTOs by passing the appropriate feature + flag to your Litestar application: + .. code-block:: python - class FooDTO(DataclassDTO[Foo]): - config = DTOConfig(experimental_codegen_backend=False) + from litestar import Litestar + from litestar.config.app import ExperimentalFeatures + + app = Litestar(experimental_features=[ExperimentalFeatures.DTO_CODEGEN]) + + + or selectively for individual DTOs: + + .. code-block:: python + + from dataclasses import dataclass + from litestar.dto import DTOConfig, DataclassDTO + + + @dataclass + class Foo: + name: str + + + class FooDTO(DataclassDTO[Foo]): + config = DTOConfig(experimental_codegen_backend=True) + + The same flag can be used to disable the backend selectively: + + .. code-block:: python + + from dataclasses import dataclass + from litestar.dto import DTOConfig, DataclassDTO + + + @dataclass + class Foo: + name: str + + + class FooDTO(DataclassDTO[Foo]): + config = DTOConfig(experimental_codegen_backend=False) Performance improvements diff --git a/3803/_sources/usage/dto/1-abstract-dto.rst.txt b/3803/_sources/usage/dto/1-abstract-dto.rst.txt index e39245aa0..de8ce1df0 100644 --- a/3803/_sources/usage/dto/1-abstract-dto.rst.txt +++ b/3803/_sources/usage/dto/1-abstract-dto.rst.txt @@ -10,7 +10,7 @@ The following factories are currently available: - :class:`DataclassDTO ` - :class:`MsgspecDTO ` -- :class:`PydanticDTO ` +- :class:`PydanticDTO ` - :class:`SQLAlchemyDTO ` Using DTO Factories @@ -120,7 +120,7 @@ Fields can also be renamed using a renaming strategy that will be applied to all Fields that are directly renamed using `rename_fields` mapping will be excluded from `rename_strategy`. -The rename strategy either accepts one of the pre-defined strategies: "camel", "pascal", "upper", "lower", or it can be provided a callback that accepts the field name as an argument and should return a string. +The rename strategy either accepts one of the pre-defined strategies: "camel", "pascal", "upper", "lower", "kebab", or it can be provided a callback that accepts the field name as a string argument and should return a string. Type checking ------------- @@ -184,21 +184,23 @@ DTO Data Sometimes we need to be able to access the data that has been parsed and validated by the DTO, but not converted into an instance of our data model. -In the following example, we create a ``Person`` model, that is a :func:`dataclass ` with 3 -required fields, ``id``, ``name``, and ``age``. +In the following example, we create a ``User`` model, that is a :func:`dataclass ` with 3 +required fields: ``id``, ``name``, and ``age``. -We also create a DTO that doesn't allow clients to set the ``id`` field on the ``Person`` model and set it on the +We also create a DTO that doesn't allow clients to set the ``id`` field on the ``User`` model and set it on the handler. .. literalinclude:: /examples/data_transfer_objects/factory/dto_data_problem_statement.py :language: python - :emphasize-lines: 19,20,21,22,28 + :emphasize-lines: 18-21,27 :linenos: -Notice that we get a ``500`` response from the handler - this is because the DTO has attempted to convert the request -data into a ``Person`` object and failed because it has no value for the required ``id`` field. +Notice that our `User` model has a model-level ``default_factory=uuid4`` +for ``id`` field. That's why we can decode the client data into this model. -One way to handle this is to create different models, e.g., we might create a ``CreatePerson`` model that has no ``id`` +However, in some cases there's no clear way to provide a default this way. + +One way to handle this is to create different models, e.g., we might create a ``UserCreate`` model that has no ``id`` field, and decode the client data into that. However, this method can become quite cumbersome when we have a lot of variability in the data that we accept from clients, for example, `PATCH `_ requests. @@ -208,11 +210,11 @@ type of the data that it will contain, and provides useful methods for interacti .. literalinclude:: /examples/data_transfer_objects/factory/dto_data_usage.py :language: python - :emphasize-lines: 7,25,27 + :emphasize-lines: 5,23,25 :linenos: In the above example, we've injected an instance of :class:`DTOData ` into our handler, -and have used that to create our ``Person`` instance, after augmenting the client data with a server generated ``id`` +and have used that to create our ``User`` instance, after augmenting the client data with a server generated ``id`` value. Consult the :class:`Reference Docs ` for more information on the methods available. @@ -230,7 +232,7 @@ nested model with excluded fields. .. literalinclude:: /examples/data_transfer_objects/factory/providing_values_for_nested_data.py :language: python - :emphasize-lines: 10,11,12,13,21,29,35 + :emphasize-lines: 9-12,20,28,34 :linenos: The double-underscore syntax ``address__id`` passed as a keyword argument to the @@ -239,7 +241,7 @@ nested attribute. In this case, it's used to provide a value for the ``id`` attr within the ``Person`` instance. This is a common convention in Python for dealing with nested structures. The double underscore can be interpreted as -"traverse through", so ``address__id`` means "traverse through address to get to id". +"traverse through", so ``address__id`` means "traverse through address to get to its id". In the context of this script, ``create_instance(id=1, address__id=2)`` is saying "create a new ``Person`` instance from the client data given an id of ``1``, and supplement the client address data with an id of ``2``". @@ -253,17 +255,17 @@ attributes in the client payload, which requires some special handling internall .. literalinclude:: /examples/data_transfer_objects/factory/patch_requests.py :language: python - :emphasize-lines: 7,21,32,34 + :emphasize-lines: 7,20,27,28,30 :linenos: -The ``PatchDTO`` class is defined for the Person class. The ``config`` attribute of ``PatchDTO`` is set to exclude the -id field, preventing clients from setting it when updating a person, and the ``partial`` attribute is set to ``True``, +The ``PatchDTO`` class is defined for the ``Person`` class. The ``config`` attribute of ``PatchDTO`` is set to exclude the +``id`` field, preventing clients from setting it when updating a person, and the ``partial`` attribute is set to ``True``, which allows the DTO to accept a subset of the model attributes. Inside the handler, the :meth:`DTOData.update_instance ` method is called to update the instance of ``Person`` before returning it. -In our request, we set only the ``name`` property of the ``Person``, from ``"Peter"`` to ``"Peter Pan"`` and received +In our request, we update only the ``name`` property of the ``Person``, from ``"Peter"`` to ``"Peter Pan"`` and receive the full object - with the modified name - back in the response. Implicit Private Fields diff --git a/3803/_sources/usage/exceptions.rst.txt b/3803/_sources/usage/exceptions.rst.txt index 956a29620..2f3cc6a83 100644 --- a/3803/_sources/usage/exceptions.rst.txt +++ b/3803/_sources/usage/exceptions.rst.txt @@ -2,20 +2,20 @@ Exceptions and exception handling ================================= Litestar define a base exception called :class:`LitestarException ` which serves -as a basis to all other exceptions. +as a base class for all other exceptions, see :mod:`API Reference `. -In general, Litestar will raise two types of exceptions: +In general, Litestar has two scenarios for exception handling: -- Exceptions that arise during application init, which fall -- Exceptions that are raised as part of the normal application flow, i.e. - exceptions in route handlers, dependencies, and middleware, that should be serialized in some fashion. +- Exceptions that are raised during application configuration, startup, and initialization, which are handled like regular Python exceptions +- Exceptions that are raised as part of the request handling, i.e. + exceptions in route handlers, dependencies, and middleware, that should be returned as a response to the end user Configuration Exceptions ------------------------ For missing extra dependencies, Litestar will raise either :class:`MissingDependencyException `. For example, if you try to use the -:doc:`SQLAlchemyPlugin ` without having SQLAlchemy installed, this will be raised when you +:ref:`SQLAlchemyPlugin ` without having SQLAlchemy installed, this will be raised when you start the application. For other configuration issues, Litestar will raise @@ -25,8 +25,8 @@ issue. Application Exceptions ---------------------- -For application exceptions, Litestar uses the class :class:`HTTPException <.exceptions.http_exceptions.HTTPException>`, -which inherits from :class:`LitestarException <.exceptions.LitestarException>`. This exception will be serialized +For application exceptions, Litestar uses the class :class:`~litestar.exceptions.http_exceptions.HTTPException`, +which inherits from :class:`~litestar.exceptions.LitestarException`. This exception will be serialized into a JSON response of the following schema: .. code-block:: json @@ -37,10 +37,10 @@ into a JSON response of the following schema: "extra": {} } -Litestar also offers several pre-configured exception subclasses with pre-set error codes that you can use, such as: +Litestar also offers several pre-configured ``HTTPException`` subclasses with pre-set error codes that you can use, such as: -.. py:currentmodule:: litestar.exceptions.http_exceptions +.. :currentmodule:: litestar.exceptions.http_exceptions +----------------------------------------+-------------+------------------------------------------+ | Exception | Status code | Description | @@ -49,26 +49,30 @@ Litestar also offers several pre-configured exception subclasses with pre-set er +----------------------------------------+-------------+------------------------------------------+ | :class:`ValidationException` | 400 | Raised when validation or parsing failed | +----------------------------------------+-------------+------------------------------------------+ -| :class:`NotFoundException` | 404 | HTTP status code 404 | -+----------------------------------------+-------------+------------------------------------------+ | :class:`NotAuthorizedException` | 401 | HTTP status code 401 | +----------------------------------------+-------------+------------------------------------------+ | :class:`PermissionDeniedException` | 403 | HTTP status code 403 | +----------------------------------------+-------------+------------------------------------------+ +| :class:`NotFoundException` | 404 | HTTP status code 404 | ++----------------------------------------+-------------+------------------------------------------+ | :class:`InternalServerException` | 500 | HTTP status code 500 | +----------------------------------------+-------------+------------------------------------------+ | :class:`ServiceUnavailableException` | 503 | HTTP status code 503 | +----------------------------------------+-------------+------------------------------------------+ -When a value fails ``pydantic`` validation, the result will be a :class:`ValidationException` with the ``extra`` key set to the -pydantic validation errors. Thus, this data will be made available for the API consumers by default. +.. :currentmodule:: None + +When a value fails validation, the result will be a :class:`~litestar.exceptions.http_exceptions.ValidationException` with the ``extra`` key set to the validation error message. + +.. warning:: All validation error messages will be made available for the API consumers by default. + If this is not your intent, adjust the exception contents. Exception handling ------------------ Litestar handles all errors by default by transforming them into **JSON responses**. If the errors are **instances of** -:class:`HTTPException`, the responses will include the appropriate ``status_code``. +:class:`~litestar.exceptions.http_exceptions.HTTPException`, the responses will include the appropriate ``status_code``. Otherwise, the responses will default to ``500 - "Internal Server Error"``. You can customize exception handling by passing a dictionary, mapping either status codes @@ -89,14 +93,6 @@ exceptions that inherit from ``HTTPException``. You could of course be more gran The choice whether to use a single function that has switching logic inside it, or multiple functions depends on your specific needs. -While it does not make much sense to have different functions with a top-level exception handling, -Litestar supports defining exception handlers on all layers of the app, with the lower layers overriding layer above -them. In the following example, the exception handler for the route handler function will only handle -the ``ValidationException`` occurring within that route handler: - -.. literalinclude:: /examples/exceptions/layered_handlers.py - :language: python - Exception handling layers ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,3 +112,10 @@ As a result of the above structure, the exceptions raised by the ASGI Router its and ``405 Method Not Allowed`` are handled only by exception handlers defined on the app layer. Thus, if you want to affect these exceptions, you will need to pass the exception handlers for them to the Litestar constructor and cannot use other layers for this purpose. + +Litestar supports defining exception handlers on all layers of the app, with the lower layers overriding layer above +them. In the following example, the exception handler for the route handler function will only handle +the ``ValidationException`` occurring within that route handler: + +.. literalinclude:: /examples/exceptions/layered_handlers.py + :language: python diff --git a/3803/_sources/usage/htmx.rst.txt b/3803/_sources/usage/htmx.rst.txt index 966b166d6..7dd2b2837 100644 --- a/3803/_sources/usage/htmx.rst.txt +++ b/3803/_sources/usage/htmx.rst.txt @@ -1,18 +1,50 @@ HTMX ==== -Litestar HTMX integration. +Litestar `HTMX `_ integration. + +HTMX is a JavaScript library that gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext. + +This section assumes that you have prior knowledge of HTMX. +If you want to learn HTMX, we recommend consulting their `official tutorial `_. + +HTMXPlugin +------------ + +a Litestar plugin ``HTMXPlugin`` is available to easily configure the default request class for all Litestar routes. + +.. code-block:: python + + from litestar.plugins.htmx import HTMXPlugin + from litestar import Litestar + + from litestar.contrib.jinja import JinjaTemplateEngine + from litestar.template.config import TemplateConfig + + from pathlib import Path + + app = Litestar( + route_handlers=[get_form], + debug=True, + plugins=[HTMXPlugin()], + template_config=TemplateConfig( + directory=Path("litestar_htmx/templates"), + engine=JinjaTemplateEngine, + ), + ) + +See :class:`~litestar.plugins.htmx.HTMXDetails` for a full list of +available properties. HTMXRequest ------------ A special :class:`~litestar.connection.Request` class, providing interaction with the -HTMX client. +HTMX client. You can configure this globally by using the ``HTMXPlugin`` or by setting the `request_class` setting on any route, controller, router, or application. .. code-block:: python - from litestar.contrib.htmx.request import HTMXRequest - from litestar.contrib.htmx.response import HTMXTemplate + from litestar.plugins.htmx import HTMXRequest, HTMXTemplate from litestar import get, Litestar from litestar.response import Template @@ -24,11 +56,8 @@ HTMX client. @get(path="/form") def get_form(request: HTMXRequest) -> Template: - htmx = request.htmx # if true will return HTMXDetails class object - if htmx: - print(htmx.current_url) - # OR - if request.htmx: + if request.htmx: # if request has "HX-Request" header, then + print(request.htmx) # HTMXDetails instance print(request.htmx.current_url) return HTMXTemplate(template_name="partial.html", context=context, push_url="/form") @@ -43,7 +72,7 @@ HTMX client. ), ) -See :class:`HTMXDetails ` for a full list of +See :class:`~litestar.plugins.htmx.HTMXDetails` for a full list of available properties. @@ -54,12 +83,12 @@ HTMX Response Classes HTMXTemplate Response Classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The most common use-case for `htmx` to render an html page or html snippet. Litestar makes this easy by providing -an :class:`HTMXTemplate ` response: +The most common use-case for HTMX to render an html page or html snippet. Litestar makes this easy by providing +an :class:`~litestar.plugins.htmx.HTMXTemplate` response: .. code-block:: python - from litestar.contrib.htmx.response import HTMXTemplate + from litestar.plugins.htmx import HTMXTemplate from litestar.response import Template @@ -89,10 +118,10 @@ an :class:`HTMXTemplate ` response: HTMX provides two types of responses - one that doesn't allow changes to the DOM and one that does. Litestar supports both of these: -1 - Responses that don't make any changes to DOM. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 - Responses that don't make any changes to DOM +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use :class:`HXStopPolling ` to stop polling for a response. +Use :class:`~litestar.plugins.htmx.HXStopPolling` to stop polling for a response. .. code-block:: python @@ -101,7 +130,7 @@ Use :class:`HXStopPolling ` to sto ... return HXStopPolling() -Use :class:`ClientRedirect ` to redirect with a page reload. +Use :class:`~litestar.plugins.htmx.ClientRedirect` to redirect with a page reload. .. code-block:: python @@ -110,7 +139,7 @@ Use :class:`ClientRedirect ` to ... return ClientRedirect(redirect_to="/contact-us") -Use :class:`ClientRefresh ` to force a full page refresh. +Use :class:`~litestar.plugins.htmx.ClientRefresh` to force a full page refresh. .. code-block:: python @@ -119,12 +148,12 @@ Use :class:`ClientRefresh ` to fo ... return ClientRefresh() -2 - Responses that may change DOM. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +2 - Responses that may change DOM +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use :class:`HXLocation ` to redirect to a new location without page reload. +Use :class:`~litestar.plugins.htmx.HXLocation` to redirect to a new location without page reload. -- Note: this class provides the ability to change ``target``, ``swapping`` method, the sent ``values``, and the ``headers``.) +.. note:: This class provides the ability to change ``target``, ``swapping`` method, the sent ``values``, and the ``headers``. .. code-block:: python @@ -138,13 +167,13 @@ Use :class:`HXLocation ` to redirect event, # an event that "triggered" the request. target="#target", # element id to target to. swap="outerHTML", # swapping method to use. - hx_headers={"attr": "val"}, # headers to pass to htmx. + hx_headers={"attr": "val"}, # headers to pass to HTMX. values={"val": "one"}, ) # values to submit with response. -Use :class:`PushUrl ` to carry a response and push a url to the browser, optionally updating the `history` stack. +Use :class:`~litestar.plugins.htmx.PushUrl` to carry a response and push a url to the browser, optionally updating the ``history`` stack. -- Note: If the value for ``push_url`` is set to ``False`` it will prevent updating browser history. +.. note:: If the value for ``push_url`` is set to ``False`` it will prevent updating browser history. .. code-block:: python @@ -153,8 +182,9 @@ Use :class:`PushUrl ` to carry a respons ... return PushUrl(content="Success!", push_url="/about") -Use :class:`ReplaceUrl ` to carry a response and replace the url in the browser's ``location`` bar. -- Note: If the value to ``replace_url`` is set to ``False`` it will prevent it updating the browser location bar. +Use :class:`~litestar.plugins.htmx.ReplaceUrl` to carry a response and replace the url in the browser's ``location`` bar. + +.. note:: If the value to ``replace_url`` is set to ``False`` it will prevent updating the browser's location. .. code-block:: python @@ -163,7 +193,7 @@ Use :class:`ReplaceUrl ` to carry a r ... return ReplaceUrl(content="Success!", replace_url="/contact-us") -Use :class:`Reswap ` to carry a response perhaps a swap +Use :class:`~litestar.plugins.htmx.Reswap` to carry a response with a possible swap. .. code-block:: python @@ -172,7 +202,7 @@ Use :class:`Reswap ` to carry a response ... return Reswap(content="Success!", method="beforebegin") -Use :class:`Retarget ` to carry a response and change the target element. +Use :class:`~litestar.plugins.htmx.Retarget` to carry a response and change the target element. .. code-block:: python @@ -181,7 +211,7 @@ Use :class:`Retarget ` to carry a respo ... return Retarget(content="Success!", target="#new-target") -Use :class:`TriggerEvent ` to carry a response and trigger an event. +Use :class:`~litestar.plugins.htmx.TriggerEvent` to carry a response and trigger an event. .. code-block:: python diff --git a/3803/_sources/usage/lifecycle-hooks.rst.txt b/3803/_sources/usage/lifecycle-hooks.rst.txt index 0e2e0fdb2..cd02833f8 100644 --- a/3803/_sources/usage/lifecycle-hooks.rst.txt +++ b/3803/_sources/usage/lifecycle-hooks.rst.txt @@ -20,7 +20,7 @@ Before Request -------------- The ``before_request`` hook runs immediately before calling the route handler function. It -can be any callable accepting a :class:`Request <.connection.Request>` as its first parameter +can be any callable accepting a :class:`~litestar.connection.Request` as its first parameter and returns either ``None`` or a value that can be used in a response. If a value is returned, the router handler for this request will be bypassed. @@ -34,7 +34,7 @@ After Request ------------- The ``after_request`` hook runs after the route handler returned and the response object -has been resolved. It can be any callable which takes a :class:`Response <.response.Response>` +has been resolved. It can be any callable which takes a :class:`~litestar.response.Response` instance as its first parameter, and returns a ``Response`` instance. The ``Response`` instance returned does not necessarily have to be the one that was received. @@ -48,7 +48,7 @@ After Response -------------- The ``after_response`` hook runs after the response has been returned by the server. -It can be any callable accepting a :class:`Request <.connection.Request>` as its first parameter +It can be any callable accepting a :class:`~litestar.connection.Request` as its first parameter and does not return any value. This hook is meant for data post-processing, transmission of data to third party @@ -60,8 +60,8 @@ services, gathering of metrics, etc. .. note:: - Since the request has already been returned by the time the `after_response` is called, - the updated state of `COUNTER` is not reflected in the response. + Since the request has already been returned by the time the ``after_response`` is called, + the updated state of ``COUNTER`` is not reflected in the response. Layered hooks diff --git a/3803/_sources/usage/logging.rst.txt b/3803/_sources/usage/logging.rst.txt index c0d2ad46c..c1b42bbc7 100644 --- a/3803/_sources/usage/logging.rst.txt +++ b/3803/_sources/usage/logging.rst.txt @@ -1,3 +1,5 @@ +.. _logging-usage: + Logging ======= diff --git a/3803/_sources/usage/metrics/prometheus.rst.txt b/3803/_sources/usage/metrics/prometheus.rst.txt index 766de0a2f..49db6555a 100644 --- a/3803/_sources/usage/metrics/prometheus.rst.txt +++ b/3803/_sources/usage/metrics/prometheus.rst.txt @@ -1,7 +1,7 @@ Prometheus ========== -Litestar includes optional Prometheus exporter that is exported from ``litestar.contrib.prometheus``. To use +Litestar includes optional Prometheus exporter that is exported from ``litestar.plugins.prometheus``. To use this package, you should first install the required dependencies: .. code-block:: bash @@ -17,12 +17,12 @@ this package, you should first install the required dependencies: Once these requirements are satisfied, you can instrument your Litestar application: -.. literalinclude:: /examples/contrib/prometheus/using_prometheus_exporter.py +.. literalinclude:: /examples/plugins/prometheus/using_prometheus_exporter.py :language: python :caption: Using the Prometheus Exporter You can also customize the configuration: -.. literalinclude:: /examples/contrib/prometheus/using_prometheus_exporter_with_extra_configs.py +.. literalinclude:: /examples/plugins/prometheus/using_prometheus_exporter_with_extra_configs.py :language: python :caption: Configuring the Prometheus Exporter diff --git a/3803/_sources/usage/middleware/builtin-middleware.rst.txt b/3803/_sources/usage/middleware/builtin-middleware.rst.txt index e95102efc..03ca6413a 100644 --- a/3803/_sources/usage/middleware/builtin-middleware.rst.txt +++ b/3803/_sources/usage/middleware/builtin-middleware.rst.txt @@ -6,7 +6,7 @@ CORS `CORS (Cross-Origin Resource Sharing) `_ is a common security mechanism that is often implemented using middleware. To enable CORS in a litestar application simply pass an instance -of :class:`CORSConfig <.config.cors.CORSConfig>` to :class:`Litestar <.app.Litestar>`: +of :class:`~litestar.config.cors.CORSConfig` to :class:`~litestar.app.Litestar`: .. code-block:: python @@ -21,7 +21,7 @@ of :class:`CORSConfig <.config.cors.CORSConfig>` to :class:`Litestar <.app.Lites CSRF ---- -CSRF (Cross-site request forgery) is a type of attack where unauthorized commands are submitted from a user that the web +`CSRF (Cross-site request forgery) `_ is a type of attack where unauthorized commands are submitted from a user that the web application trusts. This attack often uses social engineering that tricks the victim into clicking a URL that contains a maliciously crafted, unauthorized request for a particular Web application. The user’s browser then sends this maliciously crafted request to the targeted Web application. If the user is in an active session with the Web application, @@ -45,7 +45,7 @@ This middleware prevents CSRF attacks by doing the following: form field or an additional header that has this token (more on this below) To enable CSRF protection in a Litestar application simply pass an instance of -:class:`CSRFConfig <.config.csrf.CSRFConfig>` to the Litestar constructor: +:class:`~litestar.config.csrf.CSRFConfig` to the Litestar constructor: .. code-block:: python @@ -68,7 +68,7 @@ To enable CSRF protection in a Litestar application simply pass an instance of app = Litestar([get_resource, create_resource], csrf_config=csrf_config) -The following snippet demonstrates how to change the cookie name to "some-cookie-name" and header name to "some-header-name". +The following snippet demonstrates how to change the cookie name to ``"some-cookie-name"`` and header name to ``"some-header-name"``. .. code-block:: python @@ -80,11 +80,11 @@ A CSRF protected route can be accessed by any client that can make a request wit .. note:: - The form-data key can not be currently configured. It should only be passed via the key "_csrf_token" + The form-data key can not be currently configured. It should only be passed via the key ``"_csrf_token"`` In Python, any client such as `requests `_ or `httpx `_ can be used. The usage of clients or sessions is recommended due to the cookie persistence it offers across requests. -The following is an example using ``httpx.Client``. +The following is an example using `httpx.Client `_. .. code-block:: python @@ -98,7 +98,7 @@ The following is an example using ``httpx.Client``. csrf = get_response.cookies["csrftoken"] # "x-csrftoken" is the default header name - post_response_using_header = client.post("http://localhost:8000/", headers={"x-csrftoken": csrf}) + post_response_using_header = client.post("http://localhost:8000/1", headers={"x-csrftoken": csrf}) assert post_response_using_header.status_code == 201 # "_csrf_token" is the default *non* configurable form-data key @@ -121,7 +121,7 @@ Routes can be marked as being exempt from the protection offered by this middlew If you need to exempt many routes at once you might want to consider using the -:attr:`exclude <.config.csrf.CSRFConfig.exclude>` kwarg which accepts list of path +:attr:`~litestar.config.csrf.CSRFConfig.exclude` kwarg which accepts list of path patterns to skip in the middleware. .. seealso:: @@ -134,12 +134,12 @@ patterns to skip in the middleware. Allowed Hosts ------------- -Another common security mechanism is to require that each incoming request has a "Host" or "X-Forwarded-Host" header, +Another common security mechanism is to require that each incoming request has a ``"Host"`` or ``"X-Forwarded-Host"`` header, and then to restrict hosts to a specific set of domains - what's called "allowed hosts". -Litestar includes an :class:`AllowedHostsMiddleware <.middleware.allowed_hosts.AllowedHostsMiddleware>` class that can be -easily enabled by either passing an instance of :class:`AllowedHostsConfig <.config.allowed_hosts.AllowedHostsConfig>` or a -list of domains to :class:`Litestar `: +Litestar includes an :class:`~litestar.middleware.allowed_hosts.AllowedHostsMiddleware` class that can be +easily enabled by either passing an instance of :class:`~litestar.config.allowed_hosts.AllowedHostsConfig` or a +list of domains to :class:`~litestar.app.Litestar`: .. code-block:: python @@ -169,13 +169,13 @@ HTML responses can optionally be compressed. Litestar has built in support for g through the built-in Starlette classes, and brotli support can be added by installing the ``brotli`` extras. You can enable either backend by passing an instance of -:class:`CompressionConfig <.config.compression.CompressionConfig>` to ``compression_config`` of -:class:`Litestar `. +:class:`~litestar.config.compression.CompressionConfig` to ``compression_config`` of +:class:`~litestar.app.Litestar`. GZIP ^^^^ -You can enable gzip compression of responses by passing an instance of :class:`CompressionConfig <.config.compression.CompressionConfig>` with +You can enable gzip compression of responses by passing an instance of :class:`~litestar.config.compression.CompressionConfig` with the ``backend`` parameter set to ``"gzip"``. You can configure the following additional gzip-specific values: @@ -199,25 +199,25 @@ You can configure the following additional gzip-specific values: Brotli ^^^^^^ -The Brotli package is required to run this middleware. It is available as an extras to litestar with the ``brotli`` +The `Brotli `_ package is required to run this middleware. It is available as an extras to litestar with the ``brotli`` extra (``pip install litestar[brotli]``). You can enable brotli compression of responses by passing an instance of -:class:`CompressionConfig <.config.compression.CompressionConfig>` with the ``backend`` parameter set to ``"brotli"``. +:class:`~litestar.config.compression.CompressionConfig` with the ``backend`` parameter set to ``"brotli"``. You can configure the following additional brotli-specific values: * ``minimum_size``: the minimum threshold for response size to enable compression. Smaller responses will not be - compressed. Defaults is ``500``, i.e. half a kilobyte. + compressed. Default is 500, i.e. half a kilobyte * ``brotli_quality``: Range [0-11], Controls the compression-speed vs compression-density tradeoff. The higher the - quality, the slower the compression. -* ``brotli_mode``: The compression mode can be MODE_GENERIC (default), MODE_TEXT (for UTF-8 format text input), or - MODE_FONT (for WOFF 2.0). -* ``brotli_lgwin``: Base 2 logarithm of size. Range is 10 to 24. Defaults to 22. -* ``brotli_lgblock``: Base 2 logarithm of the maximum input block size. Range is 16 to 24. If set to 0, the value will - be set based on the quality. Defaults to 0. -* ``brotli_gzip_fallback``: a boolean to indicate if gzip should be used if brotli is not supported. + quality, the slower the compression. Defaults to 5 +* ``brotli_mode``: The compression mode can be ``"generic"`` (for mixed content), ``"text"`` (for UTF-8 format text input), or + ``"font"`` (for WOFF 2.0). Defaults to ``"text"`` +* ``brotli_lgwin``: Base 2 logarithm of size. Range [10-24]. Defaults to 22. +* ``brotli_lgblock``: Base 2 logarithm of the maximum input block size. Range [16-24]. If set to 0, the value will + be set based on the quality. Defaults to 0 +* ``brotli_gzip_fallback``: a boolean to indicate if gzip should be used if brotli is not supported .. code-block:: python @@ -232,31 +232,30 @@ You can configure the following additional brotli-specific values: Rate-Limit Middleware --------------------- -Litestar includes an optional :class:`RateLimitMiddleware ` that follows +Litestar includes an optional :class:`~litestar.middleware.rate_limit.RateLimitMiddleware` that follows the `IETF RateLimit draft specification `_. -To use the rate limit middleware, use the :class:`RateLimitConfig `: +To use the rate limit middleware, use the :class:`~litestar.middleware.rate_limit.RateLimitConfig`: .. literalinclude:: /examples/middleware/rate_limit.py :language: python -The only required configuration kwarg is ``rate_limit``, which expects a tuple containing a time-unit (``second``, -``minute``, ``hour``, ``day``\ ) and a value for the request quota (integer). +The only required configuration kwarg is ``rate_limit``, which expects a tuple containing a time-unit (``"second"``, +``"minute"``, ``"hour"``, ``"day"``\ ) and a value for the request quota (integer). Logging Middleware ------------------ Litestar ships with a robust logging middleware that allows logging HTTP request and responses while building on -the :doc:`logging configuration `: +the Litestar's :ref:`logging configuration `: .. literalinclude:: /examples/middleware/logging_middleware.py :language: python -The logging middleware uses the logger configuration defined on the application level, which allows for using both stdlib -logging or `structlog `_ , depending on the configuration used -(see :doc:`logging configuration ` for more details). +The logging middleware uses the logger configuration defined on the application level, which allows for using any supported logging tool, depending on the configuration used +(see :ref:`logging configuration ` for more details). Obfuscating Logging Output ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,18 +280,18 @@ The middleware will obfuscate the headers ``Authorization`` and ``X-API-KEY`` , Compression and Logging of Response Body ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If both :class:`CompressionConfig ` and -:class:`LoggingMiddleware ` have been defined for the application, the response +If both :class:`~litestar.config.compression.CompressionConfig` and +:class:`~litestar.middleware.logging.LoggingMiddleware` have been defined for the application, the response body will be omitted from response logging if it has been compressed, even if ``"body"`` has been included in -:class:`response_log_fields `. To force the body of +:class:`~litestar.middleware.logging.LoggingMiddlewareConfig.response_log_fields`. To force the body of compressed responses to be logged, set -:attr:`include_compressed_body ` to ``True`` , in +:attr:`~litestar.middleware.logging.LoggingMiddlewareConfig.include_compressed_body` to ``True`` , in addition to including ``"body"`` in ``response_log_fields``. Session Middleware ------------------ -Litestar includes a :class:`SessionMiddleware <.middleware.session.base.SessionMiddleware>`, +Litestar includes a :class:`~litestar.middleware.session.base.SessionMiddleware`, offering client- and server-side sessions. Server-side sessions are backed by Litestar's :doc:`stores `, which offer support for: @@ -316,12 +315,12 @@ add its middleware to your application's middleware stack: Since both client- and server-side sessions rely on cookies (one for storing the actual session data, the other for storing the session ID), they share most of the cookie configuration. - A complete reference of the cookie configuration can be found at :class:`BaseBackendConfig `. + A complete reference of the cookie configuration can be found at :class:`~litestar.middleware.session.base.BaseBackendConfig`. Client-side sessions ^^^^^^^^^^^^^^^^^^^^ -Client side sessions are available through the :class:`ClientSideSessionBackend `, +Client side sessions are available through the :class:`~litestar.middleware.session.client_side.ClientSideSessionBackend`, which offers strong AES-CGM encryption security best practices while support cookie splitting. .. important:: @@ -336,7 +335,7 @@ which offers strong AES-CGM encryption security best practices while support coo .. seealso:: - * :class:`CookieBackendConfig ` + * :class:`~litestar.middleware.session.client_side.CookieBackendConfig` Server-side sessions @@ -352,4 +351,4 @@ and load the appropriate data from the store .. seealso:: * :doc:`/usage/stores` - * :class:`ServerSideSessionConfig ` + * :class:`~litestar.middleware.session.server_side.ServerSideSessionConfig` diff --git a/3803/_sources/usage/middleware/creating-middleware.rst.txt b/3803/_sources/usage/middleware/creating-middleware.rst.txt index 74e8e40a3..bc111194c 100644 --- a/3803/_sources/usage/middleware/creating-middleware.rst.txt +++ b/3803/_sources/usage/middleware/creating-middleware.rst.txt @@ -2,9 +2,9 @@ Creating Middleware =================== -As mentioned in :doc:`using middleware `, a middleware in Litestar +As mentioned in :ref:`using middleware `, a middleware in Litestar is **any callable** that takes a kwarg called ``app``, which is the next ASGI handler, i.e. an -:class:`ASGIApp `, and returns an ``ASGIApp``. +:class:`~litestar.types.ASGIApp`, and returns an ``ASGIApp``. The example previously given was using a factory function, i.e.: @@ -22,14 +22,14 @@ The example previously given was using a factory function, i.e.: return my_middleware While using functions is a perfectly viable approach, you can also use classes to do the same. See the next sections on -two base classes you can use for this purpose - the :class:`MiddlewareProtocol <.middleware.base.MiddlewareProtocol>` , -which gives a bare-bones type, or the :class:`AbstractMiddleware <.middleware.base.AbstractMiddleware>` that offers a +two base classes you can use for this purpose - the :class:`~litestar.middleware.base.MiddlewareProtocol` , +which gives a bare-bones type, or the :class:`~litestar.middleware.base.AbstractMiddleware` that offers a base class with some built in functionality. Using MiddlewareProtocol ------------------------ -The :class:`MiddlewareProtocol ` class is a +The :class:`~litestar.middleware.base.MiddlewareProtocol` class is a `PEP 544 Protocol `_ that specifies the minimal implementation of a middleware as follows: @@ -50,7 +50,7 @@ this case, but rather the next middleware in the stack, which is also an ASGI ap The ``__call__`` method makes this class into a ``callable``, i.e. once instantiated this class acts like a function, that has the signature of an ASGI app: The three parameters, ``scope, receive, send`` are specified by `the ASGI specification `_, and their values originate with the ASGI -server (e.g. *uvicorn*\ ) used to run Litestar. +server (e.g. ``uvicorn``\ ) used to run Litestar. To use this protocol as a basis, simply subclass it - as you would any other class, and implement the two methods it specifies: @@ -67,20 +67,19 @@ specifies: class MyRequestLoggingMiddleware(MiddlewareProtocol): - def __init__(self, app: ASGIApp) -> None: - super().__init__(app) + def __init__(self, app: ASGIApp) -> None: # can have other parameters as well self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] == "http": request = Request(scope) - logger.info("%s - %s" % request.method, request.url) + logger.info("Got request: %s - %s", request.method, request.url) await self.app(scope, receive, send) .. important:: Although ``scope`` is used to create an instance of request by passing it to the - :class:`Request <.connection.Request>` constructor, which makes it simpler to access because it does some parsing + :class:`~litestar.connection.Request` constructor, which makes it simpler to access because it does some parsing for you already, the actual source of truth remains ``scope`` - not the request. If you need to modify the data of the request you must modify the scope object, not any ephemeral request objects created as in the above. @@ -103,7 +102,6 @@ explore another example - redirecting the request to a different url from a midd class RedirectMiddleware(MiddlewareProtocol): def __init__(self, app: ASGIApp) -> None: - super().__init__(app) self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: @@ -113,24 +111,24 @@ explore another example - redirecting the request to a different url from a midd else: await self.app(scope, receive, send) -As you can see in the above, given some condition (``request.session`` being None) we create a -:class:`ASGIRedirectResponse ` and then await it. Otherwise, we await ``self.app`` +As you can see in the above, given some condition (``request.session`` being ``None``) we create a +:class:`~litestar.response.redirect.ASGIRedirectResponse` and then await it. Otherwise, we await ``self.app`` Modifying ASGI Requests and Responses using the MiddlewareProtocol ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. important:: - If you'd like to modify a :class:`Response <.response.Response>` object after it was created for a route + If you'd like to modify a :class:`~litestar.response.Response` object after it was created for a route handler function but before the actual response message is transmitted, the correct place to do this is using the special life-cycle hook called :ref:`after_request `. The instructions in this section are for how to modify the ASGI response message itself, which is a step further in the response process. -Using the :class:`MiddlewareProtocol <.middleware.base.MiddlewareProtocol>` you can intercept and modifying both the +Using the :class:`~litestar.middleware.base.MiddlewareProtocol` you can intercept and modifying both the incoming and outgoing data in a request / response cycle by "wrapping" that respective ``receive`` and ``send`` ASGI functions. -To demonstrate this, lets say we want to append a header with a timestamp to all outgoing responses. We could achieve +To demonstrate this, let's say we want to append a header with a timestamp to all outgoing responses. We could achieve this by doing the following: .. code-block:: python @@ -150,11 +148,11 @@ this by doing the following: async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] == "http": - start_time = time.time() + start_time = time.monotonic() async def send_wrapper(message: Message) -> None: if message["type"] == "http.response.start": - process_time = time.time() - start_time + process_time = time.monotonic() - start_time headers = MutableScopeHeaders.from_message(message=message) headers["X-Process-Time"] = str(process_time) await send(message) @@ -166,21 +164,17 @@ this by doing the following: Inheriting AbstractMiddleware ----------------------------- -Litestar offers an :class:`AbstractMiddleware <.middleware.base.AbstractMiddleware>` class that can be extended to +Litestar offers an :class:`~litestar.middleware.base.AbstractMiddleware` class that can be extended to create middleware: .. code-block:: python - from typing import TYPE_CHECKING - from time import time + import time from litestar.enums import ScopeType from litestar.middleware import AbstractMiddleware from litestar.datastructures import MutableScopeHeaders - - - if TYPE_CHECKING: - from litestar.types import Message, Receive, Scope, Send + from litestar.types import Message, Receive, Scope, Send class MyMiddleware(AbstractMiddleware): @@ -188,15 +182,15 @@ create middleware: exclude = ["first_path", "second_path"] exclude_opt_key = "exclude_from_middleware" - async def __call__(self, scope: "Scope", receive: "Receive", send: "Send") -> None: - start_time = time() + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + start_time = time.monotonic() async def send_wrapper(message: "Message") -> None: if message["type"] == "http.response.start": - process_time = time() - start_time + process_time = time.monotonic() - start_time headers = MutableScopeHeaders.from_message(message=message) headers["X-Process-Time"] = str(process_time) - await send(message) + await send(message) await self.app(scope, receive, send_wrapper) @@ -204,11 +198,11 @@ The three class variables defined in the above example ``scopes``, ``exclude``, fine-tune for which routes and request types the middleware is called: -- The scopes variable is a set that can include either or both ``ScopeType.HTTP`` and ``ScopeType.WEBSOCKET`` , with the default being both. +- The scopes variable is a set that can include either or both : ``ScopeType.HTTP`` and ``ScopeType.WEBSOCKET`` , with the default being both. - ``exclude`` accepts either a single string or list of strings that are compiled into a regex against which the request's ``path`` is checked. -- ``exclude_opt_key`` is the key to use for in a route handler's ``opt`` dict for a boolean, whether to omit from the middleware. +- ``exclude_opt_key`` is the key to use for in a route handler's :class:`Router.opt ` dict for a boolean, whether to omit from the middleware. -Thus, in the following example, the middleware will only run against the route handler called ``not_excluded_handler``: +Thus, in the following example, the middleware will only run against the handler called ``not_excluded_handler`` for ``/greet`` route: .. literalinclude:: /examples/middleware/base.py :language: python @@ -222,8 +216,8 @@ Thus, in the following example, the middleware will only run against the route h Using DefineMiddleware to pass arguments ---------------------------------------- -Litestar offers a simple way to pass positional arguments (``*args``) and key-word arguments (``**kwargs``) to middleware -using the :class:`DefineMiddleware ` class. Let's extend +Litestar offers a simple way to pass positional arguments (``*args``) and keyword arguments (``**kwargs``) to middleware +using the :class:`~litestar.middleware.base.DefineMiddleware` class. Let's extend the factory function used in the examples above to take some args and kwargs and then use ``DefineMiddleware`` to pass these values to our middleware: diff --git a/3803/_sources/usage/middleware/using-middleware.rst.txt b/3803/_sources/usage/middleware/using-middleware.rst.txt index 2190676fc..47456bfc2 100644 --- a/3803/_sources/usage/middleware/using-middleware.rst.txt +++ b/3803/_sources/usage/middleware/using-middleware.rst.txt @@ -1,3 +1,5 @@ +.. _using-middleware: + Using Middleware ================ diff --git a/3803/_sources/usage/openapi/index.rst.txt b/3803/_sources/usage/openapi/index.rst.txt index 0d5a5d3c1..19ffb4c2c 100644 --- a/3803/_sources/usage/openapi/index.rst.txt +++ b/3803/_sources/usage/openapi/index.rst.txt @@ -6,15 +6,19 @@ Litestar has first class OpenAPI support offering the following features: - Automatic `OpenAPI 3.1.0 Schema `_ generation, which is available as both YAML and JSON. - Builtin support for static documentation site generation using several different libraries. -- Simple configuration using pydantic based classes. +- Full configuration using pre-defined type-safe dataclasses. Litestar includes a complete implementation of the `latest version of the OpenAPI specification `_ -using Python dataclasses. This implementation is used as a basis for generating OpenAPI specs, supporting builtins including -``dataclasses`` and ``TypedDict``, as well as Pydantic models and any 3rd party entities for which a plugin is implemented. +using Python dataclasses. This implementation is used as a basis for generating OpenAPI specs, +supporting :func:`~dataclasses.dataclass`, :class:`~typing.TypedDict`, +as well as Pydantic and msgspec models, and any 3rd party entities +for which a :ref:`plugin ` is implemented. This is also highly configurable - and users can customize the OpenAPI spec in a variety of ways - ranging from passing -configuration globally, to settings specific kwargs on route handler decorators. +configuration globally to setting +:ref:`specific kwargs on route ` +handler decorators. .. toctree:: diff --git a/3803/_sources/usage/plugins/index.rst.txt b/3803/_sources/usage/plugins/index.rst.txt index 2419afe98..5eb27c9d3 100644 --- a/3803/_sources/usage/plugins/index.rst.txt +++ b/3803/_sources/usage/plugins/index.rst.txt @@ -1,3 +1,5 @@ +.. _plugins: + ======= Plugins ======= @@ -89,11 +91,11 @@ The following example shows the actual implementation of the ``SerializationPlug :language: python :caption: ``SerializationPluginProtocol`` implementation example -:meth:`supports_type(self, field_definition: FieldDefinition) -> bool: ` +:meth:`supports_type(self, field_definition: FieldDefinition) -> bool: ` returns a :class:`bool` indicating whether the plugin supports serialization for the given type. Specifically, we return ``True`` if the parsed type is either a collection of SQLAlchemy models or a single SQLAlchemy model. -:meth:`create_dto_for_type(self, field_definition: FieldDefinition) -> type[AbstractDTO]: ` +:meth:`create_dto_for_type(self, field_definition: FieldDefinition) -> type[AbstractDTO]: ` takes a :class:`FieldDefinition ` instance as an argument and returns a :class:`SQLAlchemyDTO ` subclass and includes some logic that may be interesting to potential serialization plugin authors. diff --git a/3803/_sources/usage/requests.rst.txt b/3803/_sources/usage/requests.rst.txt index ac749f7d0..3dfef9743 100644 --- a/3803/_sources/usage/requests.rst.txt +++ b/3803/_sources/usage/requests.rst.txt @@ -160,3 +160,52 @@ The example below illustrates how to implement custom request class for the whol class on multiple layers, the layer closest to the route handler will take precedence. You can read more about this in the :ref:`usage/applications:layered architecture` section + + +Limits +------- + +Body size +^^^^^^^^^^ + +A limit for the allowed request body size can be set on all layers via the +``request_max_body_size`` parameter and defaults to 10MB. If a request body exceeds this +limit, a ``413 - Request Entity Too Large`` +response will be returned. This limit applies to all methods of consuming the request +body, including requesting it via the ``body`` parameter in a route handler and +consuming it through a manually constructed :class:`~litestar.connection.Request` +instance, e.g. in a middleware. + +To disable this limit for a specific handler / router / controller, it can be set to +:obj:`None`. + +.. danger:: + Setting ``request_max_body_size=None`` is strongly discouraged as it exposes the + application to a denial of service (DoS) attack by sending arbitrarily large + request bodies to the affected endpoint. Because Litestar has to read the whole body + to perform certain actions, such as parsing JSON, it will fill up all the available + memory / swap until the application / server crashes, should no outside limits be + imposed. + + This is generally only recommended in environments where the application is running + behind a reverse proxy such as NGINX, where a size limit is already set. + + +.. danger:: + Since ``request_max_body_size`` is handled on a per-request basis, it won't affect + middlewares or ASGI handlers when they try to access the request body via the raw + ASGI events. To avoid this, middlewares and ASGI handlers should construct a + :class:`~litestar.connection.Request` instance and use the regular + :meth:`~litestar.connection.Request.stream` / + :meth:`~litestar.connection.Request.body` or content-appropriate method to consume + the request body in a safe manner. + + +.. tip:: + For requests that define a ``Content-Length`` header, Litestar will not attempt to + read the request body should the header value exceed the ``request_max_body_size``. + + If the header value is within the allowed bounds, Litestar will verify during the + streaming of the request body that it does not exceed the size specified in the + header. Should the request exceed this size, it will abort the request with a + ``400 - Bad Request``. diff --git a/3803/_sources/usage/routing/handlers.rst.txt b/3803/_sources/usage/routing/handlers.rst.txt index abf362ead..d6207ed95 100644 --- a/3803/_sources/usage/routing/handlers.rst.txt +++ b/3803/_sources/usage/routing/handlers.rst.txt @@ -199,7 +199,7 @@ These are used exactly like :func:`@route() <.handlers.route>` with the sole exc from litestar import delete, get, patch, post, put, head from litestar.dto import DTOConfig, DTOData - from litestar.contrib.pydantic import PydanticDTO + from litestar.plugins.pydantic import PydanticDTO from pydantic import BaseModel diff --git a/3803/_sources/usage/routing/overview.rst.txt b/3803/_sources/usage/routing/overview.rst.txt index 3cda7fcfc..d67a73bee 100644 --- a/3803/_sources/usage/routing/overview.rst.txt +++ b/3803/_sources/usage/routing/overview.rst.txt @@ -137,7 +137,7 @@ Their purpose is to allow users to utilize Python OOP for better code organizati .. code-block:: python :caption: Registering a :class:`~.controller.Controller` - from litestar.contrib.pydantic import PydanticDTO + from litestar.plugins.pydantic import PydanticDTO from litestar.controller import Controller from litestar.dto import DTOConfig, DTOData from litestar.handlers import get, post, patch, delete diff --git a/3803/_sources/usage/security/abstract-authentication-middleware.rst.txt b/3803/_sources/usage/security/abstract-authentication-middleware.rst.txt index 9db3ac6c7..615c69834 100644 --- a/3803/_sources/usage/security/abstract-authentication-middleware.rst.txt +++ b/3803/_sources/usage/security/abstract-authentication-middleware.rst.txt @@ -65,7 +65,7 @@ example here let us say it is a `SQLAlchemy `_ mod # ... other fields follow, but we only require id for this example We will also need some utility methods to encode and decode tokens. To this end we will use -the `python-jose `_ library. We will also create a Pydantic model representing a +the `pyjwt `_ library. We will also create a Pydantic model representing a JWT Token: .. dropdown:: Click to see the JWT utility methods and Token model diff --git a/3803/_sources/usage/security/jwt.rst.txt b/3803/_sources/usage/security/jwt.rst.txt index fcf1abd91..a25f45be0 100644 --- a/3803/_sources/usage/security/jwt.rst.txt +++ b/3803/_sources/usage/security/jwt.rst.txt @@ -2,7 +2,7 @@ JWT Security Backends ===================== Litestar offers optional JWT based security backends. To use these make sure to install the -`python-jose `_ and `cryptography `_ +`pyjwt `_ and `cryptography `_ packages, or simply install Litestar with the ``jwt`` `extra `_: diff --git a/3803/_sources/usage/stores.rst.txt b/3803/_sources/usage/stores.rst.txt index e683eb81e..253cc9dee 100644 --- a/3803/_sources/usage/stores.rst.txt +++ b/3803/_sources/usage/stores.rst.txt @@ -35,6 +35,12 @@ Built-in stores A store backend by `redis `_. It offers all the guarantees and features of Redis, making it suitable for almost all applications. Offers `namespacing`_. +:class:`ValKeyStore ` + A store backed by `valkey `_, a fork of Redis created as the result of Redis' license changes. + Similarly to the RedisStore, it is suitable for almost all applications and supports `namespacing`_. + At the time of writing, :class:`Valkey ` is equivalent to :class:`redis.asyncio.Redis`, + and all notes pertaining to Redis also apply to Valkey. + .. admonition:: Why not memcached? :class: info diff --git a/3803/_sources/usage/testing.rst.txt b/3803/_sources/usage/testing.rst.txt index 90102f640..a2dc47d6c 100644 --- a/3803/_sources/usage/testing.rst.txt +++ b/3803/_sources/usage/testing.rst.txt @@ -42,6 +42,8 @@ We would then test it using the test client like so: from my_app.main import app + app.debug = True + def test_health_check(): with TestClient(app=app) as client: @@ -60,6 +62,8 @@ We would then test it using the test client like so: from my_app.main import app + app.debug = True + async def test_health_check(): async with AsyncTestClient(app=app) as client: @@ -90,6 +94,8 @@ Since we would probably need to use the client in multiple places, it's better t if TYPE_CHECKING: from litestar import Litestar + app.debug = True + @pytest.fixture(scope="function") def test_client() -> Iterator[TestClient[Litestar]]: @@ -114,6 +120,8 @@ Since we would probably need to use the client in multiple places, it's better t if TYPE_CHECKING: from litestar import Litestar + app.debug = True + @pytest.fixture(scope="function") async def test_client() -> AsyncIterator[AsyncTestClient[Litestar]]: @@ -279,6 +287,31 @@ But also this: assert response.text == "healthy" +Running a live server +--------------------- + +The test clients make use of HTTPX's ability to directly call into an ASGI app, without +having to run an actual server. In most cases this is sufficient but there are some +exceptions where this won't work, due to the limitations of the emulated client-server +communication. + +For example, when using server-sent events with an infinite generator, it will lock up +the test client, since HTTPX tries to consume the full response before returning a +request. + +Litestar offers two helper functions, +:func:`litestar.testing.subprocess_sync_client` and +:func:`litestar.testing.subprocess_async_client` that will +launch a Litestar instance with in a subprocess and set up an httpx client for running +tests. You can either load your actual app file or create subsets from it as you would +with the regular test client setup: + +.. literalinclude:: /examples/testing/subprocess_sse_app.py + :language: python + +.. literalinclude:: /examples/testing/test_subprocess_sse.py + :language: python + RequestFactory -------------- diff --git a/3803/_sources/usage/websockets.rst.txt b/3803/_sources/usage/websockets.rst.txt index d1bb34aaa..dc9dc7eeb 100644 --- a/3803/_sources/usage/websockets.rst.txt +++ b/3803/_sources/usage/websockets.rst.txt @@ -1,20 +1,31 @@ WebSockets ========== +There are three ways to handle WebSockets in Litestar: -Handling WebSockets in an application often involves dealing with low level constructs -such as the socket itself, setting up a loop and listening for incoming data, handling -exceptions, and parsing incoming and serializing outgoing data. In addition to the -low-level :class:`WebSocket route handler <.handlers.websocket>`, Litestar offers two -high level interfaces: +1. The low-level :class:`~litestar.handlers.websocket` route handler, providing basic + abstractions over the ASGI WebSocket interface +2. :class:`~litestar.handlers.websocket_listener` and :class:`~litestar.handlers.WebsocketListener`\ : + Reactive, event-driven WebSockets with full serialization and DTO support and support + for a synchronous interface +3. :class:`~litestar.handlers.websocket_stream` and :func:`~litestar.handlers.send_websocket_stream`\ : + Proactive, stream oriented WebSockets with full serialization and DTO support -- :class:`websocket_listener <.handlers.websocket_listener>` -- :class:`WebSocketListener <.handlers.WebsocketListener>` +The main difference between the low and high level interfaces is that, dealing with low +level interface requires, setting up a loop and listening for incoming data, handling +exceptions, client disconnects, and parsing incoming and serializing outgoing data. -These treat a WebSocket handler like any other route handler: as a callable that takes -in incoming data in an already pre-processed form and returns data to be serialized and -sent over the connection. The low level details will be handled behind the curtains. + + +WebSocket Listeners +-------------------- + +WebSocket Listeners can be used to interact with a WebSocket in an event-driven manner, +using a callback style interface. They treat a WebSocket handler like any other route +handler: A callable that takes in incoming data in an already pre-processed form and +returns data to be serialized and sent over the connection. The low level details will +be handled behind the curtains. .. code-block:: python @@ -44,7 +55,7 @@ type of data which should be received, and it will be converted accordingly. Receiving data --------------- +++++++++++++++ Data can be received in the listener via the ``data`` parameter. The data passed to this will be converted / parsed according to the given type annotation and supports @@ -78,7 +89,7 @@ form of JSON. Sending data ------------- ++++++++++++++ Sending data is done by simply returning the value to be sent from the handler function. Similar to receiving data, type annotations configure how the data is being handled. @@ -86,7 +97,8 @@ Values that are not :class:`str` or :class:`bytes` are assumed to be JSON encoda will be serialized accordingly before being sent. This serialization is available for all data types currently supported by Litestar ( :doc:`dataclasses `\ , :class:`TypedDict `, -:class:`NamedTuple `, :class:`msgspec.Struct`, etc.). +:class:`NamedTuple `, :class:`msgspec.Struct`, etc.), including +DTOs. .. tab-set:: @@ -113,25 +125,12 @@ all data types currently supported by Litestar ( :language: python -Transport modes ---------------- - -WebSockets have two transport modes: Text and binary. These can be specified -individually for receiving and sending data. - -.. note:: - It may seem intuitive that ``text`` and ``binary`` should map to :class:`str` and - :class:`bytes` respectively, but this is not the case. Listeners can receive and - send data in any format, independently of the mode. The mode only affects how - data is encoded during transport (i.e. on the protocol level). In most cases the - default mode - ``text`` - is all that's needed. Binary transport is usually employed - when sending binary blobs that don't have a meaningful string representation, such - as images. - +Setting transport modes ++++++++++++++++++++++++ -Setting the receive mode -++++++++++++++++++++++++ +Receive mode +~~~~~~~~~~~~ .. tab-set:: @@ -156,8 +155,8 @@ Setting the receive mode it will not respond to WebSocket events sending data in the text channel. -Setting the send mode -++++++++++++++++++++++ +Send mode +~~~~~~~~~ .. tab-set:: @@ -179,10 +178,10 @@ Setting the send mode Dependency injection --------------------- +++++++++++++++++++++ -:doc:`dependency-injection` is available as well and generally works the same as with -regular route handlers: +:doc:`dependency-injection` is available and generally works the same as in regular +route handlers: .. literalinclude:: /examples/websockets/dependency_injection_simple.py :language: python @@ -203,7 +202,7 @@ the ``yield`` will only be executed after the connection has been closed. Interacting with the WebSocket directly ---------------------------------------- ++++++++++++++++++++++++++++++++++++++++ Sometimes access to the socket instance is needed, in which case the :class:`WebSocket <.connection.WebSocket>` instance can be injected into the handler @@ -220,7 +219,7 @@ function via the ``socket`` argument: Customising connection acceptance ---------------------------------- ++++++++++++++++++++++++++++++++++ By default, Litestar will accept all incoming connections by awaiting ``WebSocket.accept()`` without arguments. This behavior can be customized by passing a custom ``connection_accept_handler`` function. Litestar will await this @@ -231,7 +230,7 @@ function to accept the connection. Class based WebSocket handling ------------------------------- +++++++++++++++++++++++++++++++ In addition to using a simple function as in the examples above, a class based approach is made possible by extending the @@ -254,7 +253,7 @@ encapsulate more complex logic. Custom WebSocket ----------------- +++++++++++++++++ .. versionadded:: 2.7.0 @@ -273,3 +272,118 @@ The example below illustrates how to implement a custom WebSocket class for the class on multiple layers, the layer closest to the route handler will take precedence. You can read more about this in the :ref:`usage/applications:layered architecture` section + + +WebSocket Streams +----------------- + +WebSocket streams can be used to proactively push data to a client, using an +asynchronous generator function. Data will be sent via the socket every time the +generator ``yield``\ s, until it is either exhausted or the client disconnects. + +.. literalinclude:: /examples/websockets/stream_basic.py + :language: python + :caption: Streaming the current time in 0.5 second intervals + + +Serialization ++++++++++++++ + +Just like with route handlers, type annotations configure how the data is being handled. +:class:`str` or :class:`bytes` will be sent as-is, while everything else will be encoded +as JSON before being sent. This serialization is available for all data types currently +supported by Litestar (:doc:`dataclasses `, +:class:`TypedDict `, :class:`NamedTuple `, +:class:`msgspec.Struct`, etc.), including DTOs. + + +Dependency Injection +++++++++++++++++++++ + +Dependency injection is available and works analogous to regular route handlers. + +.. important:: + One thing to keep in mind, especially for long-lived streams, is that dependencies + are scoped to the lifetime of the handler. This means that if for example a + database connection is acquired in a dependency, it will be held until the generator + stops. This may not be desirable in all cases, and acquiring resources ad-hoc inside + the generator itself preferable + + .. literalinclude:: /examples/websockets/stream_di_hog.py + :language: python + :caption: Bad: The lock will be held until the client disconnects + + + .. literalinclude:: /examples/websockets/stream_di_hog_fix.py + :language: python + :caption: Good: The lock will only be acquired when it's needed + + +Interacting with the WebSocket directly ++++++++++++++++++++++++++++++++++++++++ + +To interact with the :class:`WebSocket <.connection.WebSocket>` directly, it can be +injected into the generator function via the ``socket`` argument: + +.. literalinclude:: /examples/websockets/stream_socket_access.py + :language: python + + +Receiving data while streaming +++++++++++++++++++++++++++++++ + +By default, a stream will listen for a client disconnect in the background, and stop +the generator once received. Since this requires receiving data from the socket, it can +lead to data loss if the application is attempting to read from the same socket +simultaneously. + +.. tip:: + To prevent data loss, by default, ``websocket_stream`` will raise an + exception if it receives any data while listening for client disconnects. If + incoming data should be ignored, ``allow_data_discard`` should be set to ``True`` + +If receiving data while streaming is desired, +:func:`~litestar.handlers.send_websocket_stream` can be configured to not listen for +disconnects by setting ``listen_for_disconnect=False``. + +.. important:: + When using ``listen_for_disconnect=False``, the application needs to ensure the + disconnect event is received elsewhere, otherwise the stream will only terminate + when the generator is exhausted + + +Combining streaming and receiving data +--------------------------------------- + +To stream and receive data concurrently, the stream can be set up manually using +:func:`~litestar.handlers.send_websocket_stream` in combination with either a regular +:class:`~litestar.handlers.websocket` handler or a WebSocket listener. + +.. tab-set:: + + .. tab-item:: websocket_listener + + .. literalinclude:: /examples/websockets/stream_and_receive_listener.py + :language: python + + .. tab-item:: websocket handler + + .. literalinclude:: /examples/websockets/stream_and_receive_raw.py + :language: python + + +Transport modes +--------------- + +WebSockets have two transport modes: ``text`` and ``binary``. They dictate how bytes are +transferred over the wire and can be set independently from another, i.e. a socket can +send ``binary`` and receive ``text`` + + +It may seem intuitive that ``text`` and ``binary`` should map to :class:`str` and +:class:`bytes` respectively, but this is not the case. WebSockets can receive and +send data in any format, independently of the mode. The mode only affects how the +bytes are handled during transport (i.e. on the protocol level). In most cases the +default mode - ``text`` - is all that's needed. Binary transport is usually employed +when sending binary blobs that don't have a meaningful string representation, such +as images. diff --git a/3803/admonitions/sync-to-thread-info.html b/3803/admonitions/sync-to-thread-info.html index b2bdf811b..3616ddf76 100644 --- a/3803/admonitions/sync-to-thread-info.html +++ b/3803/admonitions/sync-to-thread-info.html @@ -1359,8 +1359,12 @@
  • pagination
  • params
  • plugins @@ -1398,6 +1402,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1538,8 +1543,10 @@ as I/O or computationally intensive tasks, can potentially block the main thread running the event loop, and in turn block the whole application.

    To mitigate this, the sync_to_thread parameter can be set to True, which -will result in the function being run in a thread pool. Should the function be -non-blocking, sync_to_thread should be set to False instead.

    +will result in the function being run in a thread pool.

    +

    If a synchronous function is non-blocking, setting sync_to_thread to False +will tell Litestar that the user is sure about its behavior +and the function can be treated as non-blocking.

    If a synchronous function is passed, without setting an explicit sync_to_thread value, a warning will be raised.

    diff --git a/3803/benchmarks.html b/3803/benchmarks.html index c035280b2..a9bdf54e1 100644 --- a/3803/benchmarks.html +++ b/3803/benchmarks.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/contribution-guide.html b/3803/contribution-guide.html index 5e235fea1..984e7b92d 100644 --- a/3803/contribution-guide.html +++ b/3803/contribution-guide.html @@ -1360,8 +1360,12 @@
  • pagination
  • params
  • plugins @@ -1399,6 +1403,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1561,96 +1566,12 @@

    Setting up the environmentGitHub Codespaces, the environment will bootstrap itself automatically. The steps below are for local development.

      -
    1. Install PDM:

      -
      - -
      -
      -
      Using our Make target to install PDM#
      -
      make install-pdm
      -
      -
      -
      -
      - -
      -
      -
      Using pipx#
      -
      pipx install pdm
      -
      -
      -
      -
      - -
      -
      -
      Using Homebrew#
      -
      brew install pdm
      -
      -
      -
      -
      -
      -
    2. +
    3. Install uv:

    4. Run make install to create a virtual environment -and install the required development dependencies or run the PDM installation command manually:

      -
      -
      Installing the documentation dependencies#
      -
      pdm install
      -
      -
      -
      -
    5. -
    6. If you’re working on the documentation and need to build it locally, install the extra dependencies with -make docs-install or:

      -
      -
      Installing the documentation dependencies#
      -
      pdm install -G:docs
      -
      -
      -
      -
    7. -
    8. Install pre-commit:

      -
      - -
      -
      -
      Using pip#
      -
      python3 -m pip install pre-commit
      -
      -
      -
      -
      - -
      -
      -
      Using pipx#
      -
      pipx install pre-commit
      -
      -
      -
      -
      - -
      -
      -
      Using Homebrew#
      -
      brew install pre-commit
      -
      -
      -
      -
      -
      -
    9. -
    10. Install our pre-commit hooks. by running make install or:

      -
      -
      Installing pre-commit hooks#
      -
      pre-commit install --install-hooks
      +and install the required development dependencies or run the uv sync command manually:

      +
      +
      Installing the documentation dependencies#
      +
      uv install
       
      @@ -1658,14 +1579,13 @@

      Setting up the environment

      Tip

      -

      Many modern IDEs like PyCharm or VS Code will enable the PDM-managed virtualenv that is created in step 2 +

      Many modern IDEs like PyCharm or VS Code will enable the uv-managed virtualenv that is created in step 2 for you automatically. If your IDE / editor does not offer this functionality, then you will need to manually activate the virtualenv yourself. Otherwise you may encounter errors or unexpected behaviour when trying to run the commands referenced within this document.

      -

      To activate the virtualenv manually, please consult PDM’s documentation on -working with virtual environments. -A simpler alternative is using the PDM plugin pdm-shell.

      +

      To activate the virtualenv manually, please consult uv’s documentation on +working with virtual environments.

      The rest of this document will assume this environment is active wherever commands are referenced.

      @@ -1768,17 +1688,17 @@

      Docs theme and appearance

      Running the docs locally#

      -

      To run or build the docs locally, you need to first install the required dependencies:

      -
      -
      Installing the documentation dependencies#
      -
      pdm install -G:docs
      +

      You can serve the documentation locally with

      +
      +
      Serving the documentation locally#
      +
      make docs-serve
       
      -

      Then you can serve the documentation with our helpful Makefile targets:

      -
      -
      Serving the documentation locally#
      -
      make docs-serve
      +

      or build it with

      +
      +
      Serving the documentation locally#
      +
      make docs
       
      @@ -1808,8 +1728,8 @@

      Adding examples/tests/examples that tests the aspects of the example that it demonstrates

    11. Reference the example in the rst file with an external reference code block, e.g.

    12. -
      - +
      +
      An example of how to use literal includes of external files#
      .. literalinclude:: /examples/test_thing.py
          :language: python
          :caption: All includes should have a descriptive caption
      @@ -1833,8 +1753,8 @@ 

      Automatically execute examplescurl command that’s being invoked. The URL is built automatically, so the specified path can just be a path relative to the app.

      In practice, this looks like the following:

      -
      - +
      +
      An example of how to use the automatic example runner#
      from typing import Dict
       
       from litestar import Litestar, get
      @@ -1853,8 +1773,8 @@ 

      Automatically execute examples - +
      +
      An example of how to use the automatic example runner#
         from typing import Dict
       
          from litestar import Litestar, get
      @@ -1884,16 +1804,16 @@ 

      Automatically execute examples#

      1. Checkout the main branch:

        -
        -
        Checking out the main branch of the litestar repository#
        +
        +
        Checking out the main branch of the litestar repository#
        git checkout main
         
      2. Run the release preparation script:

        -
        -
        Preparing a new release#
        +
        +
        Preparing a new release#
        python tools/prepare_release.py <new version number> --update-version --create-draft-release
         
        @@ -1909,8 +1829,8 @@

        Creating a New Release
      3. Review the generated changelog entry in 2.x Changelog to ensure it looks correct.

      4. Commit the changes to main:

        -
        -
        Committing the changes to the main branch#
        +
        +
        Committing the changes to the main branch#
        git commit -am "chore(release): prepare release vX.Y.Z"
         
        @@ -1918,16 +1838,16 @@

        Creating a New ReleaseReplace vX.Y.Z with the actual version number.

      5. Create a new branch for the release:

        -
        - +
        +
        Creating a new branch for the release#
        git checkout -b vX.Y.Z
         
      6. Push the changes to a vX.Y.Z branch:

        -
        -
        Pushing the changes to the vX.Y.Z branch#
        +
        +
        Pushing the changes to the vX.Y.Z branch#
        git push origin vX.Y.Z
         
        diff --git a/3803/genindex.html b/3803/genindex.html index 5e7394cf0..b213d770c 100644 --- a/3803/genindex.html +++ b/3803/genindex.html @@ -46,8 +46,14 @@ - - + + + + + @@ -1356,8 +1362,12 @@
      7. pagination
      8. params
      9. plugins @@ -1395,6 +1405,7 @@
      10. memory
      11. redis
      12. registry
      13. +
      14. valkey
      15. template
      16. @@ -1541,8 +1552,6 @@

        Symbols

      17. **kwargs (litestar.background_tasks.BackgroundTask parameter)
      18. get_asyncio_executor() (in module litestar.concurrency)
      19. -
      20. get_config_for_model_type() (litestar.contrib.pydantic.PydanticDTO class method) +
      21. get_config_for_model_type() (litestar.dto.base_dto.AbstractDTO class method)
      22. get_cookie_key_set() (litestar.middleware.session.client_side.ClientSideSessionBackend method) @@ -5643,10 +5746,10 @@

        G

      23. get_response_handler() (litestar.handlers.HTTPRouteHandler method)
      24. - - +
      25. handle_client_shutdown (litestar.stores.redis.RedisStore parameter) + +
      26. handler (litestar.app.HandlerIndex attribute)
      27. handler_id (litestar.dto.base_dto.AbstractDTO.create_for_field_definition parameter) @@ -5833,10 +5946,10 @@

        H

      28. has_path() (litestar.openapi.plugins.OpenAPIRenderPlugin method)
      29. -
      30. has_typed_init() (litestar.contrib.pydantic.PydanticDIPlugin method) +
      31. has_typed_init() (litestar.plugins.DIPlugin method)
      32. head (class in litestar.handlers) @@ -5961,7 +6074,7 @@

        H

      33. (litestar.channels.plugin.ChannelsPlugin.subscribe parameter)
      34. -
      35. history_restore_request (litestar.contrib.htmx.request.HTMXDetails property) +
      36. history_restore_request (litestar.plugins.htmx.HTMXDetails property)
      37. host (litestar.datastructures.Address attribute)
      38. @@ -5973,22 +6086,30 @@

        H

      39. (litestar.static_files.StaticFilesConfig attribute)
      40. -
      41. HTMXDetails (class in litestar.contrib.htmx.request) +
      42. HTMXConfig (class in litestar.plugins.htmx) +
      43. +
      44. HTMXDetails (class in litestar.plugins.htmx)
      45. -
      46. HTMXRequest (class in litestar.contrib.htmx.request) +
      47. HTMXHeaders (class in litestar.plugins.htmx)
      48. -
      49. HTMXTemplate (class in litestar.contrib.htmx.response) +
      50. HtmxHeaderType (class in litestar.plugins.htmx) +
      51. +
      52. HTMXPlugin (class in litestar.plugins.htmx) +
      53. +
      54. HTMXRequest (class in litestar.plugins.htmx) +
      55. +
      56. HTMXTemplate (class in litestar.plugins.htmx)
      57. HTTP_100_CONTINUE (in module litestar.status_codes)
      58. + + - @@ -6227,12 +6348,12 @@

        I

      59. ImproperlyConfiguredException
      60. -
      61. include (litestar.contrib.pydantic.PydanticInitPlugin parameter) +
      62. include (litestar.dto.config.DTOConfig attribute)
      63. include_compressed_body (litestar.middleware.logging.LoggingMiddlewareConfig attribute) @@ -6263,6 +6384,8 @@

        I

      64. (litestar.handlers.put parameter)
      65. (litestar.openapi.OpenAPIController attribute) +
      66. +
      67. (litestar.plugins.prometheus.PrometheusController attribute)
      68. (litestar.router.Router parameter)
      69. @@ -6320,6 +6443,8 @@

        I

      70. is_annotated (litestar.typing.FieldDefinition property)
      71. is_any (litestar.typing.FieldDefinition property) +
      72. +
      73. is_attrs_class() (in module litestar.plugins.attrs)
      74. is_collection (litestar.typing.FieldDefinition property)
      75. @@ -6327,10 +6452,10 @@

        I

      76. is_constrained (litestar.params.KwargDefinition property)
      77. -
      78. is_constrained_field() (litestar.contrib.pydantic.PydanticSchemaPlugin static method) +
      79. is_constrained_field() (litestar.plugins.OpenAPISchemaPlugin static method)
      80. is_dataclass_type (litestar.typing.FieldDefinition property) @@ -6395,12 +6520,14 @@

        I

      81. is_plugin_supported_field() (litestar.plugins.OpenAPISchemaPlugin method)
      82. -
      83. is_plugin_supported_type() (litestar.contrib.pydantic.PydanticSchemaPlugin static method) +
      84. is_plugin_supported_type() (litestar.plugins.attrs.AttrsSchemaPlugin static method)
      85. is_required (litestar.typing.FieldDefinition property) @@ -6425,10 +6552,10 @@

        I

      86. is_typeddict_type (litestar.typing.FieldDefinition property)
      87. -
      88. is_undefined_sentinel() (litestar.contrib.pydantic.PydanticSchemaPlugin static method) +
      89. is_undefined_sentinel() (litestar.plugins.OpenAPISchemaPlugin static method)
      90. is_union (litestar.typing.FieldDefinition property) @@ -6619,6 +6746,12 @@

        K

      91. (litestar.stores.redis.RedisStore.get parameter)
      92. (litestar.stores.redis.RedisStore.set parameter) +
      93. +
      94. (litestar.stores.valkey.ValkeyStore.delete parameter) +
      95. +
      96. (litestar.stores.valkey.ValkeyStore.get parameter) +
      97. +
      98. (litestar.stores.valkey.ValkeyStore.set parameter)
      99. (litestar.template.TemplateEngineProtocol.register_template_callable parameter)
      100. @@ -6655,6 +6788,8 @@

        K

        L

        - + - + - +
        • litestar.dto.config @@ -7113,6 +7252,8 @@

          L

        • module
        +
        +
      101. LocationType (class in litestar.plugins.htmx) +
      102. log_exceptions (litestar.logging.config.BaseLoggingConfig attribute)
      103. middleware_logging_config (litestar.plugins.structlog.StructlogConfig attribute) @@ -7889,12 +8082,12 @@

        M

      104. min_properties (litestar.openapi.spec.Schema attribute)
      105. -
      106. NamespacedStore (class in litestar.stores.base) @@ -8328,14 +8543,14 @@

        O

      107. OffsetPagination (class in litestar.pagination)
      108. -
      109. on_accept (litestar.handlers.WebsocketListener attribute) +
      110. on_accept (litestar.handlers.WebsocketListenerRouteHandler attribute)
      111. +
      112. on_accept() (litestar.handlers.WebsocketListener method) +
      113. on_accept_dependencies (litestar.handlers.WebsocketListenerRouteHandler.default_connection_lifespan parameter)
      114. on_app_init (litestar.app.Litestar parameter) @@ -8352,16 +8567,18 @@

        O

      115. (litestar.channels.plugin.ChannelsPlugin method)
      116. (litestar.contrib.opentelemetry.OpenTelemetryPlugin method) -
      117. -
      118. (litestar.contrib.pydantic.PydanticInitPlugin method) -
      119. -
      120. (litestar.contrib.pydantic.PydanticPlugin method)
      121. (litestar.plugins.flash.FlashPlugin method) +
      122. +
      123. (litestar.plugins.htmx.HTMXPlugin method)
      124. (litestar.plugins.InitPluginProtocol method)
      125. (litestar.plugins.problem_details.ProblemDetailsPlugin method) +
      126. +
      127. (litestar.plugins.pydantic.PydanticInitPlugin method) +
      128. +
      129. (litestar.plugins.pydantic.PydanticPlugin method)
      130. (litestar.plugins.structlog.StructlogPlugin method)
      131. @@ -8370,14 +8587,14 @@

        O

      132. on_cli_init() (litestar.plugins.CLIPluginProtocol method)
      133. -
      134. on_disconnect (litestar.handlers.WebsocketListener attribute) +
      135. on_disconnect (litestar.handlers.WebsocketListenerRouteHandler attribute)
      136. +
      137. on_disconnect() (litestar.handlers.WebsocketListener method) +
      138. on_disconnect_dependencies (litestar.handlers.WebsocketListenerRouteHandler.default_connection_lifespan parameter)
      139. on_event (litestar.channels.subscriber.Subscriber.run_in_background parameter) @@ -8474,10 +8691,10 @@

        O

      140. openapi_controller (litestar.openapi.OpenAPIConfig attribute)
      141. -
      142. ParametersMap (in module litestar.types)
      143. -
      144. params (litestar.contrib.htmx.response.HTMXTemplate parameter) +
      145. params (litestar.plugins.htmx.HTMXTemplate parameter)
      146. patch (class in litestar.handlers) @@ -8786,6 +9015,8 @@

        P

      147. (litestar.handlers.post parameter)
      148. (litestar.handlers.put parameter) +
      149. +
      150. (litestar.handlers.websocket_stream parameter)
      151. (litestar.handlers.WebsocketListener attribute)
      152. @@ -8818,6 +9049,8 @@

        P

      153. (litestar.openapi.plugins.SwaggerRenderPlugin parameter)
      154. (litestar.openapi.plugins.YamlRenderPlugin parameter) +
      155. +
      156. (litestar.plugins.prometheus.PrometheusController attribute)
      157. (litestar.response.base.Response.delete_cookie parameter)
      158. @@ -8948,6 +9181,8 @@

        P

      159. (litestar.datastructures.URL attribute)
      160. (litestar.stores.redis.RedisStore.with_client parameter) +
      161. +
      162. (litestar.stores.valkey.ValkeyStore.with_client parameter)
      163. (litestar.testing.RequestFactory attribute)
      164. @@ -8966,14 +9201,18 @@

        P

      165. predicate (litestar.typing.FieldDefinition.match_predicate_recursively parameter)
      166. -
      167. prefer_alias (litestar.contrib.pydantic.PydanticInitPlugin parameter) +
      168. prefer_alias (litestar.plugins.pydantic.PydanticInitPlugin parameter)
      169. prefix (litestar.openapi.spec.XML attribute) + +
      170. prefix_items (litestar.openapi.spec.Schema attribute)
      171. preflight_headers (litestar.config.cors.CORSConfig property) @@ -8994,7 +9233,13 @@

        P

      172. processors (litestar.logging.config.StructLoggingConfig attribute)
      173. -
      174. prompt (litestar.contrib.htmx.request.HTMXDetails property) +
      175. PrometheusConfig (class in litestar.plugins.prometheus) +
      176. +
      177. PrometheusController (class in litestar.plugins.prometheus) +
      178. +
      179. PrometheusMiddleware (class in litestar.plugins.prometheus) +
      180. +
      181. prompt (litestar.plugins.htmx.HTMXDetails property)
      182. propagate (litestar.logging.config.LoggingConfig attribute)
      183. @@ -9030,9 +9275,9 @@

        P

      184. (litestar.channels.plugin.ChannelsPlugin method)
      185. -
      186. push_url (litestar.contrib.htmx.response.HTMXTemplate parameter) +
      187. push_url (litestar.plugins.htmx.HTMXTemplate parameter)
      188. -
      189. PushUrl (class in litestar.contrib.htmx.response) +
      190. PushUrl (class in litestar.plugins.htmx)
      191. put (class in litestar.handlers) @@ -9046,15 +9291,15 @@

        P

      192. put_subscriber_history() (litestar.channels.plugin.ChannelsPlugin method)
      193. -
      194. PydanticDIPlugin (class in litestar.contrib.pydantic) +
      195. PydanticDIPlugin (class in litestar.plugins.pydantic)
      196. -
      197. PydanticDTO (class in litestar.contrib.pydantic) +
      198. PydanticDTO (class in litestar.plugins.pydantic)
      199. -
      200. PydanticInitPlugin (class in litestar.contrib.pydantic) +
      201. PydanticInitPlugin (class in litestar.plugins.pydantic)
      202. -
      203. PydanticPlugin (class in litestar.contrib.pydantic) +
      204. PydanticPlugin (class in litestar.plugins.pydantic)
      205. -
      206. PydanticSchemaPlugin (class in litestar.contrib.pydantic) +
      207. PydanticSchemaPlugin (class in litestar.plugins.pydantic)
      208. @@ -9078,6 +9323,10 @@

        Q

      209. renew_on_access (litestar.middleware.session.server_side.ServerSideSessionConfig attribute)
      210. -
      211. ReplaceUrl (class in litestar.contrib.htmx.response) +
      212. ReplaceUrl (class in litestar.plugins.htmx)
      213. Request (class in litestar.connection)
      214. @@ -9500,6 +9751,8 @@

        R

      215. (litestar.handlers.put parameter)
      216. (litestar.openapi.OpenAPIController attribute) +
      217. +
      218. (litestar.plugins.prometheus.PrometheusController attribute)
      219. (litestar.router.Router parameter)
      220. @@ -9516,6 +9769,28 @@

        R

      221. request_log_message (litestar.middleware.logging.LoggingMiddlewareConfig attribute)
      222. +
      223. request_max_body_size (litestar.app.Litestar parameter) + +
      224. request_media_type (litestar.testing.RequestFactory.patch parameter)
      225. + + - -
      226. Reswap (class in litestar.contrib.htmx.response) +
      227. Reswap (class in litestar.plugins.htmx)
      228. -
      229. Retarget (class in litestar.contrib.htmx.response) +
      230. Retarget (class in litestar.plugins.htmx)
      231. retrieve_cached_history() (litestar.middleware.rate_limit.RateLimitMiddleware method)
      232. @@ -9872,12 +10153,16 @@

        R

      233. (litestar.handlers.post parameter)
      234. (litestar.handlers.put parameter) +
      235. +
      236. (litestar.handlers.websocket_stream parameter)
      237. (litestar.handlers.WebsocketListener attribute)
      238. (litestar.handlers.WebsocketListenerRouteHandler parameter)
      239. (litestar.openapi.OpenAPIController attribute) +
      240. +
      241. (litestar.plugins.prometheus.PrometheusController attribute)
      242. (litestar.router.Router parameter)
      243. @@ -10041,14 +10326,16 @@

        S

      244. (litestar.params.Parameter parameter)
      245. -
      246. schema_creator (litestar.contrib.pydantic.PydanticSchemaPlugin.for_pydantic_model parameter) +
      247. schema_creator (litestar.dto.base_dto.AbstractDTO.create_openapi_schema parameter)
      248. schema_else (litestar.openapi.spec.Schema attribute) @@ -10165,6 +10452,8 @@

        S

      249. (litestar.middleware.session.base.BaseBackendConfig attribute)
      250. (litestar.openapi.spec.OAuthFlow attribute) +
      251. +
      252. (litestar.plugins.prometheus.PrometheusConfig attribute)
      253. (litestar.security.AbstractSecurityConfig attribute)
      254. @@ -10259,6 +10548,8 @@

        S

      255. (litestar.openapi.spec.OpenAPI attribute)
      256. (litestar.openapi.spec.Operation attribute) +
      257. +
      258. (litestar.plugins.prometheus.PrometheusController attribute)
      259. (litestar.router.Router parameter)
      260. @@ -10368,6 +10659,8 @@

        S

      261. send_data() (litestar.connection.WebSocket method) +
      262. +
      263. send_handler (litestar.handlers.send_websocket_stream parameter)
      264. send_json() (litestar.connection.WebSocket method) @@ -10403,6 +10696,8 @@

        S

      265. (litestar.security.jwt.OAuth2PasswordBearerAuth.login parameter)
      266. +
      267. send_websocket_stream() (in module litestar.handlers) +
      268. send_wrapper() (litestar.connection.WebSocket method)
      269. SerializationException @@ -10538,12 +10833,14 @@

        S

      270. (litestar.stores.memory.MemoryStore method)
      271. (litestar.stores.redis.RedisStore method) +
      272. +
      273. (litestar.stores.valkey.ValkeyStore method)
      274. - - +
      275. set_rate_limit_headers (litestar.middleware.rate_limit.RateLimitConfig attribute) +
      276. +
      277. set_request_class_globally (litestar.plugins.htmx.HTMXConfig attribute)
      278. set_session() (litestar.connection.ASGIConnection method)
      279. @@ -10626,6 +10925,8 @@

        S

      280. (litestar.handlers.post parameter)
      281. (litestar.handlers.put parameter) +
      282. +
      283. (litestar.handlers.websocket_stream parameter)
      284. (litestar.handlers.WebsocketListener attribute)
      285. @@ -10634,6 +10935,8 @@

        S

      286. (litestar.handlers.WebsocketRouteHandler parameter)
      287. (litestar.openapi.OpenAPIController attribute) +
      288. +
      289. (litestar.plugins.prometheus.PrometheusController attribute)
      290. (litestar.router.Router parameter)
      291. @@ -10652,6 +10955,8 @@

        S

      292. (litestar.handlers.BaseRouteHandler parameter)
      293. (litestar.openapi.OpenAPIController attribute) +
      294. +
      295. (litestar.plugins.prometheus.PrometheusController attribute)
      296. (litestar.router.Router parameter)
      297. @@ -10680,8 +10985,12 @@

        S

      298. (litestar.params.DependencyKwarg attribute)
      299. -
      300. socket (litestar.handlers.WebsocketListenerRouteHandler.default_connection_lifespan parameter) +
      301. socket (litestar.handlers.send_websocket_stream parameter) + +
      302. stale_while_revalidate (litestar.datastructures.CacheControlHeader attribute)
      303. standalone_preset_js_url (litestar.openapi.plugins.SwaggerRenderPlugin parameter) @@ -10902,6 +11211,8 @@

        S

      304. (class in litestar.response.streaming)
      305. +
      306. stream (litestar.handlers.send_websocket_stream parameter) +
      307. stream() (litestar.connection.Request method)
      308. stream_events() (litestar.channels.backends.asyncpg.AsyncPgChannelsBackend method) @@ -10973,6 +11284,10 @@

        S

      309. sub (litestar.security.jwt.Token attribute) +
      310. +
      311. subprocess_async_client() (in module litestar.testing) +
      312. +
      313. subprocess_sync_client() (in module litestar.testing)
      314. subprotocols (litestar.connection.WebSocket.accept parameter) @@ -11110,6 +11425,8 @@

        T

      315. (litestar.openapi.spec.OpenAPI attribute)
      316. (litestar.openapi.spec.Operation attribute) +
      317. +
      318. (litestar.plugins.prometheus.PrometheusController attribute)
      319. (litestar.router.Router parameter)
      320. @@ -11120,7 +11437,7 @@

        T

      321. (litestar.testing.create_test_client parameter)
      322. -
      323. target (litestar.contrib.htmx.request.HTMXDetails property) +
      324. target (litestar.plugins.htmx.HTMXDetails property)
      325. target_type (litestar.serialization.decode_json parameter) @@ -11282,12 +11599,14 @@

        T

      326. to_header_list() (litestar.datastructures.Headers method)
      327. -
      328. to_openapi_schema() (litestar.contrib.pydantic.PydanticSchemaPlugin method) +
      329. to_openapi_schema() (litestar.openapi.OpenAPIConfig method)
      330. to_response() (litestar.exceptions.responses.ExceptionResponseContent method) @@ -11420,15 +11739,17 @@

        T

      331. tracer_provider (litestar.contrib.opentelemetry.OpenTelemetryConfig attribute)
      332. -
      333. trigger (litestar.contrib.htmx.request.HTMXDetails property) +
      334. trigger (litestar.plugins.htmx.HTMXDetails property) +
      335. +
      336. trigger_event (litestar.plugins.htmx.HTMXTemplate parameter)
      337. -
      338. trigger_event (litestar.contrib.htmx.response.HTMXTemplate parameter) +
      339. trigger_name (litestar.plugins.htmx.HTMXDetails property)
      340. -
      341. trigger_name (litestar.contrib.htmx.request.HTMXDetails property) +
      342. TriggerEvent (class in litestar.plugins.htmx)
      343. -
      344. TriggerEvent (class in litestar.contrib.htmx.response) +
      345. TriggerEventType (class in litestar.plugins.htmx)
      346. -
      347. triggering_event (litestar.contrib.htmx.request.HTMXDetails property) +
      348. triggering_event (litestar.plugins.htmx.HTMXDetails property)
      349. type (litestar.openapi.spec.Schema attribute) @@ -11472,6 +11793,8 @@

        T

      350. (litestar.handlers.WebsocketListenerRouteHandler parameter)
      351. (litestar.openapi.OpenAPIController attribute) +
      352. +
      353. (litestar.plugins.prometheus.PrometheusController attribute)
      354. (litestar.router.Router parameter)
      355. @@ -11508,6 +11831,8 @@

        T

      356. (litestar.handlers.post parameter)
      357. (litestar.handlers.put parameter) +
      358. +
      359. (litestar.handlers.websocket_stream parameter)
      360. (litestar.handlers.WebsocketListener attribute)
      361. @@ -11516,6 +11841,8 @@

        T

      362. (litestar.handlers.WebsocketRouteHandler parameter)
      363. (litestar.openapi.OpenAPIController attribute) +
      364. +
      365. (litestar.plugins.prometheus.PrometheusController attribute)
      366. (litestar.response.base.Response parameter)
      367. @@ -11634,10 +11961,10 @@

        U

      368. (litestar.repository.abc.AbstractSyncRepository method)
      369. - - + @@ -11838,6 +12177,12 @@

        W

      370. warn() (litestar.types.Logger method)
      371. +
      372. warn_on_data_discard (litestar.handlers.send_websocket_stream parameter) + +
      373. warning() (litestar.types.Logger method)
      374. webhooks (litestar.openapi.OpenAPIConfig attribute) @@ -11856,6 +12201,8 @@

        W

      375. (litestar.config.app.AppConfig attribute)
      376. (litestar.controller.Controller attribute) +
      377. +
      378. (litestar.handlers.websocket_stream parameter)
      379. (litestar.handlers.WebsocketListener attribute)
      380. @@ -11864,6 +12211,8 @@

        W

      381. (litestar.handlers.WebsocketRouteHandler parameter)
      382. (litestar.openapi.OpenAPIController attribute) +
      383. +
      384. (litestar.plugins.prometheus.PrometheusController attribute)
      385. (litestar.router.Router parameter)
      386. @@ -11879,6 +12228,8 @@

        W

      387. websocket_listener (in module litestar.handlers) +
      388. +
      389. websocket_stream() (in module litestar.handlers)
      390. WebSocketAcceptEvent (class in litestar.types)
      391. @@ -11910,7 +12261,7 @@

        W

      392. template
      393. @@ -1640,12 +1645,6 @@

        SponsorsTelemetry Sports

      -
      - - Stok - -

      Stok

      -

      We invite organizations and individuals to join our sponsorship program. By becoming a sponsor on Polar (preferred), or other platforms like GitHub and Open Collective, you can play a pivotal role in our project’s growth.

      diff --git a/3803/migration/fastapi.html b/3803/migration/fastapi.html index eb24c24bc..0b29e54d8 100644 --- a/3803/migration/fastapi.html +++ b/3803/migration/fastapi.html @@ -1361,8 +1361,12 @@
    13. pagination
    14. params
    15. plugins @@ -1400,6 +1404,7 @@
    16. memory
    17. redis
    18. registry
    19. +
    20. valkey
    21. template
    22. diff --git a/3803/migration/flask.html b/3803/migration/flask.html index 513f6dc9c..a51dee3e4 100644 --- a/3803/migration/flask.html +++ b/3803/migration/flask.html @@ -1361,8 +1361,12 @@
    23. pagination
    24. params
    25. plugins @@ -1400,6 +1404,7 @@
    26. memory
    27. redis
    28. registry
    29. +
    30. valkey
    31. template
    32. diff --git a/3803/migration/index.html b/3803/migration/index.html index d06eaab78..becbdf5fa 100644 --- a/3803/migration/index.html +++ b/3803/migration/index.html @@ -1357,8 +1357,12 @@
    33. pagination
    34. params
    35. plugins @@ -1396,6 +1400,7 @@
    36. memory
    37. redis
    38. registry
    39. +
    40. valkey
    41. template
    42. diff --git a/3803/objects.inv b/3803/objects.inv index 4c69da7e50672008c1b59faec105f91a12cc1807..faa758c14d7b29bdd11cea9f94621ee524d3121c 100644 GIT binary patch literal 60377 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 literal 58512 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

      y~8w*nf$CTfKap?&EaD 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 diff --git a/3803/py-modindex.html b/3803/py-modindex.html index e2420e4ec..695262a68 100644 --- a/3803/py-modindex.html +++ b/3803/py-modindex.html @@ -46,8 +46,14 @@ - - + + + + + @@ -1359,8 +1365,12 @@

    43. pagination
    44. params
    45. plugins @@ -1398,6 +1408,7 @@
    46. memory
    47. redis
    48. registry
    49. +
    50. valkey
    51. template
    52. @@ -1832,16 +1843,36 @@

      Python Module Index

          litestar.plugins + + +     + litestar.plugins.attrs +     litestar.plugins.flash + + +     + litestar.plugins.htmx +     litestar.plugins.problem_details + + +     + litestar.plugins.prometheus + + + +     + litestar.plugins.pydantic +     @@ -1962,6 +1993,11 @@

      Python Module Index

          litestar.stores.registry + + +     + litestar.stores.valkey +     @@ -1972,6 +2008,11 @@

      Python Module Index

          litestar.testing + + +     + litestar.types +     diff --git a/3803/reference/app.html b/3803/reference/app.html index 58ffb9a83..1366ca1d6 100644 --- a/3803/reference/app.html +++ b/3803/reference/app.html @@ -1361,8 +1361,12 @@
    53. pagination
    54. params
    55. plugins @@ -1400,6 +1404,7 @@
    56. memory
    57. redis
    58. registry
    59. +
    60. valkey
    61. template
    62. @@ -1538,6 +1543,13 @@

      app#

      +
      +
      +litestar.app.DEFAULT_OPENAPI_CONFIG = OpenAPIConfig(title='Litestar API', version='1.0.0', create_examples=False, random_seed=10, contact=None, description=None, external_docs=None, license=None, security=None, components=Components(schemas={}, responses=None, parameters=None, examples=None, request_bodies=None, headers=None, security_schemes=None, links=None, callbacks=None, path_items=None), servers=[Server(url='/', description=None, variables=None)], summary=None, tags=None, terms_of_service=None, use_handler_docstrings=False, webhooks=None, operation_id_creator=<function default_operation_id_creator>, path=None, render_plugins=[<litestar.openapi.plugins.YamlRenderPlugin object>, <litestar.openapi.plugins.RedocRenderPlugin object>, <litestar.openapi.plugins.JsonRenderPlugin object>, <litestar.openapi.plugins.SwaggerRenderPlugin object>, <litestar.openapi.plugins.RapidocRenderPlugin object>, <litestar.openapi.plugins.StoplightRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>], openapi_router=None, openapi_controller=None, root_schema_site='redoc', enabled_endpoints={'openapi.yml', 'redoc', 'openapi.json', 'oauth2-redirect.html', 'swagger', 'rapidoc', 'elements', 'openapi.yaml'})#
      +

      The default OpenAPI config used if not configuration is explicitly passed to the +Litestar instance constructor.

      +
      +
      class litestar.app.HandlerIndex#
      @@ -1574,7 +1586,7 @@ and Route Handlers should be registered on it.

      -__init__(route_handlers: Sequence[ControllerRouterHandler] | None = None, *, after_exception: Sequence[AfterExceptionHookHandler] | None = None, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, allowed_hosts: Sequence[str] | AllowedHostsConfig | None = None, before_request: BeforeRequestHookHandler | None = None, before_send: Sequence[BeforeMessageSendHookHandler] | None = None, cache_control: CacheControlHeader | None = None, compression_config: CompressionConfig | None = None, cors_config: CORSConfig | None = None, csrf_config: CSRFConfig | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, debug: bool | None = None, dependencies: Dependencies | None = None, etag: ETag | None = None, event_emitter_backend: type[BaseEventEmitterBackend] = <class 'litestar.events.emitter.SimpleEventEmitter'>, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, listeners: Sequence[EventListener] | None = None, logging_config: BaseLoggingConfig | EmptyType | None = _EmptyEnum.EMPTY, middleware: Sequence[Middleware] | None = None, multipart_form_part_limit: int = 1000, on_app_init: Sequence[OnAppInitHandler] | None = None, on_shutdown: Sequence[LifespanHook] | None = None, on_startup: Sequence[LifespanHook] | None = None, openapi_config: OpenAPIConfig | None = OpenAPIConfig(title='Litestar API', version='1.0.0', create_examples=False, random_seed=10, contact=None, description=None, external_docs=None, license=None, security=None, components=Components(schemas={}, responses=None, parameters=None, examples=None, request_bodies=None, headers=None, security_schemes=None, links=None, callbacks=None, path_items=None), servers=[Server(url='/', description=None, variables=None)], summary=None, tags=None, terms_of_service=None, use_handler_docstrings=False, webhooks=None, operation_id_creator=<function default_operation_id_creator>, path=None, render_plugins=[<litestar.openapi.plugins.JsonRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>, <litestar.openapi.plugins.RedocRenderPlugin object>, <litestar.openapi.plugins.RapidocRenderPlugin object>, <litestar.openapi.plugins.StoplightRenderPlugin object>, <litestar.openapi.plugins.SwaggerRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>], openapi_router=None, openapi_controller=None, root_schema_site='redoc', enabled_endpoints={'openapi.json', 'openapi.yml', 'redoc', 'rapidoc', 'elements', 'swagger', 'oauth2-redirect.html', 'openapi.yaml'}), opt: Mapping[str, Any] | None = None, parameters: ParametersMap | None = None, path: str | None = None, plugins: Sequence[PluginProtocol] | None = None, request_class: type[Request] | None = None, response_cache_config: ResponseCacheConfig | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, security: Sequence[SecurityRequirement] | None = None, signature_namespace: Mapping[str, Any] | None = None, signature_types: Sequence[Any] | None = None, state: State | None = None, static_files_config: Sequence[StaticFilesConfig] | None = None, stores: StoreRegistry | dict[str, Store] | None = None, tags: Sequence[str] | None = None, template_config: TemplateConfigType | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, websocket_class: type[WebSocket] | None = None, lifespan: Sequence[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] | None = None, pdb_on_exception: bool | None = None, experimental_features: Iterable[ExperimentalFeatures] | None = None) None#
      +__init__(route_handlers: Sequence[ControllerRouterHandler] | None = None, *, after_exception: Sequence[AfterExceptionHookHandler] | None = None, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, allowed_hosts: Sequence[str] | AllowedHostsConfig | None = None, before_request: BeforeRequestHookHandler | None = None, before_send: Sequence[BeforeMessageSendHookHandler] | None = None, cache_control: CacheControlHeader | None = None, compression_config: CompressionConfig | None = None, cors_config: CORSConfig | None = None, csrf_config: CSRFConfig | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, debug: bool | None = None, dependencies: Dependencies | None = None, etag: ETag | None = None, event_emitter_backend: type[BaseEventEmitterBackend] = <class 'litestar.events.emitter.SimpleEventEmitter'>, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, listeners: Sequence[EventListener] | None = None, logging_config: BaseLoggingConfig | EmptyType | None = _EmptyEnum.EMPTY, middleware: Sequence[Middleware] | None = None, multipart_form_part_limit: int = 1000, on_app_init: Sequence[OnAppInitHandler] | None = None, on_shutdown: Sequence[LifespanHook] | None = None, on_startup: Sequence[LifespanHook] | None = None, openapi_config: OpenAPIConfig | None = OpenAPIConfig(title='Litestar API', version='1.0.0', create_examples=False, random_seed=10, contact=None, description=None, external_docs=None, license=None, security=None, components=Components(schemas={}, responses=None, parameters=None, examples=None, request_bodies=None, headers=None, security_schemes=None, links=None, callbacks=None, path_items=None), servers=[Server(url='/', description=None, variables=None)], summary=None, tags=None, terms_of_service=None, use_handler_docstrings=False, webhooks=None, operation_id_creator=<function default_operation_id_creator>, path=None, render_plugins=[<litestar.openapi.plugins.YamlRenderPlugin object>, <litestar.openapi.plugins.RedocRenderPlugin object>, <litestar.openapi.plugins.JsonRenderPlugin object>, <litestar.openapi.plugins.SwaggerRenderPlugin object>, <litestar.openapi.plugins.RapidocRenderPlugin object>, <litestar.openapi.plugins.StoplightRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>], openapi_router=None, openapi_controller=None, root_schema_site='redoc', enabled_endpoints={'openapi.yml', 'redoc', 'openapi.json', 'oauth2-redirect.html', 'swagger', 'rapidoc', 'elements', 'openapi.yaml'}), opt: Mapping[str, Any] | None = None, parameters: ParametersMap | None = None, path: str | None = None, plugins: Sequence[PluginProtocol] | None = None, request_class: type[Request] | None = None, request_max_body_size: int | None = 10000000, response_cache_config: ResponseCacheConfig | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, security: Sequence[SecurityRequirement] | None = None, signature_namespace: Mapping[str, Any] | None = None, signature_types: Sequence[Any] | None = None, state: State | None = None, static_files_config: Sequence[StaticFilesConfig] | None = None, stores: StoreRegistry | dict[str, Store] | None = None, tags: Sequence[str] | None = None, template_config: TemplateConfigType | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, websocket_class: type[WebSocket] | None = None, lifespan: Sequence[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] | None = None, pdb_on_exception: bool | None = None, experimental_features: Iterable[ExperimentalFeatures] | None = None) None#

      Initialize a Litestar application.

      Parameters:
      @@ -1641,6 +1653,8 @@
    63. pdb_on_exception – Drop into the PDB when an exception occurs.

    64. plugins – Sequence of plugins.

    65. request_class – An optional subclass of Request to use for http connections.

    66. +
    67. request_max_body_size – Maximum allowed size of the request body in bytes. If this size is exceeded, a +‘413 - Request Entity Too Large’ error response is returned.

    68. response_class – A custom subclass of Response to be used as the app’s default response.

    69. response_cookies – A sequence of Cookie.

    70. @@ -1904,13 +1918,6 @@
      -
      -
      -litestar.app.DEFAULT_OPENAPI_CONFIG = OpenAPIConfig(title='Litestar API', version='1.0.0', create_examples=False, random_seed=10, contact=None, description=None, external_docs=None, license=None, security=None, components=Components(schemas={}, responses=None, parameters=None, examples=None, request_bodies=None, headers=None, security_schemes=None, links=None, callbacks=None, path_items=None), servers=[Server(url='/', description=None, variables=None)], summary=None, tags=None, terms_of_service=None, use_handler_docstrings=False, webhooks=None, operation_id_creator=<function default_operation_id_creator>, path=None, render_plugins=[<litestar.openapi.plugins.JsonRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>, <litestar.openapi.plugins.RedocRenderPlugin object>, <litestar.openapi.plugins.RapidocRenderPlugin object>, <litestar.openapi.plugins.StoplightRenderPlugin object>, <litestar.openapi.plugins.SwaggerRenderPlugin object>, <litestar.openapi.plugins.YamlRenderPlugin object>], openapi_router=None, openapi_controller=None, root_schema_site='redoc', enabled_endpoints={'openapi.json', 'openapi.yml', 'redoc', 'rapidoc', 'elements', 'swagger', 'oauth2-redirect.html', 'openapi.yaml'})#
      -

      The default OpenAPI config used if not configuration is explicitly passed to the -Litestar instance constructor.

      -
      -
      @@ -1957,6 +1964,7 @@

      diff --git a/3803/reference/background_tasks.html b/3803/reference/background_tasks.html index 5312f35ee..a1f081494 100644 --- a/3803/reference/background_tasks.html +++ b/3803/reference/background_tasks.html @@ -1361,8 +1361,12 @@
    71. pagination
    72. params
    73. plugins @@ -1400,6 +1404,7 @@
    74. memory
    75. redis
    76. registry
    77. +
    78. valkey
    79. template
    80. @@ -1587,7 +1592,7 @@
      • tasks – An iterable of BackgroundTask instances.

      • run_in_task_group – If you set this value to True than the tasks will run concurrently, using -a TaskGroup. Note: This will not preserve execution order.

      • +a TaskGroup. Note: This will not preserve execution order.

      diff --git a/3803/reference/channels/backends/asyncpg.html b/3803/reference/channels/backends/asyncpg.html index a85eb8476..bf260ffc6 100644 --- a/3803/reference/channels/backends/asyncpg.html +++ b/3803/reference/channels/backends/asyncpg.html @@ -1361,8 +1361,12 @@
    81. pagination
    82. params
    83. plugins @@ -1400,6 +1404,7 @@
    84. memory
    85. redis
    86. registry
    87. +
    88. valkey
    89. template
    90. diff --git a/3803/reference/channels/backends/base.html b/3803/reference/channels/backends/base.html index dd1d99884..35c18f131 100644 --- a/3803/reference/channels/backends/base.html +++ b/3803/reference/channels/backends/base.html @@ -1361,8 +1361,12 @@
    91. pagination
    92. params
    93. plugins @@ -1400,6 +1404,7 @@
    94. memory
    95. redis
    96. registry
    97. +
    98. valkey
    99. template
    100. diff --git a/3803/reference/channels/backends/index.html b/3803/reference/channels/backends/index.html index 9e702b3b3..ddbf0677a 100644 --- a/3803/reference/channels/backends/index.html +++ b/3803/reference/channels/backends/index.html @@ -1357,8 +1357,12 @@
    101. pagination
    102. params
    103. plugins @@ -1396,6 +1400,7 @@
    104. memory
    105. redis
    106. registry
    107. +
    108. valkey
    109. template
    110. diff --git a/3803/reference/channels/backends/memory.html b/3803/reference/channels/backends/memory.html index 737afc57c..4d2bbd73c 100644 --- a/3803/reference/channels/backends/memory.html +++ b/3803/reference/channels/backends/memory.html @@ -1361,8 +1361,12 @@
    111. pagination
    112. params
    113. plugins @@ -1400,6 +1404,7 @@
    114. memory
    115. redis
    116. registry
    117. +
    118. valkey
    119. template
    120. diff --git a/3803/reference/channels/backends/psycopg.html b/3803/reference/channels/backends/psycopg.html index a82acc403..59fdc4d62 100644 --- a/3803/reference/channels/backends/psycopg.html +++ b/3803/reference/channels/backends/psycopg.html @@ -1361,8 +1361,12 @@
    121. pagination
    122. params
    123. plugins @@ -1400,6 +1404,7 @@
    124. memory
    125. redis
    126. registry
    127. +
    128. valkey
    129. template
    130. diff --git a/3803/reference/channels/backends/redis.html b/3803/reference/channels/backends/redis.html index 5c5ece023..c149c557c 100644 --- a/3803/reference/channels/backends/redis.html +++ b/3803/reference/channels/backends/redis.html @@ -1361,8 +1361,12 @@
    131. pagination
    132. params
    133. plugins @@ -1400,6 +1404,7 @@
    134. memory
    135. redis
    136. registry
    137. +
    138. valkey
    139. template
    140. diff --git a/3803/reference/channels/index.html b/3803/reference/channels/index.html index 08cf20b00..06f4a129b 100644 --- a/3803/reference/channels/index.html +++ b/3803/reference/channels/index.html @@ -1357,8 +1357,12 @@
    141. pagination
    142. params
    143. plugins @@ -1396,6 +1400,7 @@
    144. memory
    145. redis
    146. registry
    147. +
    148. valkey
    149. template
    150. diff --git a/3803/reference/channels/plugin.html b/3803/reference/channels/plugin.html index cca0fcf7e..4763401fc 100644 --- a/3803/reference/channels/plugin.html +++ b/3803/reference/channels/plugin.html @@ -1361,8 +1361,12 @@
    151. pagination
    152. params
    153. plugins @@ -1400,6 +1404,7 @@
    154. memory
    155. redis
    156. registry
    157. +
    158. valkey
    159. template
    160. diff --git a/3803/reference/channels/subscriber.html b/3803/reference/channels/subscriber.html index b1b00eb9b..33bdefb4d 100644 --- a/3803/reference/channels/subscriber.html +++ b/3803/reference/channels/subscriber.html @@ -1361,8 +1361,12 @@
    161. pagination
    162. params
    163. plugins @@ -1400,6 +1404,7 @@
    164. memory
    165. redis
    166. registry
    167. +
    168. valkey
    169. template
    170. diff --git a/3803/reference/cli.html b/3803/reference/cli.html index 3cced8419..04a5dbdaf 100644 --- a/3803/reference/cli.html +++ b/3803/reference/cli.html @@ -1361,8 +1361,12 @@
    171. pagination
    172. params
    173. plugins @@ -1400,6 +1404,7 @@
    174. memory
    175. redis
    176. registry
    177. +
    178. valkey
    179. template
    180. diff --git a/3803/reference/concurrency.html b/3803/reference/concurrency.html index 2c9f3f7fa..04cd562e2 100644 --- a/3803/reference/concurrency.html +++ b/3803/reference/concurrency.html @@ -1361,8 +1361,12 @@
    181. pagination
    182. params
    183. plugins @@ -1400,6 +1404,7 @@
    184. memory
    185. redis
    186. registry
    187. +
    188. valkey
    189. template
    190. @@ -1539,46 +1544,46 @@

      concurrency#

      -
      -async litestar.concurrency.sync_to_thread(fn: ~typing.Callable[[~P], ~litestar.concurrency.T], *args: ~typing.~P, **kwargs: ~typing.~P) T#
      -

      Run the synchronous callable fn asynchronously in a worker thread.

      -

      When called from asyncio, uses asyncio.loop.run_in_executor() to -run the callable. No executor is specified by default so the current loop’s executor -is used. A specific executor can be set using -set_asyncio_executor(). This does not affect the loop’s -default executor.

      -

      When called from trio, uses trio.to_thread.run_sync() to run the callable. No -capacity limiter is specified by default, but one can be set using -set_trio_capacity_limiter(). This does not affect trio’s -default capacity limiter.

      +
      +litestar.concurrency.get_asyncio_executor() ThreadPoolExecutor | None#
      +

      Get the executor in which synchronous callables will be run within an asyncio +context

      -
      -litestar.concurrency.set_asyncio_executor(executor: ThreadPoolExecutor | None) None#
      -

      Set the executor in which synchronous callables will be run within an asyncio +

      +litestar.concurrency.get_trio_capacity_limiter() trio.CapacityLimiter | None#
      +

      Get the capacity limiter used when running synchronous callable within a trio context

      -
      -litestar.concurrency.get_asyncio_executor() ThreadPoolExecutor | None#
      -

      Get the executor in which synchronous callables will be run within an asyncio +

      +litestar.concurrency.set_asyncio_executor(executor: ThreadPoolExecutor | None) None#
      +

      Set the executor in which synchronous callables will be run within an asyncio context

      -litestar.concurrency.set_trio_capacity_limiter(limiter: trio.CapacityLimiter | None) None#
      +litestar.concurrency.set_trio_capacity_limiter(limiter: trio.CapacityLimiter | None) None#

      Set the capacity limiter used when running synchronous callable within a trio context

      -
      -litestar.concurrency.get_trio_capacity_limiter() trio.CapacityLimiter | None#
      -

      Get the capacity limiter used when running synchronous callable within a trio -context

      +
      +async litestar.concurrency.sync_to_thread(fn: ~typing.Callable[[~P], ~litestar.concurrency.T], *args: ~typing.~P, **kwargs: ~typing.~P) T#
      +

      Run the synchronous callable fn asynchronously in a worker thread.

      +

      When called from asyncio, uses asyncio.loop.run_in_executor() to +run the callable. No executor is specified by default so the current loop’s executor +is used. A specific executor can be set using +set_asyncio_executor(). This does not affect the loop’s +default executor.

      +

      When called from trio, uses trio.to_thread.run_sync() to run the callable. No +capacity limiter is specified by default, but one can be set using +set_trio_capacity_limiter(). This does not affect trio’s +default capacity limiter.

      @@ -1627,11 +1632,11 @@
      diff --git a/3803/reference/config.html b/3803/reference/config.html index 8433c1fea..5ccb18d1c 100644 --- a/3803/reference/config.html +++ b/3803/reference/config.html @@ -1361,8 +1361,12 @@
    191. pagination
    192. params
    193. plugins @@ -1400,6 +1404,7 @@
    194. memory
    195. redis
    196. registry
    197. +
    198. valkey
    199. template
    200. @@ -1767,17 +1772,17 @@

      Can be overridden by routers and router handlers.

      -
      -
      -__init__(after_exception: list[AfterExceptionHookHandler] = <factory>, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, allowed_hosts: list[str] | AllowedHostsConfig | None = None, before_request: BeforeRequestHookHandler | None = None, before_send: list[BeforeMessageSendHookHandler] = <factory>, cache_control: CacheControlHeader | None = None, compression_config: CompressionConfig | None = None, cors_config: CORSConfig | None = None, csrf_config: CSRFConfig | None = None, debug: bool = False, dependencies: dict[str, Provide | AnyCallable] = <factory>, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, event_emitter_backend: type[BaseEventEmitterBackend] = <class 'litestar.events.emitter.SimpleEventEmitter'>, exception_handlers: ExceptionHandlersMap = <factory>, guards: list[Guard] = <factory>, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, lifespan: list[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] = <factory>, listeners: list[EventListener] = <factory>, logging_config: BaseLoggingConfig | None = None, middleware: list[Middleware] = <factory>, on_shutdown: list[LifespanHook] = <factory>, on_startup: list[LifespanHook] = <factory>, openapi_config: OpenAPIConfig | None = None, opt: dict[str, Any] = <factory>, parameters: ParametersMap = <factory>, path: str = '', pdb_on_exception: bool = False, plugins: list[PluginProtocol] = <factory>, request_class: type[Request] | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies = <factory>, response_headers: ResponseHeaders = <factory>, response_cache_config: ResponseCacheConfig = <factory>, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, route_handlers: list[ControllerRouterHandler] = <factory>, security: list[SecurityRequirement] = <factory>, signature_namespace: dict[str, Any] = <factory>, signature_types: list[Any] = <factory>, state: State = <factory>, static_files_config: list[StaticFilesConfig] = <factory>, stores: StoreRegistry | dict[str, Store] | None = None, tags: list[str] = <factory>, template_config: TemplateConfigType | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, websocket_class: type[WebSocket] | None = None, multipart_form_part_limit: int = 1000, experimental_features: list[ExperimentalFeatures] | None = None) None#
      -
      -
      parameters: ParametersMap#

      A mapping of Parameter definitions available to all application paths.

      +
      +
      +__init__(after_exception: list[AfterExceptionHookHandler] = <factory>, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, allowed_hosts: list[str] | AllowedHostsConfig | None = None, before_request: BeforeRequestHookHandler | None = None, before_send: list[BeforeMessageSendHookHandler] = <factory>, cache_control: CacheControlHeader | None = None, compression_config: CompressionConfig | None = None, cors_config: CORSConfig | None = None, csrf_config: CSRFConfig | None = None, debug: bool = False, dependencies: dict[str, Provide | AnyCallable] = <factory>, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, event_emitter_backend: type[BaseEventEmitterBackend] = <class 'litestar.events.emitter.SimpleEventEmitter'>, exception_handlers: ExceptionHandlersMap = <factory>, guards: list[Guard] = <factory>, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, lifespan: list[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] = <factory>, listeners: list[EventListener] = <factory>, logging_config: BaseLoggingConfig | None = None, middleware: list[Middleware] = <factory>, on_shutdown: list[LifespanHook] = <factory>, on_startup: list[LifespanHook] = <factory>, openapi_config: OpenAPIConfig | None = None, opt: dict[str, Any] = <factory>, parameters: ParametersMap = <factory>, path: str = '', pdb_on_exception: bool = False, plugins: list[PluginProtocol] = <factory>, request_class: type[Request] | None = None, request_max_body_size: int | None | EmptyType = _EmptyEnum.EMPTY, response_class: type[Response] | None = None, response_cookies: ResponseCookies = <factory>, response_headers: ResponseHeaders = <factory>, response_cache_config: ResponseCacheConfig = <factory>, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, route_handlers: list[ControllerRouterHandler] = <factory>, security: list[SecurityRequirement] = <factory>, signature_namespace: dict[str, Any] = <factory>, signature_types: list[Any] = <factory>, state: State = <factory>, static_files_config: list[StaticFilesConfig] = <factory>, stores: StoreRegistry | dict[str, Store] | None = None, tags: list[str] = <factory>, template_config: TemplateConfigType | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, websocket_class: type[WebSocket] | None = None, multipart_form_part_limit: int = 1000, experimental_features: list[ExperimentalFeatures] | None = None) None#
      +
      +
      path: str = ''#
      @@ -1806,6 +1811,13 @@

      An optional subclass of Request to use for http connections.

      +
      +
      +request_max_body_size: int | None | EmptyType = 0#
      +

      Maximum allowed size of the request body in bytes. If this size is exceeded, a ‘413 - Request Entity Too Large’ +error response is returned.

      +
      +
      response_class: type[Response] | None = None#
      @@ -1944,6 +1956,18 @@ __new__(value)#
      +
      +
      +DTO_CODEGEN = 'DTO_CODEGEN'#
      +

      Enable DTO codegen.

      +
      + +
      +
      +FUTURE = 'FUTURE'#
      +

      Enable future features that may be considered breaking or changing.

      +
      +
      @@ -2271,6 +2295,14 @@
      +
      +final class litestar.config.response_cache.CACHE_FOREVER#
      +

      Bases: object

      +

      Sentinel value indicating that a cached response should be stored without an expiration, explicitly skipping the +default expiration

      +
      + +
      class litestar.config.response_cache.ResponseCacheConfig#

      Bases: object

      @@ -2330,14 +2362,6 @@
      -
      -
      -final class litestar.config.response_cache.CACHE_FOREVER#
      -

      Bases: object

      -

      Sentinel value indicating that a cached response should be stored without an expiration, explicitly skipping the -default expiration

      -
      - @@ -2421,12 +2445,13 @@
    201. AppConfig.on_startup
    202. AppConfig.openapi_config
    203. AppConfig.opt
    204. -
    205. AppConfig.__init__()
    206. AppConfig.parameters
    207. +
    208. AppConfig.__init__()
    209. AppConfig.path
    210. AppConfig.pdb_on_exception
    211. AppConfig.plugins
    212. AppConfig.request_class
    213. +
    214. AppConfig.request_max_body_size
    215. AppConfig.response_class
    216. AppConfig.response_cookies
    217. AppConfig.response_headers
    218. @@ -2450,6 +2475,8 @@
    219. ExperimentalFeatures
    220. CompressionConfig
    221. +
    222. CACHE_FOREVER
    223. ResponseCacheConfig
    224. default_cache_key_builder()
    225. -
    226. CACHE_FOREVER
    227. diff --git a/3803/reference/connection.html b/3803/reference/connection.html index 46e20300f..510f30f25 100644 --- a/3803/reference/connection.html +++ b/3803/reference/connection.html @@ -1361,8 +1361,12 @@
    228. pagination
    229. params
    230. plugins @@ -1400,6 +1404,7 @@
    231. memory
    232. redis
    233. registry
    234. +
    235. valkey
    236. template
    237. diff --git a/3803/reference/contrib/htmx.html b/3803/reference/contrib/htmx.html index 308a8dea7..3f36bbf4d 100644 --- a/3803/reference/contrib/htmx.html +++ b/3803/reference/contrib/htmx.html @@ -1361,8 +1361,12 @@
    238. pagination
    239. params
    240. plugins @@ -1400,6 +1404,7 @@
    241. memory
    242. redis
    243. registry
    244. +
    245. valkey
    246. template
    247. @@ -1543,244 +1548,9 @@

      HTMX#

      Request#

      -
      -
      -class litestar.contrib.htmx.request.HTMXDetails#
      -

      Bases: object

      -

      HTMXDetails holds all the values sent by HTMX client in headers and provide convenient properties.

      -
      -
      -__init__(request: Request) None#
      -

      Initialize HTMXDetails

      -
      - -
      -
      -__bool__() bool#
      -

      Check if request is sent by an HTMX client.

      -
      - -
      -
      -property boosted: bool#
      -

      Check if request is boosted.

      -
      - -
      -
      -property current_url: str | None#
      -

      Current url value sent by HTMX client.

      -
      - -
      -
      -property current_url_abs_path: str | None#
      -

      Current url abs path value, to get query and path parameter sent by HTMX client.

      -
      - -
      -
      -property history_restore_request: bool#
      -

      If True then, request is for history restoration after a miss in the local history cache.

      -
      - -
      -
      -property prompt: str | None#
      -

      User Response to prompt.

      -
      <button hx-delete="/account" hx-prompt="Enter your account name to confirm deletion">Delete My Account</button>
      -
      -
      -
      - -
      -
      -property target: str | None#
      -

      ID of the target element if provided on the element.

      -
      - -
      -
      -property trigger: str | None#
      -

      ID of the triggered element if provided on the element.

      -
      - -
      -
      -property trigger_name: str | None#
      -

      Name of the triggered element if provided on the element.

      -
      - -
      -
      -property triggering_event: Any#
      -

      Name of the triggered event.

      -

      This value is added by event-header extension of HTMX to the Triggering-Event header to requests.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.request.HTMXRequest#
      -

      Bases: Request

      -

      HTMX Request class to work with HTMX client.

      -
      -
      -__init__(scope: Scope, receive: Receive = <function empty_receive>, send: Send = <function empty_send>) None#
      -

      Initialize HTMXRequest

      -
      - -
      -

      Response#

      -
      -
      -class litestar.contrib.htmx.response.ClientRedirect#
      -

      Bases: Response

      -

      HTMX Response class to support client side redirect.

      -
      -
      -__init__(redirect_to: str) None#
      -

      Set status code to 200 (required by HTMX), and pass redirect url.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.ClientRefresh#
      -

      Bases: Response

      -

      Response to support HTMX client page refresh

      -
      -
      -__init__() None#
      -

      Set Status code to 200 and set headers.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.HTMXTemplate#
      -

      Bases: Template

      -

      HTMX template wrapper

      -
      -
      -__init__(push_url: str | bool | None = None, re_swap: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None] | None = None, re_target: str | None = None, trigger_event: str | None = None, params: dict[str, Any] | None = None, after: Literal['receive', 'settle', 'swap', None] | None = None, **kwargs: Any) None#
      -

      Create HTMXTemplate response.

      -
      -
      Parameters:
      -
        -
      • push_url – Either a string value specifying a URL to push to browser history or False to prevent HTMX client from -pushing a url to browser history.

      • -
      • re_swap – Method value to instruct HTMX which swapping method to use.

      • -
      • re_target – Value for ‘id of target element’ to apply changes to.

      • -
      • trigger_event – Event name to trigger.

      • -
      • params – Dictionary of parameters if any required with trigger event parameter.

      • -
      • after – Changes to apply after receive, settle or swap event.

      • -
      • **kwargs – Additional arguments to pass to Template.

      • -
      -
      -
      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.HXLocation#
      -

      Bases: Response

      -

      Client side redirect without full page reload.

      -
      -
      -__init__(redirect_to: str, source: str | None = None, event: str | None = None, target: str | None = None, swap: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None] | None = None, hx_headers: dict[str, Any] | None = None, values: dict[str, str] | None = None, **kwargs: Any) None#
      -

      Initialize HXLocation, Set status code to 200 (required by HTMX), -and pass redirect url.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.HXStopPolling#
      -

      Bases: Response

      -

      Stop HTMX client from Polling.

      -
      -
      -__init__() None#
      -

      Initialize

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.PushUrl#
      -

      Bases: Generic[T], Response[T]

      -

      Response to push new url into the history stack.

      -
      -
      -__init__(content: T, push_url: str | bool, **kwargs: Any) None#
      -

      Initialize PushUrl.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.ReplaceUrl#
      -

      Bases: Generic[T], Response[T]

      -

      Response to replace url in the Browser Location bar.

      -
      -
      -__init__(content: T, replace_url: str | bool, **kwargs: Any) None#
      -

      Initialize ReplaceUrl.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.Reswap#
      -

      Bases: Generic[T], Response[T]

      -

      Response to specify how the response will be swapped.

      -
      -
      -__init__(content: T, method: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None], **kwargs: Any) None#
      -

      Initialize Reswap.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.Retarget#
      -

      Bases: Generic[T], Response[T]

      -

      Response to target different element on the page.

      -
      -
      -__init__(content: T, target: str, **kwargs: Any) None#
      -

      Initialize Retarget.

      -
      - -
      - -
      -
      -class litestar.contrib.htmx.response.TriggerEvent#
      -

      Bases: Generic[T], Response[T]

      -

      Trigger Client side event.

      -
      -
      -__init__(content: T, name: str, after: Literal['receive', 'settle', 'swap', None], params: dict[str, Any] | None = None, **kwargs: Any) None#
      -

      Initialize TriggerEvent.

      -
      - -
      -
      @@ -1828,70 +1598,8 @@

      HTMX#

      diff --git a/3803/reference/contrib/index.html b/3803/reference/contrib/index.html index a172159db..3f34b16df 100644 --- a/3803/reference/contrib/index.html +++ b/3803/reference/contrib/index.html @@ -1357,8 +1357,12 @@
    248. pagination
    249. params
    250. plugins @@ -1396,6 +1400,7 @@
    251. memory
    252. redis
    253. registry
    254. +
    255. valkey
    256. template
    257. diff --git a/3803/reference/contrib/jinja.html b/3803/reference/contrib/jinja.html index 729d1374d..1ca5cbe8b 100644 --- a/3803/reference/contrib/jinja.html +++ b/3803/reference/contrib/jinja.html @@ -1361,8 +1361,12 @@
    258. pagination
    259. params
    260. plugins @@ -1400,6 +1404,7 @@
    261. memory
    262. redis
    263. registry
    264. +
    265. valkey
    266. template
    267. diff --git a/3803/reference/contrib/jwt.html b/3803/reference/contrib/jwt.html index d4ab1dba0..e7ce21063 100644 --- a/3803/reference/contrib/jwt.html +++ b/3803/reference/contrib/jwt.html @@ -1357,8 +1357,12 @@
    268. pagination
    269. params
    270. plugins @@ -1396,6 +1400,7 @@
    271. memory
    272. redis
    273. registry
    274. +
    275. valkey
    276. template
    277. diff --git a/3803/reference/contrib/mako.html b/3803/reference/contrib/mako.html index 36a172144..d76ce5b2b 100644 --- a/3803/reference/contrib/mako.html +++ b/3803/reference/contrib/mako.html @@ -1361,8 +1361,12 @@
    278. pagination
    279. params
    280. plugins @@ -1400,6 +1404,7 @@
    281. memory
    282. redis
    283. registry
    284. +
    285. valkey
    286. template
    287. diff --git a/3803/reference/contrib/opentelemetry.html b/3803/reference/contrib/opentelemetry.html index 88099dcfb..572916505 100644 --- a/3803/reference/contrib/opentelemetry.html +++ b/3803/reference/contrib/opentelemetry.html @@ -1361,8 +1361,12 @@
    288. pagination
    289. params
    290. plugins @@ -1400,6 +1404,7 @@
    291. memory
    292. redis
    293. registry
    294. +
    295. valkey
    296. template
    297. diff --git a/3803/reference/contrib/piccolo.html b/3803/reference/contrib/piccolo.html index 9f813cbb9..7bec8f8f0 100644 --- a/3803/reference/contrib/piccolo.html +++ b/3803/reference/contrib/piccolo.html @@ -1361,8 +1361,12 @@
    298. pagination
    299. params
    300. plugins @@ -1400,6 +1404,7 @@
    301. memory
    302. redis
    303. registry
    304. +
    305. valkey
    306. template
    307. @@ -1547,7 +1552,7 @@

      Bases: AbstractDTO, Generic[T]

      -classmethod generate_field_definitions(model_type: type[piccolo.table.Table]) Generator[DTOFieldDefinition, None, None]#
      +classmethod generate_field_definitions(model_type: type[piccolo.table.Table]) Generator[DTOFieldDefinition, None, None]#

      Generate FieldDefinition instances from model_type.

      Yields:
      diff --git a/3803/reference/contrib/pydantic.html b/3803/reference/contrib/pydantic.html index 2c7a6de49..e3563794e 100644 --- a/3803/reference/contrib/pydantic.html +++ b/3803/reference/contrib/pydantic.html @@ -677,10 +677,6 @@ - -
      @@ -1361,8 +1357,12 @@
    308. pagination
    309. params
    310. plugins @@ -1400,6 +1400,7 @@
    311. memory
    312. redis
    313. registry
    314. +
    315. valkey
    316. template
    317. @@ -1541,258 +1542,6 @@

      pydantic#

      -
      -
      -class litestar.contrib.pydantic.PydanticDTO#
      -

      Bases: AbstractDTO, Generic[T]

      -

      Support for domain modelling with Pydantic.

      -
      -
      -decode_builtins(value: dict[str, Any]) Any#
      -

      Decode a dictionary of Python values into an the DTO’s datatype.

      -
      - -
      -
      -decode_bytes(value: bytes) Any#
      -

      Decode a byte string into an the DTO’s datatype.

      -
      - -
      -
      -classmethod generate_field_definitions(model_type: type[pydantic_v1.BaseModel | pydantic_v2.BaseModel]) Generator[DTOFieldDefinition, None, None]#
      -

      Generate FieldDefinition instances from model_type.

      -
      -
      Yields:
      -

      FieldDefinition instances.

      -
      -
      -
      - -
      -
      -classmethod detect_nested_field(field_definition: FieldDefinition) bool#
      -

      Return True if field_definition represents a nested model field.

      -
      -
      Parameters:
      -

      field_definition – inspect type to determine if field represents a nested model.

      -
      -
      Returns:
      -

      True if field_definition represents a nested model field.

      -
      -
      -
      - -
      -
      -classmethod get_config_for_model_type(config: DTOConfig, model_type: type[Any]) DTOConfig#
      -

      Create a new configuration for this specific model_type, during the -creation of the factory.

      -

      The returned config object will be set as the config attribute on the newly -defined factory class.

      -
      - -
      - -
      -
      -class litestar.contrib.pydantic.PydanticInitPlugin#
      -

      Bases: InitPluginProtocol

      -
      -
      -__init__(exclude: PydanticV1FieldsListType | PydanticV2FieldsListType | None = None, exclude_defaults: bool = False, exclude_none: bool = False, exclude_unset: bool = False, include: PydanticV1FieldsListType | PydanticV2FieldsListType | None = None, prefer_alias: bool = False, validate_strict: bool = False) None#
      -

      Pydantic Plugin to support serialization / validation of Pydantic types / models

      -
      -
      Parameters:
      -
        -
      • exclude – Fields to exclude during serialization

      • -
      • exclude_defaults – Fields to exclude during serialization when they are set to their default value

      • -
      • exclude_none – Fields to exclude during serialization when they are set to None

      • -
      • exclude_unset – Fields to exclude during serialization when they arenot set

      • -
      • include – Fields to exclude during serialization

      • -
      • prefer_alias – Use the by_alias=True flag when dumping models

      • -
      • validate_strict – Use strict=True when calling .model_validate on Pydantic 2.x models

      • -
      -
      -
      -
      - -
      -
      -on_app_init(app_config: AppConfig) AppConfig#
      -

      Receive the AppConfig instance after on_app_init hooks have been called.

      -
      -

      Examples

      -
      from litestar import Litestar, get
      -from litestar.di import Provide
      -from litestar.plugins import InitPluginProtocol
      -
      -
      -def get_name() -> str:
      -    return "world"
      -
      -
      -@get("/my-path")
      -def my_route_handler(name: str) -> dict[str, str]:
      -    return {"hello": name}
      -
      -
      -class MyPlugin(InitPluginProtocol):
      -    def on_app_init(self, app_config: AppConfig) -> AppConfig:
      -        app_config.dependencies["name"] = Provide(get_name)
      -        app_config.route_handlers.append(my_route_handler)
      -        return app_config
      -
      -
      -app = Litestar(plugins=[MyPlugin()])
      -
      -
      -
      -
      -
      Parameters:
      -

      app_config – The AppConfig instance.

      -
      -
      Returns:
      -

      The app config object.

      -
      -
      -
      - -
      - -
      -
      -class litestar.contrib.pydantic.PydanticSchemaPlugin#
      -

      Bases: OpenAPISchemaPlugin

      -
      -
      -__init__(prefer_alias: bool = False) None#
      -
      - -
      -
      -static is_plugin_supported_type(value: Any) bool#
      -

      Given a value of indeterminate type, determine if this value is supported by the plugin.

      -

      This is called by the default implementation of is_plugin_supported_field() for -backwards compatibility. User’s should prefer to override that method instead.

      -
      -
      Parameters:
      -

      value – An arbitrary value.

      -
      -
      Returns:
      -

      A bool indicating whether the value is supported by the plugin.

      -
      -
      -
      - -
      -
      -static is_undefined_sentinel(value: Any) bool#
      -

      Return True if value should be treated as an undefined field

      -
      - -
      -
      -static is_constrained_field(field_definition: FieldDefinition) bool#
      -

      Return True if the field should be treated as constrained. If returning -True, constraints should be defined in the field’s extras

      -
      - -
      -
      -to_openapi_schema(field_definition: FieldDefinition, schema_creator: SchemaCreator) Schema#
      -

      Given a type annotation, transform it into an OpenAPI schema class.

      -
      -
      Parameters:
      -
        -
      • field_definition – FieldDefinition instance.

      • -
      • schema_creator – An instance of the schema creator class

      • -
      -
      -
      Returns:
      -

      An OpenAPI instance.

      -
      -
      -
      - -
      -
      -classmethod for_pydantic_model(field_definition: FieldDefinition, schema_creator: SchemaCreator) Schema#
      -

      Create a schema object for a given pydantic model class.

      -
      -
      Parameters:
      -
        -
      • field_definition – FieldDefinition instance.

      • -
      • schema_creator – An instance of the schema creator class

      • -
      -
      -
      Returns:
      -

      A schema instance.

      -
      -
      -
      - -
      - -
      -
      -class litestar.contrib.pydantic.PydanticPlugin#
      -

      Bases: InitPluginProtocol

      -

      A plugin that provides Pydantic integration.

      -
      -
      -__init__(exclude: PydanticV1FieldsListType | PydanticV2FieldsListType | None = None, exclude_defaults: bool = False, exclude_none: bool = False, exclude_unset: bool = False, include: PydanticV1FieldsListType | PydanticV2FieldsListType | None = None, prefer_alias: bool = False, validate_strict: bool = False) None#
      -

      Pydantic Plugin to support serialization / validation of Pydantic types / models

      -
      -
      Parameters:
      -
        -
      • exclude – Fields to exclude during serialization

      • -
      • exclude_defaults – Fields to exclude during serialization when they are set to their default value

      • -
      • exclude_none – Fields to exclude during serialization when they are set to None

      • -
      • exclude_unset – Fields to exclude during serialization when they arenot set

      • -
      • include – Fields to exclude during serialization

      • -
      • prefer_alias – Use the by_alias=True flag when dumping models

      • -
      • validate_strict – Use strict=True when calling .model_validate on Pydantic 2.x models

      • -
      -
      -
      -
      - -
      -
      -on_app_init(app_config: AppConfig) AppConfig#
      -

      Configure application for use with Pydantic.

      -
      -
      Parameters:
      -

      app_config – The AppConfig instance.

      -
      -
      -
      - -
      - -
      -
      -class litestar.contrib.pydantic.PydanticDIPlugin#
      -

      Bases: DIPlugin

      -
      -
      -has_typed_init(type_: Any) bool#
      -

      Return True if type_ has type information available for its -__init__() method that cannot be extracted from this method’s type -annotations (e.g. a Pydantic BaseModel subclass), and -DIPlugin.get_typed_init() supports extraction of these annotations.

      -
      - -
      -
      -get_typed_init(type_: Any) tuple[inspect.Signature, dict[str, Any]]#
      -

      Return signature and type information about the type_s __init__() -method.

      -
      - -
      -
      @@ -1830,52 +1579,6 @@ - -
      diff --git a/3803/reference/datastructures/secret_values.html b/3803/reference/datastructures/secret_values.html index 7aa31399e..c079fdc1a 100644 --- a/3803/reference/datastructures/secret_values.html +++ b/3803/reference/datastructures/secret_values.html @@ -1361,8 +1361,12 @@
    318. pagination
    319. params
    320. plugins @@ -1400,6 +1404,7 @@
    321. memory
    322. redis
    323. registry
    324. +
    325. valkey
    326. template
    327. diff --git a/3803/reference/di.html b/3803/reference/di.html index c04e7c7f4..fbab7555c 100644 --- a/3803/reference/di.html +++ b/3803/reference/di.html @@ -1361,8 +1361,12 @@
    328. pagination
    329. params
    330. plugins @@ -1400,6 +1404,7 @@
    331. memory
    332. redis
    333. registry
    334. +
    335. valkey
    336. template
    337. diff --git a/3803/reference/dto/base_dto.html b/3803/reference/dto/base_dto.html index b139ae047..7ff658df3 100644 --- a/3803/reference/dto/base_dto.html +++ b/3803/reference/dto/base_dto.html @@ -1361,8 +1361,12 @@
    338. pagination
    339. params
    340. plugins @@ -1400,6 +1404,7 @@
    341. memory
    342. redis
    343. registry
    344. +
    345. valkey
    346. template
    347. diff --git a/3803/reference/dto/config.html b/3803/reference/dto/config.html index b5d0395e3..1ab919699 100644 --- a/3803/reference/dto/config.html +++ b/3803/reference/dto/config.html @@ -1361,8 +1361,12 @@
    348. pagination
    349. params
    350. plugins @@ -1400,6 +1404,7 @@
    351. memory
    352. redis
    353. registry
    354. +
    355. valkey
    356. template
    357. diff --git a/3803/reference/dto/data_structures.html b/3803/reference/dto/data_structures.html index 7c5706d19..16842577a 100644 --- a/3803/reference/dto/data_structures.html +++ b/3803/reference/dto/data_structures.html @@ -1361,8 +1361,12 @@
    358. pagination
    359. params
    360. plugins @@ -1400,6 +1404,7 @@
    361. memory
    362. redis
    363. registry
    364. +
    365. valkey
    366. template
    367. diff --git a/3803/reference/dto/dataclass_dto.html b/3803/reference/dto/dataclass_dto.html index faa60cf7d..7a6c1ce17 100644 --- a/3803/reference/dto/dataclass_dto.html +++ b/3803/reference/dto/dataclass_dto.html @@ -1361,8 +1361,12 @@
    368. pagination
    369. params
    370. plugins @@ -1400,6 +1404,7 @@
    371. memory
    372. redis
    373. registry
    374. +
    375. valkey
    376. template
    377. diff --git a/3803/reference/dto/field.html b/3803/reference/dto/field.html index cefdc9d30..d3beec5f3 100644 --- a/3803/reference/dto/field.html +++ b/3803/reference/dto/field.html @@ -1361,8 +1361,12 @@
    378. pagination
    379. params
    380. plugins @@ -1400,6 +1404,7 @@
    381. memory
    382. redis
    383. registry
    384. +
    385. valkey
    386. template
    387. diff --git a/3803/reference/dto/index.html b/3803/reference/dto/index.html index bb9ae364a..4b6238e74 100644 --- a/3803/reference/dto/index.html +++ b/3803/reference/dto/index.html @@ -1357,8 +1357,12 @@
    388. pagination
    389. params
    390. plugins @@ -1396,6 +1400,7 @@
    391. memory
    392. redis
    393. registry
    394. +
    395. valkey
    396. template
    397. diff --git a/3803/reference/dto/msgspec_dto.html b/3803/reference/dto/msgspec_dto.html index 90fc9aaca..e91074ffe 100644 --- a/3803/reference/dto/msgspec_dto.html +++ b/3803/reference/dto/msgspec_dto.html @@ -1361,8 +1361,12 @@
    398. pagination
    399. params
    400. plugins @@ -1400,6 +1404,7 @@
    401. memory
    402. redis
    403. registry
    404. +
    405. valkey
    406. template
    407. diff --git a/3803/reference/dto/types.html b/3803/reference/dto/types.html index 961231ad7..52583e0da 100644 --- a/3803/reference/dto/types.html +++ b/3803/reference/dto/types.html @@ -1361,8 +1361,12 @@
    408. pagination
    409. params
    410. plugins @@ -1400,6 +1404,7 @@
    411. memory
    412. redis
    413. registry
    414. +
    415. valkey
    416. template
    417. diff --git a/3803/reference/enums.html b/3803/reference/enums.html index 0ff7d85ed..7a8323c75 100644 --- a/3803/reference/enums.html +++ b/3803/reference/enums.html @@ -1361,8 +1361,12 @@
    418. pagination
    419. params
    420. plugins @@ -1400,6 +1404,7 @@
    421. memory
    422. redis
    423. registry
    424. +
    425. valkey
    426. template
    427. diff --git a/3803/reference/events.html b/3803/reference/events.html index fd5fed2a2..653a19dc5 100644 --- a/3803/reference/events.html +++ b/3803/reference/events.html @@ -1361,8 +1361,12 @@
    428. pagination
    429. params
    430. plugins @@ -1400,6 +1404,7 @@
    431. memory
    432. redis
    433. registry
    434. +
    435. valkey
    436. template
    437. @@ -1538,6 +1543,42 @@

      events#

      +
      +
      +class litestar.events.BaseEventEmitterBackend#
      +

      Bases: AbstractAsyncContextManager[BaseEventEmitterBackend], ABC

      +

      Abstract class used to define event emitter backends.

      +
      +
      +__init__(listeners: Sequence[EventListener]) None#
      +

      Create an event emitter instance.

      +
      +
      Parameters:
      +

      listeners – A list of listeners.

      +
      +
      +
      + +
      +
      +abstract emit(event_id: str, *args: Any, **kwargs: Any) None#
      +

      Emit an event to all attached listeners.

      +
      +
      Parameters:
      +
        +
      • event_id – The ID of the event to emit, e.g ‘my_event’.

      • +
      • *args – args to pass to the listener(s).

      • +
      • **kwargs – kwargs to pass to the listener(s)

      • +
      +
      +
      Returns:
      +

      None

      +
      +
      +
      + +
      +
      class litestar.events.EventListener#
      @@ -1622,42 +1663,6 @@
      -
      -
      -class litestar.events.BaseEventEmitterBackend#
      -

      Bases: AbstractAsyncContextManager[BaseEventEmitterBackend], ABC

      -

      Abstract class used to define event emitter backends.

      -
      -
      -__init__(listeners: Sequence[EventListener]) None#
      -

      Create an event emitter instance.

      -
      -
      Parameters:
      -

      listeners – A list of listeners.

      -
      -
      -
      - -
      -
      -abstract emit(event_id: str, *args: Any, **kwargs: Any) None#
      -

      Emit an event to all attached listeners.

      -
      -
      Parameters:
      -
        -
      • event_id – The ID of the event to emit, e.g ‘my_event’.

      • -
      • *args – args to pass to the listener(s).

      • -
      • **kwargs – kwargs to pass to the listener(s)

      • -
      -
      -
      Returns:
      -

      None

      -
      -
      -
      - -
      -
      litestar.events.listener#
      @@ -1710,6 +1715,11 @@

    diff --git a/3803/reference/exceptions.html b/3803/reference/exceptions.html index 4391e57dc..121564cb5 100644 --- a/3803/reference/exceptions.html +++ b/3803/reference/exceptions.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1910,26 +1915,18 @@
    -
    -litestar.exceptions.responses.create_exception_response(request: Request[Any, Any, Any], exc: Exception) Response#
    -

    Construct a response from an exception.

    -
    -

    Notes

    -
      -
    • For instances of HTTPException or other exception classes that have a -status_code attribute (e.g. Starlette exceptions), the status code is drawn from the exception, otherwise -response status is HTTP_500_INTERNAL_SERVER_ERROR.

    • -
    -
    +
    +litestar.exceptions.responses.create_debug_response(request: Request, exc: Exception) Response#
    +

    Create a debug response from an exception.

    Parameters:
      -
    • request – The request that triggered the exception.

    • -
    • exc – An exception.

    • +
    • request – The request that triggered the exception.

    • +
    • exc – An exception.

    Returns:
    -

    HTTP response constructed from exception details.

    +

    Debug response constructed from exception details.

    Return type:

    Response

    @@ -1938,18 +1935,26 @@
    -
    -litestar.exceptions.responses.create_debug_response(request: Request, exc: Exception) Response#
    -

    Create a debug response from an exception.

    +
    +litestar.exceptions.responses.create_exception_response(request: Request[Any, Any, Any], exc: Exception) Response#
    +

    Construct a response from an exception.

    +
    +

    Notes

    +
      +
    • For instances of HTTPException or other exception classes that have a +status_code attribute (e.g. Starlette exceptions), the status code is drawn from the exception, otherwise +response status is HTTP_500_INTERNAL_SERVER_ERROR.

    • +
    +
    Parameters:
      -
    • request – The request that triggered the exception.

    • -
    • exc – An exception.

    • +
    • request – The request that triggered the exception.

    • +
    • exc – An exception.

    Returns:
    -

    Debug response constructed from exception details.

    +

    HTTP response constructed from exception details.

    Return type:

    Response

    @@ -2081,8 +2086,8 @@
  • ExceptionResponseContent.to_response()
  • -
  • create_exception_response()
  • create_debug_response()
  • +
  • create_exception_response()
  • diff --git a/3803/reference/handlers.html b/3803/reference/handlers.html index 9e733af2e..102b14f81 100644 --- a/3803/reference/handlers.html +++ b/3803/reference/handlers.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1858,7 +1863,7 @@

    Use this decorator to decorate an HTTP handler with multiple methods.

    -__init__(path: str | Sequence[str] | None = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, http_method: HttpMethod | Method | Sequence[HttpMethod | Method], media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, signature_namespace: Mapping[str, Any] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#
    +__init__(path: str | Sequence[str] | None = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, http_method: HttpMethod | Method | Sequence[HttpMethod | Method], media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, request_max_body_size: int | None | EmptyType = _EmptyEnum.EMPTY, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, signature_namespace: Mapping[str, Any] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#

    Initialize HTTPRouteHandler.

    Parameters:
    @@ -1900,6 +1905,8 @@ ASGI Scope.

  • request_class – A custom subclass of Request to be used as route handler’s default request.

  • +
  • request_max_body_size – Maximum allowed size of the request body in bytes. If this size is exceeded, +a ‘413 - Request Entity Too Large’ error response is returned.

  • response_class – A custom subclass of Response to be used as route handler’s default response.

  • response_cookies – A sequence of Cookie instances.

  • @@ -2152,18 +2159,6 @@

    A sequence of Middleware.

    -
    -
    -on_accept: AnyCallable | None = None#
    -

    Called after a WebSocket connection has been accepted. Can receive any dependencies

    -
    - -
    -
    -on_disconnect: AnyCallable | None = None#
    -

    Called after a WebSocket connection has been disconnected. Can receive any dependencies

    -
    -
    receive_mode: WebSocketMode = 'text'#
    @@ -2247,6 +2242,20 @@
    +
    +
    +on_accept(*args: Any, **kwargs: Any) Any#
    +

    Called after a WebSocket connection +has been accepted. Can receive any dependencies

    +
    + +
    +
    +on_disconnect(*args: Any, **kwargs: Any) Any#
    +

    Called after a WebSocket connection +has been disconnected. Can receive any dependencies

    +
    +
    abstract on_receive(*args: Any, **kwargs: Any) Any#
    @@ -2260,53 +2269,6 @@
    -
    -
    -class litestar.handlers.WebsocketRouteHandler#
    -

    Bases: BaseRouteHandler

    -

    Websocket route handler decorator.

    -

    Use this decorator to decorate websocket handler functions.

    -
    -
    -__init__(path: str | list[str] | None = None, *, dependencies: Dependencies | None = None, exception_handlers: dict[int | type[Exception], ExceptionHandler] | None = None, guards: list[Guard] | None = None, middleware: list[Middleware] | None = None, name: str | None = None, opt: dict[str, Any] | None = None, signature_namespace: Mapping[str, Any] | None = None, websocket_class: type[WebSocket] | None = None, **kwargs: Any) None#
    -

    Initialize WebsocketRouteHandler

    -
    -
    Parameters:
    -
      -
    • path – A path fragment for the route handler function or a sequence of path fragments. If not given defaults -to /

    • -
    • dependencies – A string keyed mapping of dependency Provider instances.

    • -
    • exception_handlers – A mapping of status codes and/or exception types to handler functions.

    • -
    • guards – A sequence of Guard callables.

    • -
    • middleware – A sequence of Middleware.

    • -
    • name – A string identifying the route handler.

    • -
    • opt – A string keyed mapping of arbitrary values that can be accessed in Guards or -wherever you have access to Request or -ASGI Scope.

    • -
    • signature_namespace – A mapping of names to types for use in forward reference resolution during signature modelling.

    • -
    • type_encoders – A mapping of types to callables that transform them into types supported for serialization.

    • -
    • **kwargs – Any additional kwarg - will be set in the opt dictionary.

    • -
    • websocket_class – A custom subclass of WebSocket to be used as route handler’s -default websocket class.

    • -
    -
    -
    -
    - -
    -
    -resolve_websocket_class() type[litestar.connection.websocket.WebSocket]#
    -

    Return the closest custom WebSocket class in the owner graph or the default Websocket class.

    -

    This method is memoized so the computation occurs only once.

    -
    -
    Returns:
    -

    The default WebSocket class for the route handler.

    -
    -
    -
    - -
    -
    class litestar.handlers.WebsocketListenerRouteHandler#
    @@ -2415,6 +2377,53 @@
    +
    +
    +class litestar.handlers.WebsocketRouteHandler#
    +

    Bases: BaseRouteHandler

    +

    Websocket route handler decorator.

    +

    Use this decorator to decorate websocket handler functions.

    +
    +
    +__init__(path: str | list[str] | None = None, *, dependencies: Dependencies | None = None, exception_handlers: dict[int | type[Exception], ExceptionHandler] | None = None, guards: list[Guard] | None = None, middleware: list[Middleware] | None = None, name: str | None = None, opt: dict[str, Any] | None = None, signature_namespace: Mapping[str, Any] | None = None, websocket_class: type[WebSocket] | None = None, **kwargs: Any) None#
    +

    Initialize WebsocketRouteHandler

    +
    +
    Parameters:
    +
      +
    • path – A path fragment for the route handler function or a sequence of path fragments. If not given defaults +to /

    • +
    • dependencies – A string keyed mapping of dependency Provider instances.

    • +
    • exception_handlers – A mapping of status codes and/or exception types to handler functions.

    • +
    • guards – A sequence of Guard callables.

    • +
    • middleware – A sequence of Middleware.

    • +
    • name – A string identifying the route handler.

    • +
    • opt – A string keyed mapping of arbitrary values that can be accessed in Guards or +wherever you have access to Request or +ASGI Scope.

    • +
    • signature_namespace – A mapping of names to types for use in forward reference resolution during signature modelling.

    • +
    • type_encoders – A mapping of types to callables that transform them into types supported for serialization.

    • +
    • websocket_class – A custom subclass of WebSocket to be used as route handler’s +default websocket class.

    • +
    • **kwargs – Any additional kwarg - will be set in the opt dictionary.

    • +
    +
    +
    +
    + +
    +
    +resolve_websocket_class() type[litestar.connection.websocket.WebSocket]#
    +

    Return the closest custom WebSocket class in the owner graph or the default Websocket class.

    +

    This method is memoized so the computation occurs only once.

    +
    +
    Returns:
    +

    The default WebSocket class for the route handler.

    +
    +
    +
    + +
    +
    litestar.handlers.asgi#
    @@ -2703,7 +2712,7 @@

    Use this decorator to decorate an HTTP handler for PATCH requests.

    -__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#
    +__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, request_max_body_size: int | None | EmptyType = _EmptyEnum.EMPTY, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#

    Initialize patch.

    Parameters:
    @@ -2744,6 +2753,8 @@ wherever you have access to Request or ASGI Scope.

  • request_class – A custom subclass of Request to be used as route handler’s default request.

  • +
  • request_max_body_size – Maximum allowed size of the request body in bytes. If this size is exceeded, +a ‘413 - Request Entity Too Large’ error response is returned.

  • response_class – A custom subclass of Response to be used as route handler’s default response.

  • response_cookies – A sequence of Cookie instances.

  • @@ -2791,7 +2802,7 @@

    Use this decorator to decorate an HTTP handler for POST requests.

    -__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#
    +__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, request_max_body_size: int | None | EmptyType = _EmptyEnum.EMPTY, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#

    Initialize post

    Parameters:
    @@ -2832,6 +2843,8 @@ wherever you have access to Request or ASGI Scope.

  • request_class – A custom subclass of Request to be used as route handler’s default request.

  • +
  • request_max_body_size – Maximum allowed size of the request body in bytes. If this size is exceeded, +a ‘413 - Request Entity Too Large’ error response is returned.

  • response_class – A custom subclass of Response to be used as route handler’s default response.

  • response_cookies – A sequence of Cookie instances.

  • @@ -2879,7 +2892,7 @@

    Use this decorator to decorate an HTTP handler for PUT requests.

    -__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#
    +__init__(path: str | None | Sequence[str] = None, *, after_request: AfterRequestHookHandler | None = None, after_response: AfterResponseHookHandler | None = None, background: BackgroundTask | BackgroundTasks | None = None, before_request: BeforeRequestHookHandler | None = None, cache: bool | int | type[CACHE_FOREVER] = False, cache_control: CacheControlHeader | None = None, cache_key_builder: CacheKeyBuilder | None = None, dependencies: Dependencies | None = None, dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, etag: ETag | None = None, exception_handlers: ExceptionHandlersMap | None = None, guards: Sequence[Guard] | None = None, media_type: MediaType | str | None = None, middleware: Sequence[Middleware] | None = None, name: str | None = None, opt: Mapping[str, Any] | None = None, request_class: type[Request] | None = None, request_max_body_size: int | None | EmptyType = _EmptyEnum.EMPTY, response_class: type[Response] | None = None, response_cookies: ResponseCookies | None = None, response_headers: ResponseHeaders | None = None, return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, signature_namespace: Mapping[str, Any] | None = None, status_code: int | None = None, sync_to_thread: bool | None = None, content_encoding: str | None = None, content_media_type: str | None = None, deprecated: bool = False, description: str | None = None, include_in_schema: bool | EmptyType = _EmptyEnum.EMPTY, operation_class: type[Operation] = <class 'litestar.openapi.spec.operation.Operation'>, operation_id: str | OperationIDCreator | None = None, raises: Sequence[type[HTTPException]] | None = None, response_description: str | None = None, responses: Mapping[int, ResponseSpec] | None = None, security: Sequence[SecurityRequirement] | None = None, summary: str | None = None, tags: Sequence[str] | None = None, type_decoders: TypeDecodersSequence | None = None, type_encoders: TypeEncodersMap | None = None, **kwargs: Any) None#

    Initialize put

    Parameters:
    @@ -2920,6 +2933,8 @@ wherever you have access to Request or ASGI Scope.

  • request_class – A custom subclass of Request to be used as route handler’s default request.

  • +
  • request_max_body_size – Maximum allowed size of the request body in bytes. If this size is exceeded, +a ‘413 - Request Entity Too Large’ error response is returned.

  • response_class – A custom subclass of Response to be used as route handler’s default response.

  • response_cookies – A sequence of Cookie instances.

  • @@ -2965,6 +2980,49 @@

    alias of HTTPRouteHandler

    +
    +
    +async litestar.handlers.send_websocket_stream(socket: WebSocket, stream: AsyncGenerator[Any, Any], *, close: bool = True, mode: WebSocketMode = 'text', send_handler: Callable[[WebSocket, Any], Awaitable[Any]] | None = None, listen_for_disconnect: bool = False, warn_on_data_discard: bool = True) None#
    +

    Stream data to the socket from an asynchronous generator.

    +
    +

    Example

    +

    Sending the current time to the connected client every 0.5 seconds:

    +
    async def stream_current_time() -> AsyncGenerator[str, None]:
    +    while True:
    +        yield str(time.time())
    +        await asyncio.sleep(0.5)
    +
    +
    +@websocket("/time")
    +async def time_handler(socket: WebSocket) -> None:
    +    await socket.accept()
    +    await send_websocket_stream(
    +        socket,
    +        stream_current_time(),
    +        listen_for_disconnect=True,
    +    )
    +
    +
    +
    +
    +
    Parameters:
    +
      +
    • socket – The WebSocket to send to

    • +
    • stream – An asynchronous generator yielding data to send

    • +
    • close – If True, close the socket after the generator is exhausted

    • +
    • mode – WebSocket mode to use for sending when no send_handler is specified

    • +
    • send_handler – Callable to handle the send process. If None, defaults to type(socket).send_data

    • +
    • listen_for_disconnect – If True, listen for client disconnects in the background. If a client disconnects, +stop the generator and cancel sending data. Should always be True unless disconnects are handled +elsewhere, for example by reading data from the socket concurrently. Should never be set to True when +reading data from socket concurrently, as it can lead to data loss

    • +
    • warn_on_data_discard – If True and listen_for_disconnect=True, warn if during listening for client +disconnects, data is received from the socket

    • +
    +
    +
    +
    +
    litestar.handlers.websocket#
    @@ -2977,6 +3035,53 @@

    alias of WebsocketListenerRouteHandler

    +
    +
    +litestar.handlers.websocket_stream(path: str | list[str] | None = None, *, dependencies: Dependencies | None = None, exception_handlers: dict[int | type[Exception], ExceptionHandler] | None = None, guards: list[Guard] | None = None, middleware: list[Middleware] | None = None, name: str | None = None, opt: dict[str, Any] | None = None, signature_namespace: Mapping[str, Any] | None = None, websocket_class: type[WebSocket] | None = None, mode: WebSocketMode = 'text', return_dto: type[AbstractDTO] | None | EmptyType = _EmptyEnum.EMPTY, type_encoders: TypeEncodersMap | None = None, listen_for_disconnect: bool = True, warn_on_data_discard: bool = True, **kwargs: Any) Callable[[Callable[..., AsyncGenerator[Any, Any]]], WebsocketRouteHandler]#
    +

    Create a WebSocket handler that accepts a connection and sends data to it from an +async generator.

    +
    +

    Example

    +

    Sending the current time to the connected client every 0.5 seconds:

    +
    @websocket_stream("/time")
    +async def send_time() -> AsyncGenerator[str, None]:
    +    while True:
    +        yield str(time.time())
    +        await asyncio.sleep(0.5)
    +
    +
    +
    +
    +
    Parameters:
    +
      +
    • path – A path fragment for the route handler function or a sequence of path fragments. If not given defaults +to /

    • +
    • dependencies – A string keyed mapping of dependency Provider instances.

    • +
    • exception_handlers – A mapping of status codes and/or exception types to handler functions.

    • +
    • guards – A sequence of Guard callables.

    • +
    • middleware – A sequence of Middleware.

    • +
    • name – A string identifying the route handler.

    • +
    • opt – A string keyed mapping of arbitrary values that can be accessed in Guards or +wherever you have access to Request or +ASGI Scope.

    • +
    • signature_namespace – A mapping of names to types for use in forward reference resolution during signature modelling.

    • +
    • websocket_class – A custom subclass of WebSocket to be used as route handler’s +default websocket class.

    • +
    • mode – WebSocket mode used for sending

    • +
    • return_dtoAbstractDTO to use for serializing outbound response data.

    • +
    • type_encoders – A mapping of types to callables that transform them into types supported for serialization.

    • +
    • listen_for_disconnect – If True, listen for client disconnects in the background. If a client disconnects, +stop the generator and cancel sending data. Should always be True unless disconnects are handled +elsewhere, for example by reading data from the socket concurrently. Should never be set to True when +reading data from socket concurrently, as it can lead to data loss

    • +
    • warn_on_data_discard – If True and listen_for_disconnect=True, warn if during listening for client +disconnects, data is received from the socket

    • +
    • **kwargs – Any additional kwarg - will be set in the opt dictionary.

    • +
    +
    +
    +
    + @@ -3080,8 +3185,6 @@
  • WebsocketListener.exception_handlers
  • WebsocketListener.guards
  • WebsocketListener.middleware
  • -
  • WebsocketListener.on_accept
  • -
  • WebsocketListener.on_disconnect
  • WebsocketListener.receive_mode
  • WebsocketListener.send_mode
  • WebsocketListener.name
  • @@ -3092,14 +3195,11 @@
  • WebsocketListener.type_encoders
  • WebsocketListener.websocket_class
  • WebsocketListener.__init__()
  • +
  • WebsocketListener.on_accept()
  • +
  • WebsocketListener.on_disconnect()
  • WebsocketListener.on_receive()
  • -
  • WebsocketRouteHandler -
  • WebsocketListenerRouteHandler
  • +
  • WebsocketRouteHandler +
  • asgi
  • delete
  • route
  • +
  • send_websocket_stream()
  • websocket
  • websocket_listener
  • +
  • websocket_stream()
  • diff --git a/3803/reference/index.html b/3803/reference/index.html index 915157da5..45f826c38 100644 --- a/3803/reference/index.html +++ b/3803/reference/index.html @@ -1357,8 +1357,12 @@
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/logging/config.html b/3803/reference/logging/config.html index e43d3129e..c9dd18ae4 100644 --- a/3803/reference/logging/config.html +++ b/3803/reference/logging/config.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/logging/index.html b/3803/reference/logging/index.html index d40db3d3d..1524fb9d2 100644 --- a/3803/reference/logging/index.html +++ b/3803/reference/logging/index.html @@ -1357,8 +1357,12 @@
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/logging/picologging.html b/3803/reference/logging/picologging.html index 6dee87c4d..f5cbe6a46 100644 --- a/3803/reference/logging/picologging.html +++ b/3803/reference/logging/picologging.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/logging/standard.html b/3803/reference/logging/standard.html index e9b78bf5c..301ababa5 100644 --- a/3803/reference/logging/standard.html +++ b/3803/reference/logging/standard.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/allowed_hosts.html b/3803/reference/middleware/allowed_hosts.html index 21f6ac757..cd04a5c97 100644 --- a/3803/reference/middleware/allowed_hosts.html +++ b/3803/reference/middleware/allowed_hosts.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/authentication.html b/3803/reference/middleware/authentication.html index 913505b15..84ba69a70 100644 --- a/3803/reference/middleware/authentication.html +++ b/3803/reference/middleware/authentication.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1584,8 +1589,8 @@
    -abstract async authenticate_request(connection: ASGIConnection) AuthenticationResult#
    -

    Receive the http connection and return an AuthenticationResult.

    +abstract async authenticate_request(connection: ASGIConnection) AuthenticationResult# +

    Receive the http connection and return an AuthenticationResult.

    Notes

    diff --git a/3803/reference/middleware/compression.html b/3803/reference/middleware/compression.html index a17825aeb..aa37a5a57 100644 --- a/3803/reference/middleware/compression.html +++ b/3803/reference/middleware/compression.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1541,46 +1546,6 @@

    compression#

    -
    -
    -class litestar.middleware.compression.CompressionMiddleware#
    -

    Bases: AbstractMiddleware

    -

    Compression Middleware Wrapper.

    -

    This is a wrapper allowing for generic compression configuration / handler middleware

    -
    -
    -__init__(app: ASGIApp, config: CompressionConfig) None#
    -

    Initialize CompressionMiddleware

    -
    -
    Parameters:
    -
      -
    • app – The next ASGI app to call.

    • -
    • config – An instance of CompressionConfig.

    • -
    -
    -
    -
    - -
    -
    -create_compression_send_wrapper(send: Send, compression_encoding: Literal[CompressionEncoding.BROTLI, CompressionEncoding.GZIP] | str, scope: Scope) Send#
    -

    Wrap send to handle brotli compression.

    -
    -
    Parameters:
    -
      -
    • send – The ASGI send function.

    • -
    • compression_encoding – The compression encoding used.

    • -
    • scope – The ASGI connection scope

    • -
    -
    -
    Returns:
    -

    An ASGI send function.

    -
    -
    -
    - -
    -
    class litestar.middleware.compression.CompressionFacade#
    @@ -1634,6 +1599,46 @@
    +
    +
    +class litestar.middleware.compression.CompressionMiddleware#
    +

    Bases: AbstractMiddleware

    +

    Compression Middleware Wrapper.

    +

    This is a wrapper allowing for generic compression configuration / handler middleware

    +
    +
    +__init__(app: ASGIApp, config: CompressionConfig) None#
    +

    Initialize CompressionMiddleware

    +
    +
    Parameters:
    +
      +
    • app – The next ASGI app to call.

    • +
    • config – An instance of CompressionConfig.

    • +
    +
    +
    +
    + +
    +
    +create_compression_send_wrapper(send: Send, compression_encoding: Literal[CompressionEncoding.BROTLI, CompressionEncoding.GZIP] | str, scope: Scope) Send#
    +

    Wrap send to handle brotli compression.

    +
    +
    Parameters:
    +
      +
    • send – The ASGI send function.

    • +
    • compression_encoding – The compression encoding used.

    • +
    • scope – The ASGI connection scope

    • +
    +
    +
    Returns:
    +

    An ASGI send function.

    +
    +
    +
    + +
    + @@ -1680,11 +1685,6 @@ diff --git a/3803/reference/middleware/cors.html b/3803/reference/middleware/cors.html index e7ff4bb63..cad4b0c1a 100644 --- a/3803/reference/middleware/cors.html +++ b/3803/reference/middleware/cors.html @@ -1357,8 +1357,12 @@
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/csrf.html b/3803/reference/middleware/csrf.html index 258c12c15..422cf26e8 100644 --- a/3803/reference/middleware/csrf.html +++ b/3803/reference/middleware/csrf.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/index.html b/3803/reference/middleware/index.html index 8e227b655..1fc2a493f 100644 --- a/3803/reference/middleware/index.html +++ b/3803/reference/middleware/index.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1581,7 +1586,7 @@
    -abstract async authenticate_request(connection: ASGIConnection) AuthenticationResult#
    +abstract async authenticate_request(connection: ASGIConnection) AuthenticationResult#

    Receive the http connection and return an AuthenticationResult.

    Notes

    @@ -1597,7 +1602,7 @@

    NotAuthorizedException | PermissionDeniedException – if authentication fails.

    Returns:
    -

    An instance of AuthenticationResult.

    +

    An instance of AuthenticationResult.

    diff --git a/3803/reference/middleware/logging.html b/3803/reference/middleware/logging.html index 538332ba0..d9a0fb6c2 100644 --- a/3803/reference/middleware/logging.html +++ b/3803/reference/middleware/logging.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1705,7 +1710,7 @@
    -__init__(exclude: str | list[str] | None = None, exclude_opt_key: str | None = None, include_compressed_body: bool = False, logger_name: str = 'litestar', request_cookies_to_obfuscate: set[str] = <factory>, request_headers_to_obfuscate: set[str] = <factory>, response_cookies_to_obfuscate: set[str] = <factory>, response_headers_to_obfuscate: set[str] = <factory>, request_log_message: str = 'HTTP Request', response_log_message: str = 'HTTP Response', request_log_fields: ~typing.Iterable[~typing.Literal['path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body', 'scheme', 'client']] = ('path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body'), response_log_fields: ~typing.Iterable[~typing.Literal['status_code', 'headers', 'body', 'cookies']] = ('status_code', 'cookies', 'headers', 'body'), middleware_class: type[litestar.middleware.logging.LoggingMiddleware] = <class 'litestar.middleware.logging.LoggingMiddleware'>) None#
    +__init__(exclude: str | list[str] | None = None, exclude_opt_key: str | None = None, include_compressed_body: bool = False, logger_name: str = 'litestar', request_cookies_to_obfuscate: set[str] = <factory>, request_headers_to_obfuscate: set[str] = <factory>, response_cookies_to_obfuscate: set[str] = <factory>, response_headers_to_obfuscate: set[str] = <factory>, request_log_message: str = 'HTTP Request', response_log_message: str = 'HTTP Response', request_log_fields: ~typing.Collection[~typing.Literal['path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body', 'scheme', 'client']] = ('path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body'), response_log_fields: ~typing.Collection[~typing.Literal['status_code', 'headers', 'body', 'cookies']] = ('status_code', 'cookies', 'headers', 'body'), middleware_class: type[litestar.middleware.logging.LoggingMiddleware] = <class 'litestar.middleware.logging.LoggingMiddleware'>) None#
    @@ -1729,7 +1734,7 @@
    -request_log_fields: Iterable[Literal['path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body', 'scheme', 'client']] = ('path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body')#
    +request_log_fields: Collection[Literal['path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body', 'scheme', 'client']] = ('path', 'method', 'content_type', 'headers', 'cookies', 'query', 'path_params', 'body')#

    Fields to extract and log from the request.

    Notes

    @@ -1746,7 +1751,7 @@
    -response_log_fields: Iterable[Literal['status_code', 'headers', 'body', 'cookies']] = ('status_code', 'cookies', 'headers', 'body')#
    +response_log_fields: Collection[Literal['status_code', 'headers', 'body', 'cookies']] = ('status_code', 'cookies', 'headers', 'body')#

    Fields to extract and log from the response. The order of fields in the iterable determines the order of the log message logged out.

    diff --git a/3803/reference/middleware/rate_limit.html b/3803/reference/middleware/rate_limit.html index 8e5a4caef..e96f94e98 100644 --- a/3803/reference/middleware/rate_limit.html +++ b/3803/reference/middleware/rate_limit.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/session/base.html b/3803/reference/middleware/session/base.html index a1fbad8fe..41aae5fe1 100644 --- a/3803/reference/middleware/session/base.html +++ b/3803/reference/middleware/session/base.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/session/client_side.html b/3803/reference/middleware/session/client_side.html index b95674c33..bcf6f5c2e 100644 --- a/3803/reference/middleware/session/client_side.html +++ b/3803/reference/middleware/session/client_side.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/session/index.html b/3803/reference/middleware/session/index.html index dff80267b..bd82435bf 100644 --- a/3803/reference/middleware/session/index.html +++ b/3803/reference/middleware/session/index.html @@ -1357,8 +1357,12 @@
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/middleware/session/server_side.html b/3803/reference/middleware/session/server_side.html index a2263f276..01ff852d3 100644 --- a/3803/reference/middleware/session/server_side.html +++ b/3803/reference/middleware/session/server_side.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/openapi/index.html b/3803/reference/openapi/index.html index 372301d5b..d93b4ebf3 100644 --- a/3803/reference/openapi/index.html +++ b/3803/reference/openapi/index.html @@ -1357,8 +1357,12 @@
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/openapi/openapi.html b/3803/reference/openapi/openapi.html index 759253aee..0536085ea 100644 --- a/3803/reference/openapi/openapi.html +++ b/3803/reference/openapi/openapi.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1541,6 +1546,196 @@

    openapi#

    +
    +
    +class litestar.openapi.OpenAPIConfig#
    +

    Bases: object

    +

    Configuration for OpenAPI.

    +

    To enable OpenAPI schema generation and serving, pass an instance of this class to the +Litestar constructor using the openapi_config kwargs.

    +
    +
    +title: str#
    +

    Title of API documentation.

    +
    + +
    +
    +version: str#
    +

    API version, e.g. ‘1.0.0’.

    +
    + +
    +
    +create_examples: bool = False#
    +

    Generate examples using the polyfactory library.

    +
    + +
    +
    +random_seed: int = 10#
    +

    The random seed used when creating the examples to ensure deterministic generation of examples.

    +
    + +
    +
    +contact: Contact | None = None#
    +

    API contact information, should be an Contact instance.

    +
    + +
    +
    +description: str | None = None#
    +

    API description.

    +
    + +
    +
    +external_docs: ExternalDocumentation | None = None#
    +

    Links to external documentation.

    +

    Should be an instance of ExternalDocumentation.

    +
    + +
    +
    +license: License | None = None#
    +

    API Licensing information.

    +

    Should be an instance of License.

    +
    + +
    +
    +security: list[SecurityRequirement] | None = None#
    +

    API Security requirements information.

    +
    +
    Should be an instance of

    SecurityRequirement.

    +
    +
    +
    + +
    +
    +components: Components | list[Components]#
    +

    API Components information.

    +

    Should be an instance of Components or a list thereof.

    +
    + +
    +
    +servers: list[Server]#
    +

    A list of Server instances.

    +
    + +
    +
    +summary: str | None = None#
    +

    A summary text.

    +
    + +
    +
    +tags: list[Tag] | None = None#
    +

    A list of Tag instances.

    +
    + +
    +
    +__init__(title: str, version: str, create_examples: bool = False, random_seed: int = 10, contact: Contact | None = None, description: str | None = None, external_docs: ExternalDocumentation | None = None, license: License | None = None, security: list[SecurityRequirement] | None = None, components: Components | list[Components] = <factory>, servers: list[Server] = <factory>, summary: str | None = None, tags: list[Tag] | None = None, terms_of_service: str | None = None, use_handler_docstrings: bool = False, webhooks: dict[str, PathItem | Reference] | None = None, operation_id_creator: OperationIDCreator = <function default_operation_id_creator>, path: str | None = None, render_plugins: Sequence[OpenAPIRenderPlugin] = (), openapi_router: Router | None = None, openapi_controller: type[OpenAPIController] | None = None, root_schema_site: Literal['redoc', 'swagger', 'elements', 'rapidoc'] | None = None, enabled_endpoints: set[str] | None = None) None#
    +
    + +
    +
    +terms_of_service: str | None = None#
    +

    URL to page that contains terms of service.

    +
    + +
    +
    +use_handler_docstrings: bool = False#
    +

    Draw operation description from route handler docstring if not otherwise provided.

    +
    + +
    +
    +webhooks: dict[str, PathItem | Reference] | None = None#
    +

    A mapping of key to either PathItem or.

    +

    Reference objects.

    +
    + +
    +
    +operation_id_creator(http_method: Method, path_components: list[str | PathParameterDefinition]) str#
    +

    A callable that generates unique operation ids

    +
    + +
    +
    +path: str | None = None#
    +

    Base path for the OpenAPI documentation endpoints.

    +

    If no path is provided the default is /schema.

    +

    Ignored if openapi_router is provided.

    +
    + +
    +
    +render_plugins: Sequence[OpenAPIRenderPlugin] = ()#
    +

    Plugins for rendering OpenAPI documentation UIs.

    +
    + +
    +
    +openapi_router: Router | None = None#
    +

    An optional router for serving OpenAPI documentation and schema files.

    +

    If provided, path is ignored.

    +

    This parameter is also ignored if the deprecated openapi_router +kwarg is provided.

    +

    openapi_router is not required, but it can be passed to customize the configuration of the router used to +serve the documentation endpoints. For example, you can add middleware or guards to the router.

    +

    Handlers to serve the OpenAPI schema and documentation sites are added to this router according to +render_plugins, so routes shouldn’t be added that conflict with these.

    +
    + +
    +
    +openapi_controller: type[OpenAPIController] | None = None#
    +

    Controller for generating OpenAPI routes.

    +

    Must be subclass of OpenAPIController.

    +
    +

    Deprecated since version v2.8.0.

    +
    +
    + +
    +
    +root_schema_site: Literal['redoc', 'swagger', 'elements', 'rapidoc'] | None = None#
    +

    The static schema generator to use for the “root” path of /schema/.

    +
    +

    Deprecated since version v2.8.0.

    +
    +
    + +
    +
    +enabled_endpoints: set[str] | None = None#
    +

    A set of the enabled documentation sites and schema download endpoints.

    +
    +

    Deprecated since version v2.8.0.

    +
    +
    + +
    +
    +to_openapi_schema() OpenAPI#
    +

    Return an OpenAPI instance from the values stored in self.

    +
    +
    Returns:
    +

    An instance of OpenAPI.

    +
    +
    +
    + +
    +
    class litestar.openapi.OpenAPIController#
    @@ -1566,7 +1761,7 @@
    -swagger_ui_version: str = '5.1.3'#
    +swagger_ui_version: str = '5.18.2'#

    SwaggerUI version to download from the CDN.

    @@ -1603,19 +1798,19 @@
    -swagger_css_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.1.3/swagger-ui.css'#
    +swagger_css_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.18.2/swagger-ui.css'#

    Download url for the Swagger UI CSS bundle.

    -swagger_ui_bundle_js_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.1.3/swagger-ui-bundle.js'#
    +swagger_ui_bundle_js_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.18.2/swagger-ui-bundle.js'#

    Download url for the Swagger UI JS bundle.

    -swagger_ui_standalone_preset_js_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.1.3/swagger-ui-standalone-preset.js'#
    +swagger_ui_standalone_preset_js_url: str = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.18.2/swagger-ui-standalone-preset.js'#

    Download url for the Swagger Standalone Preset JS bundle.

    @@ -1794,6 +1989,13 @@ handlers under the controller.

    +
    +
    +request_max_body_size: int | None | EmptyType#
    +

    Maximum allowed size of the request body in bytes. If this size is exceeded, a ‘413 - Request Entity Too Large’ +error response is returned.

    +
    +
    response_class: type[Response] | None#
    @@ -1838,18 +2040,18 @@

    A sequence of string tags that will be appended to the schema of all route handlers under the controller.

    -
    -
    -type_encoders: TypeEncodersMap | None#
    -

    A mapping of types to callables that transform them into types supported for serialization.

    -
    -
    type_decoders: TypeDecodersSequence | None#

    A sequence of tuples, each composed of a predicate testing for type identity and a msgspec hook for deserialization.

    +
    +
    +type_encoders: TypeEncodersMap | None#
    +

    A mapping of types to callables that transform them into types supported for serialization.

    +
    +
    websocket_class: type[WebSocket] | None#
    @@ -1961,196 +2163,6 @@
    -
    -
    -class litestar.openapi.OpenAPIConfig#
    -

    Bases: object

    -

    Configuration for OpenAPI.

    -

    To enable OpenAPI schema generation and serving, pass an instance of this class to the -Litestar constructor using the openapi_config kwargs.

    -
    -
    -title: str#
    -

    Title of API documentation.

    -
    - -
    -
    -version: str#
    -

    API version, e.g. ‘1.0.0’.

    -
    - -
    -
    -create_examples: bool = False#
    -

    Generate examples using the polyfactory library.

    -
    - -
    -
    -random_seed: int = 10#
    -

    The random seed used when creating the examples to ensure deterministic generation of examples.

    -
    - -
    -
    -contact: Contact | None = None#
    -

    API contact information, should be an Contact instance.

    -
    - -
    -
    -description: str | None = None#
    -

    API description.

    -
    - -
    -
    -external_docs: ExternalDocumentation | None = None#
    -

    Links to external documentation.

    -

    Should be an instance of ExternalDocumentation.

    -
    - -
    -
    -license: License | None = None#
    -

    API Licensing information.

    -

    Should be an instance of License.

    -
    - -
    -
    -security: list[SecurityRequirement] | None = None#
    -

    API Security requirements information.

    -
    -
    Should be an instance of

    SecurityRequirement.

    -
    -
    -
    - -
    -
    -components: Components | list[Components]#
    -

    API Components information.

    -

    Should be an instance of Components or a list thereof.

    -
    - -
    -
    -servers: list[Server]#
    -

    A list of Server instances.

    -
    - -
    -
    -summary: str | None = None#
    -

    A summary text.

    -
    - -
    -
    -tags: list[Tag] | None = None#
    -

    A list of Tag instances.

    -
    - -
    -
    -__init__(title: str, version: str, create_examples: bool = False, random_seed: int = 10, contact: Contact | None = None, description: str | None = None, external_docs: ExternalDocumentation | None = None, license: License | None = None, security: list[SecurityRequirement] | None = None, components: Components | list[Components] = <factory>, servers: list[Server] = <factory>, summary: str | None = None, tags: list[Tag] | None = None, terms_of_service: str | None = None, use_handler_docstrings: bool = False, webhooks: dict[str, PathItem | Reference] | None = None, operation_id_creator: OperationIDCreator = <function default_operation_id_creator>, path: str | None = None, render_plugins: Sequence[OpenAPIRenderPlugin] = (), openapi_router: Router | None = None, openapi_controller: type[OpenAPIController] | None = None, root_schema_site: Literal['redoc', 'swagger', 'elements', 'rapidoc'] | None = None, enabled_endpoints: set[str] | None = None) None#
    -
    - -
    -
    -terms_of_service: str | None = None#
    -

    URL to page that contains terms of service.

    -
    - -
    -
    -use_handler_docstrings: bool = False#
    -

    Draw operation description from route handler docstring if not otherwise provided.

    -
    - -
    -
    -webhooks: dict[str, PathItem | Reference] | None = None#
    -

    A mapping of key to either PathItem or.

    -

    Reference objects.

    -
    - -
    -
    -operation_id_creator(http_method: Method, path_components: list[str | PathParameterDefinition]) str#
    -

    A callable that generates unique operation ids

    -
    - -
    -
    -path: str | None = None#
    -

    Base path for the OpenAPI documentation endpoints.

    -

    If no path is provided the default is /schema.

    -

    Ignored if openapi_router is provided.

    -
    - -
    -
    -render_plugins: Sequence[OpenAPIRenderPlugin] = ()#
    -

    Plugins for rendering OpenAPI documentation UIs.

    -
    - -
    -
    -openapi_router: Router | None = None#
    -

    An optional router for serving OpenAPI documentation and schema files.

    -

    If provided, path is ignored.

    -

    This parameter is also ignored if the deprecated openapi_router -kwarg is provided.

    -

    openapi_router is not required, but it can be passed to customize the configuration of the router used to -serve the documentation endpoints. For example, you can add middleware or guards to the router.

    -

    Handlers to serve the OpenAPI schema and documentation sites are added to this router according to -render_plugins, so routes shouldn’t be added that conflict with these.

    -
    - -
    -
    -openapi_controller: type[OpenAPIController] | None = None#
    -

    Controller for generating OpenAPI routes.

    -

    Must be subclass of OpenAPIController.

    -
    -

    Deprecated since version v2.8.0.

    -
    -
    - -
    -
    -root_schema_site: Literal['redoc', 'swagger', 'elements', 'rapidoc'] | None = None#
    -

    The static schema generator to use for the “root” path of /schema/.

    -
    -

    Deprecated since version v2.8.0.

    -
    -
    - -
    -
    -enabled_endpoints: set[str] | None = None#
    -

    A set of the enabled documentation sites and schema download endpoints.

    -
    -

    Deprecated since version v2.8.0.

    -
    -
    - -
    -
    -to_openapi_schema() OpenAPI#
    -

    Return an OpenAPI instance from the values stored in self.

    -
    -
    Returns:
    -

    An instance of OpenAPI.

    -
    -
    -
    - -
    -
    class litestar.openapi.ResponseSpec#
    @@ -2239,6 +2251,34 @@
    -
    -
    -class litestar.openapi.spec.XML#
    -

    Bases: BaseSchemaObject

    -

    A metadata object that allows for more fine-tuned XML model definitions.

    -

    When using arrays, XML element names are not inferred (for singular/plural forms) and the name property SHOULD -be used to add that information. See examples for expected behavior.

    -
    -
    -name: str | None = None#
    -

    Replaces the name of the element/attribute used for the described schema property. When defined within items, it -will affect the name of the individual XML elements within the list. When defined alongside type being array -(outside the items), it will affect the wrapping element and only if wrapped is True. If wrapped is -False, it will be ignored.

    -
    - -
    -
    -namespace: str | None = None#
    -

    The URI of the namespace definition. Value MUST be in the form of an absolute URI.

    -
    - -
    -
    -__init__(name: str | None = None, namespace: str | None = None, prefix: str | None = None, attribute: bool = False, wrapped: bool = False) None#
    -
    - -
    -
    -prefix: str | None = None#
    -

    The prefix to be used for the -xmlName

    -
    - -
    -
    -attribute: bool = False#
    -

    Declares whether the property definition translates to an attribute instead of an element. Default value is -False.

    -
    - -
    -
    -wrapped: bool = False#
    -

    MAY be used only for an array definition. Signifies whether the array is wrapped (for example, -<books><book/><book/></books>) or unwrapped (<book/><book/>). Default value is False. The definition -takes effect only when defined alongside type being array (outside the items).

    -
    - -
    -
    litestar.openapi.spec.SecurityRequirement#
    @@ -3722,6 +3727,15 @@ diff --git a/3803/reference/pagination.html b/3803/reference/pagination.html index 49dfbcaea..3d31c0381 100644 --- a/3803/reference/pagination.html +++ b/3803/reference/pagination.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/params.html b/3803/reference/params.html index d9b8e4d78..d166fd547 100644 --- a/3803/reference/params.html +++ b/3803/reference/params.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/reference/plugins/attrs.html b/3803/reference/plugins/attrs.html new file mode 100644 index 000000000..949c5317a --- /dev/null +++ b/3803/reference/plugins/attrs.html @@ -0,0 +1,1711 @@ + + + + + + + + + + + attrs — Litestar Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    + + + +
    +
    + +
    + + + + + + + + + + + + + +
    + +
    + + +
    +
    + +
    +
    + +
    + +
    + + + + +
    + +
    + + +
    +
    + + + + + +
    + +
    +

    attrs#

    +
    +
    +class litestar.plugins.attrs.AttrsSchemaPlugin#
    +

    Bases: OpenAPISchemaPluginProtocol

    +
    +
    +static is_plugin_supported_type(value: Any) bool#
    +

    Given a value of indeterminate type, determine if this value is supported by the plugin.

    +
    +
    Parameters:
    +

    value – An arbitrary value.

    +
    +
    Returns:
    +

    A typeguard dictating whether the value is supported by the plugin.

    +
    +
    +
    + +
    +
    +to_openapi_schema(field_definition: FieldDefinition, schema_creator: SchemaCreator) Schema#
    +

    Given a type annotation, transform it into an OpenAPI schema class.

    +
    +
    Parameters:
    +
      +
    • field_definition – FieldDefinition instance.

    • +
    • schema_creator – An instance of the schema creator class

    • +
    +
    +
    Returns:
    +

    An OpenAPI instance.

    +
    +
    +
    + +
    + +
    +
    +litestar.plugins.attrs.is_attrs_class(annotation: Any) TypeGuard[type[attr.AttrsInstance]]#
    +

    Given a type annotation determine if the annotation is a class that includes an attrs attribute.

    +
    +
    Parameters:
    +

    annotation – A type.

    +
    +
    Returns:
    +

    A typeguard determining whether the type is an attrs class.

    +
    +
    +
    + +
    + + +
    + + + + + + + +
    + + + + + + +
    +
    + +
    + +
    +
    +
    + + + + + +
    + + +
    + + \ No newline at end of file diff --git a/3803/reference/plugins/flash_messages.html b/3803/reference/plugins/flash_messages.html index 56c99b52a..a32034480 100644 --- a/3803/reference/plugins/flash_messages.html +++ b/3803/reference/plugins/flash_messages.html @@ -52,8 +52,8 @@ - - + + @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1599,20 +1604,20 @@

    previous

    -

    plugins

    +

    attrs

    next

    -

    problem details

    +

    htmx

    diff --git a/3803/reference/plugins/htmx.html b/3803/reference/plugins/htmx.html new file mode 100644 index 000000000..d18c2ce85 --- /dev/null +++ b/3803/reference/plugins/htmx.html @@ -0,0 +1,2047 @@ + + + + + + + + + + + htmx — Litestar Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    + + + +
    +
    + +
    + + + + + + + + + + + + + +
    + +
    + + +
    +
    + +
    +
    + +
    + +
    + + + + +
    + +
    + + +
    +
    + + + + + +
    + +
    +

    htmx#

    +
    +
    +class litestar.plugins.htmx.ClientRedirect#
    +

    Bases: Response

    +

    HTMX Response class to support client side redirect.

    +
    +
    +__init__(redirect_to: str) None#
    +

    Set status code to 200 (required by HTMX), and pass redirect url.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.ClientRefresh#
    +

    Bases: Response

    +

    Response to support HTMX client page refresh

    +
    +
    +__init__() None#
    +

    Set Status code to 200 and set headers.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXConfig#
    +

    Bases: object

    +

    Configuration for HTMX Plugin.

    +
    +
    +set_request_class_globally: bool = True#
    +

    Sets the app_config.request_class to the HTMXRequest class at the application level. Defaults to True

    +
    + +
    +
    +__init__(set_request_class_globally: bool = True) None#
    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXDetails#
    +

    Bases: object

    +

    HTMXDetails holds all the values sent by HTMX client in headers and provide convenient properties.

    +
    +
    +__init__(request: Request) None#
    +

    Initialize HTMXDetails

    +
    + +
    +
    +__bool__() bool#
    +

    Check if request is sent by an HTMX client.

    +
    + +
    +
    +property boosted: bool#
    +

    Check if request is boosted.

    +
    + +
    +
    +property current_url: str | None#
    +

    Current url value sent by HTMX client.

    +
    + +
    +
    +property current_url_abs_path: str | None#
    +

    Current url abs path value, to get query and path parameter sent by HTMX client.

    +
    + +
    +
    +property history_restore_request: bool#
    +

    If True then, request is for history restoration after a miss in the local history cache.

    +
    + +
    +
    +property prompt: str | None#
    +

    User Response to prompt.

    +
    <button hx-delete="/account" hx-prompt="Enter your account name to confirm deletion">Delete My Account</button>
    +
    +
    +
    + +
    +
    +property target: str | None#
    +

    ID of the target element if provided on the element.

    +
    + +
    +
    +property trigger: str | None#
    +

    ID of the triggered element if provided on the element.

    +
    + +
    +
    +property trigger_name: str | None#
    +

    Name of the triggered element if provided on the element.

    +
    + +
    +
    +property triggering_event: Any#
    +

    Name of the triggered event.

    +

    This value is added by event-header extension of HTMX to the Triggering-Event header to requests.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXHeaders#
    +

    Bases: str, Enum

    +

    Enum for HTMX Headers

    +
    +
    +__new__(value)#
    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXPlugin#
    +

    Bases: InitPluginProtocol

    +

    HTMX Plugin.

    +
    +
    +__init__(config: HTMXConfig | None = None) None#
    +

    Initialize the plugin.

    +
    +
    Parameters:
    +

    config – Configuration for flash messages, including the template engine instance.

    +
    +
    +
    + +
    +
    +on_app_init(app_config: AppConfig) AppConfig#
    +

    Register the HTMX configuration.

    +
    +
    Parameters:
    +

    app_config – The application configuration.

    +
    +
    Returns:
    +

    The application configuration with the message callable registered.

    +
    +
    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXRequest#
    +

    Bases: Request

    +

    HTMX Request class to work with HTMX client.

    +
    +
    +__init__(scope: Scope, receive: Receive = <function empty_receive>, send: Send = <function empty_send>) None#
    +

    Initialize HTMXRequest

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HTMXTemplate#
    +

    Bases: Template

    +

    HTMX template wrapper

    +
    +
    +__init__(push_url: str | bool | None = None, re_swap: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None] | None = None, re_target: str | None = None, trigger_event: str | None = None, params: dict[str, Any] | None = None, after: Literal['receive', 'settle', 'swap', None] | None = None, **kwargs: Any) None#
    +

    Create HTMXTemplate response.

    +
    +
    Parameters:
    +
      +
    • push_url – Either a string value specifying a URL to push to browser history or False to prevent HTMX client from +pushing a url to browser history.

    • +
    • re_swap – Method value to instruct HTMX which swapping method to use.

    • +
    • re_target – Value for ‘id of target element’ to apply changes to.

    • +
    • trigger_event – Event name to trigger.

    • +
    • params – Dictionary of parameters if any required with trigger event parameter.

    • +
    • after – Changes to apply after receive, settle or swap event.

    • +
    • **kwargs – Additional arguments to pass to Template.

    • +
    +
    +
    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HXLocation#
    +

    Bases: Response

    +

    Client side redirect without full page reload.

    +
    +
    +__init__(redirect_to: str, source: str | None = None, event: str | None = None, target: str | None = None, swap: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None] | None = None, hx_headers: dict[str, Any] | None = None, values: dict[str, str] | None = None, **kwargs: Any) None#
    +

    Initialize HXLocation, Set status code to 200 (required by HTMX), +and pass redirect url.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HXStopPolling#
    +

    Bases: Response

    +

    Stop HTMX client from Polling.

    +
    +
    +__init__() None#
    +

    Initialize

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.HtmxHeaderType#
    +

    Bases: TypedDict

    +

    Type for hx_headers parameter in get_headers().

    +
    + +
    +
    +class litestar.plugins.htmx.LocationType#
    +

    Bases: TypedDict

    +

    Type for HX-Location header.

    +
    + +
    +
    +class litestar.plugins.htmx.PushUrl#
    +

    Bases: Generic[T], Response[T]

    +

    Response to push new url into the history stack.

    +
    +
    +__init__(content: T, push_url: str | bool, **kwargs: Any) None#
    +

    Initialize PushUrl.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.ReplaceUrl#
    +

    Bases: Generic[T], Response[T]

    +

    Response to replace url in the Browser Location bar.

    +
    +
    +__init__(content: T, replace_url: str | bool, **kwargs: Any) None#
    +

    Initialize ReplaceUrl.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.Reswap#
    +

    Bases: Generic[T], Response[T]

    +

    Response to specify how the response will be swapped.

    +
    +
    +__init__(content: T, method: Literal['innerHTML', 'outerHTML', 'beforebegin', 'afterbegin', 'beforeend', 'afterend', 'delete', 'none', None], **kwargs: Any) None#
    +

    Initialize Reswap.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.Retarget#
    +

    Bases: Generic[T], Response[T]

    +

    Response to target different element on the page.

    +
    +
    +__init__(content: T, target: str, **kwargs: Any) None#
    +

    Initialize Retarget.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.TriggerEvent#
    +

    Bases: Generic[T], Response[T]

    +

    Trigger Client side event.

    +
    +
    +__init__(content: T, name: str, after: Literal['receive', 'settle', 'swap', None], params: dict[str, Any] | None = None, **kwargs: Any) None#
    +

    Initialize TriggerEvent.

    +
    + +
    + +
    +
    +class litestar.plugins.htmx.TriggerEventType#
    +

    Bases: TypedDict

    +

    Type for HX-Trigger header.

    +
    + +
    + + +
    + + + + + + + +
    + + + + + + +
    +
    + +
    + +
    +
    +
    + + + + + +
    + + +
    + + \ No newline at end of file diff --git a/3803/reference/plugins/index.html b/3803/reference/plugins/index.html index 6a3e24c28..d8119c532 100644 --- a/3803/reference/plugins/index.html +++ b/3803/reference/plugins/index.html @@ -52,7 +52,7 @@ - + @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1539,41 +1544,50 @@

    plugins#

    -
    -class litestar.plugins.SerializationPluginProtocol#
    -

    Bases: Protocol

    -

    Protocol used to define a serialization plugin for DTOs.

    -
    -
    -supports_type(field_definition: FieldDefinition) bool#
    -

    Given a value of indeterminate type, determine if this value is supported by the plugin.

    -
    -
    Parameters:
    -

    field_definition – A parsed type.

    -
    -
    Returns:
    -

    Whether the type is supported by the plugin.

    -
    -
    +
    +class litestar.plugins.CLIPlugin#
    +

    Bases: CLIPluginProtocol

    +

    Plugin protocol to extend the CLI Server Lifespan.

    +
    +
    +class litestar.plugins.CLIPluginProtocol#
    +

    Bases: Protocol

    +

    Plugin protocol to extend the CLI.

    -
    -create_dto_for_type(field_definition: FieldDefinition) type[AbstractDTO]#
    -

    Given a parsed type, create a DTO class.

    +
    +on_cli_init(cli: Group) None#
    +

    Called when the CLI is initialized.

    +

    This can be used to extend or override existing commands.

    Parameters:
    -

    field_definition – A parsed type.

    -
    -
    Returns:
    -

    A DTO class.

    +

    cli – The root click.Group of the Litestar CLI

    +
    +

    Examples

    +
    from litestar import Litestar
    +from litestar.plugins import CLIPluginProtocol
    +from click import Group
    +
    +
    +class CLIPlugin(CLIPluginProtocol):
    +    def on_cli_init(self, cli: Group) -> None:
    +        @cli.command()
    +        def is_debug_mode(app: Litestar):
    +            print(app.debug)
    +
    +
    +app = Litestar(plugins=[CLIPlugin()])
    +
    +
    +
    -
    -__init__(*args, **kwargs)#
    +
    +__init__(*args, **kwargs)#
    @@ -1587,7 +1601,7 @@
    abstract has_typed_init(type_: Any) bool#

    Return True if type_ has type information available for its -__init__() method that cannot be extracted from this method’s type +__init__() method that cannot be extracted from this method’s type annotations (e.g. a Pydantic BaseModel subclass), and DIPlugin.get_typed_init() supports extraction of these annotations.

    @@ -1595,19 +1609,12 @@
    abstract get_typed_init(type_: Any) tuple[Signature, dict[str, Any]]#
    -

    Return signature and type information about the type_s __init__() +

    Return signature and type information about the type_s __init__() method.

    -
    -
    -class litestar.plugins.CLIPlugin#
    -

    Bases: CLIPluginProtocol

    -

    Plugin protocol to extend the CLI Server Lifespan.

    -
    -
    class litestar.plugins.InitPluginProtocol#
    @@ -1661,49 +1668,6 @@
    -
    -
    -class litestar.plugins.OpenAPISchemaPluginProtocol#
    -

    Bases: Protocol

    -

    Plugin protocol to extend the support of OpenAPI schema generation for non-library types.

    -
    -
    -static is_plugin_supported_type(value: Any) bool#
    -

    Given a value of indeterminate type, determine if this value is supported by the plugin.

    -
    -
    Parameters:
    -

    value – An arbitrary value.

    -
    -
    Returns:
    -

    A typeguard dictating whether the value is supported by the plugin.

    -
    -
    -
    - -
    -
    -to_openapi_schema(field_definition: FieldDefinition, schema_creator: SchemaCreator) Schema#
    -

    Given a type annotation, transform it into an OpenAPI schema class.

    -
    -
    Parameters:
    -
      -
    • field_definition – An OpenAPI instance.

    • -
    • schema_creator – An instance of the openapi SchemaCreator.

    • -
    -
    -
    Returns:
    -

    An OpenAPI instance.

    -
    -
    -
    - -
    -
    -__init__(*args, **kwargs)#
    -
    - -
    -
    class litestar.plugins.OpenAPISchemaPlugin#
    @@ -1756,43 +1720,84 @@
    -
    -class litestar.plugins.CLIPluginProtocol#
    +
    +class litestar.plugins.OpenAPISchemaPluginProtocol#

    Bases: Protocol

    -

    Plugin protocol to extend the CLI.

    +

    Plugin protocol to extend the support of OpenAPI schema generation for non-library types.

    -
    -on_cli_init(cli: Group) None#
    -

    Called when the CLI is initialized.

    -

    This can be used to extend or override existing commands.

    +
    +static is_plugin_supported_type(value: Any) bool#
    +

    Given a value of indeterminate type, determine if this value is supported by the plugin.

    Parameters:
    -

    cli – The root click.Group of the Litestar CLI

    +

    value – An arbitrary value.

    +
    +
    Returns:
    +

    A typeguard dictating whether the value is supported by the plugin.

    -
    -

    Examples

    -
    from litestar import Litestar
    -from litestar.plugins import CLIPluginProtocol
    -from click import Group
    +
    +
    +
    +to_openapi_schema(field_definition: FieldDefinition, schema_creator: SchemaCreator) Schema#
    +

    Given a type annotation, transform it into an OpenAPI schema class.

    +
    +
    Parameters:
    +
      +
    • field_definition – An OpenAPI instance.

    • +
    • schema_creator – An instance of the openapi SchemaCreator.

    • +
    +
    +
    Returns:
    +

    An OpenAPI instance.

    +
    +
    +
    -class CLIPlugin(CLIPluginProtocol): - def on_cli_init(self, cli: Group) -> None: - @cli.command() - def is_debug_mode(app: Litestar): - print(app.debug) +
    +
    +__init__(*args, **kwargs)#
    +
    +
    -app = Litestar(plugins=[CLIPlugin()]) - - - +
    +
    +class litestar.plugins.SerializationPluginProtocol#
    +

    Bases: Protocol

    +

    Protocol used to define a serialization plugin for DTOs.

    +
    +
    +supports_type(field_definition: FieldDefinition) bool#
    +

    Given a value of indeterminate type, determine if this value is supported by the plugin.

    +
    +
    Parameters:
    +

    field_definition – A parsed type.

    +
    +
    Returns:
    +

    Whether the type is supported by the plugin.

    +
    +
    -
    -__init__(*args, **kwargs)#
    +
    +create_dto_for_type(field_definition: FieldDefinition) type[AbstractDTO]#
    +

    Given a parsed type, create a DTO class.

    +
    +
    Parameters:
    +

    field_definition – A parsed type.

    +
    +
    Returns:
    +

    A DTO class.

    +
    +
    +
    + +
    +
    +__init__(*args, **kwargs)#
    @@ -1821,11 +1826,11 @@

    next

    -

    flash

    +

    attrs

    @@ -1845,10 +1850,10 @@ diff --git a/3803/usage/responses.html b/3803/usage/responses.html index 1d513950c..4fd4f8114 100644 --- a/3803/usage/responses.html +++ b/3803/usage/responses.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/usage/routing/handlers.html b/3803/usage/routing/handlers.html index b627f4981..b5be60a98 100644 --- a/3803/usage/routing/handlers.html +++ b/3803/usage/routing/handlers.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1565,8 +1570,10 @@

    Route handlerssync_to_thread parameter can be set to True, which -will result in the function being run in a thread pool. Should the function be -non-blocking, sync_to_thread should be set to False instead.

    +will result in the function being run in a thread pool.

    +

    If a synchronous function is non-blocking, setting sync_to_thread to False +will tell Litestar that the user is sure about its behavior +and the function can be treated as non-blocking.

    If a synchronous function is passed, without setting an explicit sync_to_thread value, a warning will be raised.

    from litestar import delete, get, patch, post, put, head
     from litestar.dto import DTOConfig, DTOData
    -from litestar.contrib.pydantic import PydanticDTO
    +from litestar.plugins.pydantic import PydanticDTO
     
     from pydantic import BaseModel
     
    diff --git a/3803/usage/routing/index.html b/3803/usage/routing/index.html
    index 4bfdd0164..c8f0e0fcb 100644
    --- a/3803/usage/routing/index.html
    +++ b/3803/usage/routing/index.html
    @@ -1357,8 +1357,12 @@
     
  • pagination
  • params
  • plugins @@ -1396,6 +1400,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/usage/routing/overview.html b/3803/usage/routing/overview.html index 3af3bfa7b..3966ace29 100644 --- a/3803/usage/routing/overview.html +++ b/3803/usage/routing/overview.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1675,7 +1680,7 @@

    -
    from litestar.contrib.pydantic import PydanticDTO
    +
    from litestar.plugins.pydantic import PydanticDTO
     from litestar.controller import Controller
     from litestar.dto import DTOConfig, DTOData
     from litestar.handlers import get, post, patch, delete
    diff --git a/3803/usage/routing/parameters.html b/3803/usage/routing/parameters.html
    index 098319f72..517337e91 100644
    --- a/3803/usage/routing/parameters.html
    +++ b/3803/usage/routing/parameters.html
    @@ -1361,8 +1361,12 @@
     
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • diff --git a/3803/usage/security/abstract-authentication-middleware.html b/3803/usage/security/abstract-authentication-middleware.html index 5b44b8579..51e7456d4 100644 --- a/3803/usage/security/abstract-authentication-middleware.html +++ b/3803/usage/security/abstract-authentication-middleware.html @@ -1361,8 +1361,12 @@
  • pagination
  • params
  • plugins @@ -1400,6 +1404,7 @@
  • memory
  • redis
  • registry
  • +
  • valkey
  • template
  • @@ -1541,13 +1546,13 @@

    Implementing Custom Authentication#

    -

    Litestar exports AbstractAuthenticationMiddleware, which is an +

    Litestar exports AbstractAuthenticationMiddleware, which is an abstract base class (ABC) that implements the MiddlewareProtocol. To add authentication to your app using this class as a basis, subclass it and implement the abstract method authenticate_request():

    Adding authentication to your app by subclassing -AbstractAuthenticationMiddleware#
    +AbstractAuthenticationMiddleware#
    from litestar.middleware import (
        AbstractAuthenticationMiddleware,
        AuthenticationResult,
    @@ -1565,7 +1570,7 @@ 

    Implementing Custom Authenticationauthenticate_request is an async function that receives a connection instance and is supposed to return -an AuthenticationResult instance, which is a +an AuthenticationResult instance, which is a dataclass that has two attributes:

    1. user: a non-optional value representing a user. It is typed as Any so it receives any value, @@ -1601,7 +1606,7 @@

      Creating a Custom JWT Authentication Middlewarepython-jose library. We will also create a Pydantic model representing a +the pyjwt library. We will also create a Pydantic model representing a JWT Token:

      diff --git a/3803/usage/security/excluding-and-including-endpoints.html b/3803/usage/security/excluding-and-including-endpoints.html index e7b30d735..1c8bfd5a7 100644 --- a/3803/usage/security/excluding-and-including-endpoints.html +++ b/3803/usage/security/excluding-and-including-endpoints.html @@ -1361,8 +1361,12 @@
    2. pagination
    3. params
    4. plugins @@ -1400,6 +1404,7 @@
    5. memory
    6. redis
    7. registry
    8. +
    9. valkey
    10. template
    11. diff --git a/3803/usage/security/guards.html b/3803/usage/security/guards.html index 5de1b62af..b900b6046 100644 --- a/3803/usage/security/guards.html +++ b/3803/usage/security/guards.html @@ -1361,8 +1361,12 @@
    12. pagination
    13. params
    14. plugins @@ -1400,6 +1404,7 @@
    15. memory
    16. redis
    17. registry
    18. +
    19. valkey
    20. template
    21. diff --git a/3803/usage/security/index.html b/3803/usage/security/index.html index 2ff76278f..40470a8ac 100644 --- a/3803/usage/security/index.html +++ b/3803/usage/security/index.html @@ -1357,8 +1357,12 @@
    22. pagination
    23. params
    24. plugins @@ -1396,6 +1400,7 @@
    25. memory
    26. redis
    27. registry
    28. +
    29. valkey
    30. template
    31. diff --git a/3803/usage/security/jwt.html b/3803/usage/security/jwt.html index 6be1cae27..cde313043 100644 --- a/3803/usage/security/jwt.html +++ b/3803/usage/security/jwt.html @@ -1361,8 +1361,12 @@
    32. pagination
    33. params
    34. plugins @@ -1400,6 +1404,7 @@
    35. memory
    36. redis
    37. registry
    38. +
    39. valkey
    40. template
    41. @@ -1542,7 +1547,7 @@

      JWT Security Backends#

      Litestar offers optional JWT based security backends. To use these make sure to install the -python-jose and cryptography +pyjwt and cryptography packages, or simply install Litestar with the jwt extra:

      diff --git a/3803/usage/security/secret-datastructures.html b/3803/usage/security/secret-datastructures.html index 0282340f8..39e5fb338 100644 --- a/3803/usage/security/secret-datastructures.html +++ b/3803/usage/security/secret-datastructures.html @@ -1361,8 +1361,12 @@
    42. pagination
    43. params
    44. plugins @@ -1400,6 +1404,7 @@
    45. memory
    46. redis
    47. registry
    48. +
    49. valkey
    50. template
    51. diff --git a/3803/usage/security/security-backends.html b/3803/usage/security/security-backends.html index 7e4e0fa41..3d8fbe32a 100644 --- a/3803/usage/security/security-backends.html +++ b/3803/usage/security/security-backends.html @@ -1361,8 +1361,12 @@
    52. pagination
    53. params
    54. plugins @@ -1400,6 +1404,7 @@
    55. memory
    56. redis
    57. registry
    58. +
    59. valkey
    60. template
    61. diff --git a/3803/usage/static-files.html b/3803/usage/static-files.html index 8e21844d4..97a76599e 100644 --- a/3803/usage/static-files.html +++ b/3803/usage/static-files.html @@ -1361,8 +1361,12 @@
    62. pagination
    63. params
    64. plugins @@ -1400,6 +1404,7 @@
    65. memory
    66. redis
    67. registry
    68. +
    69. valkey
    70. template
    71. diff --git a/3803/usage/stores.html b/3803/usage/stores.html index 2e19067f0..60c3b434a 100644 --- a/3803/usage/stores.html +++ b/3803/usage/stores.html @@ -1361,8 +1361,12 @@
    72. pagination
    73. params
    74. plugins @@ -1400,6 +1404,7 @@
    75. memory
    76. redis
    77. registry
    78. +
    79. valkey
    80. template
    81. @@ -1561,6 +1566,11 @@

      Built-in storesRedisStore

      A store backend by redis. It offers all the guarantees and features of Redis, making it suitable for almost all applications. Offers namespacing.

      +
      ValKeyStore

      A store backed by valkey, a fork of Redis created as the result of Redis’ license changes. +Similarly to the RedisStore, it is suitable for almost all applications and supports namespacing. +At the time of writing, Valkey is equivalent to redis.asyncio.Redis, +and all notes pertaining to Redis also apply to Valkey.

      +

      Why not memcached?

      diff --git a/3803/usage/templating.html b/3803/usage/templating.html index edc39bc83..0217bd71e 100644 --- a/3803/usage/templating.html +++ b/3803/usage/templating.html @@ -1361,8 +1361,12 @@
    82. pagination
    83. params
    84. plugins @@ -1400,6 +1404,7 @@
    85. memory
    86. redis
    87. registry
    88. +
    89. valkey
    90. template
    91. diff --git a/3803/usage/testing.html b/3803/usage/testing.html index 7f2f14c2f..97cd15bcf 100644 --- a/3803/usage/testing.html +++ b/3803/usage/testing.html @@ -1361,8 +1361,12 @@
    92. pagination
    93. params
    94. plugins @@ -1400,6 +1404,7 @@
    95. memory
    96. redis
    97. registry
    98. +
    99. valkey
    100. template
    101. @@ -1571,6 +1576,8 @@

      Test Clientfrom my_app.main import app +app.debug = True + def test_health_check(): with TestClient(app=app) as client: @@ -1591,6 +1598,8 @@

      Test Clientfrom my_app.main import app +app.debug = True + async def test_health_check(): async with AsyncTestClient(app=app) as client: @@ -1624,6 +1633,8 @@

      Test Clientif TYPE_CHECKING: from litestar import Litestar +app.debug = True + @pytest.fixture(scope="function") def test_client() -> Iterator[TestClient[Litestar]]: @@ -1650,6 +1661,8 @@

      Test Clientif TYPE_CHECKING: from litestar import Litestar +app.debug = True + @pytest.fixture(scope="function") def test_client() -> Iterator[TestClient[Litestar]]: @@ -1681,6 +1694,8 @@

      Test Clientif TYPE_CHECKING: from litestar import Litestar +app.debug = True + @pytest.fixture(scope="function") async def test_client() -> AsyncIterator[AsyncTestClient[Litestar]]: @@ -1707,6 +1722,8 @@

      Test Clientif TYPE_CHECKING: from litestar import Litestar +app.debug = True + @pytest.fixture(scope="function") async def test_client() -> AsyncIterator[AsyncTestClient[Litestar]]: @@ -1744,7 +1761,7 @@

      Test Clientreturn "healthy" -app = Litestar(route_handlers=[health_check]) +app = Litestar(route_handlers=[health_check], debug=True) @pytest.fixture(scope="function") @@ -1780,7 +1797,7 @@

      Test Clientreturn "healthy" -app = Litestar(route_handlers=[health_check]) +app = Litestar(route_handlers=[health_check], debug=True) @pytest.fixture(scope="function") @@ -1822,7 +1839,7 @@

      Test Clientreturn "healthy" -app = Litestar(route_handlers=[health_check]) +app = Litestar(route_handlers=[health_check], debug=True) @pytest.fixture(scope="function") @@ -1858,7 +1875,7 @@

      Test Clientreturn "healthy" -app = Litestar(route_handlers=[health_check]) +app = Litestar(route_handlers=[health_check], debug=True) @pytest.fixture(scope="function") @@ -1962,7 +1979,7 @@

      Using sessionsreturn request.session -app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware], debug=True) def test_get_session_data() -> None: @@ -1992,7 +2009,7 @@

      Using sessionsreturn request.session -app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware], debug=True) def test_get_session_data() -> None: @@ -2018,7 +2035,7 @@

      Using sessionsrequest.session["foo"] = "bar" -app = Litestar(route_handlers=[set_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[set_session_data], middleware=[session_config.middleware], debug=True) with TestClient(app=app, session_config=session_config) as client: client.post("/test").json() @@ -2050,7 +2067,7 @@

      Using sessionsreturn request.session -app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware], debug=True) async def test_get_session_data() -> None: @@ -2081,7 +2098,7 @@

      Using sessionsreturn request.session -app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[get_session_data], middleware=[session_config.middleware], debug=True) async def test_get_session_data() -> None: @@ -2108,7 +2125,7 @@

      Using sessionsrequest.session["foo"] = "bar" -app = Litestar(route_handlers=[set_session_data], middleware=[session_config.middleware]) +app = Litestar(route_handlers=[set_session_data], middleware=[session_config.middleware], debug=True) async def test_set_session_data() -> None: @@ -2206,6 +2223,188 @@

      Creating a test app +

      Running a live server#

      +

      The test clients make use of HTTPX’s ability to directly call into an ASGI app, without +having to run an actual server. In most cases this is sufficient but there are some +exceptions where this won’t work, due to the limitations of the emulated client-server +communication.

      +

      For example, when using server-sent events with an infinite generator, it will lock up +the test client, since HTTPX tries to consume the full response before returning a +request.

      +

      Litestar offers two helper functions, +litestar.testing.subprocess_sync_client() and +litestar.testing.subprocess_async_client() that will +launch a Litestar instance with in a subprocess and set up an httpx client for running +tests. You can either load your actual app file or create subsets from it as you would +with the regular test client setup:

      +
      + +
      +
      """
      +Assemble components into an app that shall be tested
      +"""
      +
      +from typing import AsyncGenerator
      +
      +from litestar import Litestar, get
      +from litestar.response import ServerSentEvent
      +from litestar.types import SSEData
      +
      +
      +async def generator(topic: str) -> AsyncGenerator[SSEData, None]:
      +    count = 0
      +    while count < 2:
      +        yield topic
      +        count += 1
      +
      +
      +@get("/notify/{topic:str}")
      +async def get_notified(topic: str) -> ServerSentEvent:
      +    return ServerSentEvent(generator(topic), event_type="Notifier")
      +
      +
      +app = Litestar(route_handlers=[get_notified])
      +
      +
      +
      + +
      +
      """
      +Assemble components into an app that shall be tested
      +"""
      +
      +from collections.abc import AsyncGenerator
      +
      +from litestar import Litestar, get
      +from litestar.response import ServerSentEvent
      +from litestar.types import SSEData
      +
      +
      +async def generator(topic: str) -> AsyncGenerator[SSEData, None]:
      +    count = 0
      +    while count < 2:
      +        yield topic
      +        count += 1
      +
      +
      +@get("/notify/{topic:str}")
      +async def get_notified(topic: str) -> ServerSentEvent:
      +    return ServerSentEvent(generator(topic), event_type="Notifier")
      +
      +
      +app = Litestar(route_handlers=[get_notified])
      +
      +
      +
      +
      +
      + +
      +
      """
      +Test the app running in a subprocess
      +"""
      +
      +import asyncio
      +import pathlib
      +import sys
      +from typing import AsyncIterator
      +
      +import httpx
      +import httpx_sse
      +import pytest
      +
      +from litestar.testing import subprocess_async_client
      +
      +if sys.platform == "win32":
      +    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
      +
      +pytestmark = pytest.mark.anyio
      +
      +
      +@pytest.fixture(scope="session")
      +def anyio_backend() -> str:
      +    return "asyncio"
      +
      +
      +ROOT = pathlib.Path(__file__).parent
      +
      +
      +@pytest.fixture(name="async_client", scope="session")
      +async def fx_async_client() -> AsyncIterator[httpx.AsyncClient]:
      +    async with subprocess_async_client(workdir=ROOT, app="subprocess_sse_app:app") as client:
      +        yield client
      +
      +
      +async def test_subprocess_async_client(async_client: httpx.AsyncClient) -> None:
      +    """Demonstrates functionality of the async client with an infinite SSE source that cannot be tested with the
      +    regular async test client.
      +    """
      +    topic = "demo"
      +
      +    async with httpx_sse.aconnect_sse(async_client, "GET", f"/notify/{topic}") as event_source:
      +        async for event in event_source.aiter_sse():
      +            assert event.data == topic
      +            break
      +
      +
      +
      + +
      +
      """
      +Test the app running in a subprocess
      +"""
      +
      +import asyncio
      +import pathlib
      +import sys
      +from collections.abc import AsyncIterator
      +
      +import httpx
      +import httpx_sse
      +import pytest
      +
      +from litestar.testing import subprocess_async_client
      +
      +if sys.platform == "win32":
      +    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
      +
      +pytestmark = pytest.mark.anyio
      +
      +
      +@pytest.fixture(scope="session")
      +def anyio_backend() -> str:
      +    return "asyncio"
      +
      +
      +ROOT = pathlib.Path(__file__).parent
      +
      +
      +@pytest.fixture(name="async_client", scope="session")
      +async def fx_async_client() -> AsyncIterator[httpx.AsyncClient]:
      +    async with subprocess_async_client(workdir=ROOT, app="subprocess_sse_app:app") as client:
      +        yield client
      +
      +
      +async def test_subprocess_async_client(async_client: httpx.AsyncClient) -> None:
      +    """Demonstrates functionality of the async client with an infinite SSE source that cannot be tested with the
      +    regular async test client.
      +    """
      +    topic = "demo"
      +
      +    async with httpx_sse.aconnect_sse(async_client, "GET", f"/notify/{topic}") as event_source:
      +        async for event in event_source.aiter_sse():
      +            assert event.data == topic
      +            break
      +
      +
      +
      +
      +

      RequestFactory#

      Another helper is the RequestFactory class, which creates instances of @@ -2438,6 +2637,7 @@

      Using polyfactoryCreating a test app +
    102. Running a live server
    103. RequestFactory
    104. Using polyfactory
    105. diff --git a/3803/usage/websockets.html b/3803/usage/websockets.html index b7b0f51e5..1becd3af9 100644 --- a/3803/usage/websockets.html +++ b/3803/usage/websockets.html @@ -1361,8 +1361,12 @@
    106. pagination
    107. params
    108. plugins @@ -1400,6 +1404,7 @@
    109. memory
    110. redis
    111. registry
    112. +
    113. valkey
    114. template
    115. @@ -1538,18 +1543,26 @@

      WebSockets#

      -

      Handling WebSockets in an application often involves dealing with low level constructs -such as the socket itself, setting up a loop and listening for incoming data, handling -exceptions, and parsing incoming and serializing outgoing data. In addition to the -low-level WebSocket route handler, Litestar offers two -high level interfaces:

      - -

      These treat a WebSocket handler like any other route handler: as a callable that takes -in incoming data in an already pre-processed form and returns data to be serialized and -sent over the connection. The low level details will be handled behind the curtains.

      +

      There are three ways to handle WebSockets in Litestar:

      +
        +
      1. The low-level websocket route handler, providing basic +abstractions over the ASGI WebSocket interface

      2. +
      3. websocket_listener and WebsocketListener : +Reactive, event-driven WebSockets with full serialization and DTO support and support +for a synchronous interface

      4. +
      5. websocket_stream and send_websocket_stream(): +Proactive, stream oriented WebSockets with full serialization and DTO support

      6. +
      +

      The main difference between the low and high level interfaces is that, dealing with low +level interface requires, setting up a loop and listening for incoming data, handling +exceptions, client disconnects, and parsing incoming and serializing outgoing data.

      +
      +

      WebSocket Listeners#

      +

      WebSocket Listeners can be used to interact with a WebSocket in an event-driven manner, +using a callback style interface. They treat a WebSocket handler like any other route +handler: A callable that takes in incoming data in an already pre-processed form and +returns data to be serialized and sent over the connection. The low level details will +be handled behind the curtains.

      from litestar import Litestar
       from litestar.handlers.websocket_handlers import websocket_listener
       
      @@ -1573,7 +1586,7 @@ 

      WebSockets -

      Receiving data#

      +

      Receiving data#

      Data can be received in the listener via the data parameter. The data passed to this will be converted / parsed according to the given type annotation and supports str, bytes, or arbitrary dicts / or lists in the @@ -1655,14 +1668,15 @@

      Receiving data -

      Sending data#

      +

      Sending data#

      Sending data is done by simply returning the value to be sent from the handler function. Similar to receiving data, type annotations configure how the data is being handled. Values that are not str or bytes are assumed to be JSON encodable and will be serialized accordingly before being sent. This serialization is available for all data types currently supported by Litestar ( dataclasses, TypedDict, -NamedTuple, msgspec.Struct, etc.).

      +NamedTuple, msgspec.Struct, etc.), including +DTOs.