aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/fastapi
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/fastapi')
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/__init__.py25
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/__main__.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/_compat.py659
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/applications.py4585
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/background.py59
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/cli.py13
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/concurrency.py39
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/datastructures.py204
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/dependencies/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/dependencies/models.py37
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py980
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/encoders.py343
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/exception_handlers.py34
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/exceptions.py176
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/logger.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/cors.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/gzip.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/trustedhost.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/middleware/wsgi.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py3
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py344
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/models.py445
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py569
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/param_functions.py2360
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/params.py786
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/py.typed0
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/requests.py2
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/responses.py48
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/routing.py4439
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/__init__.py15
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/api_key.py288
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/base.py6
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/http.py423
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/oauth2.py638
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/open_id_connect_url.py84
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/security/utils.py10
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/staticfiles.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/templating.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/testclient.py1
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/types.py10
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/utils.py220
-rw-r--r--.venv/lib/python3.12/site-packages/fastapi/websockets.py3
45 files changed, 17866 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/fastapi/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/__init__.py
new file mode 100644
index 00000000..80eb783d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/__init__.py
@@ -0,0 +1,25 @@
+"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
+
+__version__ = "0.115.12"
+
+from starlette import status as status
+
+from .applications import FastAPI as FastAPI
+from .background import BackgroundTasks as BackgroundTasks
+from .datastructures import UploadFile as UploadFile
+from .exceptions import HTTPException as HTTPException
+from .exceptions import WebSocketException as WebSocketException
+from .param_functions import Body as Body
+from .param_functions import Cookie as Cookie
+from .param_functions import Depends as Depends
+from .param_functions import File as File
+from .param_functions import Form as Form
+from .param_functions import Header as Header
+from .param_functions import Path as Path
+from .param_functions import Query as Query
+from .param_functions import Security as Security
+from .requests import Request as Request
+from .responses import Response as Response
+from .routing import APIRouter as APIRouter
+from .websockets import WebSocket as WebSocket
+from .websockets import WebSocketDisconnect as WebSocketDisconnect
diff --git a/.venv/lib/python3.12/site-packages/fastapi/__main__.py b/.venv/lib/python3.12/site-packages/fastapi/__main__.py
new file mode 100644
index 00000000..fc36465f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/__main__.py
@@ -0,0 +1,3 @@
+from fastapi.cli import main
+
+main()
diff --git a/.venv/lib/python3.12/site-packages/fastapi/_compat.py b/.venv/lib/python3.12/site-packages/fastapi/_compat.py
new file mode 100644
index 00000000..c07e4a3b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/_compat.py
@@ -0,0 +1,659 @@
+from collections import deque
+from copy import copy
+from dataclasses import dataclass, is_dataclass
+from enum import Enum
+from functools import lru_cache
+from typing import (
+ Any,
+ Callable,
+ Deque,
+ Dict,
+ FrozenSet,
+ List,
+ Mapping,
+ Sequence,
+ Set,
+ Tuple,
+ Type,
+ Union,
+)
+
+from fastapi.exceptions import RequestErrorModel
+from fastapi.types import IncEx, ModelNameMap, UnionType
+from pydantic import BaseModel, create_model
+from pydantic.version import VERSION as PYDANTIC_VERSION
+from starlette.datastructures import UploadFile
+from typing_extensions import Annotated, Literal, get_args, get_origin
+
+PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
+PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
+
+
+sequence_annotation_to_type = {
+ Sequence: list,
+ List: list,
+ list: list,
+ Tuple: tuple,
+ tuple: tuple,
+ Set: set,
+ set: set,
+ FrozenSet: frozenset,
+ frozenset: frozenset,
+ Deque: deque,
+ deque: deque,
+}
+
+sequence_types = tuple(sequence_annotation_to_type.keys())
+
+Url: Type[Any]
+
+if PYDANTIC_V2:
+ from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError
+ from pydantic import TypeAdapter
+ from pydantic import ValidationError as ValidationError
+ from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined]
+ GetJsonSchemaHandler as GetJsonSchemaHandler,
+ )
+ from pydantic._internal._typing_extra import eval_type_lenient
+ from pydantic._internal._utils import lenient_issubclass as lenient_issubclass
+ from pydantic.fields import FieldInfo
+ from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
+ from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
+ from pydantic_core import CoreSchema as CoreSchema
+ from pydantic_core import PydanticUndefined, PydanticUndefinedType
+ from pydantic_core import Url as Url
+
+ try:
+ from pydantic_core.core_schema import (
+ with_info_plain_validator_function as with_info_plain_validator_function,
+ )
+ except ImportError: # pragma: no cover
+ from pydantic_core.core_schema import (
+ general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
+ )
+
+ RequiredParam = PydanticUndefined
+ Undefined = PydanticUndefined
+ UndefinedType = PydanticUndefinedType
+ evaluate_forwardref = eval_type_lenient
+ Validator = Any
+
+ class BaseConfig:
+ pass
+
+ class ErrorWrapper(Exception):
+ pass
+
+ @dataclass
+ class ModelField:
+ field_info: FieldInfo
+ name: str
+ mode: Literal["validation", "serialization"] = "validation"
+
+ @property
+ def alias(self) -> str:
+ a = self.field_info.alias
+ return a if a is not None else self.name
+
+ @property
+ def required(self) -> bool:
+ return self.field_info.is_required()
+
+ @property
+ def default(self) -> Any:
+ return self.get_default()
+
+ @property
+ def type_(self) -> Any:
+ return self.field_info.annotation
+
+ def __post_init__(self) -> None:
+ self._type_adapter: TypeAdapter[Any] = TypeAdapter(
+ Annotated[self.field_info.annotation, self.field_info]
+ )
+
+ def get_default(self) -> Any:
+ if self.field_info.is_required():
+ return Undefined
+ return self.field_info.get_default(call_default_factory=True)
+
+ def validate(
+ self,
+ value: Any,
+ values: Dict[str, Any] = {}, # noqa: B006
+ *,
+ loc: Tuple[Union[int, str], ...] = (),
+ ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]:
+ try:
+ return (
+ self._type_adapter.validate_python(value, from_attributes=True),
+ None,
+ )
+ except ValidationError as exc:
+ return None, _regenerate_error_with_loc(
+ errors=exc.errors(include_url=False), loc_prefix=loc
+ )
+
+ def serialize(
+ self,
+ value: Any,
+ *,
+ mode: Literal["json", "python"] = "json",
+ include: Union[IncEx, None] = None,
+ exclude: Union[IncEx, None] = None,
+ by_alias: bool = True,
+ exclude_unset: bool = False,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
+ ) -> Any:
+ # What calls this code passes a value that already called
+ # self._type_adapter.validate_python(value)
+ return self._type_adapter.dump_python(
+ value,
+ mode=mode,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+
+ def __hash__(self) -> int:
+ # Each ModelField is unique for our purposes, to allow making a dict from
+ # ModelField to its JSON Schema.
+ return id(self)
+
+ def get_annotation_from_field_info(
+ annotation: Any, field_info: FieldInfo, field_name: str
+ ) -> Any:
+ return annotation
+
+ def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
+ return errors # type: ignore[return-value]
+
+ def _model_rebuild(model: Type[BaseModel]) -> None:
+ model.model_rebuild()
+
+ def _model_dump(
+ model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
+ ) -> Any:
+ return model.model_dump(mode=mode, **kwargs)
+
+ def _get_model_config(model: BaseModel) -> Any:
+ return model.model_config
+
+ def get_schema_from_model_field(
+ *,
+ field: ModelField,
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+ ) -> Dict[str, Any]:
+ override_mode: Union[Literal["validation"], None] = (
+ None if separate_input_output_schemas else "validation"
+ )
+ # This expects that GenerateJsonSchema was already used to generate the definitions
+ json_schema = field_mapping[(field, override_mode or field.mode)]
+ if "$ref" not in json_schema:
+ # TODO remove when deprecating Pydantic v1
+ # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207
+ json_schema["title"] = (
+ field.field_info.title or field.alias.title().replace("_", " ")
+ )
+ return json_schema
+
+ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
+ return {}
+
+ def get_definitions(
+ *,
+ fields: List[ModelField],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ separate_input_output_schemas: bool = True,
+ ) -> Tuple[
+ Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ Dict[str, Dict[str, Any]],
+ ]:
+ override_mode: Union[Literal["validation"], None] = (
+ None if separate_input_output_schemas else "validation"
+ )
+ inputs = [
+ (field, override_mode or field.mode, field._type_adapter.core_schema)
+ for field in fields
+ ]
+ field_mapping, definitions = schema_generator.generate_definitions(
+ inputs=inputs
+ )
+ return field_mapping, definitions # type: ignore[return-value]
+
+ def is_scalar_field(field: ModelField) -> bool:
+ from fastapi import params
+
+ return field_annotation_is_scalar(
+ field.field_info.annotation
+ ) and not isinstance(field.field_info, params.Body)
+
+ def is_sequence_field(field: ModelField) -> bool:
+ return field_annotation_is_sequence(field.field_info.annotation)
+
+ def is_scalar_sequence_field(field: ModelField) -> bool:
+ return field_annotation_is_scalar_sequence(field.field_info.annotation)
+
+ def is_bytes_field(field: ModelField) -> bool:
+ return is_bytes_or_nonable_bytes_annotation(field.type_)
+
+ def is_bytes_sequence_field(field: ModelField) -> bool:
+ return is_bytes_sequence_annotation(field.type_)
+
+ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
+ cls = type(field_info)
+ merged_field_info = cls.from_annotation(annotation)
+ new_field_info = copy(field_info)
+ new_field_info.metadata = merged_field_info.metadata
+ new_field_info.annotation = merged_field_info.annotation
+ return new_field_info
+
+ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
+ origin_type = (
+ get_origin(field.field_info.annotation) or field.field_info.annotation
+ )
+ assert issubclass(origin_type, sequence_types) # type: ignore[arg-type]
+ return sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return]
+
+ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
+ error = ValidationError.from_exception_data(
+ "Field required", [{"type": "missing", "loc": loc, "input": {}}]
+ ).errors(include_url=False)[0]
+ error["input"] = None
+ return error # type: ignore[return-value]
+
+ def create_body_model(
+ *, fields: Sequence[ModelField], model_name: str
+ ) -> Type[BaseModel]:
+ field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields}
+ BodyModel: Type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload]
+ return BodyModel
+
+ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
+ return [
+ ModelField(field_info=field_info, name=name)
+ for name, field_info in model.model_fields.items()
+ ]
+
+else:
+ from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
+ from pydantic import AnyUrl as Url # noqa: F401
+ from pydantic import ( # type: ignore[assignment]
+ BaseConfig as BaseConfig, # noqa: F401
+ )
+ from pydantic import ValidationError as ValidationError # noqa: F401
+ from pydantic.class_validators import ( # type: ignore[no-redef]
+ Validator as Validator, # noqa: F401
+ )
+ from pydantic.error_wrappers import ( # type: ignore[no-redef]
+ ErrorWrapper as ErrorWrapper, # noqa: F401
+ )
+ from pydantic.errors import MissingError
+ from pydantic.fields import ( # type: ignore[attr-defined]
+ SHAPE_FROZENSET,
+ SHAPE_LIST,
+ SHAPE_SEQUENCE,
+ SHAPE_SET,
+ SHAPE_SINGLETON,
+ SHAPE_TUPLE,
+ SHAPE_TUPLE_ELLIPSIS,
+ )
+ from pydantic.fields import FieldInfo as FieldInfo
+ from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
+ ModelField as ModelField, # noqa: F401
+ )
+
+ # Keeping old "Required" functionality from Pydantic V1, without
+ # shadowing typing.Required.
+ RequiredParam: Any = Ellipsis # type: ignore[no-redef]
+ from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
+ Undefined as Undefined,
+ )
+ from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
+ UndefinedType as UndefinedType, # noqa: F401
+ )
+ from pydantic.schema import (
+ field_schema,
+ get_flat_models_from_fields,
+ get_model_name_map,
+ model_process_schema,
+ )
+ from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401
+ get_annotation_from_field_info as get_annotation_from_field_info,
+ )
+ from pydantic.typing import ( # type: ignore[no-redef]
+ evaluate_forwardref as evaluate_forwardref, # noqa: F401
+ )
+ from pydantic.utils import ( # type: ignore[no-redef]
+ lenient_issubclass as lenient_issubclass, # noqa: F401
+ )
+
+ GetJsonSchemaHandler = Any # type: ignore[assignment,misc]
+ JsonSchemaValue = Dict[str, Any] # type: ignore[misc]
+ CoreSchema = Any # type: ignore[assignment,misc]
+
+ sequence_shapes = {
+ SHAPE_LIST,
+ SHAPE_SET,
+ SHAPE_FROZENSET,
+ SHAPE_TUPLE,
+ SHAPE_SEQUENCE,
+ SHAPE_TUPLE_ELLIPSIS,
+ }
+ sequence_shape_to_type = {
+ SHAPE_LIST: list,
+ SHAPE_SET: set,
+ SHAPE_TUPLE: tuple,
+ SHAPE_SEQUENCE: list,
+ SHAPE_TUPLE_ELLIPSIS: list,
+ }
+
+ @dataclass
+ class GenerateJsonSchema: # type: ignore[no-redef]
+ ref_template: str
+
+ class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef]
+ pass
+
+ def with_info_plain_validator_function( # type: ignore[misc]
+ function: Callable[..., Any],
+ *,
+ ref: Union[str, None] = None,
+ metadata: Any = None,
+ serialization: Any = None,
+ ) -> Any:
+ return {}
+
+ def get_model_definitions(
+ *,
+ flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
+ model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
+ ) -> Dict[str, Any]:
+ definitions: Dict[str, Dict[str, Any]] = {}
+ for model in flat_models:
+ m_schema, m_definitions, m_nested_models = model_process_schema(
+ model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
+ )
+ definitions.update(m_definitions)
+ model_name = model_name_map[model]
+ if "description" in m_schema:
+ m_schema["description"] = m_schema["description"].split("\f")[0]
+ definitions[model_name] = m_schema
+ return definitions
+
+ def is_pv1_scalar_field(field: ModelField) -> bool:
+ from fastapi import params
+
+ field_info = field.field_info
+ if not (
+ field.shape == SHAPE_SINGLETON # type: ignore[attr-defined]
+ and not lenient_issubclass(field.type_, BaseModel)
+ and not lenient_issubclass(field.type_, dict)
+ and not field_annotation_is_sequence(field.type_)
+ and not is_dataclass(field.type_)
+ and not isinstance(field_info, params.Body)
+ ):
+ return False
+ if field.sub_fields: # type: ignore[attr-defined]
+ if not all(
+ is_pv1_scalar_field(f)
+ for f in field.sub_fields # type: ignore[attr-defined]
+ ):
+ return False
+ return True
+
+ def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
+ if (field.shape in sequence_shapes) and not lenient_issubclass( # type: ignore[attr-defined]
+ field.type_, BaseModel
+ ):
+ if field.sub_fields is not None: # type: ignore[attr-defined]
+ for sub_field in field.sub_fields: # type: ignore[attr-defined]
+ if not is_pv1_scalar_field(sub_field):
+ return False
+ return True
+ if _annotation_is_sequence(field.type_):
+ return True
+ return False
+
+ def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
+ use_errors: List[Any] = []
+ for error in errors:
+ if isinstance(error, ErrorWrapper):
+ new_errors = ValidationError( # type: ignore[call-arg]
+ errors=[error], model=RequestErrorModel
+ ).errors()
+ use_errors.extend(new_errors)
+ elif isinstance(error, list):
+ use_errors.extend(_normalize_errors(error))
+ else:
+ use_errors.append(error)
+ return use_errors
+
+ def _model_rebuild(model: Type[BaseModel]) -> None:
+ model.update_forward_refs()
+
+ def _model_dump(
+ model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
+ ) -> Any:
+ return model.dict(**kwargs)
+
+ def _get_model_config(model: BaseModel) -> Any:
+ return model.__config__ # type: ignore[attr-defined]
+
+ def get_schema_from_model_field(
+ *,
+ field: ModelField,
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+ ) -> Dict[str, Any]:
+ # This expects that GenerateJsonSchema was already used to generate the definitions
+ return field_schema( # type: ignore[no-any-return]
+ field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
+ )[0]
+
+ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
+ models = get_flat_models_from_fields(fields, known_models=set())
+ return get_model_name_map(models) # type: ignore[no-any-return]
+
+ def get_definitions(
+ *,
+ fields: List[ModelField],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ separate_input_output_schemas: bool = True,
+ ) -> Tuple[
+ Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ Dict[str, Dict[str, Any]],
+ ]:
+ models = get_flat_models_from_fields(fields, known_models=set())
+ return {}, get_model_definitions(
+ flat_models=models, model_name_map=model_name_map
+ )
+
+ def is_scalar_field(field: ModelField) -> bool:
+ return is_pv1_scalar_field(field)
+
+ def is_sequence_field(field: ModelField) -> bool:
+ return field.shape in sequence_shapes or _annotation_is_sequence(field.type_) # type: ignore[attr-defined]
+
+ def is_scalar_sequence_field(field: ModelField) -> bool:
+ return is_pv1_scalar_sequence_field(field)
+
+ def is_bytes_field(field: ModelField) -> bool:
+ return lenient_issubclass(field.type_, bytes)
+
+ def is_bytes_sequence_field(field: ModelField) -> bool:
+ return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) # type: ignore[attr-defined]
+
+ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
+ return copy(field_info)
+
+ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
+ return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return,attr-defined]
+
+ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
+ missing_field_error = ErrorWrapper(MissingError(), loc=loc) # type: ignore[call-arg]
+ new_error = ValidationError([missing_field_error], RequestErrorModel)
+ return new_error.errors()[0] # type: ignore[return-value]
+
+ def create_body_model(
+ *, fields: Sequence[ModelField], model_name: str
+ ) -> Type[BaseModel]:
+ BodyModel = create_model(model_name)
+ for f in fields:
+ BodyModel.__fields__[f.name] = f # type: ignore[index]
+ return BodyModel
+
+ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
+ return list(model.__fields__.values()) # type: ignore[attr-defined]
+
+
+def _regenerate_error_with_loc(
+ *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
+) -> List[Dict[str, Any]]:
+ updated_loc_errors: List[Any] = [
+ {**err, "loc": loc_prefix + err.get("loc", ())}
+ for err in _normalize_errors(errors)
+ ]
+
+ return updated_loc_errors
+
+
+def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
+ if lenient_issubclass(annotation, (str, bytes)):
+ return False
+ return lenient_issubclass(annotation, sequence_types)
+
+
+def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ for arg in get_args(annotation):
+ if field_annotation_is_sequence(arg):
+ return True
+ return False
+ return _annotation_is_sequence(annotation) or _annotation_is_sequence(
+ get_origin(annotation)
+ )
+
+
+def value_is_sequence(value: Any) -> bool:
+ return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
+
+
+def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
+ return (
+ lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))
+ or _annotation_is_sequence(annotation)
+ or is_dataclass(annotation)
+ )
+
+
+def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ return any(field_annotation_is_complex(arg) for arg in get_args(annotation))
+
+ return (
+ _annotation_is_complex(annotation)
+ or _annotation_is_complex(origin)
+ or hasattr(origin, "__pydantic_core_schema__")
+ or hasattr(origin, "__get_pydantic_core_schema__")
+ )
+
+
+def field_annotation_is_scalar(annotation: Any) -> bool:
+ # handle Ellipsis here to make tuple[int, ...] work nicely
+ return annotation is Ellipsis or not field_annotation_is_complex(annotation)
+
+
+def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool:
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ at_least_one_scalar_sequence = False
+ for arg in get_args(annotation):
+ if field_annotation_is_scalar_sequence(arg):
+ at_least_one_scalar_sequence = True
+ continue
+ elif not field_annotation_is_scalar(arg):
+ return False
+ return at_least_one_scalar_sequence
+ return field_annotation_is_sequence(annotation) and all(
+ field_annotation_is_scalar(sub_annotation)
+ for sub_annotation in get_args(annotation)
+ )
+
+
+def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
+ if lenient_issubclass(annotation, bytes):
+ return True
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ for arg in get_args(annotation):
+ if lenient_issubclass(arg, bytes):
+ return True
+ return False
+
+
+def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:
+ if lenient_issubclass(annotation, UploadFile):
+ return True
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ for arg in get_args(annotation):
+ if lenient_issubclass(arg, UploadFile):
+ return True
+ return False
+
+
+def is_bytes_sequence_annotation(annotation: Any) -> bool:
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ at_least_one = False
+ for arg in get_args(annotation):
+ if is_bytes_sequence_annotation(arg):
+ at_least_one = True
+ continue
+ return at_least_one
+ return field_annotation_is_sequence(annotation) and all(
+ is_bytes_or_nonable_bytes_annotation(sub_annotation)
+ for sub_annotation in get_args(annotation)
+ )
+
+
+def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
+ origin = get_origin(annotation)
+ if origin is Union or origin is UnionType:
+ at_least_one = False
+ for arg in get_args(annotation):
+ if is_uploadfile_sequence_annotation(arg):
+ at_least_one = True
+ continue
+ return at_least_one
+ return field_annotation_is_sequence(annotation) and all(
+ is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
+ for sub_annotation in get_args(annotation)
+ )
+
+
+@lru_cache
+def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
+ return get_model_fields(model)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/applications.py b/.venv/lib/python3.12/site-packages/fastapi/applications.py
new file mode 100644
index 00000000..6d427cdc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/applications.py
@@ -0,0 +1,4585 @@
+from enum import Enum
+from typing import (
+ Any,
+ Awaitable,
+ Callable,
+ Coroutine,
+ Dict,
+ List,
+ Optional,
+ Sequence,
+ Type,
+ TypeVar,
+ Union,
+)
+
+from fastapi import routing
+from fastapi.datastructures import Default, DefaultPlaceholder
+from fastapi.exception_handlers import (
+ http_exception_handler,
+ request_validation_exception_handler,
+ websocket_request_validation_exception_handler,
+)
+from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
+from fastapi.logger import logger
+from fastapi.openapi.docs import (
+ get_redoc_html,
+ get_swagger_ui_html,
+ get_swagger_ui_oauth2_redirect_html,
+)
+from fastapi.openapi.utils import get_openapi
+from fastapi.params import Depends
+from fastapi.types import DecoratedCallable, IncEx
+from fastapi.utils import generate_unique_id
+from starlette.applications import Starlette
+from starlette.datastructures import State
+from starlette.exceptions import HTTPException
+from starlette.middleware import Middleware
+from starlette.middleware.base import BaseHTTPMiddleware
+from starlette.requests import Request
+from starlette.responses import HTMLResponse, JSONResponse, Response
+from starlette.routing import BaseRoute
+from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
+from typing_extensions import Annotated, Doc, deprecated
+
+AppType = TypeVar("AppType", bound="FastAPI")
+
+
+class FastAPI(Starlette):
+ """
+ `FastAPI` app class, the main entrypoint to use FastAPI.
+
+ Read more in the
+ [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+ ```
+ """
+
+ def __init__(
+ self: AppType,
+ *,
+ debug: Annotated[
+ bool,
+ Doc(
+ """
+ Boolean indicating if debug tracebacks should be returned on server
+ errors.
+
+ Read more in the
+ [Starlette docs for Applications](https://www.starlette.io/applications/#instantiating-the-application).
+ """
+ ),
+ ] = False,
+ routes: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ **Note**: you probably shouldn't use this parameter, it is inherited
+ from Starlette and supported for compatibility.
+
+ ---
+
+ A list of routes to serve incoming HTTP and WebSocket requests.
+ """
+ ),
+ deprecated(
+ """
+ You normally wouldn't use this parameter with FastAPI, it is inherited
+ from Starlette and supported for compatibility.
+
+ In FastAPI, you normally would use the *path operation methods*,
+ like `app.get()`, `app.post()`, etc.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The title of the API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(title="ChimichangApp")
+ ```
+ """
+ ),
+ ] = "FastAPI",
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A short summary of the API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(summary="Deadpond's favorite app. Nuff said.")
+ ```
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ str,
+ Doc(
+ '''
+ A description of the API. Supports Markdown (using
+ [CommonMark syntax](https://commonmark.org/)).
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(
+ description="""
+ ChimichangApp API helps you do awesome stuff. 🚀
+
+ ## Items
+
+ You can **read items**.
+
+ ## Users
+
+ You will be able to:
+
+ * **Create users** (_not implemented_).
+ * **Read users** (_not implemented_).
+
+ """
+ )
+ ```
+ '''
+ ),
+ ] = "",
+ version: Annotated[
+ str,
+ Doc(
+ """
+ The version of the API.
+
+ **Note** This is the version of your application, not the version of
+ the OpenAPI specification nor the version of FastAPI being used.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(version="0.0.1")
+ ```
+ """
+ ),
+ ] = "0.1.0",
+ openapi_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The URL where the OpenAPI schema will be served from.
+
+ If you set it to `None`, no OpenAPI schema will be served publicly, and
+ the default automatic endpoints `/docs` and `/redoc` will also be
+ disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(openapi_url="/api/v1/openapi.json")
+ ```
+ """
+ ),
+ ] = "/openapi.json",
+ openapi_tags: Annotated[
+ Optional[List[Dict[str, Any]]],
+ Doc(
+ """
+ A list of tags used by OpenAPI, these are the same `tags` you can set
+ in the *path operations*, like:
+
+ * `@app.get("/users/", tags=["users"])`
+ * `@app.get("/items/", tags=["items"])`
+
+ The order of the tags can be used to specify the order shown in
+ tools like Swagger UI, used in the automatic path `/docs`.
+
+ It's not required to specify all the tags used.
+
+ The tags that are not declared MAY be organized randomly or based
+ on the tools' logic. Each tag name in the list MUST be unique.
+
+ The value of each item is a `dict` containing:
+
+ * `name`: The name of the tag.
+ * `description`: A short description of the tag.
+ [CommonMark syntax](https://commonmark.org/) MAY be used for rich
+ text representation.
+ * `externalDocs`: Additional external documentation for this tag. If
+ provided, it would contain a `dict` with:
+ * `description`: A short description of the target documentation.
+ [CommonMark syntax](https://commonmark.org/) MAY be used for
+ rich text representation.
+ * `url`: The URL for the target documentation. Value MUST be in
+ the form of a URL.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ tags_metadata = [
+ {
+ "name": "users",
+ "description": "Operations with users. The **login** logic is also here.",
+ },
+ {
+ "name": "items",
+ "description": "Manage items. So _fancy_ they have their own docs.",
+ "externalDocs": {
+ "description": "Items external docs",
+ "url": "https://fastapi.tiangolo.com/",
+ },
+ },
+ ]
+
+ app = FastAPI(openapi_tags=tags_metadata)
+ ```
+ """
+ ),
+ ] = None,
+ servers: Annotated[
+ Optional[List[Dict[str, Union[str, Any]]]],
+ Doc(
+ """
+ A `list` of `dict`s with connectivity information to a target server.
+
+ You would use it, for example, if your application is served from
+ different domains and you want to use the same Swagger UI in the
+ browser to interact with each of them (instead of having multiple
+ browser tabs open). Or if you want to leave fixed the possible URLs.
+
+ If the servers `list` is not provided, or is an empty `list`, the
+ default value would be a `dict` with a `url` value of `/`.
+
+ Each item in the `list` is a `dict` containing:
+
+ * `url`: A URL to the target host. This URL supports Server Variables
+ and MAY be relative, to indicate that the host location is relative
+ to the location where the OpenAPI document is being served. Variable
+ substitutions will be made when a variable is named in `{`brackets`}`.
+ * `description`: An optional string describing the host designated by
+ the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for
+ rich text representation.
+ * `variables`: A `dict` between a variable name and its value. The value
+ is used for substitution in the server's URL template.
+
+ Read more in the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(
+ servers=[
+ {"url": "https://stag.example.com", "description": "Staging environment"},
+ {"url": "https://prod.example.com", "description": "Production environment"},
+ ]
+ )
+ ```
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of global dependencies, they will be applied to each
+ *path operation*, including in sub-routers.
+
+ Read more about it in the
+ [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/).
+
+ **Example**
+
+ ```python
+ from fastapi import Depends, FastAPI
+
+ from .dependencies import func_dep_1, func_dep_2
+
+ app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)])
+ ```
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+ from fastapi.responses import ORJSONResponse
+
+ app = FastAPI(default_response_class=ORJSONResponse)
+ ```
+ """
+ ),
+ ] = Default(JSONResponse),
+ redirect_slashes: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to detect and redirect slashes in URLs when the client doesn't
+ use the same format.
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(redirect_slashes=True) # the default
+
+ @app.get("/items/")
+ async def read_items():
+ return [{"item_id": "Foo"}]
+ ```
+
+ With this app, if a client goes to `/items` (without a trailing slash),
+ they will be automatically redirected with an HTTP status code of 307
+ to `/items/`.
+ """
+ ),
+ ] = True,
+ docs_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The path to the automatic interactive API documentation.
+ It is handled in the browser by Swagger UI.
+
+ The default URL is `/docs`. You can disable it by setting it to `None`.
+
+ If `openapi_url` is set to `None`, this will be automatically disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(docs_url="/documentation", redoc_url=None)
+ ```
+ """
+ ),
+ ] = "/docs",
+ redoc_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The path to the alternative automatic interactive API documentation
+ provided by ReDoc.
+
+ The default URL is `/redoc`. You can disable it by setting it to `None`.
+
+ If `openapi_url` is set to `None`, this will be automatically disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(docs_url="/documentation", redoc_url="redocumentation")
+ ```
+ """
+ ),
+ ] = "/redoc",
+ swagger_ui_oauth2_redirect_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The OAuth2 redirect endpoint for the Swagger UI.
+
+ By default it is `/docs/oauth2-redirect`.
+
+ This is only used if you use OAuth2 (with the "Authorize" button)
+ with Swagger UI.
+ """
+ ),
+ ] = "/docs/oauth2-redirect",
+ swagger_ui_init_oauth: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ OAuth2 configuration for the Swagger UI, by default shown at `/docs`.
+
+ Read more about the available configuration options in the
+ [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/).
+ """
+ ),
+ ] = None,
+ middleware: Annotated[
+ Optional[Sequence[Middleware]],
+ Doc(
+ """
+ List of middleware to be added when creating the application.
+
+ In FastAPI you would normally do this with `app.add_middleware()`
+ instead.
+
+ Read more in the
+ [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
+ """
+ ),
+ ] = None,
+ exception_handlers: Annotated[
+ Optional[
+ Dict[
+ Union[int, Type[Exception]],
+ Callable[[Request, Any], Coroutine[Any, Any, Response]],
+ ]
+ ],
+ Doc(
+ """
+ A dictionary with handlers for exceptions.
+
+ In FastAPI, you would normally use the decorator
+ `@app.exception_handler()`.
+
+ Read more in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+ """
+ ),
+ ] = None,
+ on_startup: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of startup event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ on_shutdown: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of shutdown event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ lifespan: Annotated[
+ Optional[Lifespan[AppType]],
+ Doc(
+ """
+ A `Lifespan` context manager handler. This replaces `startup` and
+ `shutdown` functions with a single context manager.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ terms_of_service: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A URL to the Terms of Service for your API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(terms_of_service="http://example.com/terms/")
+ ```
+ """
+ ),
+ ] = None,
+ contact: Annotated[
+ Optional[Dict[str, Union[str, Any]]],
+ Doc(
+ """
+ A dictionary with the contact information for the exposed API.
+
+ It can contain several fields.
+
+ * `name`: (`str`) The name of the contact person/organization.
+ * `url`: (`str`) A URL pointing to the contact information. MUST be in
+ the format of a URL.
+ * `email`: (`str`) The email address of the contact person/organization.
+ MUST be in the format of an email address.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(
+ contact={
+ "name": "Deadpoolio the Amazing",
+ "url": "http://x-force.example.com/contact/",
+ "email": "dp@x-force.example.com",
+ }
+ )
+ ```
+ """
+ ),
+ ] = None,
+ license_info: Annotated[
+ Optional[Dict[str, Union[str, Any]]],
+ Doc(
+ """
+ A dictionary with the license information for the exposed API.
+
+ It can contain several fields.
+
+ * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The
+ license name used for the API.
+ * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression
+ for the API. The `identifier` field is mutually exclusive of the `url`
+ field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
+ * `url`: (`str`) A URL to the license used for the API. This MUST be
+ the format of a URL.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(
+ license_info={
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
+ }
+ )
+ ```
+ """
+ ),
+ ] = None,
+ openapi_prefix: Annotated[
+ str,
+ Doc(
+ """
+ A URL prefix for the OpenAPI URL.
+ """
+ ),
+ deprecated(
+ """
+ "openapi_prefix" has been deprecated in favor of "root_path", which
+ follows more closely the ASGI standard, is simpler, and more
+ automatic.
+ """
+ ),
+ ] = "",
+ root_path: Annotated[
+ str,
+ Doc(
+ """
+ A path prefix handled by a proxy that is not seen by the application
+ but is seen by external clients, which affects things like Swagger UI.
+
+ Read more about it at the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(root_path="/api/v1")
+ ```
+ """
+ ),
+ ] = "",
+ root_path_in_servers: Annotated[
+ bool,
+ Doc(
+ """
+ To disable automatically generating the URLs in the `servers` field
+ in the autogenerated OpenAPI using the `root_path`.
+
+ Read more about it in the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root_path).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(root_path_in_servers=False)
+ ```
+ """
+ ),
+ ] = True,
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ webhooks: Annotated[
+ Optional[routing.APIRouter],
+ Doc(
+ """
+ Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't
+ depend on specific *path operations*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0.
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* as deprecated. You probably don't need it,
+ but it's available.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) all the *path operations* in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ swagger_ui_parameters: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Parameters to configure Swagger UI, the autogenerated interactive API
+ documentation (by default at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ separate_input_output_schemas: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to generate separate OpenAPI schemas for request body and
+ response body when the results would be more precise.
+
+ This is particularly useful when automatically generating clients.
+
+ For example, if you have a model like:
+
+ ```python
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ tags: list[str] = []
+ ```
+
+ When `Item` is used for input, a request body, `tags` is not required,
+ the client doesn't have to provide it.
+
+ But when using `Item` for output, for a response body, `tags` is always
+ available because it has a default value, even if it's just an empty
+ list. So, the client should be able to always expect it.
+
+ In this case, there would be two different schemas, one for input and
+ another one for output.
+ """
+ ),
+ ] = True,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Extra keyword arguments to be stored in the app, not used by FastAPI
+ anywhere.
+ """
+ ),
+ ],
+ ) -> None:
+ self.debug = debug
+ self.title = title
+ self.summary = summary
+ self.description = description
+ self.version = version
+ self.terms_of_service = terms_of_service
+ self.contact = contact
+ self.license_info = license_info
+ self.openapi_url = openapi_url
+ self.openapi_tags = openapi_tags
+ self.root_path_in_servers = root_path_in_servers
+ self.docs_url = docs_url
+ self.redoc_url = redoc_url
+ self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
+ self.swagger_ui_init_oauth = swagger_ui_init_oauth
+ self.swagger_ui_parameters = swagger_ui_parameters
+ self.servers = servers or []
+ self.separate_input_output_schemas = separate_input_output_schemas
+ self.extra = extra
+ self.openapi_version: Annotated[
+ str,
+ Doc(
+ """
+ The version string of OpenAPI.
+
+ FastAPI will generate OpenAPI version 3.1.0, and will output that as
+ the OpenAPI version. But some tools, even though they might be
+ compatible with OpenAPI 3.1.0, might not recognize it as a valid.
+
+ So you could override this value to trick those tools into using
+ the generated OpenAPI. Have in mind that this is a hack. But if you
+ avoid using features added in OpenAPI 3.1.0, it might work for your
+ use case.
+
+ This is not passed as a parameter to the `FastAPI` class to avoid
+ giving the false idea that FastAPI would generate a different OpenAPI
+ schema. It is only available as an attribute.
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ app.openapi_version = "3.0.2"
+ ```
+ """
+ ),
+ ] = "3.1.0"
+ self.openapi_schema: Optional[Dict[str, Any]] = None
+ if self.openapi_url:
+ assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
+ assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'"
+ # TODO: remove when discarding the openapi_prefix parameter
+ if openapi_prefix:
+ logger.warning(
+ '"openapi_prefix" has been deprecated in favor of "root_path", which '
+ "follows more closely the ASGI standard, is simpler, and more "
+ "automatic. Check the docs at "
+ "https://fastapi.tiangolo.com/advanced/sub-applications/"
+ )
+ self.webhooks: Annotated[
+ routing.APIRouter,
+ Doc(
+ """
+ The `app.webhooks` attribute is an `APIRouter` with the *path
+ operations* that will be used just for documentation of webhooks.
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
+ """
+ ),
+ ] = webhooks or routing.APIRouter()
+ self.root_path = root_path or openapi_prefix
+ self.state: Annotated[
+ State,
+ Doc(
+ """
+ A state object for the application. This is the same object for the
+ entire application, it doesn't change from request to request.
+
+ You normally wouldn't use this in FastAPI, for most of the cases you
+ would instead use FastAPI dependencies.
+
+ This is simply inherited from Starlette.
+
+ Read more about it in the
+ [Starlette docs for Applications](https://www.starlette.io/applications/#storing-state-on-the-app-instance).
+ """
+ ),
+ ] = State()
+ self.dependency_overrides: Annotated[
+ Dict[Callable[..., Any], Callable[..., Any]],
+ Doc(
+ """
+ A dictionary with overrides for the dependencies.
+
+ Each key is the original dependency callable, and the value is the
+ actual dependency that should be called.
+
+ This is for testing, to replace expensive dependencies with testing
+ versions.
+
+ Read more about it in the
+ [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/).
+ """
+ ),
+ ] = {}
+ self.router: routing.APIRouter = routing.APIRouter(
+ routes=routes,
+ redirect_slashes=redirect_slashes,
+ dependency_overrides_provider=self,
+ on_startup=on_startup,
+ on_shutdown=on_shutdown,
+ lifespan=lifespan,
+ default_response_class=default_response_class,
+ dependencies=dependencies,
+ callbacks=callbacks,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ responses=responses,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+ self.exception_handlers: Dict[
+ Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
+ ] = {} if exception_handlers is None else dict(exception_handlers)
+ self.exception_handlers.setdefault(HTTPException, http_exception_handler)
+ self.exception_handlers.setdefault(
+ RequestValidationError, request_validation_exception_handler
+ )
+ self.exception_handlers.setdefault(
+ WebSocketRequestValidationError,
+ # Starlette still has incorrect type specification for the handlers
+ websocket_request_validation_exception_handler, # type: ignore
+ )
+
+ self.user_middleware: List[Middleware] = (
+ [] if middleware is None else list(middleware)
+ )
+ self.middleware_stack: Union[ASGIApp, None] = None
+ self.setup()
+
+ def openapi(self) -> Dict[str, Any]:
+ """
+ Generate the OpenAPI schema of the application. This is called by FastAPI
+ internally.
+
+ The first time it is called it stores the result in the attribute
+ `app.openapi_schema`, and next times it is called, it just returns that same
+ result. To avoid the cost of generating the schema every time.
+
+ If you need to modify the generated OpenAPI schema, you could modify it.
+
+ Read more in the
+ [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/).
+ """
+ if not self.openapi_schema:
+ self.openapi_schema = get_openapi(
+ title=self.title,
+ version=self.version,
+ openapi_version=self.openapi_version,
+ summary=self.summary,
+ description=self.description,
+ terms_of_service=self.terms_of_service,
+ contact=self.contact,
+ license_info=self.license_info,
+ routes=self.routes,
+ webhooks=self.webhooks.routes,
+ tags=self.openapi_tags,
+ servers=self.servers,
+ separate_input_output_schemas=self.separate_input_output_schemas,
+ )
+ return self.openapi_schema
+
+ def setup(self) -> None:
+ if self.openapi_url:
+ urls = (server_data.get("url") for server_data in self.servers)
+ server_urls = {url for url in urls if url}
+
+ async def openapi(req: Request) -> JSONResponse:
+ root_path = req.scope.get("root_path", "").rstrip("/")
+ if root_path not in server_urls:
+ if root_path and self.root_path_in_servers:
+ self.servers.insert(0, {"url": root_path})
+ server_urls.add(root_path)
+ return JSONResponse(self.openapi())
+
+ self.add_route(self.openapi_url, openapi, include_in_schema=False)
+ if self.openapi_url and self.docs_url:
+
+ async def swagger_ui_html(req: Request) -> HTMLResponse:
+ root_path = req.scope.get("root_path", "").rstrip("/")
+ openapi_url = root_path + self.openapi_url
+ oauth2_redirect_url = self.swagger_ui_oauth2_redirect_url
+ if oauth2_redirect_url:
+ oauth2_redirect_url = root_path + oauth2_redirect_url
+ return get_swagger_ui_html(
+ openapi_url=openapi_url,
+ title=f"{self.title} - Swagger UI",
+ oauth2_redirect_url=oauth2_redirect_url,
+ init_oauth=self.swagger_ui_init_oauth,
+ swagger_ui_parameters=self.swagger_ui_parameters,
+ )
+
+ self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False)
+
+ if self.swagger_ui_oauth2_redirect_url:
+
+ async def swagger_ui_redirect(req: Request) -> HTMLResponse:
+ return get_swagger_ui_oauth2_redirect_html()
+
+ self.add_route(
+ self.swagger_ui_oauth2_redirect_url,
+ swagger_ui_redirect,
+ include_in_schema=False,
+ )
+ if self.openapi_url and self.redoc_url:
+
+ async def redoc_html(req: Request) -> HTMLResponse:
+ root_path = req.scope.get("root_path", "").rstrip("/")
+ openapi_url = root_path + self.openapi_url
+ return get_redoc_html(
+ openapi_url=openapi_url, title=f"{self.title} - ReDoc"
+ )
+
+ self.add_route(self.redoc_url, redoc_html, include_in_schema=False)
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ if self.root_path:
+ scope["root_path"] = self.root_path
+ await super().__call__(scope, receive, send)
+
+ def add_api_route(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ *,
+ response_model: Any = Default(None),
+ status_code: Optional[int] = None,
+ tags: Optional[List[Union[str, Enum]]] = None,
+ dependencies: Optional[Sequence[Depends]] = None,
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ response_description: str = "Successful Response",
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
+ deprecated: Optional[bool] = None,
+ methods: Optional[List[str]] = None,
+ operation_id: Optional[str] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ include_in_schema: bool = True,
+ response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+ JSONResponse
+ ),
+ name: Optional[str] = None,
+ openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
+ ) -> None:
+ self.router.add_api_route(
+ path,
+ endpoint=endpoint,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=methods,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def api_route(
+ self,
+ path: str,
+ *,
+ response_model: Any = Default(None),
+ status_code: Optional[int] = None,
+ tags: Optional[List[Union[str, Enum]]] = None,
+ dependencies: Optional[Sequence[Depends]] = None,
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ response_description: str = "Successful Response",
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
+ deprecated: Optional[bool] = None,
+ methods: Optional[List[str]] = None,
+ operation_id: Optional[str] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ include_in_schema: bool = True,
+ response_class: Type[Response] = Default(JSONResponse),
+ name: Optional[str] = None,
+ openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.router.add_api_route(
+ path,
+ func,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=methods,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+ return func
+
+ return decorator
+
+ def add_api_websocket_route(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[Depends]] = None,
+ ) -> None:
+ self.router.add_api_websocket_route(
+ path,
+ endpoint,
+ name=name,
+ dependencies=dependencies,
+ )
+
+ def websocket(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ WebSocket path.
+ """
+ ),
+ ],
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A name for the WebSocket. Only used internally.
+ """
+ ),
+ ] = None,
+ *,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be used for this
+ WebSocket.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+ """
+ ),
+ ] = None,
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Decorate a WebSocket function.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI, WebSocket
+
+ app = FastAPI()
+
+ @app.websocket("/ws")
+ async def websocket_endpoint(websocket: WebSocket):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Message text was: {data}")
+ ```
+ """
+
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_api_websocket_route(
+ path,
+ func,
+ name=name,
+ dependencies=dependencies,
+ )
+ return func
+
+ return decorator
+
+ def include_router(
+ self,
+ router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")],
+ *,
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+
+ **Example**
+
+ ```python
+ from fastapi import Depends, FastAPI
+
+ from .dependencies import get_token_header
+ from .internal import admin
+
+ app = FastAPI()
+
+ app.include_router(
+ admin.router,
+ dependencies=[Depends(get_token_header)],
+ )
+ ```
+ """
+ ),
+ ] = None,
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all the *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ deprecated=True,
+ )
+ ```
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include (or not) all the *path operations* in this router in the
+ generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ include_in_schema=False,
+ )
+ ```
+ """
+ ),
+ ] = True,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Default response class to be used for the *path operations* in this
+ router.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+ from fastapi.responses import ORJSONResponse
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ default_response_class=ORJSONResponse,
+ )
+ ```
+ """
+ ),
+ ] = Default(JSONResponse),
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> None:
+ """
+ Include an `APIRouter` in the same app.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ from .users import users_router
+
+ app = FastAPI()
+
+ app.include_router(users_router)
+ ```
+ """
+ self.router.include_router(
+ router,
+ prefix=prefix,
+ tags=tags,
+ dependencies=dependencies,
+ responses=responses,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ default_response_class=default_response_class,
+ callbacks=callbacks,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def get(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP GET operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.get("/items/")
+ def read_items():
+ return [{"name": "Empanada"}, {"name": "Arepa"}]
+ ```
+ """
+ return self.router.get(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def put(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PUT operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.put("/items/{item_id}")
+ def replace_item(item_id: str, item: Item):
+ return {"message": "Item replaced", "id": item_id}
+ ```
+ """
+ return self.router.put(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def post(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP POST operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.post("/items/")
+ def create_item(item: Item):
+ return {"message": "Item created"}
+ ```
+ """
+ return self.router.post(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def delete(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP DELETE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.delete("/items/{item_id}")
+ def delete_item(item_id: str):
+ return {"message": "Item deleted"}
+ ```
+ """
+ return self.router.delete(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def options(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP OPTIONS operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.options("/items/")
+ def get_item_options():
+ return {"additions": ["Aji", "Guacamole"]}
+ ```
+ """
+ return self.router.options(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def head(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP HEAD operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, Response
+
+ app = FastAPI()
+
+ @app.head("/items/", status_code=204)
+ def get_items_headers(response: Response):
+ response.headers["X-Cat-Dog"] = "Alone in the world"
+ ```
+ """
+ return self.router.head(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def patch(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PATCH operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.patch("/items/")
+ def update_item(item: Item):
+ return {"message": "Item updated in place"}
+ ```
+ """
+ return self.router.patch(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def trace(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP TRACE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.put("/items/{item_id}")
+ def trace_item(item_id: str):
+ return None
+ ```
+ """
+ return self.router.trace(
+ path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def websocket_route(
+ self, path: str, name: Union[str, None] = None
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.router.add_websocket_route(path, func, name=name)
+ return func
+
+ return decorator
+
+ @deprecated(
+ """
+ on_event is deprecated, use lifespan event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ )
+ def on_event(
+ self,
+ event_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of event. `startup` or `shutdown`.
+ """
+ ),
+ ],
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an event handler for the application.
+
+ `on_event` is deprecated, use `lifespan` event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated).
+ """
+ return self.router.on_event(event_type)
+
+ def middleware(
+ self,
+ middleware_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of middleware. Currently only supports `http`.
+ """
+ ),
+ ],
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a middleware to the application.
+
+ Read more about it in the
+ [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
+
+ ## Example
+
+ ```python
+ import time
+
+ from fastapi import FastAPI, Request
+
+ app = FastAPI()
+
+
+ @app.middleware("http")
+ async def add_process_time_header(request: Request, call_next):
+ start_time = time.time()
+ response = await call_next(request)
+ process_time = time.time() - start_time
+ response.headers["X-Process-Time"] = str(process_time)
+ return response
+ ```
+ """
+
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_middleware(BaseHTTPMiddleware, dispatch=func)
+ return func
+
+ return decorator
+
+ def exception_handler(
+ self,
+ exc_class_or_status_code: Annotated[
+ Union[int, Type[Exception]],
+ Doc(
+ """
+ The Exception class this would handle, or a status code.
+ """
+ ),
+ ],
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an exception handler to the app.
+
+ Read more about it in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, Request
+ from fastapi.responses import JSONResponse
+
+
+ class UnicornException(Exception):
+ def __init__(self, name: str):
+ self.name = name
+
+
+ app = FastAPI()
+
+
+ @app.exception_handler(UnicornException)
+ async def unicorn_exception_handler(request: Request, exc: UnicornException):
+ return JSONResponse(
+ status_code=418,
+ content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
+ )
+ ```
+ """
+
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_exception_handler(exc_class_or_status_code, func)
+ return func
+
+ return decorator
diff --git a/.venv/lib/python3.12/site-packages/fastapi/background.py b/.venv/lib/python3.12/site-packages/fastapi/background.py
new file mode 100644
index 00000000..203578a4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/background.py
@@ -0,0 +1,59 @@
+from typing import Any, Callable
+
+from starlette.background import BackgroundTasks as StarletteBackgroundTasks
+from typing_extensions import Annotated, Doc, ParamSpec
+
+P = ParamSpec("P")
+
+
+class BackgroundTasks(StarletteBackgroundTasks):
+ """
+ A collection of background tasks that will be called after a response has been
+ sent to the client.
+
+ Read more about it in the
+ [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
+
+ ## Example
+
+ ```python
+ from fastapi import BackgroundTasks, FastAPI
+
+ app = FastAPI()
+
+
+ def write_notification(email: str, message=""):
+ with open("log.txt", mode="w") as email_file:
+ content = f"notification for {email}: {message}"
+ email_file.write(content)
+
+
+ @app.post("/send-notification/{email}")
+ async def send_notification(email: str, background_tasks: BackgroundTasks):
+ background_tasks.add_task(write_notification, email, message="some notification")
+ return {"message": "Notification sent in the background"}
+ ```
+ """
+
+ def add_task(
+ self,
+ func: Annotated[
+ Callable[P, Any],
+ Doc(
+ """
+ The function to call after the response is sent.
+
+ It can be a regular `def` function or an `async def` function.
+ """
+ ),
+ ],
+ *args: P.args,
+ **kwargs: P.kwargs,
+ ) -> None:
+ """
+ Add a function to be called in the background after the response is sent.
+
+ Read more about it in the
+ [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
+ """
+ return super().add_task(func, *args, **kwargs)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/cli.py b/.venv/lib/python3.12/site-packages/fastapi/cli.py
new file mode 100644
index 00000000..8d3301e9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/cli.py
@@ -0,0 +1,13 @@
+try:
+ from fastapi_cli.cli import main as cli_main
+
+except ImportError: # pragma: no cover
+ cli_main = None # type: ignore
+
+
+def main() -> None:
+ if not cli_main: # type: ignore[truthy-function]
+ message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n'
+ print(message)
+ raise RuntimeError(message) # noqa: B904
+ cli_main()
diff --git a/.venv/lib/python3.12/site-packages/fastapi/concurrency.py b/.venv/lib/python3.12/site-packages/fastapi/concurrency.py
new file mode 100644
index 00000000..3202c707
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/concurrency.py
@@ -0,0 +1,39 @@
+from contextlib import asynccontextmanager as asynccontextmanager
+from typing import AsyncGenerator, ContextManager, TypeVar
+
+import anyio.to_thread
+from anyio import CapacityLimiter
+from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa
+from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa
+from starlette.concurrency import ( # noqa
+ run_until_first_complete as run_until_first_complete,
+)
+
+_T = TypeVar("_T")
+
+
+@asynccontextmanager
+async def contextmanager_in_threadpool(
+ cm: ContextManager[_T],
+) -> AsyncGenerator[_T, None]:
+ # blocking __exit__ from running waiting on a free thread
+ # can create race conditions/deadlocks if the context manager itself
+ # has its own internal pool (e.g. a database connection pool)
+ # to avoid this we let __exit__ run without a capacity limit
+ # since we're creating a new limiter for each call, any non-zero limit
+ # works (1 is arbitrary)
+ exit_limiter = CapacityLimiter(1)
+ try:
+ yield await run_in_threadpool(cm.__enter__)
+ except Exception as e:
+ ok = bool(
+ await anyio.to_thread.run_sync(
+ cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter
+ )
+ )
+ if not ok:
+ raise e
+ else:
+ await anyio.to_thread.run_sync(
+ cm.__exit__, None, None, None, limiter=exit_limiter
+ )
diff --git a/.venv/lib/python3.12/site-packages/fastapi/datastructures.py b/.venv/lib/python3.12/site-packages/fastapi/datastructures.py
new file mode 100644
index 00000000..cf8406b0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/datastructures.py
@@ -0,0 +1,204 @@
+from typing import (
+ Any,
+ BinaryIO,
+ Callable,
+ Dict,
+ Iterable,
+ Optional,
+ Type,
+ TypeVar,
+ cast,
+)
+
+from fastapi._compat import (
+ PYDANTIC_V2,
+ CoreSchema,
+ GetJsonSchemaHandler,
+ JsonSchemaValue,
+ with_info_plain_validator_function,
+)
+from starlette.datastructures import URL as URL # noqa: F401
+from starlette.datastructures import Address as Address # noqa: F401
+from starlette.datastructures import FormData as FormData # noqa: F401
+from starlette.datastructures import Headers as Headers # noqa: F401
+from starlette.datastructures import QueryParams as QueryParams # noqa: F401
+from starlette.datastructures import State as State # noqa: F401
+from starlette.datastructures import UploadFile as StarletteUploadFile
+from typing_extensions import Annotated, Doc
+
+
+class UploadFile(StarletteUploadFile):
+ """
+ A file uploaded in a request.
+
+ Define it as a *path operation function* (or dependency) parameter.
+
+ If you are using a regular `def` function, you can use the `upload_file.file`
+ attribute to access the raw standard Python file (blocking, not async), useful and
+ needed for non-async code.
+
+ Read more about it in the
+ [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import FastAPI, File, UploadFile
+
+ app = FastAPI()
+
+
+ @app.post("/files/")
+ async def create_file(file: Annotated[bytes, File()]):
+ return {"file_size": len(file)}
+
+
+ @app.post("/uploadfile/")
+ async def create_upload_file(file: UploadFile):
+ return {"filename": file.filename}
+ ```
+ """
+
+ file: Annotated[
+ BinaryIO,
+ Doc("The standard Python file object (non-async)."),
+ ]
+ filename: Annotated[Optional[str], Doc("The original file name.")]
+ size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
+ headers: Annotated[Headers, Doc("The headers of the request.")]
+ content_type: Annotated[
+ Optional[str], Doc("The content type of the request, from the headers.")
+ ]
+
+ async def write(
+ self,
+ data: Annotated[
+ bytes,
+ Doc(
+ """
+ The bytes to write to the file.
+ """
+ ),
+ ],
+ ) -> None:
+ """
+ Write some bytes to the file.
+
+ You normally wouldn't use this from a file you read in a request.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().write(data)
+
+ async def read(
+ self,
+ size: Annotated[
+ int,
+ Doc(
+ """
+ The number of bytes to read from the file.
+ """
+ ),
+ ] = -1,
+ ) -> bytes:
+ """
+ Read some bytes from the file.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().read(size)
+
+ async def seek(
+ self,
+ offset: Annotated[
+ int,
+ Doc(
+ """
+ The position in bytes to seek to in the file.
+ """
+ ),
+ ],
+ ) -> None:
+ """
+ Move to a position in the file.
+
+ Any next read or write will be done from that position.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().seek(offset)
+
+ async def close(self) -> None:
+ """
+ Close the file.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().close()
+
+ @classmethod
+ def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
+ yield cls.validate
+
+ @classmethod
+ def validate(cls: Type["UploadFile"], v: Any) -> Any:
+ if not isinstance(v, StarletteUploadFile):
+ raise ValueError(f"Expected UploadFile, received: {type(v)}")
+ return v
+
+ @classmethod
+ def _validate(cls, __input_value: Any, _: Any) -> "UploadFile":
+ if not isinstance(__input_value, StarletteUploadFile):
+ raise ValueError(f"Expected UploadFile, received: {type(__input_value)}")
+ return cast(UploadFile, __input_value)
+
+ if not PYDANTIC_V2:
+
+ @classmethod
+ def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
+ field_schema.update({"type": "string", "format": "binary"})
+
+ @classmethod
+ def __get_pydantic_json_schema__(
+ cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
+ ) -> JsonSchemaValue:
+ return {"type": "string", "format": "binary"}
+
+ @classmethod
+ def __get_pydantic_core_schema__(
+ cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
+ ) -> CoreSchema:
+ return with_info_plain_validator_function(cls._validate)
+
+
+class DefaultPlaceholder:
+ """
+ You shouldn't use this class directly.
+
+ It's used internally to recognize when a default value has been overwritten, even
+ if the overridden default value was truthy.
+ """
+
+ def __init__(self, value: Any):
+ self.value = value
+
+ def __bool__(self) -> bool:
+ return bool(self.value)
+
+ def __eq__(self, o: object) -> bool:
+ return isinstance(o, DefaultPlaceholder) and o.value == self.value
+
+
+DefaultType = TypeVar("DefaultType")
+
+
+def Default(value: DefaultType) -> DefaultType:
+ """
+ You shouldn't use this function directly.
+
+ It's used internally to recognize when a default value has been overwritten, even
+ if the overridden default value was truthy.
+ """
+ return DefaultPlaceholder(value) # type: ignore
diff --git a/.venv/lib/python3.12/site-packages/fastapi/dependencies/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/dependencies/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/dependencies/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/fastapi/dependencies/models.py b/.venv/lib/python3.12/site-packages/fastapi/dependencies/models.py
new file mode 100644
index 00000000..418c1172
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/dependencies/models.py
@@ -0,0 +1,37 @@
+from dataclasses import dataclass, field
+from typing import Any, Callable, List, Optional, Sequence, Tuple
+
+from fastapi._compat import ModelField
+from fastapi.security.base import SecurityBase
+
+
+@dataclass
+class SecurityRequirement:
+ security_scheme: SecurityBase
+ scopes: Optional[Sequence[str]] = None
+
+
+@dataclass
+class Dependant:
+ path_params: List[ModelField] = field(default_factory=list)
+ query_params: List[ModelField] = field(default_factory=list)
+ header_params: List[ModelField] = field(default_factory=list)
+ cookie_params: List[ModelField] = field(default_factory=list)
+ body_params: List[ModelField] = field(default_factory=list)
+ dependencies: List["Dependant"] = field(default_factory=list)
+ security_requirements: List[SecurityRequirement] = field(default_factory=list)
+ name: Optional[str] = None
+ call: Optional[Callable[..., Any]] = None
+ request_param_name: Optional[str] = None
+ websocket_param_name: Optional[str] = None
+ http_connection_param_name: Optional[str] = None
+ response_param_name: Optional[str] = None
+ background_tasks_param_name: Optional[str] = None
+ security_scopes_param_name: Optional[str] = None
+ security_scopes: Optional[List[str]] = None
+ use_cache: bool = True
+ path: Optional[str] = None
+ cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
+
+ def __post_init__(self) -> None:
+ self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
diff --git a/.venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py b/.venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py
new file mode 100644
index 00000000..84dfa4d0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py
@@ -0,0 +1,980 @@
+import inspect
+from contextlib import AsyncExitStack, contextmanager
+from copy import copy, deepcopy
+from dataclasses import dataclass
+from typing import (
+ Any,
+ Callable,
+ Coroutine,
+ Dict,
+ ForwardRef,
+ List,
+ Mapping,
+ Optional,
+ Sequence,
+ Tuple,
+ Type,
+ Union,
+ cast,
+)
+
+import anyio
+from fastapi import params
+from fastapi._compat import (
+ PYDANTIC_V2,
+ ErrorWrapper,
+ ModelField,
+ RequiredParam,
+ Undefined,
+ _regenerate_error_with_loc,
+ copy_field_info,
+ create_body_model,
+ evaluate_forwardref,
+ field_annotation_is_scalar,
+ get_annotation_from_field_info,
+ get_cached_model_fields,
+ get_missing_field_error,
+ is_bytes_field,
+ is_bytes_sequence_field,
+ is_scalar_field,
+ is_scalar_sequence_field,
+ is_sequence_field,
+ is_uploadfile_or_nonable_uploadfile_annotation,
+ is_uploadfile_sequence_annotation,
+ lenient_issubclass,
+ sequence_types,
+ serialize_sequence_value,
+ value_is_sequence,
+)
+from fastapi.background import BackgroundTasks
+from fastapi.concurrency import (
+ asynccontextmanager,
+ contextmanager_in_threadpool,
+)
+from fastapi.dependencies.models import Dependant, SecurityRequirement
+from fastapi.logger import logger
+from fastapi.security.base import SecurityBase
+from fastapi.security.oauth2 import OAuth2, SecurityScopes
+from fastapi.security.open_id_connect_url import OpenIdConnect
+from fastapi.utils import create_model_field, get_path_param_names
+from pydantic import BaseModel
+from pydantic.fields import FieldInfo
+from starlette.background import BackgroundTasks as StarletteBackgroundTasks
+from starlette.concurrency import run_in_threadpool
+from starlette.datastructures import (
+ FormData,
+ Headers,
+ ImmutableMultiDict,
+ QueryParams,
+ UploadFile,
+)
+from starlette.requests import HTTPConnection, Request
+from starlette.responses import Response
+from starlette.websockets import WebSocket
+from typing_extensions import Annotated, get_args, get_origin
+
+multipart_not_installed_error = (
+ 'Form data requires "python-multipart" to be installed. \n'
+ 'You can install "python-multipart" with: \n\n'
+ "pip install python-multipart\n"
+)
+multipart_incorrect_install_error = (
+ 'Form data requires "python-multipart" to be installed. '
+ 'It seems you installed "multipart" instead. \n'
+ 'You can remove "multipart" with: \n\n'
+ "pip uninstall multipart\n\n"
+ 'And then install "python-multipart" with: \n\n'
+ "pip install python-multipart\n"
+)
+
+
+def ensure_multipart_is_installed() -> None:
+ try:
+ from python_multipart import __version__
+
+ # Import an attribute that can be mocked/deleted in testing
+ assert __version__ > "0.0.12"
+ except (ImportError, AssertionError):
+ try:
+ # __version__ is available in both multiparts, and can be mocked
+ from multipart import __version__ # type: ignore[no-redef,import-untyped]
+
+ assert __version__
+ try:
+ # parse_options_header is only available in the right multipart
+ from multipart.multipart import ( # type: ignore[import-untyped]
+ parse_options_header,
+ )
+
+ assert parse_options_header
+ except ImportError:
+ logger.error(multipart_incorrect_install_error)
+ raise RuntimeError(multipart_incorrect_install_error) from None
+ except ImportError:
+ logger.error(multipart_not_installed_error)
+ raise RuntimeError(multipart_not_installed_error) from None
+
+
+def get_param_sub_dependant(
+ *,
+ param_name: str,
+ depends: params.Depends,
+ path: str,
+ security_scopes: Optional[List[str]] = None,
+) -> Dependant:
+ assert depends.dependency
+ return get_sub_dependant(
+ depends=depends,
+ dependency=depends.dependency,
+ path=path,
+ name=param_name,
+ security_scopes=security_scopes,
+ )
+
+
+def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant:
+ assert callable(depends.dependency), (
+ "A parameter-less dependency must have a callable dependency"
+ )
+ return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path)
+
+
+def get_sub_dependant(
+ *,
+ depends: params.Depends,
+ dependency: Callable[..., Any],
+ path: str,
+ name: Optional[str] = None,
+ security_scopes: Optional[List[str]] = None,
+) -> Dependant:
+ security_requirement = None
+ security_scopes = security_scopes or []
+ if isinstance(depends, params.Security):
+ dependency_scopes = depends.scopes
+ security_scopes.extend(dependency_scopes)
+ if isinstance(dependency, SecurityBase):
+ use_scopes: List[str] = []
+ if isinstance(dependency, (OAuth2, OpenIdConnect)):
+ use_scopes = security_scopes
+ security_requirement = SecurityRequirement(
+ security_scheme=dependency, scopes=use_scopes
+ )
+ sub_dependant = get_dependant(
+ path=path,
+ call=dependency,
+ name=name,
+ security_scopes=security_scopes,
+ use_cache=depends.use_cache,
+ )
+ if security_requirement:
+ sub_dependant.security_requirements.append(security_requirement)
+ return sub_dependant
+
+
+CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
+
+
+def get_flat_dependant(
+ dependant: Dependant,
+ *,
+ skip_repeats: bool = False,
+ visited: Optional[List[CacheKey]] = None,
+) -> Dependant:
+ if visited is None:
+ visited = []
+ visited.append(dependant.cache_key)
+
+ flat_dependant = Dependant(
+ path_params=dependant.path_params.copy(),
+ query_params=dependant.query_params.copy(),
+ header_params=dependant.header_params.copy(),
+ cookie_params=dependant.cookie_params.copy(),
+ body_params=dependant.body_params.copy(),
+ security_requirements=dependant.security_requirements.copy(),
+ use_cache=dependant.use_cache,
+ path=dependant.path,
+ )
+ for sub_dependant in dependant.dependencies:
+ if skip_repeats and sub_dependant.cache_key in visited:
+ continue
+ flat_sub = get_flat_dependant(
+ sub_dependant, skip_repeats=skip_repeats, visited=visited
+ )
+ flat_dependant.path_params.extend(flat_sub.path_params)
+ flat_dependant.query_params.extend(flat_sub.query_params)
+ flat_dependant.header_params.extend(flat_sub.header_params)
+ flat_dependant.cookie_params.extend(flat_sub.cookie_params)
+ flat_dependant.body_params.extend(flat_sub.body_params)
+ flat_dependant.security_requirements.extend(flat_sub.security_requirements)
+ return flat_dependant
+
+
+def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
+ if not fields:
+ return fields
+ first_field = fields[0]
+ if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
+ fields_to_extract = get_cached_model_fields(first_field.type_)
+ return fields_to_extract
+ return fields
+
+
+def get_flat_params(dependant: Dependant) -> List[ModelField]:
+ flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
+ path_params = _get_flat_fields_from_params(flat_dependant.path_params)
+ query_params = _get_flat_fields_from_params(flat_dependant.query_params)
+ header_params = _get_flat_fields_from_params(flat_dependant.header_params)
+ cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
+ return path_params + query_params + header_params + cookie_params
+
+
+def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
+ signature = inspect.signature(call)
+ globalns = getattr(call, "__globals__", {})
+ typed_params = [
+ inspect.Parameter(
+ name=param.name,
+ kind=param.kind,
+ default=param.default,
+ annotation=get_typed_annotation(param.annotation, globalns),
+ )
+ for param in signature.parameters.values()
+ ]
+ typed_signature = inspect.Signature(typed_params)
+ return typed_signature
+
+
+def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
+ if isinstance(annotation, str):
+ annotation = ForwardRef(annotation)
+ annotation = evaluate_forwardref(annotation, globalns, globalns)
+ return annotation
+
+
+def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
+ signature = inspect.signature(call)
+ annotation = signature.return_annotation
+
+ if annotation is inspect.Signature.empty:
+ return None
+
+ globalns = getattr(call, "__globals__", {})
+ return get_typed_annotation(annotation, globalns)
+
+
+def get_dependant(
+ *,
+ path: str,
+ call: Callable[..., Any],
+ name: Optional[str] = None,
+ security_scopes: Optional[List[str]] = None,
+ use_cache: bool = True,
+) -> Dependant:
+ path_param_names = get_path_param_names(path)
+ endpoint_signature = get_typed_signature(call)
+ signature_params = endpoint_signature.parameters
+ dependant = Dependant(
+ call=call,
+ name=name,
+ path=path,
+ security_scopes=security_scopes,
+ use_cache=use_cache,
+ )
+ for param_name, param in signature_params.items():
+ is_path_param = param_name in path_param_names
+ param_details = analyze_param(
+ param_name=param_name,
+ annotation=param.annotation,
+ value=param.default,
+ is_path_param=is_path_param,
+ )
+ if param_details.depends is not None:
+ sub_dependant = get_param_sub_dependant(
+ param_name=param_name,
+ depends=param_details.depends,
+ path=path,
+ security_scopes=security_scopes,
+ )
+ dependant.dependencies.append(sub_dependant)
+ continue
+ if add_non_field_param_to_dependency(
+ param_name=param_name,
+ type_annotation=param_details.type_annotation,
+ dependant=dependant,
+ ):
+ assert param_details.field is None, (
+ f"Cannot specify multiple FastAPI annotations for {param_name!r}"
+ )
+ continue
+ assert param_details.field is not None
+ if isinstance(param_details.field.field_info, params.Body):
+ dependant.body_params.append(param_details.field)
+ else:
+ add_param_to_fields(field=param_details.field, dependant=dependant)
+ return dependant
+
+
+def add_non_field_param_to_dependency(
+ *, param_name: str, type_annotation: Any, dependant: Dependant
+) -> Optional[bool]:
+ if lenient_issubclass(type_annotation, Request):
+ dependant.request_param_name = param_name
+ return True
+ elif lenient_issubclass(type_annotation, WebSocket):
+ dependant.websocket_param_name = param_name
+ return True
+ elif lenient_issubclass(type_annotation, HTTPConnection):
+ dependant.http_connection_param_name = param_name
+ return True
+ elif lenient_issubclass(type_annotation, Response):
+ dependant.response_param_name = param_name
+ return True
+ elif lenient_issubclass(type_annotation, StarletteBackgroundTasks):
+ dependant.background_tasks_param_name = param_name
+ return True
+ elif lenient_issubclass(type_annotation, SecurityScopes):
+ dependant.security_scopes_param_name = param_name
+ return True
+ return None
+
+
+@dataclass
+class ParamDetails:
+ type_annotation: Any
+ depends: Optional[params.Depends]
+ field: Optional[ModelField]
+
+
+def analyze_param(
+ *,
+ param_name: str,
+ annotation: Any,
+ value: Any,
+ is_path_param: bool,
+) -> ParamDetails:
+ field_info = None
+ depends = None
+ type_annotation: Any = Any
+ use_annotation: Any = Any
+ if annotation is not inspect.Signature.empty:
+ use_annotation = annotation
+ type_annotation = annotation
+ # Extract Annotated info
+ if get_origin(use_annotation) is Annotated:
+ annotated_args = get_args(annotation)
+ type_annotation = annotated_args[0]
+ fastapi_annotations = [
+ arg
+ for arg in annotated_args[1:]
+ if isinstance(arg, (FieldInfo, params.Depends))
+ ]
+ fastapi_specific_annotations = [
+ arg
+ for arg in fastapi_annotations
+ if isinstance(arg, (params.Param, params.Body, params.Depends))
+ ]
+ if fastapi_specific_annotations:
+ fastapi_annotation: Union[FieldInfo, params.Depends, None] = (
+ fastapi_specific_annotations[-1]
+ )
+ else:
+ fastapi_annotation = None
+ # Set default for Annotated FieldInfo
+ if isinstance(fastapi_annotation, FieldInfo):
+ # Copy `field_info` because we mutate `field_info.default` below.
+ field_info = copy_field_info(
+ field_info=fastapi_annotation, annotation=use_annotation
+ )
+ assert (
+ field_info.default is Undefined or field_info.default is RequiredParam
+ ), (
+ f"`{field_info.__class__.__name__}` default value cannot be set in"
+ f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
+ )
+ if value is not inspect.Signature.empty:
+ assert not is_path_param, "Path parameters cannot have default values"
+ field_info.default = value
+ else:
+ field_info.default = RequiredParam
+ # Get Annotated Depends
+ elif isinstance(fastapi_annotation, params.Depends):
+ depends = fastapi_annotation
+ # Get Depends from default value
+ if isinstance(value, params.Depends):
+ assert depends is None, (
+ "Cannot specify `Depends` in `Annotated` and default value"
+ f" together for {param_name!r}"
+ )
+ assert field_info is None, (
+ "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a"
+ f" default value together for {param_name!r}"
+ )
+ depends = value
+ # Get FieldInfo from default value
+ elif isinstance(value, FieldInfo):
+ assert field_info is None, (
+ "Cannot specify FastAPI annotations in `Annotated` and default value"
+ f" together for {param_name!r}"
+ )
+ field_info = value
+ if PYDANTIC_V2:
+ field_info.annotation = type_annotation
+
+ # Get Depends from type annotation
+ if depends is not None and depends.dependency is None:
+ # Copy `depends` before mutating it
+ depends = copy(depends)
+ depends.dependency = type_annotation
+
+ # Handle non-param type annotations like Request
+ if lenient_issubclass(
+ type_annotation,
+ (
+ Request,
+ WebSocket,
+ HTTPConnection,
+ Response,
+ StarletteBackgroundTasks,
+ SecurityScopes,
+ ),
+ ):
+ assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
+ assert field_info is None, (
+ f"Cannot specify FastAPI annotation for type {type_annotation!r}"
+ )
+ # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value
+ elif field_info is None and depends is None:
+ default_value = value if value is not inspect.Signature.empty else RequiredParam
+ if is_path_param:
+ # We might check here that `default_value is RequiredParam`, but the fact is that the same
+ # parameter might sometimes be a path parameter and sometimes not. See
+ # `tests/test_infer_param_optionality.py` for an example.
+ field_info = params.Path(annotation=use_annotation)
+ elif is_uploadfile_or_nonable_uploadfile_annotation(
+ type_annotation
+ ) or is_uploadfile_sequence_annotation(type_annotation):
+ field_info = params.File(annotation=use_annotation, default=default_value)
+ elif not field_annotation_is_scalar(annotation=type_annotation):
+ field_info = params.Body(annotation=use_annotation, default=default_value)
+ else:
+ field_info = params.Query(annotation=use_annotation, default=default_value)
+
+ field = None
+ # It's a field_info, not a dependency
+ if field_info is not None:
+ # Handle field_info.in_
+ if is_path_param:
+ assert isinstance(field_info, params.Path), (
+ f"Cannot use `{field_info.__class__.__name__}` for path param"
+ f" {param_name!r}"
+ )
+ elif (
+ isinstance(field_info, params.Param)
+ and getattr(field_info, "in_", None) is None
+ ):
+ field_info.in_ = params.ParamTypes.query
+ use_annotation_from_field_info = get_annotation_from_field_info(
+ use_annotation,
+ field_info,
+ param_name,
+ )
+ if isinstance(field_info, params.Form):
+ ensure_multipart_is_installed()
+ if not field_info.alias and getattr(field_info, "convert_underscores", None):
+ alias = param_name.replace("_", "-")
+ else:
+ alias = field_info.alias or param_name
+ field_info.alias = alias
+ field = create_model_field(
+ name=param_name,
+ type_=use_annotation_from_field_info,
+ default=field_info.default,
+ alias=alias,
+ required=field_info.default in (RequiredParam, Undefined),
+ field_info=field_info,
+ )
+ if is_path_param:
+ assert is_scalar_field(field=field), (
+ "Path params must be of one of the supported types"
+ )
+ elif isinstance(field_info, params.Query):
+ assert (
+ is_scalar_field(field)
+ or is_scalar_sequence_field(field)
+ or (
+ lenient_issubclass(field.type_, BaseModel)
+ # For Pydantic v1
+ and getattr(field, "shape", 1) == 1
+ )
+ )
+
+ return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
+
+
+def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
+ field_info = field.field_info
+ field_info_in = getattr(field_info, "in_", None)
+ if field_info_in == params.ParamTypes.path:
+ dependant.path_params.append(field)
+ elif field_info_in == params.ParamTypes.query:
+ dependant.query_params.append(field)
+ elif field_info_in == params.ParamTypes.header:
+ dependant.header_params.append(field)
+ else:
+ assert field_info_in == params.ParamTypes.cookie, (
+ f"non-body parameters must be in path, query, header or cookie: {field.name}"
+ )
+ dependant.cookie_params.append(field)
+
+
+def is_coroutine_callable(call: Callable[..., Any]) -> bool:
+ if inspect.isroutine(call):
+ return inspect.iscoroutinefunction(call)
+ if inspect.isclass(call):
+ return False
+ dunder_call = getattr(call, "__call__", None) # noqa: B004
+ return inspect.iscoroutinefunction(dunder_call)
+
+
+def is_async_gen_callable(call: Callable[..., Any]) -> bool:
+ if inspect.isasyncgenfunction(call):
+ return True
+ dunder_call = getattr(call, "__call__", None) # noqa: B004
+ return inspect.isasyncgenfunction(dunder_call)
+
+
+def is_gen_callable(call: Callable[..., Any]) -> bool:
+ if inspect.isgeneratorfunction(call):
+ return True
+ dunder_call = getattr(call, "__call__", None) # noqa: B004
+ return inspect.isgeneratorfunction(dunder_call)
+
+
+async def solve_generator(
+ *, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any]
+) -> Any:
+ if is_gen_callable(call):
+ cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values))
+ elif is_async_gen_callable(call):
+ cm = asynccontextmanager(call)(**sub_values)
+ return await stack.enter_async_context(cm)
+
+
+@dataclass
+class SolvedDependency:
+ values: Dict[str, Any]
+ errors: List[Any]
+ background_tasks: Optional[StarletteBackgroundTasks]
+ response: Response
+ dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
+
+
+async def solve_dependencies(
+ *,
+ request: Union[Request, WebSocket],
+ dependant: Dependant,
+ body: Optional[Union[Dict[str, Any], FormData]] = None,
+ background_tasks: Optional[StarletteBackgroundTasks] = None,
+ response: Optional[Response] = None,
+ dependency_overrides_provider: Optional[Any] = None,
+ dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
+ async_exit_stack: AsyncExitStack,
+ embed_body_fields: bool,
+) -> SolvedDependency:
+ values: Dict[str, Any] = {}
+ errors: List[Any] = []
+ if response is None:
+ response = Response()
+ del response.headers["content-length"]
+ response.status_code = None # type: ignore
+ dependency_cache = dependency_cache or {}
+ sub_dependant: Dependant
+ for sub_dependant in dependant.dependencies:
+ sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
+ sub_dependant.cache_key = cast(
+ Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
+ )
+ call = sub_dependant.call
+ use_sub_dependant = sub_dependant
+ if (
+ dependency_overrides_provider
+ and dependency_overrides_provider.dependency_overrides
+ ):
+ original_call = sub_dependant.call
+ call = getattr(
+ dependency_overrides_provider, "dependency_overrides", {}
+ ).get(original_call, original_call)
+ use_path: str = sub_dependant.path # type: ignore
+ use_sub_dependant = get_dependant(
+ path=use_path,
+ call=call,
+ name=sub_dependant.name,
+ security_scopes=sub_dependant.security_scopes,
+ )
+
+ solved_result = await solve_dependencies(
+ request=request,
+ dependant=use_sub_dependant,
+ body=body,
+ background_tasks=background_tasks,
+ response=response,
+ dependency_overrides_provider=dependency_overrides_provider,
+ dependency_cache=dependency_cache,
+ async_exit_stack=async_exit_stack,
+ embed_body_fields=embed_body_fields,
+ )
+ background_tasks = solved_result.background_tasks
+ dependency_cache.update(solved_result.dependency_cache)
+ if solved_result.errors:
+ errors.extend(solved_result.errors)
+ continue
+ if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
+ solved = dependency_cache[sub_dependant.cache_key]
+ elif is_gen_callable(call) or is_async_gen_callable(call):
+ solved = await solve_generator(
+ call=call, stack=async_exit_stack, sub_values=solved_result.values
+ )
+ elif is_coroutine_callable(call):
+ solved = await call(**solved_result.values)
+ else:
+ solved = await run_in_threadpool(call, **solved_result.values)
+ if sub_dependant.name is not None:
+ values[sub_dependant.name] = solved
+ if sub_dependant.cache_key not in dependency_cache:
+ dependency_cache[sub_dependant.cache_key] = solved
+ path_values, path_errors = request_params_to_args(
+ dependant.path_params, request.path_params
+ )
+ query_values, query_errors = request_params_to_args(
+ dependant.query_params, request.query_params
+ )
+ header_values, header_errors = request_params_to_args(
+ dependant.header_params, request.headers
+ )
+ cookie_values, cookie_errors = request_params_to_args(
+ dependant.cookie_params, request.cookies
+ )
+ values.update(path_values)
+ values.update(query_values)
+ values.update(header_values)
+ values.update(cookie_values)
+ errors += path_errors + query_errors + header_errors + cookie_errors
+ if dependant.body_params:
+ (
+ body_values,
+ body_errors,
+ ) = await request_body_to_args( # body_params checked above
+ body_fields=dependant.body_params,
+ received_body=body,
+ embed_body_fields=embed_body_fields,
+ )
+ values.update(body_values)
+ errors.extend(body_errors)
+ if dependant.http_connection_param_name:
+ values[dependant.http_connection_param_name] = request
+ if dependant.request_param_name and isinstance(request, Request):
+ values[dependant.request_param_name] = request
+ elif dependant.websocket_param_name and isinstance(request, WebSocket):
+ values[dependant.websocket_param_name] = request
+ if dependant.background_tasks_param_name:
+ if background_tasks is None:
+ background_tasks = BackgroundTasks()
+ values[dependant.background_tasks_param_name] = background_tasks
+ if dependant.response_param_name:
+ values[dependant.response_param_name] = response
+ if dependant.security_scopes_param_name:
+ values[dependant.security_scopes_param_name] = SecurityScopes(
+ scopes=dependant.security_scopes
+ )
+ return SolvedDependency(
+ values=values,
+ errors=errors,
+ background_tasks=background_tasks,
+ response=response,
+ dependency_cache=dependency_cache,
+ )
+
+
+def _validate_value_with_model_field(
+ *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...]
+) -> Tuple[Any, List[Any]]:
+ if value is None:
+ if field.required:
+ return None, [get_missing_field_error(loc=loc)]
+ else:
+ return deepcopy(field.default), []
+ v_, errors_ = field.validate(value, values, loc=loc)
+ if isinstance(errors_, ErrorWrapper):
+ return None, [errors_]
+ elif isinstance(errors_, list):
+ new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
+ return None, new_errors
+ else:
+ return v_, []
+
+
+def _get_multidict_value(
+ field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None
+) -> Any:
+ alias = alias or field.alias
+ if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
+ value = values.getlist(alias)
+ else:
+ value = values.get(alias, None)
+ if (
+ value is None
+ or (
+ isinstance(field.field_info, params.Form)
+ and isinstance(value, str) # For type checks
+ and value == ""
+ )
+ or (is_sequence_field(field) and len(value) == 0)
+ ):
+ if field.required:
+ return
+ else:
+ return deepcopy(field.default)
+ return value
+
+
+def request_params_to_args(
+ fields: Sequence[ModelField],
+ received_params: Union[Mapping[str, Any], QueryParams, Headers],
+) -> Tuple[Dict[str, Any], List[Any]]:
+ values: Dict[str, Any] = {}
+ errors: List[Dict[str, Any]] = []
+
+ if not fields:
+ return values, errors
+
+ first_field = fields[0]
+ fields_to_extract = fields
+ single_not_embedded_field = False
+ default_convert_underscores = True
+ if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
+ fields_to_extract = get_cached_model_fields(first_field.type_)
+ single_not_embedded_field = True
+ # If headers are in a Pydantic model, the way to disable convert_underscores
+ # would be with Header(convert_underscores=False) at the Pydantic model level
+ default_convert_underscores = getattr(
+ first_field.field_info, "convert_underscores", True
+ )
+
+ params_to_process: Dict[str, Any] = {}
+
+ processed_keys = set()
+
+ for field in fields_to_extract:
+ alias = None
+ if isinstance(received_params, Headers):
+ # Handle fields extracted from a Pydantic Model for a header, each field
+ # doesn't have a FieldInfo of type Header with the default convert_underscores=True
+ convert_underscores = getattr(
+ field.field_info, "convert_underscores", default_convert_underscores
+ )
+ if convert_underscores:
+ alias = (
+ field.alias
+ if field.alias != field.name
+ else field.name.replace("_", "-")
+ )
+ value = _get_multidict_value(field, received_params, alias=alias)
+ if value is not None:
+ params_to_process[field.name] = value
+ processed_keys.add(alias or field.alias)
+ processed_keys.add(field.name)
+
+ for key, value in received_params.items():
+ if key not in processed_keys:
+ params_to_process[key] = value
+
+ if single_not_embedded_field:
+ field_info = first_field.field_info
+ assert isinstance(field_info, params.Param), (
+ "Params must be subclasses of Param"
+ )
+ loc: Tuple[str, ...] = (field_info.in_.value,)
+ v_, errors_ = _validate_value_with_model_field(
+ field=first_field, value=params_to_process, values=values, loc=loc
+ )
+ return {first_field.name: v_}, errors_
+
+ for field in fields:
+ value = _get_multidict_value(field, received_params)
+ field_info = field.field_info
+ assert isinstance(field_info, params.Param), (
+ "Params must be subclasses of Param"
+ )
+ loc = (field_info.in_.value, field.alias)
+ v_, errors_ = _validate_value_with_model_field(
+ field=field, value=value, values=values, loc=loc
+ )
+ if errors_:
+ errors.extend(errors_)
+ else:
+ values[field.name] = v_
+ return values, errors
+
+
+def _should_embed_body_fields(fields: List[ModelField]) -> bool:
+ if not fields:
+ return False
+ # More than one dependency could have the same field, it would show up as multiple
+ # fields but it's the same one, so count them by name
+ body_param_names_set = {field.name for field in fields}
+ # A top level field has to be a single field, not multiple
+ if len(body_param_names_set) > 1:
+ return True
+ first_field = fields[0]
+ # If it explicitly specifies it is embedded, it has to be embedded
+ if getattr(first_field.field_info, "embed", None):
+ return True
+ # If it's a Form (or File) field, it has to be a BaseModel to be top level
+ # otherwise it has to be embedded, so that the key value pair can be extracted
+ if isinstance(first_field.field_info, params.Form) and not lenient_issubclass(
+ first_field.type_, BaseModel
+ ):
+ return True
+ return False
+
+
+async def _extract_form_body(
+ body_fields: List[ModelField],
+ received_body: FormData,
+) -> Dict[str, Any]:
+ values = {}
+ first_field = body_fields[0]
+ first_field_info = first_field.field_info
+
+ for field in body_fields:
+ value = _get_multidict_value(field, received_body)
+ if (
+ isinstance(first_field_info, params.File)
+ and is_bytes_field(field)
+ and isinstance(value, UploadFile)
+ ):
+ value = await value.read()
+ elif (
+ is_bytes_sequence_field(field)
+ and isinstance(first_field_info, params.File)
+ and value_is_sequence(value)
+ ):
+ # For types
+ assert isinstance(value, sequence_types) # type: ignore[arg-type]
+ results: List[Union[bytes, str]] = []
+
+ async def process_fn(
+ fn: Callable[[], Coroutine[Any, Any, Any]],
+ ) -> None:
+ result = await fn()
+ results.append(result) # noqa: B023
+
+ async with anyio.create_task_group() as tg:
+ for sub_value in value:
+ tg.start_soon(process_fn, sub_value.read)
+ value = serialize_sequence_value(field=field, value=results)
+ if value is not None:
+ values[field.alias] = value
+ for key, value in received_body.items():
+ if key not in values:
+ values[key] = value
+ return values
+
+
+async def request_body_to_args(
+ body_fields: List[ModelField],
+ received_body: Optional[Union[Dict[str, Any], FormData]],
+ embed_body_fields: bool,
+) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+ values: Dict[str, Any] = {}
+ errors: List[Dict[str, Any]] = []
+ assert body_fields, "request_body_to_args() should be called with fields"
+ single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields
+ first_field = body_fields[0]
+ body_to_process = received_body
+
+ fields_to_extract: List[ModelField] = body_fields
+
+ if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
+ fields_to_extract = get_cached_model_fields(first_field.type_)
+
+ if isinstance(received_body, FormData):
+ body_to_process = await _extract_form_body(fields_to_extract, received_body)
+
+ if single_not_embedded_field:
+ loc: Tuple[str, ...] = ("body",)
+ v_, errors_ = _validate_value_with_model_field(
+ field=first_field, value=body_to_process, values=values, loc=loc
+ )
+ return {first_field.name: v_}, errors_
+ for field in body_fields:
+ loc = ("body", field.alias)
+ value: Optional[Any] = None
+ if body_to_process is not None:
+ try:
+ value = body_to_process.get(field.alias)
+ # If the received body is a list, not a dict
+ except AttributeError:
+ errors.append(get_missing_field_error(loc))
+ continue
+ v_, errors_ = _validate_value_with_model_field(
+ field=field, value=value, values=values, loc=loc
+ )
+ if errors_:
+ errors.extend(errors_)
+ else:
+ values[field.name] = v_
+ return values, errors
+
+
+def get_body_field(
+ *, flat_dependant: Dependant, name: str, embed_body_fields: bool
+) -> Optional[ModelField]:
+ """
+ Get a ModelField representing the request body for a path operation, combining
+ all body parameters into a single field if necessary.
+
+ Used to check if it's form data (with `isinstance(body_field, params.Form)`)
+ or JSON and to generate the JSON Schema for a request body.
+
+ This is **not** used to validate/parse the request body, that's done with each
+ individual body parameter.
+ """
+ if not flat_dependant.body_params:
+ return None
+ first_param = flat_dependant.body_params[0]
+ if not embed_body_fields:
+ return first_param
+ model_name = "Body_" + name
+ BodyModel = create_body_model(
+ fields=flat_dependant.body_params, model_name=model_name
+ )
+ required = any(True for f in flat_dependant.body_params if f.required)
+ BodyFieldInfo_kwargs: Dict[str, Any] = {
+ "annotation": BodyModel,
+ "alias": "body",
+ }
+ if not required:
+ BodyFieldInfo_kwargs["default"] = None
+ if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):
+ BodyFieldInfo: Type[params.Body] = params.File
+ elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
+ BodyFieldInfo = params.Form
+ else:
+ BodyFieldInfo = params.Body
+
+ body_param_media_types = [
+ f.field_info.media_type
+ for f in flat_dependant.body_params
+ if isinstance(f.field_info, params.Body)
+ ]
+ if len(set(body_param_media_types)) == 1:
+ BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0]
+ final_field = create_model_field(
+ name="body",
+ type_=BodyModel,
+ required=required,
+ alias="body",
+ field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),
+ )
+ return final_field
diff --git a/.venv/lib/python3.12/site-packages/fastapi/encoders.py b/.venv/lib/python3.12/site-packages/fastapi/encoders.py
new file mode 100644
index 00000000..451ea076
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/encoders.py
@@ -0,0 +1,343 @@
+import dataclasses
+import datetime
+from collections import defaultdict, deque
+from decimal import Decimal
+from enum import Enum
+from ipaddress import (
+ IPv4Address,
+ IPv4Interface,
+ IPv4Network,
+ IPv6Address,
+ IPv6Interface,
+ IPv6Network,
+)
+from pathlib import Path, PurePath
+from re import Pattern
+from types import GeneratorType
+from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
+from uuid import UUID
+
+from fastapi.types import IncEx
+from pydantic import BaseModel
+from pydantic.color import Color
+from pydantic.networks import AnyUrl, NameEmail
+from pydantic.types import SecretBytes, SecretStr
+from typing_extensions import Annotated, Doc
+
+from ._compat import PYDANTIC_V2, UndefinedType, Url, _model_dump
+
+
+# Taken from Pydantic v1 as is
+def isoformat(o: Union[datetime.date, datetime.time]) -> str:
+ return o.isoformat()
+
+
+# Taken from Pydantic v1 as is
+# TODO: pv2 should this return strings instead?
+def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
+ """
+ Encodes a Decimal as int of there's no exponent, otherwise float
+
+ This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
+ where a integer (but not int typed) is used. Encoding this as a float
+ results in failed round-tripping between encode and parse.
+ Our Id type is a prime example of this.
+
+ >>> decimal_encoder(Decimal("1.0"))
+ 1.0
+
+ >>> decimal_encoder(Decimal("1"))
+ 1
+ """
+ if dec_value.as_tuple().exponent >= 0: # type: ignore[operator]
+ return int(dec_value)
+ else:
+ return float(dec_value)
+
+
+ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
+ bytes: lambda o: o.decode(),
+ Color: str,
+ datetime.date: isoformat,
+ datetime.datetime: isoformat,
+ datetime.time: isoformat,
+ datetime.timedelta: lambda td: td.total_seconds(),
+ Decimal: decimal_encoder,
+ Enum: lambda o: o.value,
+ frozenset: list,
+ deque: list,
+ GeneratorType: list,
+ IPv4Address: str,
+ IPv4Interface: str,
+ IPv4Network: str,
+ IPv6Address: str,
+ IPv6Interface: str,
+ IPv6Network: str,
+ NameEmail: str,
+ Path: str,
+ Pattern: lambda o: o.pattern,
+ SecretBytes: str,
+ SecretStr: str,
+ set: list,
+ UUID: str,
+ Url: str,
+ AnyUrl: str,
+}
+
+
+def generate_encoders_by_class_tuples(
+ type_encoder_map: Dict[Any, Callable[[Any], Any]],
+) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
+ encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
+ tuple
+ )
+ for type_, encoder in type_encoder_map.items():
+ encoders_by_class_tuples[encoder] += (type_,)
+ return encoders_by_class_tuples
+
+
+encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
+
+
+def jsonable_encoder(
+ obj: Annotated[
+ Any,
+ Doc(
+ """
+ The input object to convert to JSON.
+ """
+ ),
+ ],
+ include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Pydantic's `include` parameter, passed to Pydantic models to set the
+ fields to include.
+ """
+ ),
+ ] = None,
+ exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Pydantic's `exclude` parameter, passed to Pydantic models to set the
+ fields to exclude.
+ """
+ ),
+ ] = None,
+ by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `by_alias` parameter, passed to Pydantic models to define if
+ the output should use the alias names (when provided) or the Python
+ attribute names. In an API, if you set an alias, it's probably because you
+ want to use it in the result, so you probably want to leave this set to
+ `True`.
+ """
+ ),
+ ] = True,
+ exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_unset` parameter, passed to Pydantic models to define
+ if it should exclude from the output the fields that were not explicitly
+ set (and that only had their default values).
+ """
+ ),
+ ] = False,
+ exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define
+ if it should exclude from the output the fields that had the same default
+ value, even when they were explicitly set.
+ """
+ ),
+ ] = False,
+ exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_none` parameter, passed to Pydantic models to define
+ if it should exclude from the output any fields that have a `None` value.
+ """
+ ),
+ ] = False,
+ custom_encoder: Annotated[
+ Optional[Dict[Any, Callable[[Any], Any]]],
+ Doc(
+ """
+ Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
+ a custom encoder.
+ """
+ ),
+ ] = None,
+ sqlalchemy_safe: Annotated[
+ bool,
+ Doc(
+ """
+ Exclude from the output any fields that start with the name `_sa`.
+
+ This is mainly a hack for compatibility with SQLAlchemy objects, they
+ store internal SQLAlchemy-specific state in attributes named with `_sa`,
+ and those objects can't (and shouldn't be) serialized to JSON.
+ """
+ ),
+ ] = True,
+) -> Any:
+ """
+ Convert any object to something that can be encoded in JSON.
+
+ This is used internally by FastAPI to make sure anything you return can be
+ encoded as JSON before it is sent to the client.
+
+ You can also use it yourself, for example to convert objects before saving them
+ in a database that supports only JSON.
+
+ Read more about it in the
+ [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
+ """
+ custom_encoder = custom_encoder or {}
+ if custom_encoder:
+ if type(obj) in custom_encoder:
+ return custom_encoder[type(obj)](obj)
+ else:
+ for encoder_type, encoder_instance in custom_encoder.items():
+ if isinstance(obj, encoder_type):
+ return encoder_instance(obj)
+ if include is not None and not isinstance(include, (set, dict)):
+ include = set(include)
+ if exclude is not None and not isinstance(exclude, (set, dict)):
+ exclude = set(exclude)
+ if isinstance(obj, BaseModel):
+ # TODO: remove when deprecating Pydantic v1
+ encoders: Dict[Any, Any] = {}
+ if not PYDANTIC_V2:
+ encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
+ if custom_encoder:
+ encoders.update(custom_encoder)
+ obj_dict = _model_dump(
+ obj,
+ mode="json",
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_none=exclude_none,
+ exclude_defaults=exclude_defaults,
+ )
+ if "__root__" in obj_dict:
+ obj_dict = obj_dict["__root__"]
+ return jsonable_encoder(
+ obj_dict,
+ exclude_none=exclude_none,
+ exclude_defaults=exclude_defaults,
+ # TODO: remove when deprecating Pydantic v1
+ custom_encoder=encoders,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
+ if dataclasses.is_dataclass(obj):
+ obj_dict = dataclasses.asdict(obj)
+ return jsonable_encoder(
+ obj_dict,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ custom_encoder=custom_encoder,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
+ if isinstance(obj, Enum):
+ return obj.value
+ if isinstance(obj, PurePath):
+ return str(obj)
+ if isinstance(obj, (str, int, float, type(None))):
+ return obj
+ if isinstance(obj, UndefinedType):
+ return None
+ if isinstance(obj, dict):
+ encoded_dict = {}
+ allowed_keys = set(obj.keys())
+ if include is not None:
+ allowed_keys &= set(include)
+ if exclude is not None:
+ allowed_keys -= set(exclude)
+ for key, value in obj.items():
+ if (
+ (
+ not sqlalchemy_safe
+ or (not isinstance(key, str))
+ or (not key.startswith("_sa"))
+ )
+ and (value is not None or not exclude_none)
+ and key in allowed_keys
+ ):
+ encoded_key = jsonable_encoder(
+ key,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_none=exclude_none,
+ custom_encoder=custom_encoder,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
+ encoded_value = jsonable_encoder(
+ value,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_none=exclude_none,
+ custom_encoder=custom_encoder,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
+ encoded_dict[encoded_key] = encoded_value
+ return encoded_dict
+ if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)):
+ encoded_list = []
+ for item in obj:
+ encoded_list.append(
+ jsonable_encoder(
+ item,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ custom_encoder=custom_encoder,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
+ )
+ return encoded_list
+
+ if type(obj) in ENCODERS_BY_TYPE:
+ return ENCODERS_BY_TYPE[type(obj)](obj)
+ for encoder, classes_tuple in encoders_by_class_tuples.items():
+ if isinstance(obj, classes_tuple):
+ return encoder(obj)
+
+ try:
+ data = dict(obj)
+ except Exception as e:
+ errors: List[Exception] = []
+ errors.append(e)
+ try:
+ data = vars(obj)
+ except Exception as e:
+ errors.append(e)
+ raise ValueError(errors) from e
+ return jsonable_encoder(
+ data,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ custom_encoder=custom_encoder,
+ sqlalchemy_safe=sqlalchemy_safe,
+ )
diff --git a/.venv/lib/python3.12/site-packages/fastapi/exception_handlers.py b/.venv/lib/python3.12/site-packages/fastapi/exception_handlers.py
new file mode 100644
index 00000000..6c2ba7fe
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/exception_handlers.py
@@ -0,0 +1,34 @@
+from fastapi.encoders import jsonable_encoder
+from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
+from fastapi.utils import is_body_allowed_for_status_code
+from fastapi.websockets import WebSocket
+from starlette.exceptions import HTTPException
+from starlette.requests import Request
+from starlette.responses import JSONResponse, Response
+from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
+
+
+async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
+ headers = getattr(exc, "headers", None)
+ if not is_body_allowed_for_status_code(exc.status_code):
+ return Response(status_code=exc.status_code, headers=headers)
+ return JSONResponse(
+ {"detail": exc.detail}, status_code=exc.status_code, headers=headers
+ )
+
+
+async def request_validation_exception_handler(
+ request: Request, exc: RequestValidationError
+) -> JSONResponse:
+ return JSONResponse(
+ status_code=HTTP_422_UNPROCESSABLE_ENTITY,
+ content={"detail": jsonable_encoder(exc.errors())},
+ )
+
+
+async def websocket_request_validation_exception_handler(
+ websocket: WebSocket, exc: WebSocketRequestValidationError
+) -> None:
+ await websocket.close(
+ code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())
+ )
diff --git a/.venv/lib/python3.12/site-packages/fastapi/exceptions.py b/.venv/lib/python3.12/site-packages/fastapi/exceptions.py
new file mode 100644
index 00000000..44d4ada8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/exceptions.py
@@ -0,0 +1,176 @@
+from typing import Any, Dict, Optional, Sequence, Type, Union
+
+from pydantic import BaseModel, create_model
+from starlette.exceptions import HTTPException as StarletteHTTPException
+from starlette.exceptions import WebSocketException as StarletteWebSocketException
+from typing_extensions import Annotated, Doc
+
+
+class HTTPException(StarletteHTTPException):
+ """
+ An HTTP exception you can raise in your own code to show errors to the client.
+
+ This is for client errors, invalid authentication, invalid data, etc. Not for server
+ errors in your code.
+
+ Read more about it in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, HTTPException
+
+ app = FastAPI()
+
+ items = {"foo": "The Foo Wrestlers"}
+
+
+ @app.get("/items/{item_id}")
+ async def read_item(item_id: str):
+ if item_id not in items:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return {"item": items[item_id]}
+ ```
+ """
+
+ def __init__(
+ self,
+ status_code: Annotated[
+ int,
+ Doc(
+ """
+ HTTP status code to send to the client.
+ """
+ ),
+ ],
+ detail: Annotated[
+ Any,
+ Doc(
+ """
+ Any data to be sent to the client in the `detail` key of the JSON
+ response.
+ """
+ ),
+ ] = None,
+ headers: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ Any headers to send to the client in the response.
+ """
+ ),
+ ] = None,
+ ) -> None:
+ super().__init__(status_code=status_code, detail=detail, headers=headers)
+
+
+class WebSocketException(StarletteWebSocketException):
+ """
+ A WebSocket exception you can raise in your own code to show errors to the client.
+
+ This is for client errors, invalid authentication, invalid data, etc. Not for server
+ errors in your code.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import (
+ Cookie,
+ FastAPI,
+ WebSocket,
+ WebSocketException,
+ status,
+ )
+
+ app = FastAPI()
+
+ @app.websocket("/items/{item_id}/ws")
+ async def websocket_endpoint(
+ *,
+ websocket: WebSocket,
+ session: Annotated[str | None, Cookie()] = None,
+ item_id: str,
+ ):
+ if session is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Session cookie is: {session}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
+ ```
+ """
+
+ def __init__(
+ self,
+ code: Annotated[
+ int,
+ Doc(
+ """
+ A closing code from the
+ [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1).
+ """
+ ),
+ ],
+ reason: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ The reason to close the WebSocket connection.
+
+ It is UTF-8-encoded data. The interpretation of the reason is up to the
+ application, it is not specified by the WebSocket specification.
+
+ It could contain text that could be human-readable or interpretable
+ by the client code, etc.
+ """
+ ),
+ ] = None,
+ ) -> None:
+ super().__init__(code=code, reason=reason)
+
+
+RequestErrorModel: Type[BaseModel] = create_model("Request")
+WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket")
+
+
+class FastAPIError(RuntimeError):
+ """
+ A generic, FastAPI-specific error.
+ """
+
+
+class ValidationException(Exception):
+ def __init__(self, errors: Sequence[Any]) -> None:
+ self._errors = errors
+
+ def errors(self) -> Sequence[Any]:
+ return self._errors
+
+
+class RequestValidationError(ValidationException):
+ def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
+ super().__init__(errors)
+ self.body = body
+
+
+class WebSocketRequestValidationError(ValidationException):
+ pass
+
+
+class ResponseValidationError(ValidationException):
+ def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
+ super().__init__(errors)
+ self.body = body
+
+ def __str__(self) -> str:
+ message = f"{len(self._errors)} validation errors:\n"
+ for err in self._errors:
+ message += f" {err}\n"
+ return message
diff --git a/.venv/lib/python3.12/site-packages/fastapi/logger.py b/.venv/lib/python3.12/site-packages/fastapi/logger.py
new file mode 100644
index 00000000..5b2c4ad5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/logger.py
@@ -0,0 +1,3 @@
+import logging
+
+logger = logging.getLogger("fastapi")
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/__init__.py
new file mode 100644
index 00000000..620296d5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/__init__.py
@@ -0,0 +1 @@
+from starlette.middleware import Middleware as Middleware
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/cors.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/cors.py
new file mode 100644
index 00000000..8dfaad0d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/cors.py
@@ -0,0 +1 @@
+from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/gzip.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/gzip.py
new file mode 100644
index 00000000..bbeb2cc7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/gzip.py
@@ -0,0 +1 @@
+from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py
new file mode 100644
index 00000000..b7a3d8e0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/httpsredirect.py
@@ -0,0 +1,3 @@
+from starlette.middleware.httpsredirect import ( # noqa
+ HTTPSRedirectMiddleware as HTTPSRedirectMiddleware,
+)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/trustedhost.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/trustedhost.py
new file mode 100644
index 00000000..08d7e035
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/trustedhost.py
@@ -0,0 +1,3 @@
+from starlette.middleware.trustedhost import ( # noqa
+ TrustedHostMiddleware as TrustedHostMiddleware,
+)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/middleware/wsgi.py b/.venv/lib/python3.12/site-packages/fastapi/middleware/wsgi.py
new file mode 100644
index 00000000..c4c6a797
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/middleware/wsgi.py
@@ -0,0 +1 @@
+from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py
new file mode 100644
index 00000000..d724ee3c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/constants.py
@@ -0,0 +1,3 @@
+METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
+REF_PREFIX = "#/components/schemas/"
+REF_TEMPLATE = "#/components/schemas/{model}"
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py
new file mode 100644
index 00000000..c2ec358d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/docs.py
@@ -0,0 +1,344 @@
+import json
+from typing import Any, Dict, Optional
+
+from fastapi.encoders import jsonable_encoder
+from starlette.responses import HTMLResponse
+from typing_extensions import Annotated, Doc
+
+swagger_ui_default_parameters: Annotated[
+ Dict[str, Any],
+ Doc(
+ """
+ Default configurations for Swagger UI.
+
+ You can use it as a template to add any other configurations needed.
+ """
+ ),
+] = {
+ "dom_id": "#swagger-ui",
+ "layout": "BaseLayout",
+ "deepLinking": True,
+ "showExtensions": True,
+ "showCommonExtensions": True,
+}
+
+
+def get_swagger_ui_html(
+ *,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that Swagger UI should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `<title>` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ swagger_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
+ swagger_css_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI CSS.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
+ swagger_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ oauth2_redirect_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
+ """
+ ),
+ ] = None,
+ init_oauth: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ A dictionary with Swagger UI OAuth2 initialization configurations.
+ """
+ ),
+ ] = None,
+ swagger_ui_parameters: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Configuration parameters for Swagger UI.
+
+ It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters].
+ """
+ ),
+ ] = None,
+) -> HTMLResponse:
+ """
+ Generate and return the HTML that loads Swagger UI for the interactive
+ API docs (normally served at `/docs`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load Swagger UI's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/)
+ and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
+ current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
+ if swagger_ui_parameters:
+ current_swagger_ui_parameters.update(swagger_ui_parameters)
+
+ html = f"""
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <link type="text/css" rel="stylesheet" href="{swagger_css_url}">
+ <link rel="shortcut icon" href="{swagger_favicon_url}">
+ <title>{title}</title>
+ </head>
+ <body>
+ <div id="swagger-ui">
+ </div>
+ <script src="{swagger_js_url}"></script>
+ <!-- `SwaggerUIBundle` is now available on the page -->
+ <script>
+ const ui = SwaggerUIBundle({{
+ url: '{openapi_url}',
+ """
+
+ for key, value in current_swagger_ui_parameters.items():
+ html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"
+
+ if oauth2_redirect_url:
+ html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
+
+ html += """
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+ ],
+ })"""
+
+ if init_oauth:
+ html += f"""
+ ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
+ """
+
+ html += """
+ </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(html)
+
+
+def get_redoc_html(
+ *,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that ReDoc should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `<title>` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ redoc_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the ReDoc JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
+ redoc_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ with_google_fonts: Annotated[
+ bool,
+ Doc(
+ """
+ Load and use Google Fonts.
+ """
+ ),
+ ] = True,
+) -> HTMLResponse:
+ """
+ Generate and return the HTML response that loads ReDoc for the alternative
+ API docs (normally served at `/redoc`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load ReDoc's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
+ html = f"""
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>{title}</title>
+ <!-- needed for adaptive design -->
+ <meta charset="utf-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ """
+ if with_google_fonts:
+ html += """
+ <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
+ """
+ html += f"""
+ <link rel="shortcut icon" href="{redoc_favicon_url}">
+ <!--
+ ReDoc doesn't change outer page styles
+ -->
+ <style>
+ body {{
+ margin: 0;
+ padding: 0;
+ }}
+ </style>
+ </head>
+ <body>
+ <noscript>
+ ReDoc requires Javascript to function. Please enable it to browse the documentation.
+ </noscript>
+ <redoc spec-url="{openapi_url}"></redoc>
+ <script src="{redoc_js_url}"> </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(html)
+
+
+def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:
+ """
+ Generate the HTML response with the OAuth2 redirection for Swagger UI.
+
+ You normally don't need to use or change this.
+ """
+ # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html
+ html = """
+ <!doctype html>
+ <html lang="en-US">
+ <head>
+ <title>Swagger UI: OAuth2 Redirect</title>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ function run () {
+ var oauth2 = window.opener.swaggerUIRedirectOauth2;
+ var sentState = oauth2.state;
+ var redirectUrl = oauth2.redirectUrl;
+ var isValid, qp, arr;
+
+ if (/code|token|error/.test(window.location.hash)) {
+ qp = window.location.hash.substring(1).replace('?', '&');
+ } else {
+ qp = location.search.substring(1);
+ }
+
+ arr = qp.split("&");
+ arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
+ qp = qp ? JSON.parse('{' + arr.join() + '}',
+ function (key, value) {
+ return key === "" ? value : decodeURIComponent(value);
+ }
+ ) : {};
+
+ isValid = qp.state === sentState;
+
+ if ((
+ oauth2.auth.schema.get("flow") === "accessCode" ||
+ oauth2.auth.schema.get("flow") === "authorizationCode" ||
+ oauth2.auth.schema.get("flow") === "authorization_code"
+ ) && !oauth2.auth.code) {
+ if (!isValid) {
+ oauth2.errCb({
+ authId: oauth2.auth.name,
+ source: "auth",
+ level: "warning",
+ message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
+ });
+ }
+
+ if (qp.code) {
+ delete oauth2.state;
+ oauth2.auth.code = qp.code;
+ oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
+ } else {
+ let oauthErrorMsg;
+ if (qp.error) {
+ oauthErrorMsg = "["+qp.error+"]: " +
+ (qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
+ (qp.error_uri ? "More info: "+qp.error_uri : "");
+ }
+
+ oauth2.errCb({
+ authId: oauth2.auth.name,
+ source: "auth",
+ level: "error",
+ message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
+ });
+ }
+ } else {
+ oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
+ }
+ window.close();
+ }
+
+ if (document.readyState !== 'loading') {
+ run();
+ } else {
+ document.addEventListener('DOMContentLoaded', function () {
+ run();
+ });
+ }
+ </script>
+ </body>
+ </html>
+ """
+ return HTMLResponse(content=html)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py
new file mode 100644
index 00000000..ed07b40f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/models.py
@@ -0,0 +1,445 @@
+from enum import Enum
+from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union
+
+from fastapi._compat import (
+ PYDANTIC_V2,
+ CoreSchema,
+ GetJsonSchemaHandler,
+ JsonSchemaValue,
+ _model_rebuild,
+ with_info_plain_validator_function,
+)
+from fastapi.logger import logger
+from pydantic import AnyUrl, BaseModel, Field
+from typing_extensions import Annotated, Literal, TypedDict
+from typing_extensions import deprecated as typing_deprecated
+
+try:
+ import email_validator
+
+ assert email_validator # make autoflake ignore the unused import
+ from pydantic import EmailStr
+except ImportError: # pragma: no cover
+
+ class EmailStr(str): # type: ignore
+ @classmethod
+ def __get_validators__(cls) -> Iterable[Callable[..., Any]]:
+ yield cls.validate
+
+ @classmethod
+ def validate(cls, v: Any) -> str:
+ logger.warning(
+ "email-validator not installed, email fields will be treated as str.\n"
+ "To install, run: pip install email-validator"
+ )
+ return str(v)
+
+ @classmethod
+ def _validate(cls, __input_value: Any, _: Any) -> str:
+ logger.warning(
+ "email-validator not installed, email fields will be treated as str.\n"
+ "To install, run: pip install email-validator"
+ )
+ return str(__input_value)
+
+ @classmethod
+ def __get_pydantic_json_schema__(
+ cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
+ ) -> JsonSchemaValue:
+ return {"type": "string", "format": "email"}
+
+ @classmethod
+ def __get_pydantic_core_schema__(
+ cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
+ ) -> CoreSchema:
+ return with_info_plain_validator_function(cls._validate)
+
+
+class BaseModelWithConfig(BaseModel):
+ if PYDANTIC_V2:
+ model_config = {"extra": "allow"}
+
+ else:
+
+ class Config:
+ extra = "allow"
+
+
+class Contact(BaseModelWithConfig):
+ name: Optional[str] = None
+ url: Optional[AnyUrl] = None
+ email: Optional[EmailStr] = None
+
+
+class License(BaseModelWithConfig):
+ name: str
+ identifier: Optional[str] = None
+ url: Optional[AnyUrl] = None
+
+
+class Info(BaseModelWithConfig):
+ title: str
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ termsOfService: Optional[str] = None
+ contact: Optional[Contact] = None
+ license: Optional[License] = None
+ version: str
+
+
+class ServerVariable(BaseModelWithConfig):
+ enum: Annotated[Optional[List[str]], Field(min_length=1)] = None
+ default: str
+ description: Optional[str] = None
+
+
+class Server(BaseModelWithConfig):
+ url: Union[AnyUrl, str]
+ description: Optional[str] = None
+ variables: Optional[Dict[str, ServerVariable]] = None
+
+
+class Reference(BaseModel):
+ ref: str = Field(alias="$ref")
+
+
+class Discriminator(BaseModel):
+ propertyName: str
+ mapping: Optional[Dict[str, str]] = None
+
+
+class XML(BaseModelWithConfig):
+ name: Optional[str] = None
+ namespace: Optional[str] = None
+ prefix: Optional[str] = None
+ attribute: Optional[bool] = None
+ wrapped: Optional[bool] = None
+
+
+class ExternalDocumentation(BaseModelWithConfig):
+ description: Optional[str] = None
+ url: AnyUrl
+
+
+class Schema(BaseModelWithConfig):
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
+ # Core Vocabulary
+ schema_: Optional[str] = Field(default=None, alias="$schema")
+ vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
+ id: Optional[str] = Field(default=None, alias="$id")
+ anchor: Optional[str] = Field(default=None, alias="$anchor")
+ dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
+ ref: Optional[str] = Field(default=None, alias="$ref")
+ dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
+ defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs")
+ comment: Optional[str] = Field(default=None, alias="$comment")
+ # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
+ # A Vocabulary for Applying Subschemas
+ allOf: Optional[List["SchemaOrBool"]] = None
+ anyOf: Optional[List["SchemaOrBool"]] = None
+ oneOf: Optional[List["SchemaOrBool"]] = None
+ not_: Optional["SchemaOrBool"] = Field(default=None, alias="not")
+ if_: Optional["SchemaOrBool"] = Field(default=None, alias="if")
+ then: Optional["SchemaOrBool"] = None
+ else_: Optional["SchemaOrBool"] = Field(default=None, alias="else")
+ dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None
+ prefixItems: Optional[List["SchemaOrBool"]] = None
+ # TODO: uncomment and remove below when deprecating Pydantic v1
+ # It generales a list of schemas for tuples, before prefixItems was available
+ # items: Optional["SchemaOrBool"] = None
+ items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None
+ contains: Optional["SchemaOrBool"] = None
+ properties: Optional[Dict[str, "SchemaOrBool"]] = None
+ patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None
+ additionalProperties: Optional["SchemaOrBool"] = None
+ propertyNames: Optional["SchemaOrBool"] = None
+ unevaluatedItems: Optional["SchemaOrBool"] = None
+ unevaluatedProperties: Optional["SchemaOrBool"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
+ # A Vocabulary for Structural Validation
+ type: Optional[str] = None
+ enum: Optional[List[Any]] = None
+ const: Optional[Any] = None
+ multipleOf: Optional[float] = Field(default=None, gt=0)
+ maximum: Optional[float] = None
+ exclusiveMaximum: Optional[float] = None
+ minimum: Optional[float] = None
+ exclusiveMinimum: Optional[float] = None
+ maxLength: Optional[int] = Field(default=None, ge=0)
+ minLength: Optional[int] = Field(default=None, ge=0)
+ pattern: Optional[str] = None
+ maxItems: Optional[int] = Field(default=None, ge=0)
+ minItems: Optional[int] = Field(default=None, ge=0)
+ uniqueItems: Optional[bool] = None
+ maxContains: Optional[int] = Field(default=None, ge=0)
+ minContains: Optional[int] = Field(default=None, ge=0)
+ maxProperties: Optional[int] = Field(default=None, ge=0)
+ minProperties: Optional[int] = Field(default=None, ge=0)
+ required: Optional[List[str]] = None
+ dependentRequired: Optional[Dict[str, Set[str]]] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
+ # Vocabularies for Semantic Content With "format"
+ format: Optional[str] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
+ # A Vocabulary for the Contents of String-Encoded Data
+ contentEncoding: Optional[str] = None
+ contentMediaType: Optional[str] = None
+ contentSchema: Optional["SchemaOrBool"] = None
+ # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
+ # A Vocabulary for Basic Meta-Data Annotations
+ title: Optional[str] = None
+ description: Optional[str] = None
+ default: Optional[Any] = None
+ deprecated: Optional[bool] = None
+ readOnly: Optional[bool] = None
+ writeOnly: Optional[bool] = None
+ examples: Optional[List[Any]] = None
+ # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
+ # Schema Object
+ discriminator: Optional[Discriminator] = None
+ xml: Optional[XML] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+ example: Annotated[
+ Optional[Any],
+ typing_deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = None
+
+
+# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
+# A JSON Schema MUST be an object or a boolean.
+SchemaOrBool = Union[Schema, bool]
+
+
+class Example(TypedDict, total=False):
+ summary: Optional[str]
+ description: Optional[str]
+ value: Optional[Any]
+ externalValue: Optional[AnyUrl]
+
+ if PYDANTIC_V2: # type: ignore [misc]
+ __pydantic_config__ = {"extra": "allow"}
+
+ else:
+
+ class Config:
+ extra = "allow"
+
+
+class ParameterInType(Enum):
+ query = "query"
+ header = "header"
+ path = "path"
+ cookie = "cookie"
+
+
+class Encoding(BaseModelWithConfig):
+ contentType: Optional[str] = None
+ headers: Optional[Dict[str, Union["Header", Reference]]] = None
+ style: Optional[str] = None
+ explode: Optional[bool] = None
+ allowReserved: Optional[bool] = None
+
+
+class MediaType(BaseModelWithConfig):
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
+ example: Optional[Any] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ encoding: Optional[Dict[str, Encoding]] = None
+
+
+class ParameterBase(BaseModelWithConfig):
+ description: Optional[str] = None
+ required: Optional[bool] = None
+ deprecated: Optional[bool] = None
+ # Serialization rules for simple scenarios
+ style: Optional[str] = None
+ explode: Optional[bool] = None
+ allowReserved: Optional[bool] = None
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
+ example: Optional[Any] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ # Serialization rules for more complex scenarios
+ content: Optional[Dict[str, MediaType]] = None
+
+
+class Parameter(ParameterBase):
+ name: str
+ in_: ParameterInType = Field(alias="in")
+
+
+class Header(ParameterBase):
+ pass
+
+
+class RequestBody(BaseModelWithConfig):
+ description: Optional[str] = None
+ content: Dict[str, MediaType]
+ required: Optional[bool] = None
+
+
+class Link(BaseModelWithConfig):
+ operationRef: Optional[str] = None
+ operationId: Optional[str] = None
+ parameters: Optional[Dict[str, Union[Any, str]]] = None
+ requestBody: Optional[Union[Any, str]] = None
+ description: Optional[str] = None
+ server: Optional[Server] = None
+
+
+class Response(BaseModelWithConfig):
+ description: str
+ headers: Optional[Dict[str, Union[Header, Reference]]] = None
+ content: Optional[Dict[str, MediaType]] = None
+ links: Optional[Dict[str, Union[Link, Reference]]] = None
+
+
+class Operation(BaseModelWithConfig):
+ tags: Optional[List[str]] = None
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+ operationId: Optional[str] = None
+ parameters: Optional[List[Union[Parameter, Reference]]] = None
+ requestBody: Optional[Union[RequestBody, Reference]] = None
+ # Using Any for Specification Extensions
+ responses: Optional[Dict[str, Union[Response, Any]]] = None
+ callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None
+ deprecated: Optional[bool] = None
+ security: Optional[List[Dict[str, List[str]]]] = None
+ servers: Optional[List[Server]] = None
+
+
+class PathItem(BaseModelWithConfig):
+ ref: Optional[str] = Field(default=None, alias="$ref")
+ summary: Optional[str] = None
+ description: Optional[str] = None
+ get: Optional[Operation] = None
+ put: Optional[Operation] = None
+ post: Optional[Operation] = None
+ delete: Optional[Operation] = None
+ options: Optional[Operation] = None
+ head: Optional[Operation] = None
+ patch: Optional[Operation] = None
+ trace: Optional[Operation] = None
+ servers: Optional[List[Server]] = None
+ parameters: Optional[List[Union[Parameter, Reference]]] = None
+
+
+class SecuritySchemeType(Enum):
+ apiKey = "apiKey"
+ http = "http"
+ oauth2 = "oauth2"
+ openIdConnect = "openIdConnect"
+
+
+class SecurityBase(BaseModelWithConfig):
+ type_: SecuritySchemeType = Field(alias="type")
+ description: Optional[str] = None
+
+
+class APIKeyIn(Enum):
+ query = "query"
+ header = "header"
+ cookie = "cookie"
+
+
+class APIKey(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type")
+ in_: APIKeyIn = Field(alias="in")
+ name: str
+
+
+class HTTPBase(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type")
+ scheme: str
+
+
+class HTTPBearer(HTTPBase):
+ scheme: Literal["bearer"] = "bearer"
+ bearerFormat: Optional[str] = None
+
+
+class OAuthFlow(BaseModelWithConfig):
+ refreshUrl: Optional[str] = None
+ scopes: Dict[str, str] = {}
+
+
+class OAuthFlowImplicit(OAuthFlow):
+ authorizationUrl: str
+
+
+class OAuthFlowPassword(OAuthFlow):
+ tokenUrl: str
+
+
+class OAuthFlowClientCredentials(OAuthFlow):
+ tokenUrl: str
+
+
+class OAuthFlowAuthorizationCode(OAuthFlow):
+ authorizationUrl: str
+ tokenUrl: str
+
+
+class OAuthFlows(BaseModelWithConfig):
+ implicit: Optional[OAuthFlowImplicit] = None
+ password: Optional[OAuthFlowPassword] = None
+ clientCredentials: Optional[OAuthFlowClientCredentials] = None
+ authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
+
+
+class OAuth2(SecurityBase):
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
+ flows: OAuthFlows
+
+
+class OpenIdConnect(SecurityBase):
+ type_: SecuritySchemeType = Field(
+ default=SecuritySchemeType.openIdConnect, alias="type"
+ )
+ openIdConnectUrl: str
+
+
+SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
+
+
+class Components(BaseModelWithConfig):
+ schemas: Optional[Dict[str, Union[Schema, Reference]]] = None
+ responses: Optional[Dict[str, Union[Response, Reference]]] = None
+ parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None
+ examples: Optional[Dict[str, Union[Example, Reference]]] = None
+ requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None
+ headers: Optional[Dict[str, Union[Header, Reference]]] = None
+ securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None
+ links: Optional[Dict[str, Union[Link, Reference]]] = None
+ # Using Any for Specification Extensions
+ callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
+ pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None
+
+
+class Tag(BaseModelWithConfig):
+ name: str
+ description: Optional[str] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+
+
+class OpenAPI(BaseModelWithConfig):
+ openapi: str
+ info: Info
+ jsonSchemaDialect: Optional[str] = None
+ servers: Optional[List[Server]] = None
+ # Using Any for Specification Extensions
+ paths: Optional[Dict[str, Union[PathItem, Any]]] = None
+ webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None
+ components: Optional[Components] = None
+ security: Optional[List[Dict[str, List[str]]]] = None
+ tags: Optional[List[Tag]] = None
+ externalDocs: Optional[ExternalDocumentation] = None
+
+
+_model_rebuild(Schema)
+_model_rebuild(Operation)
+_model_rebuild(Encoding)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py b/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py
new file mode 100644
index 00000000..808646cc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/openapi/utils.py
@@ -0,0 +1,569 @@
+import http.client
+import inspect
+import warnings
+from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
+
+from fastapi import routing
+from fastapi._compat import (
+ GenerateJsonSchema,
+ JsonSchemaValue,
+ ModelField,
+ Undefined,
+ get_compat_model_name_map,
+ get_definitions,
+ get_schema_from_model_field,
+ lenient_issubclass,
+)
+from fastapi.datastructures import DefaultPlaceholder
+from fastapi.dependencies.models import Dependant
+from fastapi.dependencies.utils import (
+ _get_flat_fields_from_params,
+ get_flat_dependant,
+ get_flat_params,
+)
+from fastapi.encoders import jsonable_encoder
+from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
+from fastapi.openapi.models import OpenAPI
+from fastapi.params import Body, ParamTypes
+from fastapi.responses import Response
+from fastapi.types import ModelNameMap
+from fastapi.utils import (
+ deep_dict_update,
+ generate_operation_id_for_path,
+ is_body_allowed_for_status_code,
+)
+from pydantic import BaseModel
+from starlette.responses import JSONResponse
+from starlette.routing import BaseRoute
+from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
+from typing_extensions import Literal
+
+validation_error_definition = {
+ "title": "ValidationError",
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ "required": ["loc", "msg", "type"],
+}
+
+validation_error_response_definition = {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": REF_PREFIX + "ValidationError"},
+ }
+ },
+}
+
+status_code_ranges: Dict[str, str] = {
+ "1XX": "Information",
+ "2XX": "Success",
+ "3XX": "Redirection",
+ "4XX": "Client Error",
+ "5XX": "Server Error",
+ "DEFAULT": "Default Response",
+}
+
+
+def get_openapi_security_definitions(
+ flat_dependant: Dependant,
+) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+ security_definitions = {}
+ operation_security = []
+ for security_requirement in flat_dependant.security_requirements:
+ security_definition = jsonable_encoder(
+ security_requirement.security_scheme.model,
+ by_alias=True,
+ exclude_none=True,
+ )
+ security_name = security_requirement.security_scheme.scheme_name
+ security_definitions[security_name] = security_definition
+ operation_security.append({security_name: security_requirement.scopes})
+ return security_definitions, operation_security
+
+
+def _get_openapi_operation_parameters(
+ *,
+ dependant: Dependant,
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> List[Dict[str, Any]]:
+ parameters = []
+ flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
+ path_params = _get_flat_fields_from_params(flat_dependant.path_params)
+ query_params = _get_flat_fields_from_params(flat_dependant.query_params)
+ header_params = _get_flat_fields_from_params(flat_dependant.header_params)
+ cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
+ parameter_groups = [
+ (ParamTypes.path, path_params),
+ (ParamTypes.query, query_params),
+ (ParamTypes.header, header_params),
+ (ParamTypes.cookie, cookie_params),
+ ]
+ default_convert_underscores = True
+ if len(flat_dependant.header_params) == 1:
+ first_field = flat_dependant.header_params[0]
+ if lenient_issubclass(first_field.type_, BaseModel):
+ default_convert_underscores = getattr(
+ first_field.field_info, "convert_underscores", True
+ )
+ for param_type, param_group in parameter_groups:
+ for param in param_group:
+ field_info = param.field_info
+ # field_info = cast(Param, field_info)
+ if not getattr(field_info, "include_in_schema", True):
+ continue
+ param_schema = get_schema_from_model_field(
+ field=param,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ name = param.alias
+ convert_underscores = getattr(
+ param.field_info,
+ "convert_underscores",
+ default_convert_underscores,
+ )
+ if (
+ param_type == ParamTypes.header
+ and param.alias == param.name
+ and convert_underscores
+ ):
+ name = param.name.replace("_", "-")
+
+ parameter = {
+ "name": name,
+ "in": param_type.value,
+ "required": param.required,
+ "schema": param_schema,
+ }
+ if field_info.description:
+ parameter["description"] = field_info.description
+ openapi_examples = getattr(field_info, "openapi_examples", None)
+ example = getattr(field_info, "example", None)
+ if openapi_examples:
+ parameter["examples"] = jsonable_encoder(openapi_examples)
+ elif example != Undefined:
+ parameter["example"] = jsonable_encoder(example)
+ if getattr(field_info, "deprecated", None):
+ parameter["deprecated"] = True
+ parameters.append(parameter)
+ return parameters
+
+
+def get_openapi_operation_request_body(
+ *,
+ body_field: Optional[ModelField],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> Optional[Dict[str, Any]]:
+ if not body_field:
+ return None
+ assert isinstance(body_field, ModelField)
+ body_schema = get_schema_from_model_field(
+ field=body_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ field_info = cast(Body, body_field.field_info)
+ request_media_type = field_info.media_type
+ required = body_field.required
+ request_body_oai: Dict[str, Any] = {}
+ if required:
+ request_body_oai["required"] = required
+ request_media_content: Dict[str, Any] = {"schema": body_schema}
+ if field_info.openapi_examples:
+ request_media_content["examples"] = jsonable_encoder(
+ field_info.openapi_examples
+ )
+ elif field_info.example != Undefined:
+ request_media_content["example"] = jsonable_encoder(field_info.example)
+ request_body_oai["content"] = {request_media_type: request_media_content}
+ return request_body_oai
+
+
+def generate_operation_id(
+ *, route: routing.APIRoute, method: str
+) -> str: # pragma: nocover
+ warnings.warn(
+ "fastapi.openapi.utils.generate_operation_id() was deprecated, "
+ "it is not used internally, and will be removed soon",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ if route.operation_id:
+ return route.operation_id
+ path: str = route.path_format
+ return generate_operation_id_for_path(name=route.name, path=path, method=method)
+
+
+def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
+ if route.summary:
+ return route.summary
+ return route.name.replace("_", " ").title()
+
+
+def get_openapi_operation_metadata(
+ *, route: routing.APIRoute, method: str, operation_ids: Set[str]
+) -> Dict[str, Any]:
+ operation: Dict[str, Any] = {}
+ if route.tags:
+ operation["tags"] = route.tags
+ operation["summary"] = generate_operation_summary(route=route, method=method)
+ if route.description:
+ operation["description"] = route.description
+ operation_id = route.operation_id or route.unique_id
+ if operation_id in operation_ids:
+ message = (
+ f"Duplicate Operation ID {operation_id} for function "
+ + f"{route.endpoint.__name__}"
+ )
+ file_name = getattr(route.endpoint, "__globals__", {}).get("__file__")
+ if file_name:
+ message += f" at {file_name}"
+ warnings.warn(message, stacklevel=1)
+ operation_ids.add(operation_id)
+ operation["operationId"] = operation_id
+ if route.deprecated:
+ operation["deprecated"] = route.deprecated
+ return operation
+
+
+def get_openapi_path(
+ *,
+ route: routing.APIRoute,
+ operation_ids: Set[str],
+ schema_generator: GenerateJsonSchema,
+ model_name_map: ModelNameMap,
+ field_mapping: Dict[
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+ ],
+ separate_input_output_schemas: bool = True,
+) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
+ path = {}
+ security_schemes: Dict[str, Any] = {}
+ definitions: Dict[str, Any] = {}
+ assert route.methods is not None, "Methods must be a list"
+ if isinstance(route.response_class, DefaultPlaceholder):
+ current_response_class: Type[Response] = route.response_class.value
+ else:
+ current_response_class = route.response_class
+ assert current_response_class, "A response class is needed to generate OpenAPI"
+ route_response_media_type: Optional[str] = current_response_class.media_type
+ if route.include_in_schema:
+ for method in route.methods:
+ operation = get_openapi_operation_metadata(
+ route=route, method=method, operation_ids=operation_ids
+ )
+ parameters: List[Dict[str, Any]] = []
+ flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
+ security_definitions, operation_security = get_openapi_security_definitions(
+ flat_dependant=flat_dependant
+ )
+ if operation_security:
+ operation.setdefault("security", []).extend(operation_security)
+ if security_definitions:
+ security_schemes.update(security_definitions)
+ operation_parameters = _get_openapi_operation_parameters(
+ dependant=route.dependant,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ parameters.extend(operation_parameters)
+ if parameters:
+ all_parameters = {
+ (param["in"], param["name"]): param for param in parameters
+ }
+ required_parameters = {
+ (param["in"], param["name"]): param
+ for param in parameters
+ if param.get("required")
+ }
+ # Make sure required definitions of the same parameter take precedence
+ # over non-required definitions
+ all_parameters.update(required_parameters)
+ operation["parameters"] = list(all_parameters.values())
+ if method in METHODS_WITH_BODY:
+ request_body_oai = get_openapi_operation_request_body(
+ body_field=route.body_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if request_body_oai:
+ operation["requestBody"] = request_body_oai
+ if route.callbacks:
+ callbacks = {}
+ for callback in route.callbacks:
+ if isinstance(callback, routing.APIRoute):
+ (
+ cb_path,
+ cb_security_schemes,
+ cb_definitions,
+ ) = get_openapi_path(
+ route=callback,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ callbacks[callback.name] = {callback.path: cb_path}
+ operation["callbacks"] = callbacks
+ if route.status_code is not None:
+ status_code = str(route.status_code)
+ else:
+ # It would probably make more sense for all response classes to have an
+ # explicit default status_code, and to extract it from them, instead of
+ # doing this inspection tricks, that would probably be in the future
+ # TODO: probably make status_code a default class attribute for all
+ # responses in Starlette
+ response_signature = inspect.signature(current_response_class.__init__)
+ status_code_param = response_signature.parameters.get("status_code")
+ if status_code_param is not None:
+ if isinstance(status_code_param.default, int):
+ status_code = str(status_code_param.default)
+ operation.setdefault("responses", {}).setdefault(status_code, {})[
+ "description"
+ ] = route.response_description
+ if route_response_media_type and is_body_allowed_for_status_code(
+ route.status_code
+ ):
+ response_schema = {"type": "string"}
+ if lenient_issubclass(current_response_class, JSONResponse):
+ if route.response_field:
+ response_schema = get_schema_from_model_field(
+ field=route.response_field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ else:
+ response_schema = {}
+ operation.setdefault("responses", {}).setdefault(
+ status_code, {}
+ ).setdefault("content", {}).setdefault(route_response_media_type, {})[
+ "schema"
+ ] = response_schema
+ if route.responses:
+ operation_responses = operation.setdefault("responses", {})
+ for (
+ additional_status_code,
+ additional_response,
+ ) in route.responses.items():
+ process_response = additional_response.copy()
+ process_response.pop("model", None)
+ status_code_key = str(additional_status_code).upper()
+ if status_code_key == "DEFAULT":
+ status_code_key = "default"
+ openapi_response = operation_responses.setdefault(
+ status_code_key, {}
+ )
+ assert isinstance(process_response, dict), (
+ "An additional response must be a dict"
+ )
+ field = route.response_fields.get(additional_status_code)
+ additional_field_schema: Optional[Dict[str, Any]] = None
+ if field:
+ additional_field_schema = get_schema_from_model_field(
+ field=field,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ media_type = route_response_media_type or "application/json"
+ additional_schema = (
+ process_response.setdefault("content", {})
+ .setdefault(media_type, {})
+ .setdefault("schema", {})
+ )
+ deep_dict_update(additional_schema, additional_field_schema)
+ status_text: Optional[str] = status_code_ranges.get(
+ str(additional_status_code).upper()
+ ) or http.client.responses.get(int(additional_status_code))
+ description = (
+ process_response.get("description")
+ or openapi_response.get("description")
+ or status_text
+ or "Additional Response"
+ )
+ deep_dict_update(openapi_response, process_response)
+ openapi_response["description"] = description
+ http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
+ all_route_params = get_flat_params(route.dependant)
+ if (all_route_params or route.body_field) and not any(
+ status in operation["responses"]
+ for status in [http422, "4XX", "default"]
+ ):
+ operation["responses"][http422] = {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": REF_PREFIX + "HTTPValidationError"}
+ }
+ },
+ }
+ if "ValidationError" not in definitions:
+ definitions.update(
+ {
+ "ValidationError": validation_error_definition,
+ "HTTPValidationError": validation_error_response_definition,
+ }
+ )
+ if route.openapi_extra:
+ deep_dict_update(operation, route.openapi_extra)
+ path[method.lower()] = operation
+ return path, security_schemes, definitions
+
+
+def get_fields_from_routes(
+ routes: Sequence[BaseRoute],
+) -> List[ModelField]:
+ body_fields_from_routes: List[ModelField] = []
+ responses_from_routes: List[ModelField] = []
+ request_fields_from_routes: List[ModelField] = []
+ callback_flat_models: List[ModelField] = []
+ for route in routes:
+ if getattr(route, "include_in_schema", None) and isinstance(
+ route, routing.APIRoute
+ ):
+ if route.body_field:
+ assert isinstance(route.body_field, ModelField), (
+ "A request body must be a Pydantic Field"
+ )
+ body_fields_from_routes.append(route.body_field)
+ if route.response_field:
+ responses_from_routes.append(route.response_field)
+ if route.response_fields:
+ responses_from_routes.extend(route.response_fields.values())
+ if route.callbacks:
+ callback_flat_models.extend(get_fields_from_routes(route.callbacks))
+ params = get_flat_params(route.dependant)
+ request_fields_from_routes.extend(params)
+
+ flat_models = callback_flat_models + list(
+ body_fields_from_routes + responses_from_routes + request_fields_from_routes
+ )
+ return flat_models
+
+
+def get_openapi(
+ *,
+ title: str,
+ version: str,
+ openapi_version: str = "3.1.0",
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ routes: Sequence[BaseRoute],
+ webhooks: Optional[Sequence[BaseRoute]] = None,
+ tags: Optional[List[Dict[str, Any]]] = None,
+ servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
+ terms_of_service: Optional[str] = None,
+ contact: Optional[Dict[str, Union[str, Any]]] = None,
+ license_info: Optional[Dict[str, Union[str, Any]]] = None,
+ separate_input_output_schemas: bool = True,
+) -> Dict[str, Any]:
+ info: Dict[str, Any] = {"title": title, "version": version}
+ if summary:
+ info["summary"] = summary
+ if description:
+ info["description"] = description
+ if terms_of_service:
+ info["termsOfService"] = terms_of_service
+ if contact:
+ info["contact"] = contact
+ if license_info:
+ info["license"] = license_info
+ output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
+ if servers:
+ output["servers"] = servers
+ components: Dict[str, Dict[str, Any]] = {}
+ paths: Dict[str, Dict[str, Any]] = {}
+ webhook_paths: Dict[str, Dict[str, Any]] = {}
+ operation_ids: Set[str] = set()
+ all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
+ model_name_map = get_compat_model_name_map(all_fields)
+ schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
+ field_mapping, definitions = get_definitions(
+ fields=all_fields,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ for route in routes or []:
+ if isinstance(route, routing.APIRoute):
+ result = get_openapi_path(
+ route=route,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if result:
+ path, security_schemes, path_definitions = result
+ if path:
+ paths.setdefault(route.path_format, {}).update(path)
+ if security_schemes:
+ components.setdefault("securitySchemes", {}).update(
+ security_schemes
+ )
+ if path_definitions:
+ definitions.update(path_definitions)
+ for webhook in webhooks or []:
+ if isinstance(webhook, routing.APIRoute):
+ result = get_openapi_path(
+ route=webhook,
+ operation_ids=operation_ids,
+ schema_generator=schema_generator,
+ model_name_map=model_name_map,
+ field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
+ )
+ if result:
+ path, security_schemes, path_definitions = result
+ if path:
+ webhook_paths.setdefault(webhook.path_format, {}).update(path)
+ if security_schemes:
+ components.setdefault("securitySchemes", {}).update(
+ security_schemes
+ )
+ if path_definitions:
+ definitions.update(path_definitions)
+ if definitions:
+ components["schemas"] = {k: definitions[k] for k in sorted(definitions)}
+ if components:
+ output["components"] = components
+ output["paths"] = paths
+ if webhook_paths:
+ output["webhooks"] = webhook_paths
+ if tags:
+ output["tags"] = tags
+ return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore
diff --git a/.venv/lib/python3.12/site-packages/fastapi/param_functions.py b/.venv/lib/python3.12/site-packages/fastapi/param_functions.py
new file mode 100644
index 00000000..b3621626
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/param_functions.py
@@ -0,0 +1,2360 @@
+from typing import Any, Callable, Dict, List, Optional, Sequence, Union
+
+from fastapi import params
+from fastapi._compat import Undefined
+from fastapi.openapi.models import Example
+from typing_extensions import Annotated, Doc, deprecated
+
+_Unset: Any = Undefined
+
+
+def Path( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = ...,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ """
+ Declare a path parameter for a *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/).
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import FastAPI, Path
+
+ app = FastAPI()
+
+
+ @app.get("/items/{item_id}")
+ async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")],
+ ):
+ return {"item_id": item_id}
+ ```
+ """
+ return params.Path(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Query( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.Query(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Header( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ convert_underscores: Annotated[
+ bool,
+ Doc(
+ """
+ Automatically convert underscores to hyphens in the parameter field name.
+
+ Read more about it in the
+ [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion)
+ """
+ ),
+ ] = True,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.Header(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ convert_underscores=convert_underscores,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Cookie( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.Cookie(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Body( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ embed: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ When `embed` is `True`, the parameter will be expected in a JSON body as a
+ key instead of being the JSON body itself.
+
+ This happens automatically when more than one `Body` parameter is declared.
+
+ Read more about it in the
+ [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter).
+ """
+ ),
+ ] = None,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "application/json",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.Body(
+ default=default,
+ default_factory=default_factory,
+ embed=embed,
+ media_type=media_type,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Form( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "application/x-www-form-urlencoded",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.Form(
+ default=default,
+ default_factory=default_factory,
+ media_type=media_type,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def File( # noqa: N802
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
+ *,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "multipart/form-data",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
+ regex: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Union[deprecated, str, bool, None],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
+) -> Any:
+ return params.File(
+ default=default,
+ default_factory=default_factory,
+ media_type=media_type,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+def Depends( # noqa: N802
+ dependency: Annotated[
+ Optional[Callable[..., Any]],
+ Doc(
+ """
+ A "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you, just pass the object
+ directly.
+ """
+ ),
+ ] = None,
+ *,
+ use_cache: Annotated[
+ bool,
+ Doc(
+ """
+ By default, after a dependency is called the first time in a request, if
+ the dependency is declared again for the rest of the request (for example
+ if the dependency is needed by several dependencies), the value will be
+ re-used for the rest of the request.
+
+ Set `use_cache` to `False` to disable this behavior and ensure the
+ dependency is called again (if declared more than once) in the same request.
+ """
+ ),
+ ] = True,
+) -> Any:
+ """
+ Declare a FastAPI dependency.
+
+ It takes a single "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/).
+
+ **Example**
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+
+ app = FastAPI()
+
+
+ async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+ @app.get("/items/")
+ async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
+ ```
+ """
+ return params.Depends(dependency=dependency, use_cache=use_cache)
+
+
+def Security( # noqa: N802
+ dependency: Annotated[
+ Optional[Callable[..., Any]],
+ Doc(
+ """
+ A "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you, just pass the object
+ directly.
+ """
+ ),
+ ] = None,
+ *,
+ scopes: Annotated[
+ Optional[Sequence[str]],
+ Doc(
+ """
+ OAuth2 scopes required for the *path operation* that uses this Security
+ dependency.
+
+ The term "scope" comes from the OAuth2 specification, it seems to be
+ intentionally vague and interpretable. It normally refers to permissions,
+ in cases to roles.
+
+ These scopes are integrated with OpenAPI (and the API docs at `/docs`).
+ So they are visible in the OpenAPI specification.
+ )
+ """
+ ),
+ ] = None,
+ use_cache: Annotated[
+ bool,
+ Doc(
+ """
+ By default, after a dependency is called the first time in a request, if
+ the dependency is declared again for the rest of the request (for example
+ if the dependency is needed by several dependencies), the value will be
+ re-used for the rest of the request.
+
+ Set `use_cache` to `False` to disable this behavior and ensure the
+ dependency is called again (if declared more than once) in the same request.
+ """
+ ),
+ ] = True,
+) -> Any:
+ """
+ Declare a FastAPI Security dependency.
+
+ The only difference with a regular dependency is that it can declare OAuth2
+ scopes that will be integrated with OpenAPI and the automatic UI docs (by default
+ at `/docs`).
+
+ It takes a single "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you.
+
+ Read more about it in the
+ [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and
+ in the
+ [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
+
+ **Example**
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Security, FastAPI
+
+ from .db import User
+ from .security import get_current_active_user
+
+ app = FastAPI()
+
+ @app.get("/users/me/items/")
+ async def read_own_items(
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+ ):
+ return [{"item_id": "Foo", "owner": current_user.username}]
+ ```
+ """
+ return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/params.py b/.venv/lib/python3.12/site-packages/fastapi/params.py
new file mode 100644
index 00000000..8f5601dd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/params.py
@@ -0,0 +1,786 @@
+import warnings
+from enum import Enum
+from typing import Any, Callable, Dict, List, Optional, Sequence, Union
+
+from fastapi.openapi.models import Example
+from pydantic.fields import FieldInfo
+from typing_extensions import Annotated, deprecated
+
+from ._compat import (
+ PYDANTIC_V2,
+ PYDANTIC_VERSION_MINOR_TUPLE,
+ Undefined,
+)
+
+_Unset: Any = Undefined
+
+
+class ParamTypes(Enum):
+ query = "query"
+ header = "header"
+ path = "path"
+ cookie = "cookie"
+
+
+class Param(FieldInfo):
+ in_: ParamTypes
+
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ if example is not _Unset:
+ warnings.warn(
+ "`example` has been deprecated, please use `examples` instead",
+ category=DeprecationWarning,
+ stacklevel=4,
+ )
+ self.example = example
+ self.include_in_schema = include_in_schema
+ self.openapi_examples = openapi_examples
+ kwargs = dict(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ discriminator=discriminator,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ **extra,
+ )
+ if examples is not None:
+ kwargs["examples"] = examples
+ if regex is not None:
+ warnings.warn(
+ "`regex` has been deprecated, please use `pattern` instead",
+ category=DeprecationWarning,
+ stacklevel=4,
+ )
+ current_json_schema_extra = json_schema_extra or extra
+ if PYDANTIC_VERSION_MINOR_TUPLE < (2, 7):
+ self.deprecated = deprecated
+ else:
+ kwargs["deprecated"] = deprecated
+ if PYDANTIC_V2:
+ kwargs.update(
+ {
+ "annotation": annotation,
+ "alias_priority": alias_priority,
+ "validation_alias": validation_alias,
+ "serialization_alias": serialization_alias,
+ "strict": strict,
+ "json_schema_extra": current_json_schema_extra,
+ }
+ )
+ kwargs["pattern"] = pattern or regex
+ else:
+ kwargs["regex"] = pattern or regex
+ kwargs.update(**current_json_schema_extra)
+ use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}
+
+ super().__init__(**use_kwargs)
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.default})"
+
+
+class Path(Param):
+ in_ = ParamTypes.path
+
+ def __init__(
+ self,
+ default: Any = ...,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ assert default is ..., "Path parameters cannot have a default value"
+ self.in_ = self.in_
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class Query(Param):
+ in_ = ParamTypes.query
+
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class Header(Param):
+ in_ = ParamTypes.header
+
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ convert_underscores: bool = True,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ self.convert_underscores = convert_underscores
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class Cookie(Param):
+ in_ = ParamTypes.cookie
+
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class Body(FieldInfo):
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ embed: Union[bool, None] = None,
+ media_type: str = "application/json",
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ self.embed = embed
+ self.media_type = media_type
+ if example is not _Unset:
+ warnings.warn(
+ "`example` has been deprecated, please use `examples` instead",
+ category=DeprecationWarning,
+ stacklevel=4,
+ )
+ self.example = example
+ self.include_in_schema = include_in_schema
+ self.openapi_examples = openapi_examples
+ kwargs = dict(
+ default=default,
+ default_factory=default_factory,
+ alias=alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ discriminator=discriminator,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ **extra,
+ )
+ if examples is not None:
+ kwargs["examples"] = examples
+ if regex is not None:
+ warnings.warn(
+ "`regex` has been deprecated, please use `pattern` instead",
+ category=DeprecationWarning,
+ stacklevel=4,
+ )
+ current_json_schema_extra = json_schema_extra or extra
+ if PYDANTIC_VERSION_MINOR_TUPLE < (2, 7):
+ self.deprecated = deprecated
+ else:
+ kwargs["deprecated"] = deprecated
+ if PYDANTIC_V2:
+ kwargs.update(
+ {
+ "annotation": annotation,
+ "alias_priority": alias_priority,
+ "validation_alias": validation_alias,
+ "serialization_alias": serialization_alias,
+ "strict": strict,
+ "json_schema_extra": current_json_schema_extra,
+ }
+ )
+ kwargs["pattern"] = pattern or regex
+ else:
+ kwargs["regex"] = pattern or regex
+ kwargs.update(**current_json_schema_extra)
+
+ use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}
+
+ super().__init__(**use_kwargs)
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.default})"
+
+
+class Form(Body):
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ media_type: str = "application/x-www-form-urlencoded",
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ media_type=media_type,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class File(Form):
+ def __init__(
+ self,
+ default: Any = Undefined,
+ *,
+ default_factory: Union[Callable[[], Any], None] = _Unset,
+ annotation: Optional[Any] = None,
+ media_type: str = "multipart/form-data",
+ alias: Optional[str] = None,
+ alias_priority: Union[int, None] = _Unset,
+ # TODO: update when deprecating Pydantic v1, import these types
+ # validation_alias: str | AliasPath | AliasChoices | None
+ validation_alias: Union[str, None] = None,
+ serialization_alias: Union[str, None] = None,
+ title: Optional[str] = None,
+ description: Optional[str] = None,
+ gt: Optional[float] = None,
+ ge: Optional[float] = None,
+ lt: Optional[float] = None,
+ le: Optional[float] = None,
+ min_length: Optional[int] = None,
+ max_length: Optional[int] = None,
+ pattern: Optional[str] = None,
+ regex: Annotated[
+ Optional[str],
+ deprecated(
+ "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
+ ),
+ ] = None,
+ discriminator: Union[str, None] = None,
+ strict: Union[bool, None] = _Unset,
+ multiple_of: Union[float, None] = _Unset,
+ allow_inf_nan: Union[bool, None] = _Unset,
+ max_digits: Union[int, None] = _Unset,
+ decimal_places: Union[int, None] = _Unset,
+ examples: Optional[List[Any]] = None,
+ example: Annotated[
+ Optional[Any],
+ deprecated(
+ "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
+ "although still supported. Use examples instead."
+ ),
+ ] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
+ include_in_schema: bool = True,
+ json_schema_extra: Union[Dict[str, Any], None] = None,
+ **extra: Any,
+ ):
+ super().__init__(
+ default=default,
+ default_factory=default_factory,
+ annotation=annotation,
+ media_type=media_type,
+ alias=alias,
+ alias_priority=alias_priority,
+ validation_alias=validation_alias,
+ serialization_alias=serialization_alias,
+ title=title,
+ description=description,
+ gt=gt,
+ ge=ge,
+ lt=lt,
+ le=le,
+ min_length=min_length,
+ max_length=max_length,
+ pattern=pattern,
+ regex=regex,
+ discriminator=discriminator,
+ strict=strict,
+ multiple_of=multiple_of,
+ allow_inf_nan=allow_inf_nan,
+ max_digits=max_digits,
+ decimal_places=decimal_places,
+ deprecated=deprecated,
+ example=example,
+ examples=examples,
+ openapi_examples=openapi_examples,
+ include_in_schema=include_in_schema,
+ json_schema_extra=json_schema_extra,
+ **extra,
+ )
+
+
+class Depends:
+ def __init__(
+ self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
+ ):
+ self.dependency = dependency
+ self.use_cache = use_cache
+
+ def __repr__(self) -> str:
+ attr = getattr(self.dependency, "__name__", type(self.dependency).__name__)
+ cache = "" if self.use_cache else ", use_cache=False"
+ return f"{self.__class__.__name__}({attr}{cache})"
+
+
+class Security(Depends):
+ def __init__(
+ self,
+ dependency: Optional[Callable[..., Any]] = None,
+ *,
+ scopes: Optional[Sequence[str]] = None,
+ use_cache: bool = True,
+ ):
+ super().__init__(dependency=dependency, use_cache=use_cache)
+ self.scopes = scopes or []
diff --git a/.venv/lib/python3.12/site-packages/fastapi/py.typed b/.venv/lib/python3.12/site-packages/fastapi/py.typed
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/py.typed
diff --git a/.venv/lib/python3.12/site-packages/fastapi/requests.py b/.venv/lib/python3.12/site-packages/fastapi/requests.py
new file mode 100644
index 00000000..d16552c0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/requests.py
@@ -0,0 +1,2 @@
+from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401
+from starlette.requests import Request as Request # noqa: F401
diff --git a/.venv/lib/python3.12/site-packages/fastapi/responses.py b/.venv/lib/python3.12/site-packages/fastapi/responses.py
new file mode 100644
index 00000000..6c8db6f3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/responses.py
@@ -0,0 +1,48 @@
+from typing import Any
+
+from starlette.responses import FileResponse as FileResponse # noqa
+from starlette.responses import HTMLResponse as HTMLResponse # noqa
+from starlette.responses import JSONResponse as JSONResponse # noqa
+from starlette.responses import PlainTextResponse as PlainTextResponse # noqa
+from starlette.responses import RedirectResponse as RedirectResponse # noqa
+from starlette.responses import Response as Response # noqa
+from starlette.responses import StreamingResponse as StreamingResponse # noqa
+
+try:
+ import ujson
+except ImportError: # pragma: nocover
+ ujson = None # type: ignore
+
+
+try:
+ import orjson
+except ImportError: # pragma: nocover
+ orjson = None # type: ignore
+
+
+class UJSONResponse(JSONResponse):
+ """
+ JSON response using the high-performance ujson library to serialize data to JSON.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
+ """
+
+ def render(self, content: Any) -> bytes:
+ assert ujson is not None, "ujson must be installed to use UJSONResponse"
+ return ujson.dumps(content, ensure_ascii=False).encode("utf-8")
+
+
+class ORJSONResponse(JSONResponse):
+ """
+ JSON response using the high-performance orjson library to serialize data to JSON.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
+ """
+
+ def render(self, content: Any) -> bytes:
+ assert orjson is not None, "orjson must be installed to use ORJSONResponse"
+ return orjson.dumps(
+ content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
+ )
diff --git a/.venv/lib/python3.12/site-packages/fastapi/routing.py b/.venv/lib/python3.12/site-packages/fastapi/routing.py
new file mode 100644
index 00000000..457481e3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/routing.py
@@ -0,0 +1,4439 @@
+import asyncio
+import dataclasses
+import email.message
+import inspect
+import json
+from contextlib import AsyncExitStack, asynccontextmanager
+from enum import Enum, IntEnum
+from typing import (
+ Any,
+ AsyncIterator,
+ Callable,
+ Coroutine,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Sequence,
+ Set,
+ Tuple,
+ Type,
+ Union,
+)
+
+from fastapi import params
+from fastapi._compat import (
+ ModelField,
+ Undefined,
+ _get_model_config,
+ _model_dump,
+ _normalize_errors,
+ lenient_issubclass,
+)
+from fastapi.datastructures import Default, DefaultPlaceholder
+from fastapi.dependencies.models import Dependant
+from fastapi.dependencies.utils import (
+ _should_embed_body_fields,
+ get_body_field,
+ get_dependant,
+ get_flat_dependant,
+ get_parameterless_sub_dependant,
+ get_typed_return_annotation,
+ solve_dependencies,
+)
+from fastapi.encoders import jsonable_encoder
+from fastapi.exceptions import (
+ FastAPIError,
+ RequestValidationError,
+ ResponseValidationError,
+ WebSocketRequestValidationError,
+)
+from fastapi.types import DecoratedCallable, IncEx
+from fastapi.utils import (
+ create_cloned_field,
+ create_model_field,
+ generate_unique_id,
+ get_value_or_default,
+ is_body_allowed_for_status_code,
+)
+from pydantic import BaseModel
+from starlette import routing
+from starlette.concurrency import run_in_threadpool
+from starlette.exceptions import HTTPException
+from starlette.requests import Request
+from starlette.responses import JSONResponse, Response
+from starlette.routing import (
+ BaseRoute,
+ Match,
+ compile_path,
+ get_name,
+ request_response,
+ websocket_session,
+)
+from starlette.routing import Mount as Mount # noqa
+from starlette.types import AppType, ASGIApp, Lifespan, Scope
+from starlette.websockets import WebSocket
+from typing_extensions import Annotated, Doc, deprecated
+
+
+def _prepare_response_content(
+ res: Any,
+ *,
+ exclude_unset: bool,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
+) -> Any:
+ if isinstance(res, BaseModel):
+ read_with_orm_mode = getattr(_get_model_config(res), "read_with_orm_mode", None)
+ if read_with_orm_mode:
+ # Let from_orm extract the data from this model instead of converting
+ # it now to a dict.
+ # Otherwise, there's no way to extract lazy data that requires attribute
+ # access instead of dict iteration, e.g. lazy relationships.
+ return res
+ return _model_dump(
+ res,
+ by_alias=True,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ elif isinstance(res, list):
+ return [
+ _prepare_response_content(
+ item,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ for item in res
+ ]
+ elif isinstance(res, dict):
+ return {
+ k: _prepare_response_content(
+ v,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ for k, v in res.items()
+ }
+ elif dataclasses.is_dataclass(res):
+ return dataclasses.asdict(res)
+ return res
+
+
+def _merge_lifespan_context(
+ original_context: Lifespan[Any], nested_context: Lifespan[Any]
+) -> Lifespan[Any]:
+ @asynccontextmanager
+ async def merged_lifespan(
+ app: AppType,
+ ) -> AsyncIterator[Optional[Mapping[str, Any]]]:
+ async with original_context(app) as maybe_original_state:
+ async with nested_context(app) as maybe_nested_state:
+ if maybe_nested_state is None and maybe_original_state is None:
+ yield None # old ASGI compatibility
+ else:
+ yield {**(maybe_nested_state or {}), **(maybe_original_state or {})}
+
+ return merged_lifespan # type: ignore[return-value]
+
+
+async def serialize_response(
+ *,
+ field: Optional[ModelField] = None,
+ response_content: Any,
+ include: Optional[IncEx] = None,
+ exclude: Optional[IncEx] = None,
+ by_alias: bool = True,
+ exclude_unset: bool = False,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
+ is_coroutine: bool = True,
+) -> Any:
+ if field:
+ errors = []
+ if not hasattr(field, "serialize"):
+ # pydantic v1
+ response_content = _prepare_response_content(
+ response_content,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ if is_coroutine:
+ value, errors_ = field.validate(response_content, {}, loc=("response",))
+ else:
+ value, errors_ = await run_in_threadpool(
+ field.validate, response_content, {}, loc=("response",)
+ )
+ if isinstance(errors_, list):
+ errors.extend(errors_)
+ elif errors_:
+ errors.append(errors_)
+ if errors:
+ raise ResponseValidationError(
+ errors=_normalize_errors(errors), body=response_content
+ )
+
+ if hasattr(field, "serialize"):
+ return field.serialize(
+ value,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+
+ return jsonable_encoder(
+ value,
+ include=include,
+ exclude=exclude,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ else:
+ return jsonable_encoder(response_content)
+
+
+async def run_endpoint_function(
+ *, dependant: Dependant, values: Dict[str, Any], is_coroutine: bool
+) -> Any:
+ # Only called by get_request_handler. Has been split into its own function to
+ # facilitate profiling endpoints, since inner functions are harder to profile.
+ assert dependant.call is not None, "dependant.call must be a function"
+
+ if is_coroutine:
+ return await dependant.call(**values)
+ else:
+ return await run_in_threadpool(dependant.call, **values)
+
+
+def get_request_handler(
+ dependant: Dependant,
+ body_field: Optional[ModelField] = None,
+ status_code: Optional[int] = None,
+ response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
+ response_field: Optional[ModelField] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ dependency_overrides_provider: Optional[Any] = None,
+ embed_body_fields: bool = False,
+) -> Callable[[Request], Coroutine[Any, Any, Response]]:
+ assert dependant.call is not None, "dependant.call must be a function"
+ is_coroutine = asyncio.iscoroutinefunction(dependant.call)
+ is_body_form = body_field and isinstance(body_field.field_info, params.Form)
+ if isinstance(response_class, DefaultPlaceholder):
+ actual_response_class: Type[Response] = response_class.value
+ else:
+ actual_response_class = response_class
+
+ async def app(request: Request) -> Response:
+ response: Union[Response, None] = None
+ async with AsyncExitStack() as file_stack:
+ try:
+ body: Any = None
+ if body_field:
+ if is_body_form:
+ body = await request.form()
+ file_stack.push_async_callback(body.close)
+ else:
+ body_bytes = await request.body()
+ if body_bytes:
+ json_body: Any = Undefined
+ content_type_value = request.headers.get("content-type")
+ if not content_type_value:
+ json_body = await request.json()
+ else:
+ message = email.message.Message()
+ message["content-type"] = content_type_value
+ if message.get_content_maintype() == "application":
+ subtype = message.get_content_subtype()
+ if subtype == "json" or subtype.endswith("+json"):
+ json_body = await request.json()
+ if json_body != Undefined:
+ body = json_body
+ else:
+ body = body_bytes
+ except json.JSONDecodeError as e:
+ validation_error = RequestValidationError(
+ [
+ {
+ "type": "json_invalid",
+ "loc": ("body", e.pos),
+ "msg": "JSON decode error",
+ "input": {},
+ "ctx": {"error": e.msg},
+ }
+ ],
+ body=e.doc,
+ )
+ raise validation_error from e
+ except HTTPException:
+ # If a middleware raises an HTTPException, it should be raised again
+ raise
+ except Exception as e:
+ http_error = HTTPException(
+ status_code=400, detail="There was an error parsing the body"
+ )
+ raise http_error from e
+ errors: List[Any] = []
+ async with AsyncExitStack() as async_exit_stack:
+ solved_result = await solve_dependencies(
+ request=request,
+ dependant=dependant,
+ body=body,
+ dependency_overrides_provider=dependency_overrides_provider,
+ async_exit_stack=async_exit_stack,
+ embed_body_fields=embed_body_fields,
+ )
+ errors = solved_result.errors
+ if not errors:
+ raw_response = await run_endpoint_function(
+ dependant=dependant,
+ values=solved_result.values,
+ is_coroutine=is_coroutine,
+ )
+ if isinstance(raw_response, Response):
+ if raw_response.background is None:
+ raw_response.background = solved_result.background_tasks
+ response = raw_response
+ else:
+ response_args: Dict[str, Any] = {
+ "background": solved_result.background_tasks
+ }
+ # If status_code was set, use it, otherwise use the default from the
+ # response class, in the case of redirect it's 307
+ current_status_code = (
+ status_code
+ if status_code
+ else solved_result.response.status_code
+ )
+ if current_status_code is not None:
+ response_args["status_code"] = current_status_code
+ if solved_result.response.status_code:
+ response_args["status_code"] = (
+ solved_result.response.status_code
+ )
+ content = await serialize_response(
+ field=response_field,
+ response_content=raw_response,
+ include=response_model_include,
+ exclude=response_model_exclude,
+ by_alias=response_model_by_alias,
+ exclude_unset=response_model_exclude_unset,
+ exclude_defaults=response_model_exclude_defaults,
+ exclude_none=response_model_exclude_none,
+ is_coroutine=is_coroutine,
+ )
+ response = actual_response_class(content, **response_args)
+ if not is_body_allowed_for_status_code(response.status_code):
+ response.body = b""
+ response.headers.raw.extend(solved_result.response.headers.raw)
+ if errors:
+ validation_error = RequestValidationError(
+ _normalize_errors(errors), body=body
+ )
+ raise validation_error
+ if response is None:
+ raise FastAPIError(
+ "No response object was returned. There's a high chance that the "
+ "application code is raising an exception and a dependency with yield "
+ "has a block with a bare except, or a block with except Exception, "
+ "and is not raising the exception again. Read more about it in the "
+ "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
+ )
+ return response
+
+ return app
+
+
+def get_websocket_app(
+ dependant: Dependant,
+ dependency_overrides_provider: Optional[Any] = None,
+ embed_body_fields: bool = False,
+) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
+ async def app(websocket: WebSocket) -> None:
+ async with AsyncExitStack() as async_exit_stack:
+ # TODO: remove this scope later, after a few releases
+ # This scope fastapi_astack is no longer used by FastAPI, kept for
+ # compatibility, just in case
+ websocket.scope["fastapi_astack"] = async_exit_stack
+ solved_result = await solve_dependencies(
+ request=websocket,
+ dependant=dependant,
+ dependency_overrides_provider=dependency_overrides_provider,
+ async_exit_stack=async_exit_stack,
+ embed_body_fields=embed_body_fields,
+ )
+ if solved_result.errors:
+ raise WebSocketRequestValidationError(
+ _normalize_errors(solved_result.errors)
+ )
+ assert dependant.call is not None, "dependant.call must be a function"
+ await dependant.call(**solved_result.values)
+
+ return app
+
+
+class APIWebSocketRoute(routing.WebSocketRoute):
+ def __init__(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ *,
+ name: Optional[str] = None,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ dependency_overrides_provider: Optional[Any] = None,
+ ) -> None:
+ self.path = path
+ self.endpoint = endpoint
+ self.name = get_name(endpoint) if name is None else name
+ self.dependencies = list(dependencies or [])
+ self.path_regex, self.path_format, self.param_convertors = compile_path(path)
+ self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
+ for depends in self.dependencies[::-1]:
+ self.dependant.dependencies.insert(
+ 0,
+ get_parameterless_sub_dependant(depends=depends, path=self.path_format),
+ )
+ self._flat_dependant = get_flat_dependant(self.dependant)
+ self._embed_body_fields = _should_embed_body_fields(
+ self._flat_dependant.body_params
+ )
+ self.app = websocket_session(
+ get_websocket_app(
+ dependant=self.dependant,
+ dependency_overrides_provider=dependency_overrides_provider,
+ embed_body_fields=self._embed_body_fields,
+ )
+ )
+
+ def matches(self, scope: Scope) -> Tuple[Match, Scope]:
+ match, child_scope = super().matches(scope)
+ if match != Match.NONE:
+ child_scope["route"] = self
+ return match, child_scope
+
+
+class APIRoute(routing.Route):
+ def __init__(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ *,
+ response_model: Any = Default(None),
+ status_code: Optional[int] = None,
+ tags: Optional[List[Union[str, Enum]]] = None,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ response_description: str = "Successful Response",
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
+ deprecated: Optional[bool] = None,
+ name: Optional[str] = None,
+ methods: Optional[Union[Set[str], List[str]]] = None,
+ operation_id: Optional[str] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ include_in_schema: bool = True,
+ response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+ JSONResponse
+ ),
+ dependency_overrides_provider: Optional[Any] = None,
+ callbacks: Optional[List[BaseRoute]] = None,
+ openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Union[
+ Callable[["APIRoute"], str], DefaultPlaceholder
+ ] = Default(generate_unique_id),
+ ) -> None:
+ self.path = path
+ self.endpoint = endpoint
+ if isinstance(response_model, DefaultPlaceholder):
+ return_annotation = get_typed_return_annotation(endpoint)
+ if lenient_issubclass(return_annotation, Response):
+ response_model = None
+ else:
+ response_model = return_annotation
+ self.response_model = response_model
+ self.summary = summary
+ self.response_description = response_description
+ self.deprecated = deprecated
+ self.operation_id = operation_id
+ self.response_model_include = response_model_include
+ self.response_model_exclude = response_model_exclude
+ self.response_model_by_alias = response_model_by_alias
+ self.response_model_exclude_unset = response_model_exclude_unset
+ self.response_model_exclude_defaults = response_model_exclude_defaults
+ self.response_model_exclude_none = response_model_exclude_none
+ self.include_in_schema = include_in_schema
+ self.response_class = response_class
+ self.dependency_overrides_provider = dependency_overrides_provider
+ self.callbacks = callbacks
+ self.openapi_extra = openapi_extra
+ self.generate_unique_id_function = generate_unique_id_function
+ self.tags = tags or []
+ self.responses = responses or {}
+ self.name = get_name(endpoint) if name is None else name
+ self.path_regex, self.path_format, self.param_convertors = compile_path(path)
+ if methods is None:
+ methods = ["GET"]
+ self.methods: Set[str] = {method.upper() for method in methods}
+ if isinstance(generate_unique_id_function, DefaultPlaceholder):
+ current_generate_unique_id: Callable[[APIRoute], str] = (
+ generate_unique_id_function.value
+ )
+ else:
+ current_generate_unique_id = generate_unique_id_function
+ self.unique_id = self.operation_id or current_generate_unique_id(self)
+ # normalize enums e.g. http.HTTPStatus
+ if isinstance(status_code, IntEnum):
+ status_code = int(status_code)
+ self.status_code = status_code
+ if self.response_model:
+ assert is_body_allowed_for_status_code(status_code), (
+ f"Status code {status_code} must not have a response body"
+ )
+ response_name = "Response_" + self.unique_id
+ self.response_field = create_model_field(
+ name=response_name,
+ type_=self.response_model,
+ mode="serialization",
+ )
+ # Create a clone of the field, so that a Pydantic submodel is not returned
+ # as is just because it's an instance of a subclass of a more limited class
+ # e.g. UserInDB (containing hashed_password) could be a subclass of User
+ # that doesn't have the hashed_password. But because it's a subclass, it
+ # would pass the validation and be returned as is.
+ # By being a new field, no inheritance will be passed as is. A new model
+ # will always be created.
+ # TODO: remove when deprecating Pydantic v1
+ self.secure_cloned_response_field: Optional[ModelField] = (
+ create_cloned_field(self.response_field)
+ )
+ else:
+ self.response_field = None # type: ignore
+ self.secure_cloned_response_field = None
+ self.dependencies = list(dependencies or [])
+ self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
+ # if a "form feed" character (page break) is found in the description text,
+ # truncate description text to the content preceding the first "form feed"
+ self.description = self.description.split("\f")[0].strip()
+ response_fields = {}
+ for additional_status_code, response in self.responses.items():
+ assert isinstance(response, dict), "An additional response must be a dict"
+ model = response.get("model")
+ if model:
+ assert is_body_allowed_for_status_code(additional_status_code), (
+ f"Status code {additional_status_code} must not have a response body"
+ )
+ response_name = f"Response_{additional_status_code}_{self.unique_id}"
+ response_field = create_model_field(
+ name=response_name, type_=model, mode="serialization"
+ )
+ response_fields[additional_status_code] = response_field
+ if response_fields:
+ self.response_fields: Dict[Union[int, str], ModelField] = response_fields
+ else:
+ self.response_fields = {}
+
+ assert callable(endpoint), "An endpoint must be a callable"
+ self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
+ for depends in self.dependencies[::-1]:
+ self.dependant.dependencies.insert(
+ 0,
+ get_parameterless_sub_dependant(depends=depends, path=self.path_format),
+ )
+ self._flat_dependant = get_flat_dependant(self.dependant)
+ self._embed_body_fields = _should_embed_body_fields(
+ self._flat_dependant.body_params
+ )
+ self.body_field = get_body_field(
+ flat_dependant=self._flat_dependant,
+ name=self.unique_id,
+ embed_body_fields=self._embed_body_fields,
+ )
+ self.app = request_response(self.get_route_handler())
+
+ def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
+ return get_request_handler(
+ dependant=self.dependant,
+ body_field=self.body_field,
+ status_code=self.status_code,
+ response_class=self.response_class,
+ response_field=self.secure_cloned_response_field,
+ response_model_include=self.response_model_include,
+ response_model_exclude=self.response_model_exclude,
+ response_model_by_alias=self.response_model_by_alias,
+ response_model_exclude_unset=self.response_model_exclude_unset,
+ response_model_exclude_defaults=self.response_model_exclude_defaults,
+ response_model_exclude_none=self.response_model_exclude_none,
+ dependency_overrides_provider=self.dependency_overrides_provider,
+ embed_body_fields=self._embed_body_fields,
+ )
+
+ def matches(self, scope: Scope) -> Tuple[Match, Scope]:
+ match, child_scope = super().matches(scope)
+ if match != Match.NONE:
+ child_scope["route"] = self
+ return match, child_scope
+
+
+class APIRouter(routing.Router):
+ """
+ `APIRouter` class, used to group *path operations*, for example to structure
+ an app in multiple files. It would then be included in the `FastAPI` app, or
+ in another `APIRouter` (ultimately included in the app).
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+
+ @router.get("/users/", tags=["users"])
+ async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
+
+
+ app.include_router(router)
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+ """
+ ),
+ ] = Default(JSONResponse),
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ routes: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ **Note**: you probably shouldn't use this parameter, it is inherited
+ from Starlette and supported for compatibility.
+
+ ---
+
+ A list of routes to serve incoming HTTP and WebSocket requests.
+ """
+ ),
+ deprecated(
+ """
+ You normally wouldn't use this parameter with FastAPI, it is inherited
+ from Starlette and supported for compatibility.
+
+ In FastAPI, you normally would use the *path operation methods*,
+ like `router.get()`, `router.post()`, etc.
+ """
+ ),
+ ] = None,
+ redirect_slashes: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to detect and redirect slashes in URLs when the client doesn't
+ use the same format.
+ """
+ ),
+ ] = True,
+ default: Annotated[
+ Optional[ASGIApp],
+ Doc(
+ """
+ Default function handler for this router. Used to handle
+ 404 Not Found errors.
+ """
+ ),
+ ] = None,
+ dependency_overrides_provider: Annotated[
+ Optional[Any],
+ Doc(
+ """
+ Only used internally by FastAPI to handle dependency overrides.
+
+ You shouldn't need to use it. It normally points to the `FastAPI` app
+ object.
+ """
+ ),
+ ] = None,
+ route_class: Annotated[
+ Type[APIRoute],
+ Doc(
+ """
+ Custom route (*path operation*) class to be used by this router.
+
+ Read more about it in the
+ [FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router).
+ """
+ ),
+ ] = APIRoute,
+ on_startup: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of startup event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ on_shutdown: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of shutdown event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ # the generic to Lifespan[AppType] is the type of the top level application
+ # which the router cannot know statically, so we use typing.Any
+ lifespan: Annotated[
+ Optional[Lifespan[Any]],
+ Doc(
+ """
+ A `Lifespan` context manager handler. This replaces `startup` and
+ `shutdown` functions with a single context manager.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) all the *path operations* in this router in the
+ generated OpenAPI.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> None:
+ super().__init__(
+ routes=routes,
+ redirect_slashes=redirect_slashes,
+ default=default,
+ on_startup=on_startup,
+ on_shutdown=on_shutdown,
+ lifespan=lifespan,
+ )
+ if prefix:
+ assert prefix.startswith("/"), "A path prefix must start with '/'"
+ assert not prefix.endswith("/"), (
+ "A path prefix must not end with '/', as the routes will start with '/'"
+ )
+ self.prefix = prefix
+ self.tags: List[Union[str, Enum]] = tags or []
+ self.dependencies = list(dependencies or [])
+ self.deprecated = deprecated
+ self.include_in_schema = include_in_schema
+ self.responses = responses or {}
+ self.callbacks = callbacks or []
+ self.dependency_overrides_provider = dependency_overrides_provider
+ self.route_class = route_class
+ self.default_response_class = default_response_class
+ self.generate_unique_id_function = generate_unique_id_function
+
+ def route(
+ self,
+ path: str,
+ methods: Optional[List[str]] = None,
+ name: Optional[str] = None,
+ include_in_schema: bool = True,
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_route(
+ path,
+ func,
+ methods=methods,
+ name=name,
+ include_in_schema=include_in_schema,
+ )
+ return func
+
+ return decorator
+
+ def add_api_route(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ *,
+ response_model: Any = Default(None),
+ status_code: Optional[int] = None,
+ tags: Optional[List[Union[str, Enum]]] = None,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ response_description: str = "Successful Response",
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
+ deprecated: Optional[bool] = None,
+ methods: Optional[Union[Set[str], List[str]]] = None,
+ operation_id: Optional[str] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ include_in_schema: bool = True,
+ response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+ JSONResponse
+ ),
+ name: Optional[str] = None,
+ route_class_override: Optional[Type[APIRoute]] = None,
+ callbacks: Optional[List[BaseRoute]] = None,
+ openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Union[
+ Callable[[APIRoute], str], DefaultPlaceholder
+ ] = Default(generate_unique_id),
+ ) -> None:
+ route_class = route_class_override or self.route_class
+ responses = responses or {}
+ combined_responses = {**self.responses, **responses}
+ current_response_class = get_value_or_default(
+ response_class, self.default_response_class
+ )
+ current_tags = self.tags.copy()
+ if tags:
+ current_tags.extend(tags)
+ current_dependencies = self.dependencies.copy()
+ if dependencies:
+ current_dependencies.extend(dependencies)
+ current_callbacks = self.callbacks.copy()
+ if callbacks:
+ current_callbacks.extend(callbacks)
+ current_generate_unique_id = get_value_or_default(
+ generate_unique_id_function, self.generate_unique_id_function
+ )
+ route = route_class(
+ self.prefix + path,
+ endpoint=endpoint,
+ response_model=response_model,
+ status_code=status_code,
+ tags=current_tags,
+ dependencies=current_dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=combined_responses,
+ deprecated=deprecated or self.deprecated,
+ methods=methods,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema and self.include_in_schema,
+ response_class=current_response_class,
+ name=name,
+ dependency_overrides_provider=self.dependency_overrides_provider,
+ callbacks=current_callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=current_generate_unique_id,
+ )
+ self.routes.append(route)
+
+ def api_route(
+ self,
+ path: str,
+ *,
+ response_model: Any = Default(None),
+ status_code: Optional[int] = None,
+ tags: Optional[List[Union[str, Enum]]] = None,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ summary: Optional[str] = None,
+ description: Optional[str] = None,
+ response_description: str = "Successful Response",
+ responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
+ deprecated: Optional[bool] = None,
+ methods: Optional[List[str]] = None,
+ operation_id: Optional[str] = None,
+ response_model_include: Optional[IncEx] = None,
+ response_model_exclude: Optional[IncEx] = None,
+ response_model_by_alias: bool = True,
+ response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
+ include_in_schema: bool = True,
+ response_class: Type[Response] = Default(JSONResponse),
+ name: Optional[str] = None,
+ callbacks: Optional[List[BaseRoute]] = None,
+ openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_api_route(
+ path,
+ func,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=methods,
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+ return func
+
+ return decorator
+
+ def add_api_websocket_route(
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ ) -> None:
+ current_dependencies = self.dependencies.copy()
+ if dependencies:
+ current_dependencies.extend(dependencies)
+
+ route = APIWebSocketRoute(
+ self.prefix + path,
+ endpoint=endpoint,
+ name=name,
+ dependencies=current_dependencies,
+ dependency_overrides_provider=self.dependency_overrides_provider,
+ )
+ self.routes.append(route)
+
+ def websocket(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ WebSocket path.
+ """
+ ),
+ ],
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A name for the WebSocket. Only used internally.
+ """
+ ),
+ ] = None,
+ *,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be used for this
+ WebSocket.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+ """
+ ),
+ ] = None,
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Decorate a WebSocket function.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ **Example**
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI, WebSocket
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.websocket("/ws")
+ async def websocket_endpoint(websocket: WebSocket):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Message text was: {data}")
+
+ app.include_router(router)
+ ```
+ """
+
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_api_websocket_route(
+ path, func, name=name, dependencies=dependencies
+ )
+ return func
+
+ return decorator
+
+ def websocket_route(
+ self, path: str, name: Union[str, None] = None
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_websocket_route(path, func, name=name)
+ return func
+
+ return decorator
+
+ def include_router(
+ self,
+ router: Annotated["APIRouter", Doc("The `APIRouter` to include.")],
+ *,
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+ """
+ ),
+ ] = Default(JSONResponse),
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include (or not) all the *path operations* in this router in the
+ generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> None:
+ """
+ Include another `APIRouter` in the same current `APIRouter`.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ internal_router = APIRouter()
+ users_router = APIRouter()
+
+ @users_router.get("/users/")
+ def read_users():
+ return [{"name": "Rick"}, {"name": "Morty"}]
+
+ internal_router.include_router(users_router)
+ app.include_router(internal_router)
+ ```
+ """
+ if prefix:
+ assert prefix.startswith("/"), "A path prefix must start with '/'"
+ assert not prefix.endswith("/"), (
+ "A path prefix must not end with '/', as the routes will start with '/'"
+ )
+ else:
+ for r in router.routes:
+ path = getattr(r, "path") # noqa: B009
+ name = getattr(r, "name", "unknown")
+ if path is not None and not path:
+ raise FastAPIError(
+ f"Prefix and path cannot be both empty (path operation: {name})"
+ )
+ if responses is None:
+ responses = {}
+ for route in router.routes:
+ if isinstance(route, APIRoute):
+ combined_responses = {**responses, **route.responses}
+ use_response_class = get_value_or_default(
+ route.response_class,
+ router.default_response_class,
+ default_response_class,
+ self.default_response_class,
+ )
+ current_tags = []
+ if tags:
+ current_tags.extend(tags)
+ if route.tags:
+ current_tags.extend(route.tags)
+ current_dependencies: List[params.Depends] = []
+ if dependencies:
+ current_dependencies.extend(dependencies)
+ if route.dependencies:
+ current_dependencies.extend(route.dependencies)
+ current_callbacks = []
+ if callbacks:
+ current_callbacks.extend(callbacks)
+ if route.callbacks:
+ current_callbacks.extend(route.callbacks)
+ current_generate_unique_id = get_value_or_default(
+ route.generate_unique_id_function,
+ router.generate_unique_id_function,
+ generate_unique_id_function,
+ self.generate_unique_id_function,
+ )
+ self.add_api_route(
+ prefix + route.path,
+ route.endpoint,
+ response_model=route.response_model,
+ status_code=route.status_code,
+ tags=current_tags,
+ dependencies=current_dependencies,
+ summary=route.summary,
+ description=route.description,
+ response_description=route.response_description,
+ responses=combined_responses,
+ deprecated=route.deprecated or deprecated or self.deprecated,
+ methods=route.methods,
+ operation_id=route.operation_id,
+ response_model_include=route.response_model_include,
+ response_model_exclude=route.response_model_exclude,
+ response_model_by_alias=route.response_model_by_alias,
+ response_model_exclude_unset=route.response_model_exclude_unset,
+ response_model_exclude_defaults=route.response_model_exclude_defaults,
+ response_model_exclude_none=route.response_model_exclude_none,
+ include_in_schema=route.include_in_schema
+ and self.include_in_schema
+ and include_in_schema,
+ response_class=use_response_class,
+ name=route.name,
+ route_class_override=type(route),
+ callbacks=current_callbacks,
+ openapi_extra=route.openapi_extra,
+ generate_unique_id_function=current_generate_unique_id,
+ )
+ elif isinstance(route, routing.Route):
+ methods = list(route.methods or [])
+ self.add_route(
+ prefix + route.path,
+ route.endpoint,
+ methods=methods,
+ include_in_schema=route.include_in_schema,
+ name=route.name,
+ )
+ elif isinstance(route, APIWebSocketRoute):
+ current_dependencies = []
+ if dependencies:
+ current_dependencies.extend(dependencies)
+ if route.dependencies:
+ current_dependencies.extend(route.dependencies)
+ self.add_api_websocket_route(
+ prefix + route.path,
+ route.endpoint,
+ dependencies=current_dependencies,
+ name=route.name,
+ )
+ elif isinstance(route, routing.WebSocketRoute):
+ self.add_websocket_route(
+ prefix + route.path, route.endpoint, name=route.name
+ )
+ for handler in router.on_startup:
+ self.add_event_handler("startup", handler)
+ for handler in router.on_shutdown:
+ self.add_event_handler("shutdown", handler)
+ self.lifespan_context = _merge_lifespan_context(
+ self.lifespan_context,
+ router.lifespan_context,
+ )
+
+ def get(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP GET operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.get("/items/")
+ def read_items():
+ return [{"name": "Empanada"}, {"name": "Arepa"}]
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["GET"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def put(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PUT operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.put("/items/{item_id}")
+ def replace_item(item_id: str, item: Item):
+ return {"message": "Item replaced", "id": item_id}
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["PUT"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def post(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP POST operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.post("/items/")
+ def create_item(item: Item):
+ return {"message": "Item created"}
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["POST"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def delete(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP DELETE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.delete("/items/{item_id}")
+ def delete_item(item_id: str):
+ return {"message": "Item deleted"}
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["DELETE"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def options(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP OPTIONS operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.options("/items/")
+ def get_item_options():
+ return {"additions": ["Aji", "Guacamole"]}
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["OPTIONS"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def head(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP HEAD operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.head("/items/", status_code=204)
+ def get_items_headers(response: Response):
+ response.headers["X-Cat-Dog"] = "Alone in the world"
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["HEAD"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def patch(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PATCH operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.patch("/items/")
+ def update_item(item: Item):
+ return {"message": "Item updated in place"}
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["PATCH"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def trace(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP TRACE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.trace("/items/{item_id}")
+ def trace_item(item_id: str):
+ return None
+
+ app.include_router(router)
+ ```
+ """
+ return self.api_route(
+ path=path,
+ response_model=response_model,
+ status_code=status_code,
+ tags=tags,
+ dependencies=dependencies,
+ summary=summary,
+ description=description,
+ response_description=response_description,
+ responses=responses,
+ deprecated=deprecated,
+ methods=["TRACE"],
+ operation_id=operation_id,
+ response_model_include=response_model_include,
+ response_model_exclude=response_model_exclude,
+ response_model_by_alias=response_model_by_alias,
+ response_model_exclude_unset=response_model_exclude_unset,
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
+ include_in_schema=include_in_schema,
+ response_class=response_class,
+ name=name,
+ callbacks=callbacks,
+ openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ @deprecated(
+ """
+ on_event is deprecated, use lifespan event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ )
+ def on_event(
+ self,
+ event_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of event. `startup` or `shutdown`.
+ """
+ ),
+ ],
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an event handler for the router.
+
+ `on_event` is deprecated, use `lifespan` event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated).
+ """
+
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_event_handler(event_type, func)
+ return func
+
+ return decorator
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/__init__.py b/.venv/lib/python3.12/site-packages/fastapi/security/__init__.py
new file mode 100644
index 00000000..3aa6bf21
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/__init__.py
@@ -0,0 +1,15 @@
+from .api_key import APIKeyCookie as APIKeyCookie
+from .api_key import APIKeyHeader as APIKeyHeader
+from .api_key import APIKeyQuery as APIKeyQuery
+from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials
+from .http import HTTPBasic as HTTPBasic
+from .http import HTTPBasicCredentials as HTTPBasicCredentials
+from .http import HTTPBearer as HTTPBearer
+from .http import HTTPDigest as HTTPDigest
+from .oauth2 import OAuth2 as OAuth2
+from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer
+from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer
+from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm
+from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict
+from .oauth2 import SecurityScopes as SecurityScopes
+from .open_id_connect_url import OpenIdConnect as OpenIdConnect
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/api_key.py b/.venv/lib/python3.12/site-packages/fastapi/security/api_key.py
new file mode 100644
index 00000000..70c2dca8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/api_key.py
@@ -0,0 +1,288 @@
+from typing import Optional
+
+from fastapi.openapi.models import APIKey, APIKeyIn
+from fastapi.security.base import SecurityBase
+from starlette.exceptions import HTTPException
+from starlette.requests import Request
+from starlette.status import HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc
+
+
+class APIKeyBase(SecurityBase):
+ @staticmethod
+ def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:
+ if not api_key:
+ if auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ return None
+ return api_key
+
+
+class APIKeyQuery(APIKeyBase):
+ """
+ API key authentication using a query parameter.
+
+ This defines the name of the query parameter that should be provided in the request
+ with the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the query parameter automatically and provides it as the
+ dependency result. But it doesn't define how to send that API key to the client.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyQuery
+
+ app = FastAPI()
+
+ query_scheme = APIKeyQuery(name="api_key")
+
+
+ @app.get("/items/")
+ async def read_items(api_key: str = Depends(query_scheme)):
+ return {"api_key": api_key}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ name: Annotated[
+ str,
+ Doc("Query parameter name."),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the query parameter is not provided, `APIKeyQuery` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the query parameter is not
+ available, instead of erroring out, the dependency result will be
+ `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a query
+ parameter or in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
+ ):
+ self.model: APIKey = APIKey(
+ **{"in": APIKeyIn.query}, # type: ignore[arg-type]
+ name=name,
+ description=description,
+ )
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ api_key = request.query_params.get(self.model.name)
+ return self.check_api_key(api_key, self.auto_error)
+
+
+class APIKeyHeader(APIKeyBase):
+ """
+ API key authentication using a header.
+
+ This defines the name of the header that should be provided in the request with
+ the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the header automatically and provides it as the dependency
+ result. But it doesn't define how to send that key to the client.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyHeader
+
+ app = FastAPI()
+
+ header_scheme = APIKeyHeader(name="x-key")
+
+
+ @app.get("/items/")
+ async def read_items(key: str = Depends(header_scheme)):
+ return {"key": key}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ name: Annotated[str, Doc("Header name.")],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the header is not provided, `APIKeyHeader` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the header is not available,
+ instead of erroring out, the dependency result will be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a header or
+ in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
+ ):
+ self.model: APIKey = APIKey(
+ **{"in": APIKeyIn.header}, # type: ignore[arg-type]
+ name=name,
+ description=description,
+ )
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ api_key = request.headers.get(self.model.name)
+ return self.check_api_key(api_key, self.auto_error)
+
+
+class APIKeyCookie(APIKeyBase):
+ """
+ API key authentication using a cookie.
+
+ This defines the name of the cookie that should be provided in the request with
+ the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the cookie automatically and provides it as the dependency
+ result. But it doesn't define how to set that cookie.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyCookie
+
+ app = FastAPI()
+
+ cookie_scheme = APIKeyCookie(name="session")
+
+
+ @app.get("/items/")
+ async def read_items(session: str = Depends(cookie_scheme)):
+ return {"session": session}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ name: Annotated[str, Doc("Cookie name.")],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the cookie is not provided, `APIKeyCookie` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the cookie is not available,
+ instead of erroring out, the dependency result will be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a cookie or
+ in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
+ ):
+ self.model: APIKey = APIKey(
+ **{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
+ name=name,
+ description=description,
+ )
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ api_key = request.cookies.get(self.model.name)
+ return self.check_api_key(api_key, self.auto_error)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/base.py b/.venv/lib/python3.12/site-packages/fastapi/security/base.py
new file mode 100644
index 00000000..c43555de
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/base.py
@@ -0,0 +1,6 @@
+from fastapi.openapi.models import SecurityBase as SecurityBaseModel
+
+
+class SecurityBase:
+ model: SecurityBaseModel
+ scheme_name: str
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/http.py b/.venv/lib/python3.12/site-packages/fastapi/security/http.py
new file mode 100644
index 00000000..9ab2df3c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/http.py
@@ -0,0 +1,423 @@
+import binascii
+from base64 import b64decode
+from typing import Optional
+
+from fastapi.exceptions import HTTPException
+from fastapi.openapi.models import HTTPBase as HTTPBaseModel
+from fastapi.openapi.models import HTTPBearer as HTTPBearerModel
+from fastapi.security.base import SecurityBase
+from fastapi.security.utils import get_authorization_scheme_param
+from pydantic import BaseModel
+from starlette.requests import Request
+from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc
+
+
+class HTTPBasicCredentials(BaseModel):
+ """
+ The HTTP Basic credentials given as the result of using `HTTPBasic` in a
+ dependency.
+
+ Read more about it in the
+ [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).
+ """
+
+ username: Annotated[str, Doc("The HTTP Basic username.")]
+ password: Annotated[str, Doc("The HTTP Basic password.")]
+
+
+class HTTPAuthorizationCredentials(BaseModel):
+ """
+ The HTTP authorization credentials in the result of using `HTTPBearer` or
+ `HTTPDigest` in a dependency.
+
+ The HTTP authorization header value is split by the first space.
+
+ The first part is the `scheme`, the second part is the `credentials`.
+
+ For example, in an HTTP Bearer token scheme, the client will send a header
+ like:
+
+ ```
+ Authorization: Bearer deadbeef12346
+ ```
+
+ In this case:
+
+ * `scheme` will have the value `"Bearer"`
+ * `credentials` will have the value `"deadbeef12346"`
+ """
+
+ scheme: Annotated[
+ str,
+ Doc(
+ """
+ The HTTP authorization scheme extracted from the header value.
+ """
+ ),
+ ]
+ credentials: Annotated[
+ str,
+ Doc(
+ """
+ The HTTP authorization credentials extracted from the header value.
+ """
+ ),
+ ]
+
+
+class HTTPBase(SecurityBase):
+ def __init__(
+ self,
+ *,
+ scheme: str,
+ scheme_name: Optional[str] = None,
+ description: Optional[str] = None,
+ auto_error: bool = True,
+ ):
+ self.model = HTTPBaseModel(scheme=scheme, description=description)
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(
+ self, request: Request
+ ) -> Optional[HTTPAuthorizationCredentials]:
+ authorization = request.headers.get("Authorization")
+ scheme, credentials = get_authorization_scheme_param(authorization)
+ if not (authorization and scheme and credentials):
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ else:
+ return None
+ return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)
+
+
+class HTTPBasic(HTTPBase):
+ """
+ HTTP Basic authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPBasicCredentials` object containing the
+ `username` and the `password`.
+
+ Read more about it in the
+ [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPBasic, HTTPBasicCredentials
+
+ app = FastAPI()
+
+ security = HTTPBasic()
+
+
+ @app.get("/users/me")
+ def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
+ return {"username": credentials.username, "password": credentials.password}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ realm: Annotated[
+ Optional[str],
+ Doc(
+ """
+ HTTP Basic authentication realm.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Basic authentication is not provided (a
+ header), `HTTPBasic` will automatically cancel the request and send the
+ client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Basic authentication
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in HTTP Basic
+ authentication or in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
+ ):
+ self.model = HTTPBaseModel(scheme="basic", description=description)
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.realm = realm
+ self.auto_error = auto_error
+
+ async def __call__( # type: ignore
+ self, request: Request
+ ) -> Optional[HTTPBasicCredentials]:
+ authorization = request.headers.get("Authorization")
+ scheme, param = get_authorization_scheme_param(authorization)
+ if self.realm:
+ unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'}
+ else:
+ unauthorized_headers = {"WWW-Authenticate": "Basic"}
+ if not authorization or scheme.lower() != "basic":
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_401_UNAUTHORIZED,
+ detail="Not authenticated",
+ headers=unauthorized_headers,
+ )
+ else:
+ return None
+ invalid_user_credentials_exc = HTTPException(
+ status_code=HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials",
+ headers=unauthorized_headers,
+ )
+ try:
+ data = b64decode(param).decode("ascii")
+ except (ValueError, UnicodeDecodeError, binascii.Error):
+ raise invalid_user_credentials_exc # noqa: B904
+ username, separator, password = data.partition(":")
+ if not separator:
+ raise invalid_user_credentials_exc
+ return HTTPBasicCredentials(username=username, password=password)
+
+
+class HTTPBearer(HTTPBase):
+ """
+ HTTP Bearer token authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPAuthorizationCredentials` object containing
+ the `scheme` and the `credentials`.
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
+
+ app = FastAPI()
+
+ security = HTTPBearer()
+
+
+ @app.get("/users/me")
+ def read_current_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
+ ):
+ return {"scheme": credentials.scheme, "credentials": credentials.credentials}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Bearer token is not provided (in an
+ `Authorization` header), `HTTPBearer` will automatically cancel the
+ request and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Bearer token
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in an HTTP
+ Bearer token or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description)
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(
+ self, request: Request
+ ) -> Optional[HTTPAuthorizationCredentials]:
+ authorization = request.headers.get("Authorization")
+ scheme, credentials = get_authorization_scheme_param(authorization)
+ if not (authorization and scheme and credentials):
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ else:
+ return None
+ if scheme.lower() != "bearer":
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN,
+ detail="Invalid authentication credentials",
+ )
+ else:
+ return None
+ return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)
+
+
+class HTTPDigest(HTTPBase):
+ """
+ HTTP Digest authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPAuthorizationCredentials` object containing
+ the `scheme` and the `credentials`.
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
+
+ app = FastAPI()
+
+ security = HTTPDigest()
+
+
+ @app.get("/users/me")
+ def read_current_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
+ ):
+ return {"scheme": credentials.scheme, "credentials": credentials.credentials}
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Digest is not provided, `HTTPDigest` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Digest is not
+ available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in HTTP
+ Digest or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ self.model = HTTPBaseModel(scheme="digest", description=description)
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(
+ self, request: Request
+ ) -> Optional[HTTPAuthorizationCredentials]:
+ authorization = request.headers.get("Authorization")
+ scheme, credentials = get_authorization_scheme_param(authorization)
+ if not (authorization and scheme and credentials):
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ else:
+ return None
+ if scheme.lower() != "digest":
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN,
+ detail="Invalid authentication credentials",
+ )
+ else:
+ return None
+ return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/oauth2.py b/.venv/lib/python3.12/site-packages/fastapi/security/oauth2.py
new file mode 100644
index 00000000..5ffad598
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/oauth2.py
@@ -0,0 +1,638 @@
+from typing import Any, Dict, List, Optional, Union, cast
+
+from fastapi.exceptions import HTTPException
+from fastapi.openapi.models import OAuth2 as OAuth2Model
+from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
+from fastapi.param_functions import Form
+from fastapi.security.base import SecurityBase
+from fastapi.security.utils import get_authorization_scheme_param
+from starlette.requests import Request
+from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
+
+# TODO: import from typing when deprecating Python 3.9
+from typing_extensions import Annotated, Doc
+
+
+class OAuth2PasswordRequestForm:
+ """
+ This is a dependency class to collect the `username` and `password` as form data
+ for an OAuth2 password flow.
+
+ The OAuth2 specification dictates that for a password flow the data should be
+ collected using form data (instead of JSON) and that it should have the specific
+ fields `username` and `password`.
+
+ All the initialization parameters are extracted from the request.
+
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import OAuth2PasswordRequestForm
+
+ app = FastAPI()
+
+
+ @app.post("/login")
+ def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
+ data = {}
+ data["scopes"] = []
+ for scope in form_data.scopes:
+ data["scopes"].append(scope)
+ if form_data.client_id:
+ data["client_id"] = form_data.client_id
+ if form_data.client_secret:
+ data["client_secret"] = form_data.client_secret
+ return data
+ ```
+
+ Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
+ You could have custom internal logic to separate it by colon characters (`:`) or
+ similar, and get the two parts `items` and `read`. Many applications do that to
+ group and organize permissions, you could do it as well in your application, just
+ know that that it is application specific, it's not part of the specification.
+ """
+
+ def __init__(
+ self,
+ *,
+ grant_type: Annotated[
+ Union[str, None],
+ Form(pattern="^password$"),
+ Doc(
+ """
+ The OAuth2 spec says it is required and MUST be the fixed string
+ "password". Nevertheless, this dependency class is permissive and
+ allows not passing it. If you want to enforce it, use instead the
+ `OAuth2PasswordRequestFormStrict` dependency.
+ """
+ ),
+ ] = None,
+ username: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `username` string. The OAuth2 spec requires the exact field name
+ `username`.
+ """
+ ),
+ ],
+ password: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `password` string. The OAuth2 spec requires the exact field name
+ `password".
+ """
+ ),
+ ],
+ scope: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ A single string with actually several scopes separated by spaces. Each
+ scope is also a string.
+
+ For example, a single string with:
+
+ ```python
+ "items:read items:write users:read profile openid"
+ ````
+
+ would represent the scopes:
+
+ * `items:read`
+ * `items:write`
+ * `users:read`
+ * `profile`
+ * `openid`
+ """
+ ),
+ ] = "",
+ client_id: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_id`, it can be sent as part of the form fields.
+ But the OAuth2 specification recommends sending the `client_id` and
+ `client_secret` (if any) using HTTP Basic auth.
+ """
+ ),
+ ] = None,
+ client_secret: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_password` (and a `client_id`), they can be sent
+ as part of the form fields. But the OAuth2 specification recommends
+ sending the `client_id` and `client_secret` (if any) using HTTP Basic
+ auth.
+ """
+ ),
+ ] = None,
+ ):
+ self.grant_type = grant_type
+ self.username = username
+ self.password = password
+ self.scopes = scope.split()
+ self.client_id = client_id
+ self.client_secret = client_secret
+
+
+class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
+ """
+ This is a dependency class to collect the `username` and `password` as form data
+ for an OAuth2 password flow.
+
+ The OAuth2 specification dictates that for a password flow the data should be
+ collected using form data (instead of JSON) and that it should have the specific
+ fields `username` and `password`.
+
+ All the initialization parameters are extracted from the request.
+
+ The only difference between `OAuth2PasswordRequestFormStrict` and
+ `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the
+ client to send the form field `grant_type` with the value `"password"`, which
+ is required in the OAuth2 specification (it seems that for no particular reason),
+ while for `OAuth2PasswordRequestForm` `grant_type` is optional.
+
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import OAuth2PasswordRequestForm
+
+ app = FastAPI()
+
+
+ @app.post("/login")
+ def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):
+ data = {}
+ data["scopes"] = []
+ for scope in form_data.scopes:
+ data["scopes"].append(scope)
+ if form_data.client_id:
+ data["client_id"] = form_data.client_id
+ if form_data.client_secret:
+ data["client_secret"] = form_data.client_secret
+ return data
+ ```
+
+ Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
+ You could have custom internal logic to separate it by colon characters (`:`) or
+ similar, and get the two parts `items` and `read`. Many applications do that to
+ group and organize permissions, you could do it as well in your application, just
+ know that that it is application specific, it's not part of the specification.
+
+
+ grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
+ This dependency is strict about it. If you want to be permissive, use instead the
+ OAuth2PasswordRequestForm dependency class.
+ username: username string. The OAuth2 spec requires the exact field name "username".
+ password: password string. The OAuth2 spec requires the exact field name "password".
+ scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.
+ "items:read items:write users:read profile openid"
+ client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
+ using HTTP Basic auth, as: client_id:client_secret
+ client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
+ using HTTP Basic auth, as: client_id:client_secret
+ """
+
+ def __init__(
+ self,
+ grant_type: Annotated[
+ str,
+ Form(pattern="^password$"),
+ Doc(
+ """
+ The OAuth2 spec says it is required and MUST be the fixed string
+ "password". This dependency is strict about it. If you want to be
+ permissive, use instead the `OAuth2PasswordRequestForm` dependency
+ class.
+ """
+ ),
+ ],
+ username: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `username` string. The OAuth2 spec requires the exact field name
+ `username`.
+ """
+ ),
+ ],
+ password: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `password` string. The OAuth2 spec requires the exact field name
+ `password".
+ """
+ ),
+ ],
+ scope: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ A single string with actually several scopes separated by spaces. Each
+ scope is also a string.
+
+ For example, a single string with:
+
+ ```python
+ "items:read items:write users:read profile openid"
+ ````
+
+ would represent the scopes:
+
+ * `items:read`
+ * `items:write`
+ * `users:read`
+ * `profile`
+ * `openid`
+ """
+ ),
+ ] = "",
+ client_id: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_id`, it can be sent as part of the form fields.
+ But the OAuth2 specification recommends sending the `client_id` and
+ `client_secret` (if any) using HTTP Basic auth.
+ """
+ ),
+ ] = None,
+ client_secret: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_password` (and a `client_id`), they can be sent
+ as part of the form fields. But the OAuth2 specification recommends
+ sending the `client_id` and `client_secret` (if any) using HTTP Basic
+ auth.
+ """
+ ),
+ ] = None,
+ ):
+ super().__init__(
+ grant_type=grant_type,
+ username=username,
+ password=password,
+ scope=scope,
+ client_id=client_id,
+ client_secret=client_secret,
+ )
+
+
+class OAuth2(SecurityBase):
+ """
+ This is the base class for OAuth2 authentication, an instance of it would be used
+ as a dependency. All other OAuth2 classes inherit from it and customize it for
+ each OAuth2 flow.
+
+ You normally would not create a new class inheriting from it but use one of the
+ existing subclasses, and maybe compose them if you want to support multiple flows.
+
+ Read more about it in the
+ [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).
+ """
+
+ def __init__(
+ self,
+ *,
+ flows: Annotated[
+ Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]],
+ Doc(
+ """
+ The dictionary of OAuth2 flows.
+ """
+ ),
+ ] = OAuthFlowsModel(),
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Authorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ self.model = OAuth2Model(
+ flows=cast(OAuthFlowsModel, flows), description=description
+ )
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ authorization = request.headers.get("Authorization")
+ if not authorization:
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ else:
+ return None
+ return authorization
+
+
+class OAuth2PasswordBearer(OAuth2):
+ """
+ OAuth2 flow for authentication using a bearer token obtained with a password.
+ An instance of it would be used as a dependency.
+
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
+ """
+
+ def __init__(
+ self,
+ tokenUrl: Annotated[
+ str,
+ Doc(
+ """
+ The URL to obtain the OAuth2 token. This would be the *path operation*
+ that has `OAuth2PasswordRequestForm` as a dependency.
+ """
+ ),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ scopes: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ The OAuth2 scopes that would be required by the *path operations* that
+ use this dependency.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Authorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ if not scopes:
+ scopes = {}
+ flows = OAuthFlowsModel(
+ password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes})
+ )
+ super().__init__(
+ flows=flows,
+ scheme_name=scheme_name,
+ description=description,
+ auto_error=auto_error,
+ )
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ authorization = request.headers.get("Authorization")
+ scheme, param = get_authorization_scheme_param(authorization)
+ if not authorization or scheme.lower() != "bearer":
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_401_UNAUTHORIZED,
+ detail="Not authenticated",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ else:
+ return None
+ return param
+
+
+class OAuth2AuthorizationCodeBearer(OAuth2):
+ """
+ OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code
+ flow. An instance of it would be used as a dependency.
+ """
+
+ def __init__(
+ self,
+ authorizationUrl: str,
+ tokenUrl: Annotated[
+ str,
+ Doc(
+ """
+ The URL to obtain the OAuth2 token.
+ """
+ ),
+ ],
+ refreshUrl: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The URL to refresh the token and obtain a new one.
+ """
+ ),
+ ] = None,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ scopes: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ The OAuth2 scopes that would be required by the *path operations* that
+ use this dependency.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Authorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ if not scopes:
+ scopes = {}
+ flows = OAuthFlowsModel(
+ authorizationCode=cast(
+ Any,
+ {
+ "authorizationUrl": authorizationUrl,
+ "tokenUrl": tokenUrl,
+ "refreshUrl": refreshUrl,
+ "scopes": scopes,
+ },
+ )
+ )
+ super().__init__(
+ flows=flows,
+ scheme_name=scheme_name,
+ description=description,
+ auto_error=auto_error,
+ )
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ authorization = request.headers.get("Authorization")
+ scheme, param = get_authorization_scheme_param(authorization)
+ if not authorization or scheme.lower() != "bearer":
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_401_UNAUTHORIZED,
+ detail="Not authenticated",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ else:
+ return None # pragma: nocover
+ return param
+
+
+class SecurityScopes:
+ """
+ This is a special class that you can define in a parameter in a dependency to
+ obtain the OAuth2 scopes required by all the dependencies in the same chain.
+
+ This way, multiple dependencies can have different scopes, even when used in the
+ same *path operation*. And with this, you can access all the scopes required in
+ all those dependencies in a single place.
+
+ Read more about it in the
+ [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
+ """
+
+ def __init__(
+ self,
+ scopes: Annotated[
+ Optional[List[str]],
+ Doc(
+ """
+ This will be filled by FastAPI.
+ """
+ ),
+ ] = None,
+ ):
+ self.scopes: Annotated[
+ List[str],
+ Doc(
+ """
+ The list of all the scopes required by dependencies.
+ """
+ ),
+ ] = scopes or []
+ self.scope_str: Annotated[
+ str,
+ Doc(
+ """
+ All the scopes required by all the dependencies in a single string
+ separated by spaces, as defined in the OAuth2 specification.
+ """
+ ),
+ ] = " ".join(self.scopes)
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/open_id_connect_url.py b/.venv/lib/python3.12/site-packages/fastapi/security/open_id_connect_url.py
new file mode 100644
index 00000000..c8cceb91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/open_id_connect_url.py
@@ -0,0 +1,84 @@
+from typing import Optional
+
+from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
+from fastapi.security.base import SecurityBase
+from starlette.exceptions import HTTPException
+from starlette.requests import Request
+from starlette.status import HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc
+
+
+class OpenIdConnect(SecurityBase):
+ """
+ OpenID Connect authentication class. An instance of it would be used as a
+ dependency.
+ """
+
+ def __init__(
+ self,
+ *,
+ openIdConnectUrl: Annotated[
+ str,
+ Doc(
+ """
+ The OpenID Connect URL.
+ """
+ ),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Authorization header is provided, required for
+ OpenID Connect authentication, it will automatically cancel the request
+ and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OpenID
+ Connect or in a cookie).
+ """
+ ),
+ ] = True,
+ ):
+ self.model = OpenIdConnectModel(
+ openIdConnectUrl=openIdConnectUrl, description=description
+ )
+ self.scheme_name = scheme_name or self.__class__.__name__
+ self.auto_error = auto_error
+
+ async def __call__(self, request: Request) -> Optional[str]:
+ authorization = request.headers.get("Authorization")
+ if not authorization:
+ if self.auto_error:
+ raise HTTPException(
+ status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
+ )
+ else:
+ return None
+ return authorization
diff --git a/.venv/lib/python3.12/site-packages/fastapi/security/utils.py b/.venv/lib/python3.12/site-packages/fastapi/security/utils.py
new file mode 100644
index 00000000..fa7a450b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/security/utils.py
@@ -0,0 +1,10 @@
+from typing import Optional, Tuple
+
+
+def get_authorization_scheme_param(
+ authorization_header_value: Optional[str],
+) -> Tuple[str, str]:
+ if not authorization_header_value:
+ return "", ""
+ scheme, _, param = authorization_header_value.partition(" ")
+ return scheme, param
diff --git a/.venv/lib/python3.12/site-packages/fastapi/staticfiles.py b/.venv/lib/python3.12/site-packages/fastapi/staticfiles.py
new file mode 100644
index 00000000..299015d4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/staticfiles.py
@@ -0,0 +1 @@
+from starlette.staticfiles import StaticFiles as StaticFiles # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/templating.py b/.venv/lib/python3.12/site-packages/fastapi/templating.py
new file mode 100644
index 00000000..0cb86848
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/templating.py
@@ -0,0 +1 @@
+from starlette.templating import Jinja2Templates as Jinja2Templates # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/testclient.py b/.venv/lib/python3.12/site-packages/fastapi/testclient.py
new file mode 100644
index 00000000..4012406a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/testclient.py
@@ -0,0 +1 @@
+from starlette.testclient import TestClient as TestClient # noqa
diff --git a/.venv/lib/python3.12/site-packages/fastapi/types.py b/.venv/lib/python3.12/site-packages/fastapi/types.py
new file mode 100644
index 00000000..3205654c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/types.py
@@ -0,0 +1,10 @@
+import types
+from enum import Enum
+from typing import Any, Callable, Dict, Set, Type, TypeVar, Union
+
+from pydantic import BaseModel
+
+DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
+UnionType = getattr(types, "UnionType", Union)
+ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
+IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
diff --git a/.venv/lib/python3.12/site-packages/fastapi/utils.py b/.venv/lib/python3.12/site-packages/fastapi/utils.py
new file mode 100644
index 00000000..4c7350fe
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/utils.py
@@ -0,0 +1,220 @@
+import re
+import warnings
+from dataclasses import is_dataclass
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Dict,
+ MutableMapping,
+ Optional,
+ Set,
+ Type,
+ Union,
+ cast,
+)
+from weakref import WeakKeyDictionary
+
+import fastapi
+from fastapi._compat import (
+ PYDANTIC_V2,
+ BaseConfig,
+ ModelField,
+ PydanticSchemaGenerationError,
+ Undefined,
+ UndefinedType,
+ Validator,
+ lenient_issubclass,
+)
+from fastapi.datastructures import DefaultPlaceholder, DefaultType
+from pydantic import BaseModel, create_model
+from pydantic.fields import FieldInfo
+from typing_extensions import Literal
+
+if TYPE_CHECKING: # pragma: nocover
+ from .routing import APIRoute
+
+# Cache for `create_cloned_field`
+_CLONED_TYPES_CACHE: MutableMapping[Type[BaseModel], Type[BaseModel]] = (
+ WeakKeyDictionary()
+)
+
+
+def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
+ if status_code is None:
+ return True
+ # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1
+ if status_code in {
+ "default",
+ "1XX",
+ "2XX",
+ "3XX",
+ "4XX",
+ "5XX",
+ }:
+ return True
+ current_status_code = int(status_code)
+ return not (current_status_code < 200 or current_status_code in {204, 205, 304})
+
+
+def get_path_param_names(path: str) -> Set[str]:
+ return set(re.findall("{(.*?)}", path))
+
+
+def create_model_field(
+ name: str,
+ type_: Any,
+ class_validators: Optional[Dict[str, Validator]] = None,
+ default: Optional[Any] = Undefined,
+ required: Union[bool, UndefinedType] = Undefined,
+ model_config: Type[BaseConfig] = BaseConfig,
+ field_info: Optional[FieldInfo] = None,
+ alias: Optional[str] = None,
+ mode: Literal["validation", "serialization"] = "validation",
+) -> ModelField:
+ class_validators = class_validators or {}
+ if PYDANTIC_V2:
+ field_info = field_info or FieldInfo(
+ annotation=type_, default=default, alias=alias
+ )
+ else:
+ field_info = field_info or FieldInfo()
+ kwargs = {"name": name, "field_info": field_info}
+ if PYDANTIC_V2:
+ kwargs.update({"mode": mode})
+ else:
+ kwargs.update(
+ {
+ "type_": type_,
+ "class_validators": class_validators,
+ "default": default,
+ "required": required,
+ "model_config": model_config,
+ "alias": alias,
+ }
+ )
+ try:
+ return ModelField(**kwargs) # type: ignore[arg-type]
+ except (RuntimeError, PydanticSchemaGenerationError):
+ raise fastapi.exceptions.FastAPIError(
+ "Invalid args for response field! Hint: "
+ f"check that {type_} is a valid Pydantic field type. "
+ "If you are using a return type annotation that is not a valid Pydantic "
+ "field (e.g. Union[Response, dict, None]) you can disable generating the "
+ "response model from the type annotation with the path operation decorator "
+ "parameter response_model=None. Read more: "
+ "https://fastapi.tiangolo.com/tutorial/response-model/"
+ ) from None
+
+
+def create_cloned_field(
+ field: ModelField,
+ *,
+ cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None,
+) -> ModelField:
+ if PYDANTIC_V2:
+ return field
+ # cloned_types caches already cloned types to support recursive models and improve
+ # performance by avoiding unnecessary cloning
+ if cloned_types is None:
+ cloned_types = _CLONED_TYPES_CACHE
+
+ original_type = field.type_
+ if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"):
+ original_type = original_type.__pydantic_model__
+ use_type = original_type
+ if lenient_issubclass(original_type, BaseModel):
+ original_type = cast(Type[BaseModel], original_type)
+ use_type = cloned_types.get(original_type)
+ if use_type is None:
+ use_type = create_model(original_type.__name__, __base__=original_type)
+ cloned_types[original_type] = use_type
+ for f in original_type.__fields__.values():
+ use_type.__fields__[f.name] = create_cloned_field(
+ f, cloned_types=cloned_types
+ )
+ new_field = create_model_field(name=field.name, type_=use_type)
+ new_field.has_alias = field.has_alias # type: ignore[attr-defined]
+ new_field.alias = field.alias # type: ignore[misc]
+ new_field.class_validators = field.class_validators # type: ignore[attr-defined]
+ new_field.default = field.default # type: ignore[misc]
+ new_field.required = field.required # type: ignore[misc]
+ new_field.model_config = field.model_config # type: ignore[attr-defined]
+ new_field.field_info = field.field_info
+ new_field.allow_none = field.allow_none # type: ignore[attr-defined]
+ new_field.validate_always = field.validate_always # type: ignore[attr-defined]
+ if field.sub_fields: # type: ignore[attr-defined]
+ new_field.sub_fields = [ # type: ignore[attr-defined]
+ create_cloned_field(sub_field, cloned_types=cloned_types)
+ for sub_field in field.sub_fields # type: ignore[attr-defined]
+ ]
+ if field.key_field: # type: ignore[attr-defined]
+ new_field.key_field = create_cloned_field( # type: ignore[attr-defined]
+ field.key_field, # type: ignore[attr-defined]
+ cloned_types=cloned_types,
+ )
+ new_field.validators = field.validators # type: ignore[attr-defined]
+ new_field.pre_validators = field.pre_validators # type: ignore[attr-defined]
+ new_field.post_validators = field.post_validators # type: ignore[attr-defined]
+ new_field.parse_json = field.parse_json # type: ignore[attr-defined]
+ new_field.shape = field.shape # type: ignore[attr-defined]
+ new_field.populate_validators() # type: ignore[attr-defined]
+ return new_field
+
+
+def generate_operation_id_for_path(
+ *, name: str, path: str, method: str
+) -> str: # pragma: nocover
+ warnings.warn(
+ "fastapi.utils.generate_operation_id_for_path() was deprecated, "
+ "it is not used internally, and will be removed soon",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ operation_id = f"{name}{path}"
+ operation_id = re.sub(r"\W", "_", operation_id)
+ operation_id = f"{operation_id}_{method.lower()}"
+ return operation_id
+
+
+def generate_unique_id(route: "APIRoute") -> str:
+ operation_id = f"{route.name}{route.path_format}"
+ operation_id = re.sub(r"\W", "_", operation_id)
+ assert route.methods
+ operation_id = f"{operation_id}_{list(route.methods)[0].lower()}"
+ return operation_id
+
+
+def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None:
+ for key, value in update_dict.items():
+ if (
+ key in main_dict
+ and isinstance(main_dict[key], dict)
+ and isinstance(value, dict)
+ ):
+ deep_dict_update(main_dict[key], value)
+ elif (
+ key in main_dict
+ and isinstance(main_dict[key], list)
+ and isinstance(update_dict[key], list)
+ ):
+ main_dict[key] = main_dict[key] + update_dict[key]
+ else:
+ main_dict[key] = value
+
+
+def get_value_or_default(
+ first_item: Union[DefaultPlaceholder, DefaultType],
+ *extra_items: Union[DefaultPlaceholder, DefaultType],
+) -> Union[DefaultPlaceholder, DefaultType]:
+ """
+ Pass items or `DefaultPlaceholder`s by descending priority.
+
+ The first one to _not_ be a `DefaultPlaceholder` will be returned.
+
+ Otherwise, the first item (a `DefaultPlaceholder`) will be returned.
+ """
+ items = (first_item,) + extra_items
+ for item in items:
+ if not isinstance(item, DefaultPlaceholder):
+ return item
+ return first_item
diff --git a/.venv/lib/python3.12/site-packages/fastapi/websockets.py b/.venv/lib/python3.12/site-packages/fastapi/websockets.py
new file mode 100644
index 00000000..55a4ac4a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fastapi/websockets.py
@@ -0,0 +1,3 @@
+from starlette.websockets import WebSocket as WebSocket # noqa
+from starlette.websockets import WebSocketDisconnect as WebSocketDisconnect # noqa
+from starlette.websockets import WebSocketState as WebSocketState # noqa