diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/litestar/config')
14 files changed, 619 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/litestar/config/__init__.py b/venv/lib/python3.11/site-packages/litestar/config/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__init__.py diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/__init__.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..c6ef8a3 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/__init__.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/allowed_hosts.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/allowed_hosts.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..f340305 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/allowed_hosts.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/app.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/app.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..a84a2f7 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/app.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/compression.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/compression.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..b6d9382 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/compression.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/cors.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/cors.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..9965625 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/cors.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/csrf.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/csrf.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..5056590 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/csrf.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/__pycache__/response_cache.cpython-311.pyc b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/response_cache.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..0ca0cf9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/__pycache__/response_cache.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/litestar/config/allowed_hosts.py b/venv/lib/python3.11/site-packages/litestar/config/allowed_hosts.py new file mode 100644 index 0000000..4c8e6ac --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/allowed_hosts.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING + +from litestar.exceptions import ImproperlyConfiguredException + +__all__ = ("AllowedHostsConfig",) + + +if TYPE_CHECKING: + from litestar.types import Scopes + + +@dataclass +class AllowedHostsConfig: + """Configuration for allowed hosts protection. + + To enable allowed hosts protection, pass an instance of this class to the :class:`Litestar <litestar.app.Litestar>` + constructor using the ``allowed_hosts`` key. + """ + + allowed_hosts: list[str] = field(default_factory=lambda: ["*"]) + """A list of trusted hosts. + + Use ``*.`` to allow all hosts, or prefix domains with ``*.`` to allow all sub domains. + """ + exclude: str | list[str] | None = field(default=None) + """A pattern or list of patterns to skip in the Allowed Hosts middleware.""" + exclude_opt_key: str | None = field(default=None) + """An identifier to use on routes to disable hosts check for a particular route.""" + scopes: Scopes | None = field(default=None) + """ASGI scopes processed by the middleware, if None both ``http`` and ``websocket`` will be processed.""" + www_redirect: bool = field(default=True) + """A boolean dictating whether to redirect requests that start with ``www.`` and otherwise match a trusted host.""" + + def __post_init__(self) -> None: + """Ensure that the trusted hosts have correct domain wildcards.""" + for host in self.allowed_hosts: + if host != "*" and "*" in host and not host.startswith("*."): + raise ImproperlyConfiguredException( + "domain wildcards can only appear in the beginning of the domain, e.g. ``*.example.com``" + ) diff --git a/venv/lib/python3.11/site-packages/litestar/config/app.py b/venv/lib/python3.11/site-packages/litestar/config/app.py new file mode 100644 index 0000000..0acefb1 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/app.py @@ -0,0 +1,223 @@ +from __future__ import annotations + +import enum +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Callable + +from litestar.config.allowed_hosts import AllowedHostsConfig +from litestar.config.response_cache import ResponseCacheConfig +from litestar.datastructures import State +from litestar.events.emitter import SimpleEventEmitter +from litestar.types.empty import Empty + +if TYPE_CHECKING: + from contextlib import AbstractAsyncContextManager + + from litestar import Litestar, Response + from litestar.config.compression import CompressionConfig + from litestar.config.cors import CORSConfig + from litestar.config.csrf import CSRFConfig + from litestar.connection import Request, WebSocket + from litestar.datastructures import CacheControlHeader, ETag + from litestar.di import Provide + from litestar.dto import AbstractDTO + from litestar.events.emitter import BaseEventEmitterBackend + from litestar.events.listener import EventListener + from litestar.logging.config import BaseLoggingConfig + from litestar.openapi.config import OpenAPIConfig + from litestar.openapi.spec import SecurityRequirement + from litestar.plugins import PluginProtocol + from litestar.static_files.config import StaticFilesConfig + from litestar.stores.base import Store + from litestar.stores.registry import StoreRegistry + from litestar.types import ( + AfterExceptionHookHandler, + AfterRequestHookHandler, + AfterResponseHookHandler, + AnyCallable, + BeforeMessageSendHookHandler, + BeforeRequestHookHandler, + ControllerRouterHandler, + ExceptionHandlersMap, + Guard, + Middleware, + ParametersMap, + ResponseCookies, + ResponseHeaders, + TypeEncodersMap, + ) + from litestar.types.callable_types import LifespanHook + from litestar.types.composite_types import TypeDecodersSequence + from litestar.types.empty import EmptyType + from litestar.types.internal_types import TemplateConfigType + + +__all__ = ( + "AppConfig", + "ExperimentalFeatures", +) + + +@dataclass +class AppConfig: + """The parameters provided to the ``Litestar`` app are used to instantiate an instance, and then the instance is + passed to any callbacks registered to ``on_app_init`` in the order they are provided. + + The final attribute values are used to instantiate the application object. + """ + + after_exception: list[AfterExceptionHookHandler] = field(default_factory=list) + """An application level :class:`exception hook handler <.types.AfterExceptionHookHandler>` or list thereof. + + This hook is called after an exception occurs. In difference to exception handlers, it is not meant to return a + response - only to process the exception (e.g. log it, send it to Sentry etc.). + """ + after_request: AfterRequestHookHandler | None = field(default=None) + """A sync or async function executed after the route handler function returned and the response object has been + resolved. + + Receives the response object which may be any subclass of :class:`Response <.response.Response>`. + """ + after_response: AfterResponseHookHandler | None = field(default=None) + """A sync or async function called after the response has been awaited. It receives the + :class:`Request <.connection.Request>` object and should not return any values. + """ + allowed_hosts: list[str] | AllowedHostsConfig | None = field(default=None) + """If set enables the builtin allowed hosts middleware.""" + before_request: BeforeRequestHookHandler | None = field(default=None) + """A sync or async function called immediately before calling the route handler. Receives the + :class:`Request <.connection.Request>` instance and any non-``None`` return value is used for the response, + bypassing the route handler. + """ + before_send: list[BeforeMessageSendHookHandler] = field(default_factory=list) + """An application level :class:`before send hook handler <.types.BeforeMessageSendHookHandler>` or list thereof. + + This hook is called when the ASGI send function is called. + """ + cache_control: CacheControlHeader | None = field(default=None) + """A ``cache-control`` header of type :class:`CacheControlHeader <.datastructures.CacheControlHeader>` to add to + route handlers of this app. + + Can be overridden by route handlers. + """ + compression_config: CompressionConfig | None = field(default=None) + """Configures compression behaviour of the application, this enabled a builtin or user defined Compression + middleware. + """ + cors_config: CORSConfig | None = field(default=None) + """If set this enables the builtin CORS middleware.""" + csrf_config: CSRFConfig | None = field(default=None) + """If set this enables the builtin CSRF middleware.""" + debug: bool = field(default=False) + """If ``True``, app errors rendered as HTML with a stack trace.""" + dependencies: dict[str, Provide | AnyCallable] = field(default_factory=dict) + """A string keyed dictionary of dependency :class:`Provider <.di.Provide>` instances.""" + dto: type[AbstractDTO] | None | EmptyType = field(default=Empty) + """:class:`AbstractDTO <.dto.base_dto.AbstractDTO>` to use for (de)serializing and validation of request data.""" + etag: ETag | None = field(default=None) + """An ``etag`` header of type :class:`ETag <.datastructures.ETag>` to add to route handlers of this app. + + Can be overridden by route handlers. + """ + event_emitter_backend: type[BaseEventEmitterBackend] = field(default=SimpleEventEmitter) + """A subclass of :class:`BaseEventEmitterBackend <.events.emitter.BaseEventEmitterBackend>`.""" + exception_handlers: ExceptionHandlersMap = field(default_factory=dict) + """A dictionary that maps handler functions to status codes and/or exception types.""" + guards: list[Guard] = field(default_factory=list) + """A list of :class:`Guard <.types.Guard>` callables.""" + include_in_schema: bool | EmptyType = field(default=Empty) + """A boolean flag dictating whether the route handler should be documented in the OpenAPI schema""" + lifespan: list[Callable[[Litestar], AbstractAsyncContextManager] | AbstractAsyncContextManager] = field( + default_factory=list + ) + """A list of callables returning async context managers, wrapping the lifespan of the ASGI application""" + listeners: list[EventListener] = field(default_factory=list) + """A list of :class:`EventListener <.events.listener.EventListener>`.""" + logging_config: BaseLoggingConfig | None = field(default=None) + """An instance of :class:`BaseLoggingConfig <.logging.config.BaseLoggingConfig>` subclass.""" + middleware: list[Middleware] = field(default_factory=list) + """A list of :class:`Middleware <.types.Middleware>`.""" + on_shutdown: list[LifespanHook] = field(default_factory=list) + """A list of :class:`LifespanHook <.types.LifespanHook>` called during application shutdown.""" + on_startup: list[LifespanHook] = field(default_factory=list) + """A list of :class:`LifespanHook <.types.LifespanHook>` called during application startup.""" + openapi_config: OpenAPIConfig | None = field(default=None) + """Defaults to :data:`DEFAULT_OPENAPI_CONFIG <litestar.app.DEFAULT_OPENAPI_CONFIG>`""" + opt: dict[str, Any] = field(default_factory=dict) + """A string keyed dictionary of arbitrary values that can be accessed in :class:`Guards <.types.Guard>` or + wherever you have access to :class:`Request <.connection.Request>` or :class:`ASGI Scope <litestar.types.Scope>`. + + Can be overridden by routers and router handlers. + """ + parameters: ParametersMap = field(default_factory=dict) + """A mapping of :class:`Parameter <.params.Parameter>` definitions available to all application paths.""" + pdb_on_exception: bool = field(default=False) + """Drop into the PDB on an exception""" + plugins: list[PluginProtocol] = field(default_factory=list) + """List of :class:`SerializationPluginProtocol <.plugins.SerializationPluginProtocol>`.""" + request_class: type[Request] | None = field(default=None) + """An optional subclass of :class:`Request <.connection.Request>` to use for http connections.""" + response_class: type[Response] | None = field(default=None) + """A custom subclass of :class:`Response <.response.Response>` to be used as the app's default response.""" + response_cookies: ResponseCookies = field(default_factory=list) + """A list of :class:`Cookie <.datastructures.Cookie>`.""" + response_headers: ResponseHeaders = field(default_factory=list) + """A string keyed dictionary mapping :class:`ResponseHeader <.datastructures.ResponseHeader>`.""" + response_cache_config: ResponseCacheConfig = field(default_factory=ResponseCacheConfig) + """Configures caching behavior of the application.""" + return_dto: type[AbstractDTO] | None | EmptyType = field(default=Empty) + """:class:`AbstractDTO <.dto.base_dto.AbstractDTO>` to use for serializing outbound response + data. + """ + route_handlers: list[ControllerRouterHandler] = field(default_factory=list) + """A required list of route handlers, which can include instances of :class:`Router <.router.Router>`, + subclasses of :class:`Controller <.controller.Controller>` or any function decorated by the route handler + decorators. + """ + security: list[SecurityRequirement] = field(default_factory=list) + """A list of dictionaries that will be added to the schema of all route handlers in the application. See + :data:`SecurityRequirement <.openapi.spec.SecurityRequirement>` for details. + """ + signature_namespace: dict[str, Any] = field(default_factory=dict) + """A mapping of names to types for use in forward reference resolution during signature modeling.""" + signature_types: list[Any] = field(default_factory=list) + """A sequence of types for use in forward reference resolution during signature modeling. + + These types will be added to the signature namespace using their ``__name__`` attribute. + """ + state: State = field(default_factory=State) + """A :class:`State` <.datastructures.State>` instance holding application state.""" + static_files_config: list[StaticFilesConfig] = field(default_factory=list) + """An instance or list of :class:`StaticFilesConfig <.static_files.StaticFilesConfig>`.""" + stores: StoreRegistry | dict[str, Store] | None = None + """Central registry of :class:`Store <.stores.base.Store>` to be made available and be used throughout the + application. Can be either a dictionary mapping strings to :class:`Store <.stores.base.Store>` instances, or an + instance of :class:`StoreRegistry <.stores.registry.StoreRegistry>`. + """ + tags: list[str] = field(default_factory=list) + """A list of string tags that will be appended to the schema of all route handlers under the application.""" + template_config: TemplateConfigType | None = field(default=None) + """An instance of :class:`TemplateConfig <.template.TemplateConfig>`.""" + type_decoders: TypeDecodersSequence | None = field(default=None) + """A sequence of tuples, each composed of a predicate testing for type identity and a msgspec hook for deserialization.""" + type_encoders: TypeEncodersMap | None = field(default=None) + """A mapping of types to callables that transform them into types supported for serialization.""" + websocket_class: type[WebSocket] | None = field(default=None) + """An optional subclass of :class:`WebSocket <.connection.WebSocket>` to use for websocket connections.""" + multipart_form_part_limit: int = field(default=1000) + """The maximal number of allowed parts in a multipart/formdata request. This limit is intended to protect from + DoS attacks.""" + experimental_features: list[ExperimentalFeatures] | None = None + + def __post_init__(self) -> None: + """Normalize the allowed hosts to be a config or None. + + Returns: + Optional config. + """ + if self.allowed_hosts and isinstance(self.allowed_hosts, list): + self.allowed_hosts = AllowedHostsConfig(allowed_hosts=self.allowed_hosts) + + +class ExperimentalFeatures(str, enum.Enum): + DTO_CODEGEN = "DTO_CODEGEN" diff --git a/venv/lib/python3.11/site-packages/litestar/config/compression.py b/venv/lib/python3.11/site-packages/litestar/config/compression.py new file mode 100644 index 0000000..c339329 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/compression.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Literal + +from litestar.exceptions import ImproperlyConfiguredException +from litestar.middleware.compression import CompressionMiddleware +from litestar.middleware.compression.gzip_facade import GzipCompression + +if TYPE_CHECKING: + from litestar.middleware.compression.facade import CompressionFacade + +__all__ = ("CompressionConfig",) + + +@dataclass +class CompressionConfig: + """Configuration for response compression. + + To enable response compression, pass an instance of this class to the :class:`Litestar <.app.Litestar>` constructor + using the ``compression_config`` key. + """ + + backend: Literal["gzip", "brotli"] | str + """The backend to use. + + If the value given is `gzip` or `brotli`, then the builtin gzip and brotli compression is used. + """ + minimum_size: int = field(default=500) + """Minimum response size (bytes) to enable compression, affects all backends.""" + gzip_compress_level: int = field(default=9) + """Range ``[0-9]``, see :doc:`python:library/gzip`.""" + brotli_quality: int = field(default=5) + """Range ``[0-11]``, Controls the compression-speed vs compression-density tradeoff. + + The higher the quality, the slower the compression. + """ + brotli_mode: Literal["generic", "text", "font"] = "text" + """``MODE_GENERIC``, ``MODE_TEXT`` (for UTF-8 format text input, default) or ``MODE_FONT`` (for WOFF 2.0).""" + brotli_lgwin: int = field(default=22) + """Base 2 logarithm of size. + + Range is 10 to 24. Defaults to 22. + """ + brotli_lgblock: Literal[0, 16, 17, 18, 19, 20, 21, 22, 23, 24] = 0 + """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: bool = True + """Use GZIP if Brotli is not supported.""" + middleware_class: type[CompressionMiddleware] = CompressionMiddleware + """Middleware class to use, should be a subclass of :class:`CompressionMiddleware`.""" + exclude: str | list[str] | None = None + """A pattern or list of patterns to skip in the compression middleware.""" + exclude_opt_key: str | None = None + """An identifier to use on routes to disable compression for a particular route.""" + compression_facade: type[CompressionFacade] = GzipCompression + """The compression facade to use for the actual compression.""" + backend_config: Any = None + """Configuration specific to the backend.""" + gzip_fallback: bool = True + """Use GZIP as a fallback if the provided backend is not supported by the client.""" + + def __post_init__(self) -> None: + if self.minimum_size <= 0: + raise ImproperlyConfiguredException("minimum_size must be greater than 0") + + if self.backend == "gzip": + if self.gzip_compress_level < 0 or self.gzip_compress_level > 9: + raise ImproperlyConfiguredException("gzip_compress_level must be a value between 0 and 9") + elif self.backend == "brotli": + # Brotli is not guaranteed to be installed. + from litestar.middleware.compression.brotli_facade import BrotliCompression + + if self.brotli_quality < 0 or self.brotli_quality > 11: + raise ImproperlyConfiguredException("brotli_quality must be a value between 0 and 11") + + if self.brotli_lgwin < 10 or self.brotli_lgwin > 24: + raise ImproperlyConfiguredException("brotli_lgwin must be a value between 10 and 24") + + self.gzip_fallback = self.brotli_gzip_fallback + self.compression_facade = BrotliCompression diff --git a/venv/lib/python3.11/site-packages/litestar/config/cors.py b/venv/lib/python3.11/site-packages/litestar/config/cors.py new file mode 100644 index 0000000..d3e2ccf --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/cors.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +import re +from dataclasses import dataclass, field +from functools import cached_property +from typing import TYPE_CHECKING, Literal, Pattern + +from litestar.constants import DEFAULT_ALLOWED_CORS_HEADERS + +__all__ = ("CORSConfig",) + + +if TYPE_CHECKING: + from litestar.types import Method + + +@dataclass +class CORSConfig: + """Configuration for CORS (Cross-Origin Resource Sharing). + + To enable CORS, pass an instance of this class to the :class:`Litestar <litestar.app.Litestar>` constructor using the + 'cors_config' key. + """ + + allow_origins: list[str] = field(default_factory=lambda: ["*"]) + """List of origins that are allowed. + + Can use '*' in any component of the path, e.g. 'domain.*'. Sets the 'Access-Control-Allow-Origin' header. + """ + allow_methods: list[Literal["*"] | Method] = field(default_factory=lambda: ["*"]) + """List of allowed HTTP methods. + + Sets the 'Access-Control-Allow-Methods' header. + """ + allow_headers: list[str] = field(default_factory=lambda: ["*"]) + """List of allowed headers. + + Sets the 'Access-Control-Allow-Headers' header. + """ + allow_credentials: bool = field(default=False) + """Boolean dictating whether or not to set the 'Access-Control-Allow-Credentials' header.""" + allow_origin_regex: str | None = field(default=None) + """Regex to match origins against.""" + expose_headers: list[str] = field(default_factory=list) + """List of headers that are exposed via the 'Access-Control-Expose-Headers' header.""" + max_age: int = field(default=600) + """Response caching TTL in seconds, defaults to 600. + + Sets the 'Access-Control-Max-Age' header. + """ + + def __post_init__(self) -> None: + self.allow_headers = [v.lower() for v in self.allow_headers] + + @cached_property + def allowed_origins_regex(self) -> Pattern[str]: + """Get or create a compiled regex for allowed origins. + + Returns: + A compiled regex of the allowed path. + """ + origins = self.allow_origins + if self.allow_origin_regex: + origins.append(self.allow_origin_regex) + return re.compile("|".join([origin.replace("*.", r".*\.") for origin in origins])) + + @cached_property + def is_allow_all_origins(self) -> bool: + """Get a cached boolean flag dictating whether all origins are allowed. + + Returns: + Boolean dictating whether all origins are allowed. + """ + return "*" in self.allow_origins + + @cached_property + def is_allow_all_methods(self) -> bool: + """Get a cached boolean flag dictating whether all methods are allowed. + + Returns: + Boolean dictating whether all methods are allowed. + """ + return "*" in self.allow_methods + + @cached_property + def is_allow_all_headers(self) -> bool: + """Get a cached boolean flag dictating whether all headers are allowed. + + Returns: + Boolean dictating whether all headers are allowed. + """ + return "*" in self.allow_headers + + @cached_property + def preflight_headers(self) -> dict[str, str]: + """Get cached pre-flight headers. + + Returns: + A dictionary of headers to set on the response object. + """ + headers: dict[str, str] = {"Access-Control-Max-Age": str(self.max_age)} + if self.is_allow_all_origins: + headers["Access-Control-Allow-Origin"] = "*" + else: + headers["Vary"] = "Origin" + if self.allow_credentials: + headers["Access-Control-Allow-Credentials"] = str(self.allow_credentials).lower() + if not self.is_allow_all_headers: + headers["Access-Control-Allow-Headers"] = ", ".join( + sorted(set(self.allow_headers) | DEFAULT_ALLOWED_CORS_HEADERS) # pyright: ignore + ) + if self.allow_methods: + headers["Access-Control-Allow-Methods"] = ", ".join( + sorted( + {"DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"} + if self.is_allow_all_methods + else set(self.allow_methods) + ) + ) + return headers + + @cached_property + def simple_headers(self) -> dict[str, str]: + """Get cached simple headers. + + Returns: + A dictionary of headers to set on the response object. + """ + simple_headers = {} + if self.is_allow_all_origins: + simple_headers["Access-Control-Allow-Origin"] = "*" + if self.allow_credentials: + simple_headers["Access-Control-Allow-Credentials"] = "true" + if self.expose_headers: + simple_headers["Access-Control-Expose-Headers"] = ", ".join(sorted(set(self.expose_headers))) + return simple_headers + + def is_origin_allowed(self, origin: str) -> bool: + """Check whether a given origin is allowed. + + Args: + origin: An origin header value. + + Returns: + Boolean determining whether an origin is allowed. + """ + return bool(self.is_allow_all_origins or self.allowed_origins_regex.fullmatch(origin)) diff --git a/venv/lib/python3.11/site-packages/litestar/config/csrf.py b/venv/lib/python3.11/site-packages/litestar/config/csrf.py new file mode 100644 index 0000000..5094a5b --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/csrf.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Literal + +__all__ = ("CSRFConfig",) + + +if TYPE_CHECKING: + from litestar.types import Method + + +@dataclass +class CSRFConfig: + """Configuration for CSRF (Cross Site Request Forgery) protection. + + To enable CSRF protection, pass an instance of this class to the :class:`Litestar <litestar.app.Litestar>` constructor using + the 'csrf_config' key. + """ + + secret: str + """A string that is used to create an HMAC to sign the CSRF token.""" + cookie_name: str = field(default="csrftoken") + """The CSRF cookie name.""" + cookie_path: str = field(default="/") + """The CSRF cookie path.""" + header_name: str = field(default="x-csrftoken") + """The header that will be expected in each request.""" + cookie_secure: bool = field(default=False) + """A boolean value indicating whether to set the ``Secure`` attribute on the cookie.""" + cookie_httponly: bool = field(default=False) + """A boolean value indicating whether to set the ``HttpOnly`` attribute on the cookie.""" + cookie_samesite: Literal["lax", "strict", "none"] = field(default="lax") + """The value to set in the ``SameSite`` attribute of the cookie.""" + cookie_domain: str | None = field(default=None) + """Specifies which hosts can receive the cookie.""" + safe_methods: set[Method] = field(default_factory=lambda: {"GET", "HEAD"}) + """A set of "safe methods" that can set the cookie.""" + exclude: str | list[str] | None = field(default=None) + """A pattern or list of patterns to skip in the CSRF middleware.""" + exclude_from_csrf_key: str = "exclude_from_csrf" + """An identifier to use on routes to disable CSRF for a particular route.""" diff --git a/venv/lib/python3.11/site-packages/litestar/config/response_cache.py b/venv/lib/python3.11/site-packages/litestar/config/response_cache.py new file mode 100644 index 0000000..4f1dfe9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/config/response_cache.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Callable, final +from urllib.parse import urlencode + +from litestar.status_codes import ( + HTTP_200_OK, + HTTP_300_MULTIPLE_CHOICES, + HTTP_301_MOVED_PERMANENTLY, + HTTP_308_PERMANENT_REDIRECT, +) + +if TYPE_CHECKING: + from litestar import Litestar + from litestar.connection import Request + from litestar.stores.base import Store + from litestar.types import CacheKeyBuilder, HTTPScope + +__all__ = ("ResponseCacheConfig", "default_cache_key_builder", "CACHE_FOREVER") + + +@final +class CACHE_FOREVER: # noqa: N801 + """Sentinel value indicating that a cached response should be stored without an expiration, explicitly skipping the + default expiration + """ + + +def default_cache_key_builder(request: Request[Any, Any, Any]) -> str: + """Given a request object, returns a cache key by combining + the request method and path with the sorted query params. + + Args: + request: request used to generate cache key. + + Returns: + A combination of url path and query parameters + """ + query_params: list[tuple[str, Any]] = list(request.query_params.dict().items()) + query_params.sort(key=lambda x: x[0]) + return request.method + request.url.path + urlencode(query_params, doseq=True) + + +def default_do_cache_predicate(_: HTTPScope, status_code: int) -> bool: + """Given a status code, returns a boolean indicating whether the response should be cached. + + Args: + _: ASGI scope. + status_code: status code of the response. + + Returns: + A boolean indicating whether the response should be cached. + """ + return HTTP_200_OK <= status_code < HTTP_300_MULTIPLE_CHOICES or status_code in ( + HTTP_301_MOVED_PERMANENTLY, + HTTP_308_PERMANENT_REDIRECT, + ) + + +@dataclass +class ResponseCacheConfig: + """Configuration for response caching. + + To enable response caching, pass an instance of this class to :class:`Litestar <.app.Litestar>` using the + ``response_cache_config`` key. + """ + + default_expiration: int | None = 60 + """Default cache expiration in seconds used when a route handler is configured with ``cache=True``.""" + key_builder: CacheKeyBuilder = field(default=default_cache_key_builder) + """:class:`CacheKeyBuilder <.types.CacheKeyBuilder>`. Defaults to :func:`default_cache_key_builder`.""" + store: str = "response_cache" + """Name of the :class:`Store <.stores.base.Store>` to use.""" + cache_response_filter: Callable[[HTTPScope, int], bool] = field(default=default_do_cache_predicate) + """A callable that receives connection scope and a status code, and returns a boolean indicating whether the + response should be cached.""" + + def get_store_from_app(self, app: Litestar) -> Store: + """Get the store defined in :attr:`store` from an :class:`Litestar <.app.Litestar>` instance.""" + return app.stores.get(self.store) |