]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
♻️ Upgrade internal syntax to Python 3.9+ 🎉 (#14564)
authorSebastián Ramírez <tiangolo@gmail.com>
Wed, 17 Dec 2025 21:25:59 +0000 (13:25 -0800)
committerGitHub <noreply@github.com>
Wed, 17 Dec 2025 21:25:59 +0000 (21:25 +0000)
142 files changed:
docs_src/header_params/tutorial003_an_py39.py
fastapi/_compat/main.py
fastapi/_compat/may_v1.py
fastapi/_compat/model_field.py
fastapi/_compat/shared.py
fastapi/_compat/v1.py
fastapi/_compat/v2.py
fastapi/applications.py
fastapi/background.py
fastapi/concurrency.py
fastapi/datastructures.py
fastapi/dependencies/models.py
fastapi/dependencies/utils.py
fastapi/encoders.py
fastapi/exceptions.py
fastapi/openapi/docs.py
fastapi/openapi/models.py
fastapi/openapi/utils.py
fastapi/param_functions.py
fastapi/params.py
fastapi/routing.py
fastapi/security/api_key.py
fastapi/security/http.py
fastapi/security/oauth2.py
fastapi/security/open_id_connect_url.py
fastapi/security/utils.py
fastapi/temp_pydantic_v1_params.py
fastapi/types.py
fastapi/utils.py
pdm_build.py
scripts/docs.py
scripts/mkdocs_hooks.py
scripts/notify_translations.py
scripts/people.py
tests/main.py
tests/test_additional_properties.py
tests/test_additional_responses_custom_validationerror.py
tests/test_additional_responses_response_class.py
tests/test_allow_inf_nan_in_enforcing.py
tests/test_ambiguous_params.py
tests/test_annotated.py
tests/test_arbitrary_types.py
tests/test_compat.py
tests/test_compat_params_v1.py
tests/test_custom_schema_fields.py
tests/test_datastructures.py
tests/test_dependency_after_yield_raise.py
tests/test_dependency_after_yield_streaming.py
tests/test_dependency_after_yield_websockets.py
tests/test_dependency_class.py
tests/test_dependency_contextmanager.py
tests/test_dependency_contextvars.py
tests/test_dependency_duplicates.py
tests/test_dependency_paramless.py
tests/test_dependency_partial.py
tests/test_dependency_security_overrides.py
tests/test_dependency_wrapped.py
tests/test_dependency_yield_scope.py
tests/test_dependency_yield_scope_websockets.py
tests/test_file_and_form_order_issue_9116.py
tests/test_form_default.py
tests/test_forms_single_model.py
tests/test_forms_single_param.py
tests/test_generate_unique_id_function.py
tests/test_generic_parameterless_depends.py
tests/test_get_model_definitions_formfeed_escape.py
tests/test_invalid_path_param.py
tests/test_invalid_sequence_param.py
tests/test_multi_body_errors.py
tests/test_multi_query_errors.py
tests/test_no_schema_split.py
tests/test_openapi_schema_type.py
tests/test_openapi_separate_input_output_schemas.py
tests/test_optional_file_list.py
tests/test_params_repr.py
tests/test_pydantic_v1_v2_01.py
tests/test_pydantic_v1_v2_list.py
tests/test_pydantic_v1_v2_mixed.py
tests/test_pydantic_v1_v2_multifile/main.py
tests/test_pydantic_v1_v2_multifile/modelsv1.py
tests/test_pydantic_v1_v2_multifile/modelsv2.py
tests/test_pydantic_v1_v2_multifile/modelsv2b.py
tests/test_pydantic_v1_v2_noneable.py
tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py
tests/test_regex_deprecated_body.py
tests/test_regex_deprecated_params.py
tests/test_request_body_parameters_media_type.py
tests/test_request_params/test_body/test_list.py
tests/test_request_params/test_body/test_optional_list.py
tests/test_request_params/test_body/test_optional_str.py
tests/test_request_params/test_body/test_required_str.py
tests/test_request_params/test_body/utils.py
tests/test_request_params/test_cookie/test_optional_str.py
tests/test_request_params/test_cookie/test_required_str.py
tests/test_request_params/test_file/test_list.py
tests/test_request_params/test_file/test_optional.py
tests/test_request_params/test_file/test_optional_list.py
tests/test_request_params/test_file/test_required.py
tests/test_request_params/test_file/utils.py
tests/test_request_params/test_form/test_list.py
tests/test_request_params/test_form/test_optional_list.py
tests/test_request_params/test_form/test_optional_str.py
tests/test_request_params/test_form/test_required_str.py
tests/test_request_params/test_form/utils.py
tests/test_request_params/test_header/test_list.py
tests/test_request_params/test_header/test_optional_list.py
tests/test_request_params/test_header/test_optional_str.py
tests/test_request_params/test_header/test_required_str.py
tests/test_request_params/test_path/test_required_str.py
tests/test_request_params/test_query/test_list.py
tests/test_request_params/test_query/test_optional_list.py
tests/test_request_params/test_query/test_optional_str.py
tests/test_request_params/test_query/test_required_str.py
tests/test_response_by_alias.py
tests/test_response_class_no_mediatype.py
tests/test_response_code_no_body.py
tests/test_response_model_as_return_annotation.py
tests/test_response_model_data_filter.py
tests/test_response_model_data_filter_no_inheritance.py
tests/test_response_model_invalid.py
tests/test_response_model_sub_types.py
tests/test_router_events.py
tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py
tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py
tests/test_security_scopes.py
tests/test_security_scopes_dont_propagate.py
tests/test_security_scopes_sub_dependency.py
tests/test_serialize_response.py
tests/test_serialize_response_dataclass.py
tests/test_serialize_response_model.py
tests/test_stringified_annotation_dependency.py
tests/test_stringified_annotations_simple.py
tests/test_tuples.py
tests/test_tutorial/test_websockets/test_tutorial003.py
tests/test_union_body_discriminator.py
tests/test_union_body_discriminator_annotated.py
tests/test_union_forms.py
tests/test_validate_response.py
tests/test_validate_response_dataclass.py
tests/test_validate_response_recursive/app.py
tests/test_webhooks_security.py
tests/test_ws_dependencies.py

index c1dd4996113f1a8f038016e415bd2e8677b15164..5aad89407e8e35db91f7682327e825188bf25126 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Annotated, List, Union
+from typing import Annotated, Union
 
 from fastapi import FastAPI, Header
 
@@ -6,5 +6,5 @@ app = FastAPI()
 
 
 @app.get("/items/")
-async def read_items(x_token: Annotated[Union[List[str], None], Header()] = None):
+async def read_items(x_token: Annotated[Union[list[str], None], Header()] = None):
     return {"X-Token values": x_token}
index e5275950e80df301b1ebbf28b0e33d35e794ff18..2043a66781e981a5dd1301fbeb4987cae651eb30 100644 (file)
@@ -1,12 +1,8 @@
 import sys
+from collections.abc import Sequence
 from functools import lru_cache
 from typing import (
     Any,
-    Dict,
-    List,
-    Sequence,
-    Tuple,
-    Type,
 )
 
 from fastapi._compat import may_v1
@@ -50,7 +46,7 @@ else:
 
 
 @lru_cache
-def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
+def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]:
     if lenient_issubclass(model, may_v1.BaseModel):
         from fastapi._compat import v1
 
@@ -119,7 +115,7 @@ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
 
 def create_body_model(
     *, fields: Sequence[ModelField], model_name: str
-) -> Type[BaseModel]:
+) -> type[BaseModel]:
     if fields and isinstance(fields[0], may_v1.ModelField):
         from fastapi._compat import v1
 
@@ -221,7 +217,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
         return v2.serialize_sequence_value(field=field, value=value)  # type: ignore[arg-type]
 
 
-def _model_rebuild(model: Type[BaseModel]) -> None:
+def _model_rebuild(model: type[BaseModel]) -> None:
     if lenient_issubclass(model, may_v1.BaseModel):
         from fastapi._compat import v1
 
@@ -232,7 +228,7 @@ def _model_rebuild(model: Type[BaseModel]) -> None:
         v2._model_rebuild(model)
 
 
-def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
+def get_compat_model_name_map(fields: list[ModelField]) -> ModelNameMap:
     v1_model_fields = [
         field for field in fields if isinstance(field, may_v1.ModelField)
     ]
@@ -266,15 +262,15 @@ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
 
 def get_definitions(
     *,
-    fields: List[ModelField],
+    fields: list[ModelField],
     model_name_map: ModelNameMap,
     separate_input_output_schemas: bool = True,
-) -> Tuple[
-    Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]],
+) -> tuple[
+    dict[
+        tuple[ModelField, Literal["validation", "serialization"]],
         may_v1.JsonSchemaValue,
     ],
-    Dict[str, Dict[str, Any]],
+    dict[str, dict[str, Any]],
 ]:
     if sys.version_info < (3, 14):
         v1_fields = [field for field in fields if isinstance(field, may_v1.ModelField)]
@@ -315,12 +311,12 @@ def get_schema_from_model_field(
     *,
     field: ModelField,
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]],
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]],
         may_v1.JsonSchemaValue,
     ],
     separate_input_output_schemas: bool = True,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
     if isinstance(field, may_v1.ModelField):
         from fastapi._compat import v1
 
index beea4d167f735f510ab81beaf97678c5ef7d54bf..c7721622834b72394248a198f0c1d3a7f7f7f9f8 100644 (file)
@@ -1,5 +1,6 @@
 import sys
-from typing import Any, Dict, List, Literal, Sequence, Tuple, Type, Union
+from collections.abc import Sequence
+from typing import Any, Literal, Union
 
 from fastapi.types import ModelNameMap
 
@@ -60,14 +61,14 @@ if sys.version_info >= (3, 14):
 
     def get_definitions(
         *,
-        fields: List[ModelField],
+        fields: list[ModelField],
         model_name_map: ModelNameMap,
         separate_input_output_schemas: bool = True,
-    ) -> Tuple[
-        Dict[
-            Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    ) -> tuple[
+        dict[
+            tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
         ],
-        Dict[str, Dict[str, Any]],
+        dict[str, dict[str, Any]],
     ]:
         return {}, {}  # pragma: no cover
 
@@ -94,11 +95,11 @@ else:
     from .v1 import get_definitions as get_definitions
 
 
-RequestErrorModel: Type[BaseModel] = create_model("Request")
+RequestErrorModel: type[BaseModel] = create_model("Request")
 
 
-def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
-    use_errors: List[Any] = []
+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]
@@ -113,9 +114,9 @@ def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
 
 
 def _regenerate_error_with_loc(
-    *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
-) -> List[Dict[str, Any]]:
-    updated_loc_errors: List[Any] = [
+    *, 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)
     ]
index fa2008c5e0bcf0bfe759e11d955e40a92af6a94d..47d05cb9468ca8aa5ba78a06ac15b6850eb43f61 100644 (file)
@@ -1,8 +1,5 @@
 from typing import (
     Any,
-    Dict,
-    List,
-    Tuple,
     Union,
 )
 
@@ -34,10 +31,10 @@ class ModelField(Protocol):
     def validate(
         self,
         value: Any,
-        values: Dict[str, Any] = {},  # noqa: B006
+        values: dict[str, Any] = {},  # noqa: B006
         *,
-        loc: Tuple[Union[int, str], ...] = (),
-    ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]: ...
+        loc: tuple[Union[int, str], ...] = (),
+    ) -> tuple[Any, Union[list[dict[str, Any]], None]]: ...
 
     def serialize(
         self,
index c4dd54dec67b7f9488d3e8ada94b05d773b05cb0..3a11e88ac931f7b17a0f8233d1f208b29dbd9b6a 100644 (file)
@@ -2,17 +2,11 @@ import sys
 import types
 import typing
 from collections import deque
+from collections.abc import Mapping, Sequence
 from dataclasses import is_dataclass
 from typing import (
+    Annotated,
     Any,
-    Deque,
-    FrozenSet,
-    List,
-    Mapping,
-    Sequence,
-    Set,
-    Tuple,
-    Type,
     Union,
 )
 
@@ -21,7 +15,7 @@ from fastapi.types import UnionType
 from pydantic import BaseModel
 from pydantic.version import VERSION as PYDANTIC_VERSION
 from starlette.datastructures import UploadFile
-from typing_extensions import Annotated, get_args, get_origin
+from typing_extensions import get_args, get_origin
 
 # Copy from Pydantic v2, compatible with v1
 if sys.version_info < (3, 10):
@@ -39,26 +33,21 @@ 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]
+Url: type[Any]
 
 
 # Copy of Pydantic v2, compatible with v1
 def lenient_issubclass(
-    cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]
+    cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None]
 ) -> bool:
     try:
         return isinstance(cls, type) and issubclass(cls, class_or_tuple)  # type: ignore[arg-type]
@@ -68,13 +57,13 @@ def lenient_issubclass(
         raise  # pragma: no cover
 
 
-def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
+def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:
     if lenient_issubclass(annotation, (str, bytes)):
         return False
-    return lenient_issubclass(annotation, sequence_types)  # type: ignore[arg-type]
+    return lenient_issubclass(annotation, sequence_types)
 
 
-def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
+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):
@@ -87,10 +76,10 @@ def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
 
 
 def value_is_sequence(value: Any) -> bool:
-    return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))  # type: ignore[arg-type]
+    return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))
 
 
-def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
+def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
     return (
         lenient_issubclass(
             annotation, (BaseModel, may_v1.BaseModel, Mapping, UploadFile)
@@ -100,7 +89,7 @@ def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
     )
 
 
-def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
+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))
@@ -121,7 +110,7 @@ def field_annotation_is_scalar(annotation: Any) -> bool:
     return annotation is Ellipsis or not field_annotation_is_complex(annotation)
 
 
-def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool:
+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
index e17ce8beafdd68bf4335065e987d240bfdd02379..b29a61f7343e691735c088b115c601cb46780013 100644 (file)
@@ -1,15 +1,10 @@
+from collections.abc import Sequence
 from copy import copy
 from dataclasses import dataclass, is_dataclass
 from enum import Enum
 from typing import (
     Any,
     Callable,
-    Dict,
-    List,
-    Sequence,
-    Set,
-    Tuple,
-    Type,
     Union,
 )
 
@@ -124,7 +119,7 @@ else:
 
 
 GetJsonSchemaHandler = Any
-JsonSchemaValue = Dict[str, Any]
+JsonSchemaValue = dict[str, Any]
 CoreSchema = Any
 Url = AnyUrl
 
@@ -154,7 +149,7 @@ class PydanticSchemaGenerationError(Exception):
     pass
 
 
-RequestErrorModel: Type[BaseModel] = create_model("Request")
+RequestErrorModel: type[BaseModel] = create_model("Request")
 
 
 def with_info_plain_validator_function(
@@ -169,10 +164,10 @@ def with_info_plain_validator_function(
 
 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]] = {}
+    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
@@ -219,7 +214,7 @@ def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
     return False
 
 
-def _model_rebuild(model: Type[BaseModel]) -> None:
+def _model_rebuild(model: type[BaseModel]) -> None:
     model.update_forward_refs()
 
 
@@ -237,11 +232,11 @@ def get_schema_from_model_field(
     *,
     field: ModelField,
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ],
     separate_input_output_schemas: bool = True,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
     return field_schema(  # type: ignore[no-any-return]
         field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
     )[0]
@@ -254,12 +249,12 @@ def get_schema_from_model_field(
 
 def get_definitions(
     *,
-    fields: List[ModelField],
+    fields: list[ModelField],
     model_name_map: ModelNameMap,
     separate_input_output_schemas: bool = True,
-) -> Tuple[
-    Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
-    Dict[str, Dict[str, Any]],
+) -> 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)
@@ -293,7 +288,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
     return sequence_shape_to_type[field.shape](value)  # type: ignore[no-any-return]
 
 
-def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
+def get_missing_field_error(loc: tuple[str, ...]) -> dict[str, Any]:
     missing_field_error = ErrorWrapper(MissingError(), loc=loc)
     new_error = ValidationError([missing_field_error], RequestErrorModel)
     return new_error.errors()[0]  # type: ignore[return-value]
@@ -301,12 +296,12 @@ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
 
 def create_body_model(
     *, fields: Sequence[ModelField], model_name: str
-) -> Type[BaseModel]:
+) -> 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]:
+def get_model_fields(model: type[BaseModel]) -> list[ModelField]:
     return list(model.__fields__.values())  # type: ignore[attr-defined]
index a17d62556896c889a4620a679b0175c246078835..c4fa49e4032b9e673cf2a7e80621f89b0607e0f2 100644 (file)
@@ -1,16 +1,12 @@
 import re
 import warnings
+from collections.abc import Sequence
 from copy import copy, deepcopy
 from dataclasses import dataclass, is_dataclass
 from enum import Enum
 from typing import (
+    Annotated,
     Any,
-    Dict,
-    List,
-    Sequence,
-    Set,
-    Tuple,
-    Type,
     Union,
     cast,
 )
@@ -33,7 +29,7 @@ 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
-from typing_extensions import Annotated, Literal, get_args, get_origin
+from typing_extensions import Literal, get_args, get_origin
 
 try:
     from pydantic_core.core_schema import (
@@ -77,7 +73,7 @@ _Attrs = {
 
 
 # TODO: remove when dropping support for Pydantic < v2.12.3
-def asdict(field_info: FieldInfo) -> Dict[str, Any]:
+def asdict(field_info: FieldInfo) -> dict[str, Any]:
     attributes = {}
     for attr in _Attrs:
         value = getattr(field_info, attr, Undefined)
@@ -169,10 +165,10 @@ class ModelField:
     def validate(
         self,
         value: Any,
-        values: Dict[str, Any] = {},  # noqa: B006
+        values: dict[str, Any] = {},  # noqa: B006
         *,
-        loc: Tuple[Union[int, str], ...] = (),
-    ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]:
+        loc: tuple[Union[int, str], ...] = (),
+    ) -> tuple[Any, Union[list[dict[str, Any]], None]]:
         try:
             return (
                 self._type_adapter.validate_python(value, from_attributes=True),
@@ -220,7 +216,7 @@ def get_annotation_from_field_info(
     return annotation
 
 
-def _model_rebuild(model: Type[BaseModel]) -> None:
+def _model_rebuild(model: type[BaseModel]) -> None:
     model.model_rebuild()
 
 
@@ -245,11 +241,11 @@ def get_schema_from_model_field(
     *,
     field: ModelField,
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ],
     separate_input_output_schemas: bool = True,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
     override_mode: Union[Literal["validation"], None] = (
         None
         if (separate_input_output_schemas or _has_computed_fields(field))
@@ -277,9 +273,9 @@ def get_definitions(
     fields: Sequence[ModelField],
     model_name_map: ModelNameMap,
     separate_input_output_schemas: bool = True,
-) -> Tuple[
-    Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
-    Dict[str, Dict[str, Any]],
+) -> tuple[
+    dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
+    dict[str, dict[str, Any]],
 ]:
     schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
     validation_fields = [field for field in fields if field.mode == "validation"]
@@ -324,7 +320,7 @@ def get_definitions(
         for field in list(fields) + list(unique_flat_model_fields)
     ]
     field_mapping, definitions = schema_generator.generate_definitions(inputs=inputs)
-    for item_def in cast(Dict[str, Dict[str, Any]], definitions).values():
+    for item_def in cast(dict[str, dict[str, Any]], definitions).values():
         if "description" in item_def:
             item_description = cast(str, item_def["description"]).split("\f")[0]
             item_def["description"] = item_description
@@ -338,9 +334,9 @@ def get_definitions(
 
 def _replace_refs(
     *,
-    schema: Dict[str, Any],
-    old_name_to_new_name_map: Dict[str, str],
-) -> Dict[str, Any]:
+    schema: dict[str, Any],
+    old_name_to_new_name_map: dict[str, str],
+) -> dict[str, Any]:
     new_schema = deepcopy(schema)
     for key, value in new_schema.items():
         if key == "$ref":
@@ -375,13 +371,13 @@ def _replace_refs(
 def _remap_definitions_and_field_mappings(
     *,
     model_name_map: ModelNameMap,
-    definitions: Dict[str, Any],
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    definitions: dict[str, Any],
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ],
-) -> Tuple[
-    Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
-    Dict[str, Any],
+) -> tuple[
+    dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
+    dict[str, Any],
 ]:
     old_name_to_new_name_map = {}
     for field_key, schema in field_mapping.items():
@@ -394,8 +390,8 @@ def _remap_definitions_and_field_mappings(
             continue
         old_name_to_new_name_map[old_name] = new_name
 
-    new_field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    new_field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ] = {}
     for field_key, schema in field_mapping.items():
         new_schema = _replace_refs(
@@ -461,10 +457,10 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
             origin_type = get_origin(union_arg) or union_arg
             break
     assert issubclass(origin_type, shared.sequence_types)  # type: ignore[arg-type]
-    return shared.sequence_annotation_to_type[origin_type](value)  # type: ignore[no-any-return]
+    return shared.sequence_annotation_to_type[origin_type](value)  # type: ignore[no-any-return,index]
 
 
-def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
+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]
@@ -474,14 +470,14 @@ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
 
 def create_body_model(
     *, fields: Sequence[ModelField], model_name: str
-) -> Type[BaseModel]:
+) -> 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]
+    BodyModel: type[BaseModel] = create_model(model_name, **field_params)  # type: ignore[call-overload]
     return BodyModel
 
 
-def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
-    model_fields: List[ModelField] = []
+def get_model_fields(model: type[BaseModel]) -> list[ModelField]:
+    model_fields: list[ModelField] = []
     for name, field_info in model.model_fields.items():
         type_ = field_info.annotation
         if lenient_issubclass(type_, (BaseModel, dict)) or is_dataclass(type_):
@@ -501,17 +497,17 @@ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
 # Duplicate of several schema functions from Pydantic v1 to make them compatible with
 # Pydantic v2 and allow mixing the models
 
-TypeModelOrEnum = Union[Type["BaseModel"], Type[Enum]]
-TypeModelSet = Set[TypeModelOrEnum]
+TypeModelOrEnum = Union[type["BaseModel"], type[Enum]]
+TypeModelSet = set[TypeModelOrEnum]
 
 
 def normalize_name(name: str) -> str:
     return re.sub(r"[^a-zA-Z0-9.\-_]", "_", name)
 
 
-def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str]:
+def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str]:
     name_model_map = {}
-    conflicting_names: Set[str] = set()
+    conflicting_names: set[str] = set()
     for model in unique_models:
         model_name = normalize_name(model.__name__)
         if model_name in conflicting_names:
@@ -528,7 +524,7 @@ def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str
 
 
 def get_flat_models_from_model(
-    model: Type["BaseModel"], known_models: Union[TypeModelSet, None] = None
+    model: type["BaseModel"], known_models: Union[TypeModelSet, None] = None
 ) -> TypeModelSet:
     known_models = known_models or set()
     fields = get_model_fields(model)
index 02193312b9e682da3087d40f90d3507c3af336db..54175cb3b0e3ac305d5ba17a7e2c4718a15a1fd1 100644 (file)
@@ -1,14 +1,10 @@
+from collections.abc import Awaitable, Coroutine, Sequence
 from enum import Enum
 from typing import (
+    Annotated,
     Any,
-    Awaitable,
     Callable,
-    Coroutine,
-    Dict,
-    List,
     Optional,
-    Sequence,
-    Type,
     TypeVar,
     Union,
 )
@@ -44,7 +40,7 @@ from starlette.requests import Request
 from starlette.responses import HTMLResponse, JSONResponse, Response
 from starlette.routing import BaseRoute
 from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send
-from typing_extensions import Annotated, deprecated
+from typing_extensions import deprecated
 
 AppType = TypeVar("AppType", bound="FastAPI")
 
@@ -81,7 +77,7 @@ class FastAPI(Starlette):
             ),
         ] = False,
         routes: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 **Note**: you probably shouldn't use this parameter, it is inherited
@@ -230,7 +226,7 @@ class FastAPI(Starlette):
             ),
         ] = "/openapi.json",
         openapi_tags: Annotated[
-            Optional[List[Dict[str, Any]]],
+            Optional[list[dict[str, Any]]],
             Doc(
                 """
                 A list of tags used by OpenAPI, these are the same `tags` you can set
@@ -290,7 +286,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         servers: Annotated[
-            Optional[List[Dict[str, Union[str, Any]]]],
+            Optional[list[dict[str, Union[str, Any]]]],
             Doc(
                 """
                 A `list` of `dict`s with connectivity information to a target server.
@@ -361,7 +357,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         default_response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 The default response class to be used.
@@ -467,7 +463,7 @@ class FastAPI(Starlette):
             ),
         ] = "/docs/oauth2-redirect",
         swagger_ui_init_oauth: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 OAuth2 configuration for the Swagger UI, by default shown at `/docs`.
@@ -493,8 +489,8 @@ class FastAPI(Starlette):
         ] = None,
         exception_handlers: Annotated[
             Optional[
-                Dict[
-                    Union[int, Type[Exception]],
+                dict[
+                    Union[int, type[Exception]],
                     Callable[[Request, Any], Coroutine[Any, Any, Response]],
                 ]
             ],
@@ -567,7 +563,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         contact: Annotated[
-            Optional[Dict[str, Union[str, Any]]],
+            Optional[dict[str, Union[str, Any]]],
             Doc(
                 """
                 A dictionary with the contact information for the exposed API.
@@ -600,7 +596,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         license_info: Annotated[
-            Optional[Dict[str, Union[str, Any]]],
+            Optional[dict[str, Union[str, Any]]],
             Doc(
                 """
                 A dictionary with the license information for the exposed API.
@@ -689,7 +685,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses to be shown in OpenAPI.
@@ -705,7 +701,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 OpenAPI callbacks that should apply to all *path operations*.
@@ -762,7 +758,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         swagger_ui_parameters: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Parameters to configure Swagger UI, the autogenerated interactive API
@@ -820,7 +816,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         openapi_external_docs: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 This field allows you to provide additional external documentation links.
@@ -906,7 +902,7 @@ class FastAPI(Starlette):
                 """
             ),
         ] = "3.1.0"
-        self.openapi_schema: Optional[Dict[str, Any]] = None
+        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'"
@@ -949,7 +945,7 @@ class FastAPI(Starlette):
             ),
         ] = State()
         self.dependency_overrides: Annotated[
-            Dict[Callable[..., Any], Callable[..., Any]],
+            dict[Callable[..., Any], Callable[..., Any]],
             Doc(
                 """
                 A dictionary with overrides for the dependencies.
@@ -980,7 +976,7 @@ class FastAPI(Starlette):
             responses=responses,
             generate_unique_id_function=generate_unique_id_function,
         )
-        self.exception_handlers: Dict[
+        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)
@@ -993,7 +989,7 @@ class FastAPI(Starlette):
             websocket_request_validation_exception_handler,  # type: ignore
         )
 
-        self.user_middleware: List[Middleware] = (
+        self.user_middleware: list[Middleware] = (
             [] if middleware is None else list(middleware)
         )
         self.middleware_stack: Union[ASGIApp, None] = None
@@ -1047,7 +1043,7 @@ class FastAPI(Starlette):
             app = cls(app, *args, **kwargs)
         return app
 
-    def openapi(self) -> Dict[str, Any]:
+    def openapi(self) -> dict[str, Any]:
         """
         Generate the OpenAPI schema of the application. This is called by FastAPI
         internally.
@@ -1145,14 +1141,14 @@ class FastAPI(Starlette):
         *,
         response_model: Any = Default(None),
         status_code: Optional[int] = None,
-        tags: Optional[List[Union[str, Enum]]] = 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,
+        responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
         deprecated: Optional[bool] = None,
-        methods: Optional[List[str]] = None,
+        methods: Optional[list[str]] = None,
         operation_id: Optional[str] = None,
         response_model_include: Optional[IncEx] = None,
         response_model_exclude: Optional[IncEx] = None,
@@ -1161,11 +1157,11 @@ class FastAPI(Starlette):
         response_model_exclude_defaults: bool = False,
         response_model_exclude_none: bool = False,
         include_in_schema: bool = True,
-        response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+        response_class: Union[type[Response], DefaultPlaceholder] = Default(
             JSONResponse
         ),
         name: Optional[str] = None,
-        openapi_extra: Optional[Dict[str, Any]] = None,
+        openapi_extra: Optional[dict[str, Any]] = None,
         generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
             generate_unique_id
         ),
@@ -1203,14 +1199,14 @@ class FastAPI(Starlette):
         *,
         response_model: Any = Default(None),
         status_code: Optional[int] = None,
-        tags: Optional[List[Union[str, Enum]]] = 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,
+        responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
         deprecated: Optional[bool] = None,
-        methods: Optional[List[str]] = None,
+        methods: Optional[list[str]] = None,
         operation_id: Optional[str] = None,
         response_model_include: Optional[IncEx] = None,
         response_model_exclude: Optional[IncEx] = None,
@@ -1219,9 +1215,9 @@ class FastAPI(Starlette):
         response_model_exclude_defaults: bool = False,
         response_model_exclude_none: bool = False,
         include_in_schema: bool = True,
-        response_class: Type[Response] = Default(JSONResponse),
+        response_class: type[Response] = Default(JSONResponse),
         name: Optional[str] = None,
-        openapi_extra: Optional[Dict[str, Any]] = None,
+        openapi_extra: Optional[dict[str, Any]] = None,
         generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
             generate_unique_id
         ),
@@ -1343,7 +1339,7 @@ class FastAPI(Starlette):
         *,
         prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to all the *path operations* in this
@@ -1385,7 +1381,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses to be shown in OpenAPI.
@@ -1452,7 +1448,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         default_response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Default response class to be used for the *path operations* in this
@@ -1480,7 +1476,7 @@ class FastAPI(Starlette):
             ),
         ] = Default(JSONResponse),
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -1603,7 +1599,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -1669,7 +1665,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -1810,7 +1806,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -1831,7 +1827,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -1847,7 +1843,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -1976,7 +1972,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2042,7 +2038,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2183,7 +2179,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2204,7 +2200,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2220,7 +2216,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -2354,7 +2350,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2420,7 +2416,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2561,7 +2557,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2582,7 +2578,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2598,7 +2594,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -2732,7 +2728,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2798,7 +2794,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2939,7 +2935,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2960,7 +2956,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2976,7 +2972,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3105,7 +3101,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3171,7 +3167,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -3312,7 +3308,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -3333,7 +3329,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -3349,7 +3345,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3478,7 +3474,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3544,7 +3540,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -3685,7 +3681,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -3706,7 +3702,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -3722,7 +3718,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3851,7 +3847,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3917,7 +3913,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -4058,7 +4054,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -4079,7 +4075,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -4095,7 +4091,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -4229,7 +4225,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -4295,7 +4291,7 @@ class FastAPI(Starlette):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -4436,7 +4432,7 @@ class FastAPI(Starlette):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -4457,7 +4453,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -4473,7 +4469,7 @@ class FastAPI(Starlette):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -4628,7 +4624,7 @@ class FastAPI(Starlette):
     def exception_handler(
         self,
         exc_class_or_status_code: Annotated[
-            Union[int, Type[Exception]],
+            Union[int, type[Exception]],
             Doc(
                 """
                 The Exception class this would handle, or a status code.
index 6d4a30d4421e8074fcbae2a7981378b19e8687d3..20803ba6707bf960ecf94ae10cdaa49249e002da 100644 (file)
@@ -1,8 +1,8 @@
-from typing import Any, Callable
+from typing import Annotated, Any, Callable
 
 from annotated_doc import Doc
 from starlette.background import BackgroundTasks as StarletteBackgroundTasks
-from typing_extensions import Annotated, ParamSpec
+from typing_extensions import ParamSpec
 
 P = ParamSpec("P")
 
index 3202c70789ad37f934a67bfe19d3bc8f45efe513..76a5a2eb128bc8c22d61d986ab2cdc434178dd24 100644 (file)
@@ -1,5 +1,7 @@
+from collections.abc import AsyncGenerator
+from contextlib import AbstractContextManager
 from contextlib import asynccontextmanager as asynccontextmanager
-from typing import AsyncGenerator, ContextManager, TypeVar
+from typing import TypeVar
 
 import anyio.to_thread
 from anyio import CapacityLimiter
@@ -14,7 +16,7 @@ _T = TypeVar("_T")
 
 @asynccontextmanager
 async def contextmanager_in_threadpool(
-    cm: ContextManager[_T],
+    cm: AbstractContextManager[_T],
 ) -> AsyncGenerator[_T, None]:
     # blocking __exit__ from running waiting on a free thread
     # can create race conditions/deadlocks if the context manager itself
index 8ad9aa11a6fd8e8f16b62cd8b278e6f8184cef9f..b38a326def01dc878db7ff4bcfbe70a7d06159cb 100644 (file)
@@ -1,11 +1,10 @@
+from collections.abc import Iterable
 from typing import (
+    Annotated,
     Any,
     BinaryIO,
     Callable,
-    Dict,
-    Iterable,
     Optional,
-    Type,
     TypeVar,
     cast,
 )
@@ -23,7 +22,6 @@ 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
 
 
 class UploadFile(StarletteUploadFile):
@@ -138,11 +136,11 @@ class UploadFile(StarletteUploadFile):
         return await super().close()
 
     @classmethod
-    def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
+    def __get_validators__(cls: type["UploadFile"]) -> Iterable[Callable[..., Any]]:
         yield cls.validate
 
     @classmethod
-    def validate(cls: Type["UploadFile"], v: Any) -> Any:
+    def validate(cls: type["UploadFile"], v: Any) -> Any:
         if not isinstance(v, StarletteUploadFile):
             raise ValueError(f"Expected UploadFile, received: {type(v)}")
         return v
@@ -155,7 +153,7 @@ class UploadFile(StarletteUploadFile):
 
     # TODO: remove when deprecating Pydantic v1
     @classmethod
-    def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
+    def __modify_schema__(cls, field_schema: dict[str, Any]) -> None:
         field_schema.update({"type": "string", "format": "binary"})
 
     @classmethod
@@ -166,7 +164,7 @@ class UploadFile(StarletteUploadFile):
 
     @classmethod
     def __get_pydantic_core_schema__(
-        cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
+        cls, source: type[Any], handler: Callable[[Any], CoreSchema]
     ) -> CoreSchema:
         from ._compat.v2 import with_info_plain_validator_function
 
index 6c4bf18b37b593f05ffd66b886238ac76a9d11d7..58392326d6f59738ac4f1d7634e8c88b913a484c 100644 (file)
@@ -2,7 +2,7 @@ import inspect
 import sys
 from dataclasses import dataclass, field
 from functools import cached_property, partial
-from typing import Any, Callable, List, Optional, Union
+from typing import Any, Callable, Optional, Union
 
 from fastapi._compat import ModelField
 from fastapi.security.base import SecurityBase
@@ -30,12 +30,12 @@ def _impartial(func: Callable[..., Any]) -> Callable[..., Any]:
 
 @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)
+    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)
     name: Optional[str] = None
     call: Optional[Callable[..., Any]] = None
     request_param_name: Optional[str] = None
@@ -44,14 +44,14 @@ class Dependant:
     response_param_name: Optional[str] = None
     background_tasks_param_name: Optional[str] = None
     security_scopes_param_name: Optional[str] = None
-    own_oauth_scopes: Optional[List[str]] = None
-    parent_oauth_scopes: Optional[List[str]] = None
+    own_oauth_scopes: Optional[list[str]] = None
+    parent_oauth_scopes: Optional[list[str]] = None
     use_cache: bool = True
     path: Optional[str] = None
     scope: Union[Literal["function", "request"], None] = None
 
     @cached_property
-    def oauth_scopes(self) -> List[str]:
+    def oauth_scopes(self) -> list[str]:
         scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []
         # This doesn't use a set to preserve order, just in case
         for scope in self.own_oauth_scopes or []:
@@ -98,7 +98,7 @@ class Dependant:
         return unwrapped
 
     @cached_property
-    def _security_dependencies(self) -> List["Dependant"]:
+    def _security_dependencies(self) -> list["Dependant"]:
         security_deps = [dep for dep in self.dependencies if dep._is_security_scheme]
         return security_deps
 
index cc7e55b4b0dc27f92eff760fd1f7f7549f9ab799..3db006a9189cd0920a32a6518912fab359444cab 100644 (file)
@@ -1,21 +1,16 @@
 import dataclasses
 import inspect
 import sys
+from collections.abc import Coroutine, Mapping, Sequence
 from contextlib import AsyncExitStack, contextmanager
 from copy import copy, deepcopy
 from dataclasses import dataclass
 from typing import (
+    Annotated,
     Any,
     Callable,
-    Coroutine,
-    Dict,
     ForwardRef,
-    List,
-    Mapping,
     Optional,
-    Sequence,
-    Tuple,
-    Type,
     Union,
     cast,
 )
@@ -75,7 +70,7 @@ from starlette.datastructures import (
 from starlette.requests import HTTPConnection, Request
 from starlette.responses import Response
 from starlette.websockets import WebSocket
-from typing_extensions import Annotated, Literal, get_args, get_origin
+from typing_extensions import Literal, get_args, get_origin
 
 from .. import temp_pydantic_v1_params
 
@@ -125,7 +120,7 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De
     assert callable(depends.dependency), (
         "A parameter-less dependency must have a callable dependency"
     )
-    own_oauth_scopes: List[str] = []
+    own_oauth_scopes: list[str] = []
     if isinstance(depends, params.Security) and depends.scopes:
         own_oauth_scopes.extend(depends.scopes)
     return get_dependant(
@@ -140,8 +135,8 @@ def get_flat_dependant(
     dependant: Dependant,
     *,
     skip_repeats: bool = False,
-    visited: Optional[List[DependencyCacheKey]] = None,
-    parent_oauth_scopes: Optional[List[str]] = None,
+    visited: Optional[list[DependencyCacheKey]] = None,
+    parent_oauth_scopes: Optional[list[str]] = None,
 ) -> Dependant:
     if visited is None:
         visited = []
@@ -190,7 +185,7 @@ def get_flat_dependant(
     return flat_dependant
 
 
-def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
+def _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]:
     if not fields:
         return fields
     first_field = fields[0]
@@ -200,7 +195,7 @@ def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
     return fields
 
 
-def get_flat_params(dependant: Dependant) -> List[ModelField]:
+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)
@@ -239,7 +234,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
     return typed_signature
 
 
-def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
+def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
     if isinstance(annotation, str):
         annotation = ForwardRef(annotation)
         annotation = evaluate_forwardref(annotation, globalns, globalns)
@@ -265,8 +260,8 @@ def get_dependant(
     path: str,
     call: Callable[..., Any],
     name: Optional[str] = None,
-    own_oauth_scopes: Optional[List[str]] = None,
-    parent_oauth_scopes: Optional[List[str]] = None,
+    own_oauth_scopes: Optional[list[str]] = None,
+    parent_oauth_scopes: Optional[list[str]] = None,
     use_cache: bool = True,
     scope: Union[Literal["function", "request"], None] = None,
 ) -> Dependant:
@@ -303,7 +298,7 @@ def get_dependant(
                     f'The dependency "{dependant.call.__name__}" has a scope of '
                     '"request", it cannot depend on dependencies with scope "function".'
                 )
-            sub_own_oauth_scopes: List[str] = []
+            sub_own_oauth_scopes: list[str] = []
             if isinstance(param_details.depends, params.Security):
                 if param_details.depends.scopes:
                     sub_own_oauth_scopes = list(param_details.depends.scopes)
@@ -572,7 +567,7 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
 
 
 async def _solve_generator(
-    *, dependant: Dependant, stack: AsyncExitStack, sub_values: Dict[str, Any]
+    *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any]
 ) -> Any:
     assert dependant.call
     if dependant.is_async_gen_callable:
@@ -584,22 +579,22 @@ async def _solve_generator(
 
 @dataclass
 class SolvedDependency:
-    values: Dict[str, Any]
-    errors: List[Any]
+    values: dict[str, Any]
+    errors: list[Any]
     background_tasks: Optional[StarletteBackgroundTasks]
     response: Response
-    dependency_cache: Dict[DependencyCacheKey, Any]
+    dependency_cache: dict[DependencyCacheKey, Any]
 
 
 async def solve_dependencies(
     *,
     request: Union[Request, WebSocket],
     dependant: Dependant,
-    body: Optional[Union[Dict[str, Any], FormData]] = None,
+    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[DependencyCacheKey, Any]] = None,
+    dependency_cache: Optional[dict[DependencyCacheKey, Any]] = None,
     # TODO: remove this parameter later, no longer used, not removing it yet as some
     # people might be monkey patching this function (although that's not supported)
     async_exit_stack: AsyncExitStack,
@@ -613,8 +608,8 @@ async def solve_dependencies(
     assert isinstance(function_astack, AsyncExitStack), (
         "fastapi_function_astack not found in request scope"
     )
-    values: Dict[str, Any] = {}
-    errors: List[Any] = []
+    values: dict[str, Any] = {}
+    errors: list[Any] = []
     if response is None:
         response = Response()
         del response.headers["content-length"]
@@ -732,8 +727,8 @@ async def solve_dependencies(
 
 
 def _validate_value_with_model_field(
-    *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...]
-) -> Tuple[Any, List[Any]]:
+    *, 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)]
@@ -776,9 +771,9 @@ def _get_multidict_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]] = []
+) -> tuple[dict[str, Any], list[Any]]:
+    values: dict[str, Any] = {}
+    errors: list[dict[str, Any]] = []
 
     if not fields:
         return values, errors
@@ -796,7 +791,7 @@ def request_params_to_args(
             first_field.field_info, "convert_underscores", True
         )
 
-    params_to_process: Dict[str, Any] = {}
+    params_to_process: dict[str, Any] = {}
 
     processed_keys = set()
 
@@ -833,7 +828,7 @@ def request_params_to_args(
         assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (
             "Params must be subclasses of Param"
         )
-        loc: Tuple[str, ...] = (field_info.in_.value,)
+        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
         )
@@ -875,7 +870,7 @@ def is_union_of_base_models(field_type: Any) -> bool:
     return True
 
 
-def _should_embed_body_fields(fields: List[ModelField]) -> bool:
+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
@@ -900,9 +895,9 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
 
 
 async def _extract_form_body(
-    body_fields: List[ModelField],
+    body_fields: list[ModelField],
     received_body: FormData,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
     values = {}
 
     for field in body_fields:
@@ -920,8 +915,8 @@ async def _extract_form_body(
             and value_is_sequence(value)
         ):
             # For types
-            assert isinstance(value, sequence_types)  # type: ignore[arg-type]
-            results: List[Union[bytes, str]] = []
+            assert isinstance(value, sequence_types)
+            results: list[Union[bytes, str]] = []
 
             async def process_fn(
                 fn: Callable[[], Coroutine[Any, Any, Any]],
@@ -947,18 +942,18 @@ async def _extract_form_body(
 
 
 async def request_body_to_args(
-    body_fields: List[ModelField],
-    received_body: Optional[Union[Dict[str, Any], FormData]],
+    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]] = []
+) -> 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
+    fields_to_extract: list[ModelField] = body_fields
 
     if (
         single_not_embedded_field
@@ -971,7 +966,7 @@ async def request_body_to_args(
         body_to_process = await _extract_form_body(fields_to_extract, received_body)
 
     if single_not_embedded_field:
-        loc: Tuple[str, ...] = ("body",)
+        loc: tuple[str, ...] = ("body",)
         v_, errors_ = _validate_value_with_model_field(
             field=first_field, value=body_to_process, values=values, loc=loc
         )
@@ -1019,19 +1014,19 @@ def get_body_field(
         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] = {
+    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
+        BodyFieldInfo: type[params.Body] = params.File
     elif any(
         isinstance(f.field_info, temp_pydantic_v1_params.File)
         for f in flat_dependant.body_params
     ):
-        BodyFieldInfo: Type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File  # type: ignore[no-redef]
+        BodyFieldInfo: type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File  # type: ignore[no-redef]
     elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
         BodyFieldInfo = params.Form
     elif any(
index 7939510895503e05d436d90506aa06fe13a95df0..cbeeee4559f08360f9e869159478b17f2c5dcf40 100644 (file)
@@ -14,7 +14,7 @@ from ipaddress import (
 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 typing import Annotated, Any, Callable, Optional, Union
 from uuid import UUID
 
 from annotated_doc import Doc
@@ -24,7 +24,6 @@ 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
 
 from ._compat import Url, _is_undefined, _model_dump
 
@@ -61,7 +60,7 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
         return float(dec_value)
 
 
-ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
+ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = {
     bytes: lambda o: o.decode(),
     Color: str,
     may_v1.Color: str,
@@ -98,9 +97,9 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
 
 
 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(
+    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():
@@ -180,7 +179,7 @@ def jsonable_encoder(
         ),
     ] = False,
     custom_encoder: Annotated[
-        Optional[Dict[Any, Callable[[Any], Any]]],
+        Optional[dict[Any, Callable[[Any], Any]]],
         Doc(
             """
             Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
@@ -227,7 +226,7 @@ def jsonable_encoder(
         exclude = set(exclude)
     if isinstance(obj, (BaseModel, may_v1.BaseModel)):
         # TODO: remove when deprecating Pydantic v1
-        encoders: Dict[Any, Any] = {}
+        encoders: dict[Any, Any] = {}
         if isinstance(obj, may_v1.BaseModel):
             encoders = getattr(obj.__config__, "json_encoders", {})  # type: ignore[attr-defined]
             if custom_encoder:
@@ -336,7 +335,7 @@ def jsonable_encoder(
     try:
         data = dict(obj)
     except Exception as e:
-        errors: List[Exception] = []
+        errors: list[Exception] = []
         errors.append(e)
         try:
             data = vars(obj)
index a46e823506c64b22a666868d76f00ff934f149d1..8e0c55902306b2d2445a84d61a104ec1a87ab17e 100644 (file)
@@ -1,10 +1,10 @@
-from typing import Any, Dict, Optional, Sequence, Type, TypedDict, Union
+from collections.abc import Sequence
+from typing import Annotated, Any, Optional, TypedDict, Union
 
 from annotated_doc import Doc
 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
 
 
 class EndpointContext(TypedDict, total=False):
@@ -62,7 +62,7 @@ class HTTPException(StarletteHTTPException):
             ),
         ] = None,
         headers: Annotated[
-            Optional[Dict[str, str]],
+            Optional[dict[str, str]],
             Doc(
                 """
                 Any headers to send to the client in the response.
@@ -144,8 +144,8 @@ class WebSocketException(StarletteWebSocketException):
         super().__init__(code=code, reason=reason)
 
 
-RequestErrorModel: Type[BaseModel] = create_model("Request")
-WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket")
+RequestErrorModel: type[BaseModel] = create_model("Request")
+WebSocketErrorModel: type[BaseModel] = create_model("WebSocket")
 
 
 class FastAPIError(RuntimeError):
index 74b23a3706a4d42aeeddc103bfe42e0eb530d8da..82380f85d97db63a91b3518e9c0a9217b6fa62fd 100644 (file)
@@ -1,13 +1,12 @@
 import json
-from typing import Any, Dict, Optional
+from typing import Annotated, Any, Optional
 
 from annotated_doc import Doc
 from fastapi.encoders import jsonable_encoder
 from starlette.responses import HTMLResponse
-from typing_extensions import Annotated
 
 swagger_ui_default_parameters: Annotated[
-    Dict[str, Any],
+    dict[str, Any],
     Doc(
         """
         Default configurations for Swagger UI.
@@ -82,7 +81,7 @@ def get_swagger_ui_html(
         ),
     ] = None,
     init_oauth: Annotated[
-        Optional[Dict[str, Any]],
+        Optional[dict[str, Any]],
         Doc(
             """
             A dictionary with Swagger UI OAuth2 initialization configurations.
@@ -90,7 +89,7 @@ def get_swagger_ui_html(
         ),
     ] = None,
     swagger_ui_parameters: Annotated[
-        Optional[Dict[str, Any]],
+        Optional[dict[str, Any]],
         Doc(
             """
             Configuration parameters for Swagger UI.
index 81d276aed65fe7a9b059044279e5f43a3ec7eeed..7aa80f5cb0a96ee76e15d08fc1bebabda1d7828a 100644 (file)
@@ -1,5 +1,6 @@
+from collections.abc import Iterable
 from enum import Enum
-from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union
+from typing import Annotated, Any, Callable, Optional, Union
 
 from fastapi._compat import (
     PYDANTIC_V2,
@@ -11,7 +12,7 @@ from fastapi._compat import (
 )
 from fastapi.logger import logger
 from pydantic import AnyUrl, BaseModel, Field
-from typing_extensions import Annotated, Literal, TypedDict
+from typing_extensions import Literal, TypedDict
 from typing_extensions import deprecated as typing_deprecated
 
 try:
@@ -50,7 +51,7 @@ except ImportError:  # pragma: no cover
 
         @classmethod
         def __get_pydantic_core_schema__(
-            cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
+            cls, source: type[Any], handler: Callable[[Any], CoreSchema]
         ) -> CoreSchema:
             return with_info_plain_validator_function(cls._validate)
 
@@ -88,7 +89,7 @@ class Info(BaseModelWithConfig):
 
 
 class ServerVariable(BaseModelWithConfig):
-    enum: Annotated[Optional[List[str]], Field(min_length=1)] = None
+    enum: Annotated[Optional[list[str]], Field(min_length=1)] = None
     default: str
     description: Optional[str] = None
 
@@ -96,7 +97,7 @@ class ServerVariable(BaseModelWithConfig):
 class Server(BaseModelWithConfig):
     url: Union[AnyUrl, str]
     description: Optional[str] = None
-    variables: Optional[Dict[str, ServerVariable]] = None
+    variables: Optional[dict[str, ServerVariable]] = None
 
 
 class Reference(BaseModel):
@@ -105,7 +106,7 @@ class Reference(BaseModel):
 
 class Discriminator(BaseModel):
     propertyName: str
-    mapping: Optional[Dict[str, str]] = None
+    mapping: Optional[dict[str, str]] = None
 
 
 class XML(BaseModelWithConfig):
@@ -137,34 +138,34 @@ class Schema(BaseModelWithConfig):
     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")
+    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
+    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
+    dependentSchemas: Optional[dict[str, "SchemaOrBool"]] = None
+    prefixItems: Optional[list["SchemaOrBool"]] = None
     # TODO: uncomment and remove below when deprecating Pydantic v1
     # It generates a list of schemas for tuples, before prefixItems was available
     # items: Optional["SchemaOrBool"] = None
-    items: Optional[Union["SchemaOrBool", List["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
+    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[Union[SchemaType, List[SchemaType]]] = None
-    enum: Optional[List[Any]] = None
+    type: Optional[Union[SchemaType, list[SchemaType]]] = None
+    enum: Optional[list[Any]] = None
     const: Optional[Any] = None
     multipleOf: Optional[float] = Field(default=None, gt=0)
     maximum: Optional[float] = None
@@ -181,8 +182,8 @@ class Schema(BaseModelWithConfig):
     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
+    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
@@ -199,7 +200,7 @@ class Schema(BaseModelWithConfig):
     deprecated: Optional[bool] = None
     readOnly: Optional[bool] = None
     writeOnly: Optional[bool] = None
-    examples: Optional[List[Any]] = 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
@@ -243,7 +244,7 @@ class ParameterInType(Enum):
 
 class Encoding(BaseModelWithConfig):
     contentType: Optional[str] = None
-    headers: Optional[Dict[str, Union["Header", Reference]]] = None
+    headers: Optional[dict[str, Union["Header", Reference]]] = None
     style: Optional[str] = None
     explode: Optional[bool] = None
     allowReserved: Optional[bool] = None
@@ -252,8 +253,8 @@ class Encoding(BaseModelWithConfig):
 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
+    examples: Optional[dict[str, Union[Example, Reference]]] = None
+    encoding: Optional[dict[str, Encoding]] = None
 
 
 class ParameterBase(BaseModelWithConfig):
@@ -266,9 +267,9 @@ class ParameterBase(BaseModelWithConfig):
     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
+    examples: Optional[dict[str, Union[Example, Reference]]] = None
     # Serialization rules for more complex scenarios
-    content: Optional[Dict[str, MediaType]] = None
+    content: Optional[dict[str, MediaType]] = None
 
 
 class Parameter(ParameterBase):
@@ -282,14 +283,14 @@ class Header(ParameterBase):
 
 class RequestBody(BaseModelWithConfig):
     description: Optional[str] = None
-    content: Dict[str, MediaType]
+    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
+    parameters: Optional[dict[str, Union[Any, str]]] = None
     requestBody: Optional[Union[Any, str]] = None
     description: Optional[str] = None
     server: Optional[Server] = None
@@ -297,25 +298,25 @@ class Link(BaseModelWithConfig):
 
 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
+    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
+    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
+    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
+    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
+    security: Optional[list[dict[str, list[str]]]] = None
+    servers: Optional[list[Server]] = None
 
 
 class PathItem(BaseModelWithConfig):
@@ -330,8 +331,8 @@ class PathItem(BaseModelWithConfig):
     head: Optional[Operation] = None
     patch: Optional[Operation] = None
     trace: Optional[Operation] = None
-    servers: Optional[List[Server]] = None
-    parameters: Optional[List[Union[Parameter, Reference]]] = None
+    servers: Optional[list[Server]] = None
+    parameters: Optional[list[Union[Parameter, Reference]]] = None
 
 
 class SecuritySchemeType(Enum):
@@ -370,7 +371,7 @@ class HTTPBearer(HTTPBase):
 
 class OAuthFlow(BaseModelWithConfig):
     refreshUrl: Optional[str] = None
-    scopes: Dict[str, str] = {}
+    scopes: dict[str, str] = {}
 
 
 class OAuthFlowImplicit(OAuthFlow):
@@ -413,17 +414,17 @@ 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
+    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
+    callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None
+    pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None
 
 
 class Tag(BaseModelWithConfig):
@@ -436,13 +437,13 @@ class OpenAPI(BaseModelWithConfig):
     openapi: str
     info: Info
     jsonSchemaDialect: Optional[str] = None
-    servers: Optional[List[Server]] = 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
+    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
+    security: Optional[list[dict[str, list[str]]]] = None
+    tags: Optional[list[Tag]] = None
     externalDocs: Optional[ExternalDocumentation] = None
 
 
index 9fe2044f26c494088e8013fca950cd125df2482d..a99d4188e75f2d84b22ddcb4d6e7fbf14ab6cc53 100644 (file)
@@ -1,7 +1,8 @@
 import http.client
 import inspect
 import warnings
-from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
+from collections.abc import Sequence
+from typing import Any, Optional, Union, cast
 
 from fastapi import routing
 from fastapi._compat import (
@@ -66,7 +67,7 @@ validation_error_response_definition = {
     },
 }
 
-status_code_ranges: Dict[str, str] = {
+status_code_ranges: dict[str, str] = {
     "1XX": "Information",
     "2XX": "Success",
     "3XX": "Redirection",
@@ -78,10 +79,10 @@ status_code_ranges: Dict[str, str] = {
 
 def get_openapi_security_definitions(
     flat_dependant: Dependant,
-) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+) -> tuple[dict[str, Any], list[dict[str, Any]]]:
     security_definitions = {}
     # Use a dict to merge scopes for same security scheme
-    operation_security_dict: Dict[str, List[str]] = {}
+    operation_security_dict: dict[str, list[str]] = {}
     for security_dependency in flat_dependant._security_dependencies:
         security_definition = jsonable_encoder(
             security_dependency._security_scheme.model,
@@ -106,11 +107,11 @@ def _get_openapi_operation_parameters(
     *,
     dependant: Dependant,
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ],
     separate_input_output_schemas: bool = True,
-) -> List[Dict[str, Any]]:
+) -> 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)
@@ -179,11 +180,11 @@ def get_openapi_operation_request_body(
     *,
     body_field: Optional[ModelField],
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    field_mapping: dict[
+        tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
     ],
     separate_input_output_schemas: bool = True,
-) -> Optional[Dict[str, Any]]:
+) -> Optional[dict[str, Any]]:
     if not body_field:
         return None
     assert _is_model_field(body_field)
@@ -196,10 +197,10 @@ def get_openapi_operation_request_body(
     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] = {}
+    request_body_oai: dict[str, Any] = {}
     if required:
         request_body_oai["required"] = required
-    request_media_content: Dict[str, Any] = {"schema": body_schema}
+    request_media_content: dict[str, Any] = {"schema": body_schema}
     if field_info.openapi_examples:
         request_media_content["examples"] = jsonable_encoder(
             field_info.openapi_examples
@@ -232,9 +233,9 @@ def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
 
 
 def get_openapi_operation_metadata(
-    *, route: routing.APIRoute, method: str, operation_ids: Set[str]
-) -> Dict[str, Any]:
-    operation: Dict[str, Any] = {}
+    *, 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)
@@ -260,19 +261,19 @@ def get_openapi_operation_metadata(
 def get_openapi_path(
     *,
     route: routing.APIRoute,
-    operation_ids: Set[str],
+    operation_ids: set[str],
     model_name_map: ModelNameMap,
-    field_mapping: Dict[
-        Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
+    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]]:
+) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
     path = {}
-    security_schemes: Dict[str, Any] = {}
-    definitions: Dict[str, Any] = {}
+    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
+        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"
@@ -282,7 +283,7 @@ def get_openapi_path(
             operation = get_openapi_operation_metadata(
                 route=route, method=method, operation_ids=operation_ids
             )
-            parameters: List[Dict[str, Any]] = []
+            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
@@ -390,7 +391,7 @@ def get_openapi_path(
                         "An additional response must be a dict"
                     )
                     field = route.response_fields.get(additional_status_code)
-                    additional_field_schema: Optional[Dict[str, Any]] = None
+                    additional_field_schema: Optional[dict[str, Any]] = None
                     if field:
                         additional_field_schema = get_schema_from_model_field(
                             field=field,
@@ -445,11 +446,11 @@ def get_openapi_path(
 
 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] = []
+) -> 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
@@ -483,15 +484,15 @@ def get_openapi(
     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,
+    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,
+    contact: Optional[dict[str, Union[str, Any]]] = None,
+    license_info: Optional[dict[str, Union[str, Any]]] = None,
     separate_input_output_schemas: bool = True,
-    external_docs: Optional[Dict[str, Any]] = None,
-) -> Dict[str, Any]:
-    info: Dict[str, Any] = {"title": title, "version": version}
+    external_docs: Optional[dict[str, Any]] = None,
+) -> dict[str, Any]:
+    info: dict[str, Any] = {"title": title, "version": version}
     if summary:
         info["summary"] = summary
     if description:
@@ -502,13 +503,13 @@ def get_openapi(
         info["contact"] = contact
     if license_info:
         info["license"] = license_info
-    output: Dict[str, Any] = {"openapi": openapi_version, "info": 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()
+    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)
     field_mapping, definitions = get_definitions(
index e32f755933ba506530d9278c4bc2a58d615a7c23..844542594ba959e69a68a6f66cb4f4c78c18bcdb 100644 (file)
@@ -1,10 +1,11 @@
-from typing import Any, Callable, Dict, List, Optional, Sequence, Union
+from collections.abc import Sequence
+from typing import Annotated, Any, Callable, Optional, Union
 
 from annotated_doc import Doc
 from fastapi import params
 from fastapi._compat import Undefined
 from fastapi.openapi.models import Example
-from typing_extensions import Annotated, Literal, deprecated
+from typing_extensions import Literal, deprecated
 
 _Unset: Any = Undefined
 
@@ -209,7 +210,7 @@ def Path(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -224,7 +225,7 @@ def Path(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -262,7 +263,7 @@ def Path(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -534,7 +535,7 @@ def Query(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -549,7 +550,7 @@ def Query(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -587,7 +588,7 @@ def Query(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -849,7 +850,7 @@ def Header(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -864,7 +865,7 @@ def Header(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -902,7 +903,7 @@ def Header(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -1154,7 +1155,7 @@ def Cookie(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -1169,7 +1170,7 @@ def Cookie(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -1207,7 +1208,7 @@ def Cookie(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -1481,7 +1482,7 @@ def Body(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -1496,7 +1497,7 @@ def Body(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -1534,7 +1535,7 @@ def Body(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -1796,7 +1797,7 @@ def Form(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -1811,7 +1812,7 @@ def Form(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -1849,7 +1850,7 @@ def Form(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
@@ -2110,7 +2111,7 @@ def File(  # noqa: N802
         ),
     ] = _Unset,
     examples: Annotated[
-        Optional[List[Any]],
+        Optional[list[Any]],
         Doc(
             """
             Example values for this field.
@@ -2125,7 +2126,7 @@ def File(  # noqa: N802
         ),
     ] = _Unset,
     openapi_examples: Annotated[
-        Optional[Dict[str, Example]],
+        Optional[dict[str, Example]],
         Doc(
             """
             OpenAPI-specific examples.
@@ -2163,7 +2164,7 @@ def File(  # noqa: N802
         ),
     ] = True,
     json_schema_extra: Annotated[
-        Union[Dict[str, Any], None],
+        Union[dict[str, Any], None],
         Doc(
             """
             Any additional JSON schema data.
index b6d0f08e314bbbaec1944f138f2b7cc58322e9f0..4990d0e70e2f57568d48a95f431de1caf9406f9a 100644 (file)
@@ -1,11 +1,12 @@
 import warnings
+from collections.abc import Sequence
 from dataclasses import dataclass
 from enum import Enum
-from typing import Any, Callable, Dict, List, Optional, Sequence, Union
+from typing import Annotated, Any, Callable, Optional, Union
 
 from fastapi.openapi.models import Example
 from pydantic.fields import FieldInfo
-from typing_extensions import Annotated, Literal, deprecated
+from typing_extensions import Literal, deprecated
 
 from ._compat import (
     PYDANTIC_V2,
@@ -59,7 +60,7 @@ class Param(FieldInfo):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -67,10 +68,10 @@ class Param(FieldInfo):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         if example is not _Unset:
@@ -177,7 +178,7 @@ class Path(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -185,10 +186,10 @@ class Path(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         assert default is ..., "Path parameters cannot have a default value"
@@ -263,7 +264,7 @@ class Query(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -271,10 +272,10 @@ class Query(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -348,7 +349,7 @@ class Header(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -356,10 +357,10 @@ class Header(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         self.convert_underscores = convert_underscores
@@ -433,7 +434,7 @@ class Cookie(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -441,10 +442,10 @@ class Cookie(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -517,7 +518,7 @@ class Body(FieldInfo):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -525,10 +526,10 @@ class Body(FieldInfo):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         self.embed = embed
@@ -637,7 +638,7 @@ class Form(Body):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -645,10 +646,10 @@ class Form(Body):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -721,7 +722,7 @@ class File(Form):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -729,10 +730,10 @@ class File(Form):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
index 9be2b44bc1beb2c2ff3b67c93733439ab6688450..fa6904a6b602c9e51afe9892fc13a857615fd865 100644 (file)
@@ -3,23 +3,21 @@ import email.message
 import functools
 import inspect
 import json
-from contextlib import AsyncExitStack, asynccontextmanager
-from enum import Enum, IntEnum
-from typing import (
-    Any,
+from collections.abc import (
     AsyncIterator,
     Awaitable,
-    Callable,
     Collection,
     Coroutine,
-    Dict,
-    List,
     Mapping,
-    Optional,
     Sequence,
-    Set,
-    Tuple,
-    Type,
+)
+from contextlib import AsyncExitStack, asynccontextmanager
+from enum import Enum, IntEnum
+from typing import (
+    Annotated,
+    Any,
+    Callable,
+    Optional,
     Union,
 )
 
@@ -77,7 +75,7 @@ from starlette.routing import (
 from starlette.routing import Mount as Mount  # noqa
 from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send
 from starlette.websockets import WebSocket
-from typing_extensions import Annotated, deprecated
+from typing_extensions import deprecated
 
 
 # Copy of starlette.routing.request_response modified to include the
@@ -214,7 +212,7 @@ def _merge_lifespan_context(
 
 
 # Cache for endpoint context to avoid re-extracting on every request
-_endpoint_context_cache: Dict[int, EndpointContext] = {}
+_endpoint_context_cache: dict[int, EndpointContext] = {}
 
 
 def _extract_endpoint_context(func: Any) -> EndpointContext:
@@ -306,7 +304,7 @@ async def serialize_response(
 
 
 async def run_endpoint_function(
-    *, dependant: Dependant, values: Dict[str, Any], is_coroutine: bool
+    *, 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.
@@ -322,7 +320,7 @@ 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_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse),
     response_field: Optional[ModelField] = None,
     response_model_include: Optional[IncEx] = None,
     response_model_exclude: Optional[IncEx] = None,
@@ -339,7 +337,7 @@ def get_request_handler(
         body_field.field_info, (params.Form, temp_pydantic_v1_params.Form)
     )
     if isinstance(response_class, DefaultPlaceholder):
-        actual_response_class: Type[Response] = response_class.value
+        actual_response_class: type[Response] = response_class.value
     else:
         actual_response_class = response_class
 
@@ -412,7 +410,7 @@ def get_request_handler(
             raise http_error from e
 
         # Solve dependencies and run path operation function, auto-closing dependencies
-        errors: List[Any] = []
+        errors: list[Any] = []
         async_exit_stack = request.scope.get("fastapi_inner_astack")
         assert isinstance(async_exit_stack, AsyncExitStack), (
             "fastapi_inner_astack not found in request scope"
@@ -437,7 +435,7 @@ def get_request_handler(
                     raw_response.background = solved_result.background_tasks
                 response = raw_response
             else:
-                response_args: Dict[str, Any] = {
+                response_args: dict[str, Any] = {
                     "background": solved_result.background_tasks
                 }
                 # If status_code was set, use it, otherwise use the default from the
@@ -550,7 +548,7 @@ class APIWebSocketRoute(routing.WebSocketRoute):
             )
         )
 
-    def matches(self, scope: Scope) -> Tuple[Match, Scope]:
+    def matches(self, scope: Scope) -> tuple[Match, Scope]:
         match, child_scope = super().matches(scope)
         if match != Match.NONE:
             child_scope["route"] = self
@@ -565,15 +563,15 @@ class APIRoute(routing.Route):
         *,
         response_model: Any = Default(None),
         status_code: Optional[int] = None,
-        tags: Optional[List[Union[str, Enum]]] = 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,
+        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,
+        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,
@@ -582,12 +580,12 @@ class APIRoute(routing.Route):
         response_model_exclude_defaults: bool = False,
         response_model_exclude_none: bool = False,
         include_in_schema: bool = True,
-        response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+        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,
+        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),
@@ -623,7 +621,7 @@ class APIRoute(routing.Route):
         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}
+        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
@@ -678,7 +676,7 @@ class APIRoute(routing.Route):
                 )
                 response_fields[additional_status_code] = response_field
         if response_fields:
-            self.response_fields: Dict[Union[int, str], ModelField] = response_fields
+            self.response_fields: dict[Union[int, str], ModelField] = response_fields
         else:
             self.response_fields = {}
 
@@ -719,7 +717,7 @@ class APIRoute(routing.Route):
             embed_body_fields=self._embed_body_fields,
         )
 
-    def matches(self, scope: Scope) -> Tuple[Match, Scope]:
+    def matches(self, scope: Scope) -> tuple[Match, Scope]:
         match, child_scope = super().matches(scope)
         if match != Match.NONE:
             child_scope["route"] = self
@@ -758,7 +756,7 @@ class APIRouter(routing.Router):
         *,
         prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to all the *path operations* in this
@@ -784,7 +782,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         default_response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 The default response class to be used.
@@ -795,7 +793,7 @@ class APIRouter(routing.Router):
             ),
         ] = Default(JSONResponse),
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses to be shown in OpenAPI.
@@ -811,7 +809,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 OpenAPI callbacks that should apply to all *path operations* in this
@@ -825,7 +823,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         routes: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 **Note**: you probably shouldn't use this parameter, it is inherited
@@ -876,7 +874,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         route_class: Annotated[
-            Type[APIRoute],
+            type[APIRoute],
             Doc(
                 """
                 Custom route (*path operation*) class to be used by this router.
@@ -982,7 +980,7 @@ class APIRouter(routing.Router):
                 "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.tags: list[Union[str, Enum]] = tags or []
         self.dependencies = list(dependencies or [])
         self.deprecated = deprecated
         self.include_in_schema = include_in_schema
@@ -1019,14 +1017,14 @@ class APIRouter(routing.Router):
         *,
         response_model: Any = Default(None),
         status_code: Optional[int] = None,
-        tags: Optional[List[Union[str, Enum]]] = 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,
+        responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
         deprecated: Optional[bool] = None,
-        methods: Optional[Union[Set[str], List[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,
@@ -1035,13 +1033,13 @@ class APIRouter(routing.Router):
         response_model_exclude_defaults: bool = False,
         response_model_exclude_none: bool = False,
         include_in_schema: bool = True,
-        response_class: Union[Type[Response], DefaultPlaceholder] = Default(
+        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,
+        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),
@@ -1100,14 +1098,14 @@ class APIRouter(routing.Router):
         *,
         response_model: Any = Default(None),
         status_code: Optional[int] = None,
-        tags: Optional[List[Union[str, Enum]]] = 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,
+        responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
         deprecated: Optional[bool] = None,
-        methods: Optional[List[str]] = None,
+        methods: Optional[list[str]] = None,
         operation_id: Optional[str] = None,
         response_model_include: Optional[IncEx] = None,
         response_model_exclude: Optional[IncEx] = None,
@@ -1116,10 +1114,10 @@ class APIRouter(routing.Router):
         response_model_exclude_defaults: bool = False,
         response_model_exclude_none: bool = False,
         include_in_schema: bool = True,
-        response_class: Type[Response] = Default(JSONResponse),
+        response_class: type[Response] = Default(JSONResponse),
         name: Optional[str] = None,
-        callbacks: Optional[List[BaseRoute]] = None,
-        openapi_extra: Optional[Dict[str, Any]] = None,
+        callbacks: Optional[list[BaseRoute]] = None,
+        openapi_extra: Optional[dict[str, Any]] = None,
         generate_unique_id_function: Callable[[APIRoute], str] = Default(
             generate_unique_id
         ),
@@ -1259,7 +1257,7 @@ class APIRouter(routing.Router):
         *,
         prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to all the *path operations* in this
@@ -1285,7 +1283,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         default_response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 The default response class to be used.
@@ -1296,7 +1294,7 @@ class APIRouter(routing.Router):
             ),
         ] = Default(JSONResponse),
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses to be shown in OpenAPI.
@@ -1312,7 +1310,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 OpenAPI callbacks that should apply to all *path operations* in this
@@ -1417,7 +1415,7 @@ class APIRouter(routing.Router):
                     current_tags.extend(tags)
                 if route.tags:
                     current_tags.extend(route.tags)
-                current_dependencies: List[params.Depends] = []
+                current_dependencies: list[params.Depends] = []
                 if dependencies:
                     current_dependencies.extend(dependencies)
                 if route.dependencies:
@@ -1558,7 +1556,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -1624,7 +1622,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -1765,7 +1763,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -1786,7 +1784,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -1802,7 +1800,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -1935,7 +1933,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2001,7 +1999,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2142,7 +2140,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2163,7 +2161,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2179,7 +2177,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -2317,7 +2315,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2383,7 +2381,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2524,7 +2522,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2545,7 +2543,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2561,7 +2559,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -2699,7 +2697,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -2765,7 +2763,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -2906,7 +2904,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -2927,7 +2925,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -2943,7 +2941,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3076,7 +3074,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3142,7 +3140,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -3283,7 +3281,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -3304,7 +3302,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -3320,7 +3318,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3453,7 +3451,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3519,7 +3517,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -3660,7 +3658,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -3681,7 +3679,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -3697,7 +3695,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -3835,7 +3833,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -3901,7 +3899,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -4042,7 +4040,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -4063,7 +4061,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -4079,7 +4077,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
@@ -4217,7 +4215,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         tags: Annotated[
-            Optional[List[Union[str, Enum]]],
+            Optional[list[Union[str, Enum]]],
             Doc(
                 """
                 A list of tags to be applied to the *path operation*.
@@ -4283,7 +4281,7 @@ class APIRouter(routing.Router):
             ),
         ] = "Successful Response",
         responses: Annotated[
-            Optional[Dict[Union[int, str], Dict[str, Any]]],
+            Optional[dict[Union[int, str], dict[str, Any]]],
             Doc(
                 """
                 Additional responses that could be returned by this *path operation*.
@@ -4424,7 +4422,7 @@ class APIRouter(routing.Router):
             ),
         ] = True,
         response_class: Annotated[
-            Type[Response],
+            type[Response],
             Doc(
                 """
                 Response class to be used for this *path operation*.
@@ -4445,7 +4443,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         callbacks: Annotated[
-            Optional[List[BaseRoute]],
+            Optional[list[BaseRoute]],
             Doc(
                 """
                 List of *path operations* that will be used as OpenAPI callbacks.
@@ -4461,7 +4459,7 @@ class APIRouter(routing.Router):
             ),
         ] = None,
         openapi_extra: Annotated[
-            Optional[Dict[str, Any]],
+            Optional[dict[str, Any]],
             Doc(
                 """
                 Extra metadata to be included in the OpenAPI schema for this *path
index 81c7be10d6bf4b9326804e14768e0bac4291b254..18dfb8e6187c3eb2f667ef1beb80c51a27a70394 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Optional, Union
+from typing import Annotated, Optional, Union
 
 from annotated_doc import Doc
 from fastapi.openapi.models import APIKey, APIKeyIn
@@ -6,7 +6,6 @@ from fastapi.security.base import SecurityBase
 from starlette.exceptions import HTTPException
 from starlette.requests import Request
 from starlette.status import HTTP_401_UNAUTHORIZED
-from typing_extensions import Annotated
 
 
 class APIKeyBase(SecurityBase):
index 0d1bbba3a079d651bde40016df0fac896422d4ea..b4c3bc6d85d78195e3b5959ba0cd0a11fffd33e1 100644 (file)
@@ -1,6 +1,6 @@
 import binascii
 from base64 import b64decode
-from typing import Dict, Optional
+from typing import Annotated, Optional
 
 from annotated_doc import Doc
 from fastapi.exceptions import HTTPException
@@ -11,7 +11,6 @@ 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
-from typing_extensions import Annotated
 
 
 class HTTPBasicCredentials(BaseModel):
@@ -82,7 +81,7 @@ class HTTPBase(SecurityBase):
         self.scheme_name = scheme_name or self.__class__.__name__
         self.auto_error = auto_error
 
-    def make_authenticate_headers(self) -> Dict[str, str]:
+    def make_authenticate_headers(self) -> dict[str, str]:
         return {"WWW-Authenticate": f"{self.model.scheme.title()}"}
 
     def make_not_authenticated_error(self) -> HTTPException:
@@ -197,7 +196,7 @@ class HTTPBasic(HTTPBase):
         self.realm = realm
         self.auto_error = auto_error
 
-    def make_authenticate_headers(self) -> Dict[str, str]:
+    def make_authenticate_headers(self) -> dict[str, str]:
         if self.realm:
             return {"WWW-Authenticate": f'Basic realm="{self.realm}"'}
         return {"WWW-Authenticate": "Basic"}
index b41b0f8778d8fcd35790675396aed252c6cc549a..fc49ba1903e51bbd97d6bdb8d62aa9ce509f998c 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Any, Dict, List, Optional, Union, cast
+from typing import Annotated, Any, Optional, Union, cast
 
 from annotated_doc import Doc
 from fastapi.exceptions import HTTPException
@@ -10,9 +10,6 @@ from fastapi.security.utils import get_authorization_scheme_param
 from starlette.requests import Request
 from starlette.status import HTTP_401_UNAUTHORIZED
 
-# TODO: import from typing when deprecating Python 3.9
-from typing_extensions import Annotated
-
 
 class OAuth2PasswordRequestForm:
     """
@@ -323,7 +320,7 @@ class OAuth2(SecurityBase):
         self,
         *,
         flows: Annotated[
-            Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]],
+            Union[OAuthFlowsModel, dict[str, dict[str, Any]]],
             Doc(
                 """
                 The dictionary of OAuth2 flows.
@@ -440,7 +437,7 @@ class OAuth2PasswordBearer(OAuth2):
             ),
         ] = None,
         scopes: Annotated[
-            Optional[Dict[str, str]],
+            Optional[dict[str, str]],
             Doc(
                 """
                 The OAuth2 scopes that would be required by the *path operations* that
@@ -553,7 +550,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
             ),
         ] = None,
         scopes: Annotated[
-            Optional[Dict[str, str]],
+            Optional[dict[str, str]],
             Doc(
                 """
                 The OAuth2 scopes that would be required by the *path operations* that
@@ -639,7 +636,7 @@ class SecurityScopes:
     def __init__(
         self,
         scopes: Annotated[
-            Optional[List[str]],
+            Optional[list[str]],
             Doc(
                 """
                 This will be filled by FastAPI.
@@ -648,7 +645,7 @@ class SecurityScopes:
         ] = None,
     ):
         self.scopes: Annotated[
-            List[str],
+            list[str],
             Doc(
                 """
                 The list of all the scopes required by dependencies.
index e574a56a82ca09cf2bdff8410f7bb5ccffb0afd7..f4d953351e74036d4dcc0803dc714fdb06f14d6d 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 from annotated_doc import Doc
 from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
@@ -6,7 +6,6 @@ from fastapi.security.base import SecurityBase
 from starlette.exceptions import HTTPException
 from starlette.requests import Request
 from starlette.status import HTTP_401_UNAUTHORIZED
-from typing_extensions import Annotated
 
 
 class OpenIdConnect(SecurityBase):
index fa7a450b74e813e66fd6e9a140d48c29215503bb..002e68b4458a4e726dbaad493272fd3c6f71789c 100644 (file)
@@ -1,9 +1,9 @@
-from typing import Optional, Tuple
+from typing import Optional
 
 
 def get_authorization_scheme_param(
     authorization_header_value: Optional[str],
-) -> Tuple[str, str]:
+) -> tuple[str, str]:
     if not authorization_header_value:
         return "", ""
     scheme, _, param = authorization_header_value.partition(" ")
index e41d712308ed1ca20660c8d29ffa739f6e7c28d8..b6c804dc44981e6c950068cc79e6b435b903cd69 100644 (file)
@@ -1,9 +1,9 @@
 import warnings
-from typing import Any, Callable, Dict, List, Optional, Union
+from typing import Annotated, Any, Callable, Optional, Union
 
 from fastapi.openapi.models import Example
 from fastapi.params import ParamTypes
-from typing_extensions import Annotated, deprecated
+from typing_extensions import deprecated
 
 from ._compat.may_v1 import FieldInfo, Undefined
 from ._compat.shared import PYDANTIC_VERSION_MINOR_TUPLE
@@ -47,7 +47,7 @@ class Param(FieldInfo):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -55,10 +55,10 @@ class Param(FieldInfo):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         if example is not _Unset:
@@ -148,7 +148,7 @@ class Path(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -156,10 +156,10 @@ class Path(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         assert default is ..., "Path parameters cannot have a default value"
@@ -234,7 +234,7 @@ class Query(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -242,10 +242,10 @@ class Query(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -319,7 +319,7 @@ class Header(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -327,10 +327,10 @@ class Header(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         self.convert_underscores = convert_underscores
@@ -404,7 +404,7 @@ class Cookie(Param):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -412,10 +412,10 @@ class Cookie(Param):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -488,7 +488,7 @@ class Body(FieldInfo):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -496,10 +496,10 @@ class Body(FieldInfo):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         self.embed = embed
@@ -591,7 +591,7 @@ class Form(Body):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -599,10 +599,10 @@ class Form(Body):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
@@ -675,7 +675,7 @@ class File(Form):  # type: ignore[misc]
         allow_inf_nan: Union[bool, None] = _Unset,
         max_digits: Union[int, None] = _Unset,
         decimal_places: Union[int, None] = _Unset,
-        examples: Optional[List[Any]] = None,
+        examples: Optional[list[Any]] = None,
         example: Annotated[
             Optional[Any],
             deprecated(
@@ -683,10 +683,10 @@ class File(Form):  # type: ignore[misc]
                 "although still supported. Use examples instead."
             ),
         ] = _Unset,
-        openapi_examples: Optional[Dict[str, Example]] = None,
+        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,
+        json_schema_extra: Union[dict[str, Any], None] = None,
         **extra: Any,
     ):
         super().__init__(
index 3f4e81a7cca9487527f4ed0ebdc2e1f5a1cc0bdb..d3e980cb439d6e7936efa53129c5246831a0a429 100644 (file)
@@ -1,11 +1,11 @@
 import types
 from enum import Enum
-from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union
+from typing import Any, Callable, Optional, 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]]
-DependencyCacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...], str]
+ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str]
+IncEx = Union[set[int], set[str], dict[int, Any], dict[str, Any]]
+DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str]
index b3b89ed2b47fb5928b6688bdbdddf21c960ccb2c..5b93b9af8e09198d7000711dd6b833a0d668aee6 100644 (file)
@@ -1,14 +1,11 @@
 import re
 import warnings
+from collections.abc import MutableMapping
 from dataclasses import is_dataclass
 from typing import (
     TYPE_CHECKING,
     Any,
-    Dict,
-    MutableMapping,
     Optional,
-    Set,
-    Type,
     Union,
     cast,
 )
@@ -36,7 +33,7 @@ if TYPE_CHECKING:  # pragma: nocover
     from .routing import APIRoute
 
 # Cache for `create_cloned_field`
-_CLONED_TYPES_CACHE: MutableMapping[Type[BaseModel], Type[BaseModel]] = (
+_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = (
     WeakKeyDictionary()
 )
 
@@ -58,7 +55,7 @@ def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
     return not (current_status_code < 200 or current_status_code in {204, 205, 304})
 
 
-def get_path_param_names(path: str) -> Set[str]:
+def get_path_param_names(path: str) -> set[str]:
     return set(re.findall("{(.*?)}", path))
 
 
@@ -76,10 +73,10 @@ _invalid_args_message = (
 def create_model_field(
     name: str,
     type_: Any,
-    class_validators: Optional[Dict[str, Validator]] = None,
+    class_validators: Optional[dict[str, Validator]] = None,
     default: Optional[Any] = Undefined,
     required: Union[bool, UndefinedType] = Undefined,
-    model_config: Union[Type[BaseConfig], None] = None,
+    model_config: Union[type[BaseConfig], None] = None,
     field_info: Optional[FieldInfo] = None,
     alias: Optional[str] = None,
     mode: Literal["validation", "serialization"] = "validation",
@@ -141,7 +138,7 @@ def create_model_field(
 def create_cloned_field(
     field: ModelField,
     *,
-    cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None,
+    cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None,
 ) -> ModelField:
     if PYDANTIC_V2:
         from ._compat import v2
@@ -161,7 +158,7 @@ def create_cloned_field(
         original_type = original_type.__pydantic_model__
     use_type = original_type
     if lenient_issubclass(original_type, v1.BaseModel):
-        original_type = cast(Type[v1.BaseModel], original_type)
+        original_type = cast(type[v1.BaseModel], original_type)
         use_type = cloned_types.get(original_type)
         if use_type is None:
             use_type = v1.create_model(original_type.__name__, __base__=original_type)
@@ -224,7 +221,7 @@ def generate_unique_id(route: "APIRoute") -> str:
     return operation_id
 
 
-def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None:
+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
index c83222b33685819dcb0d8ec08df5ed94bcc1cdaf..a0eb88eebbb51de9cd850e6982150ad65f856d48 100644 (file)
@@ -1,5 +1,5 @@
 import os
-from typing import Any, Dict
+from typing import Any
 
 from pdm.backend.hooks import Context
 
@@ -9,12 +9,12 @@ TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "fastapi")
 def pdm_build_initialize(context: Context) -> None:
     metadata = context.config.metadata
     # Get custom config for the current package, from the env var
-    config: Dict[str, Any] = context.config.data["tool"]["tiangolo"][
+    config: dict[str, Any] = context.config.data["tool"]["tiangolo"][
         "_internal-slim-build"
     ]["packages"].get(TIANGOLO_BUILD_PACKAGE)
     if not config:
         return
-    project_config: Dict[str, Any] = config["project"]
+    project_config: dict[str, Any] = config["project"]
     # Override main [project] configs with custom configs for this package
     for key, value in project_config.items():
         metadata[key] = value
index b35bb3627f556a5ad30943929c2155cc396650e3..bf7d9de395c27110c42e6f08d1fd13fddd868fc5 100644 (file)
@@ -8,7 +8,7 @@ from html.parser import HTMLParser
 from http.server import HTTPServer, SimpleHTTPRequestHandler
 from multiprocessing import Pool
 from pathlib import Path
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Optional, Union
 
 import mkdocs.utils
 import typer
@@ -82,11 +82,11 @@ def slugify(text: str) -> str:
     )
 
 
-def get_en_config() -> Dict[str, Any]:
+def get_en_config() -> dict[str, Any]:
     return mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8"))
 
 
-def get_lang_paths() -> List[Path]:
+def get_lang_paths() -> list[Path]:
     return sorted(docs_path.iterdir())
 
 
@@ -334,14 +334,14 @@ def live(
     )
 
 
-def get_updated_config_content() -> Dict[str, Any]:
+def get_updated_config_content() -> dict[str, Any]:
     config = get_en_config()
     languages = [{"en": "/"}]
-    new_alternate: List[Dict[str, str]] = []
+    new_alternate: list[dict[str, str]] = []
     # Language names sourced from https://quickref.me/iso-639-1
     # Contributors may wish to update or change these, e.g. to fix capitalization.
     language_names_path = Path(__file__).parent / "../docs/language_names.yml"
-    local_language_names: Dict[str, str] = mkdocs.utils.yaml_load(
+    local_language_names: dict[str, str] = mkdocs.utils.yaml_load(
         language_names_path.read_text(encoding="utf-8")
     )
     for lang_path in get_lang_paths():
@@ -530,7 +530,7 @@ def add_permalinks_page(path: Path, update_existing: bool = False):
 
 
 @app.command()
-def add_permalinks_pages(pages: List[Path], update_existing: bool = False) -> None:
+def add_permalinks_pages(pages: list[Path], update_existing: bool = False) -> None:
     """
     Add or update header permalinks in specific pages of En docs.
     """
index 09cfa99e389b55e3219b2da59260a4b5e8958080..4b781270a2c58a66d0cc496aa7ce84fab2de8f09 100644 (file)
@@ -1,6 +1,6 @@
 from functools import lru_cache
 from pathlib import Path
-from typing import Any, List, Union
+from typing import Any, Union
 
 import material
 from mkdocs.config.defaults import MkDocsConfig
@@ -27,7 +27,7 @@ def get_missing_translation_content(docs_dir: str) -> str:
 
 
 @lru_cache
-def get_mkdocs_material_langs() -> List[str]:
+def get_mkdocs_material_langs() -> list[str]:
     material_path = Path(material.__file__).parent
     material_langs_path = material_path / "templates" / "partials" / "languages"
     langs = [file.stem for file in material_langs_path.glob("*.html")]
@@ -65,7 +65,7 @@ def resolve_file(*, item: str, files: Files, config: MkDocsConfig) -> None:
             )
 
 
-def resolve_files(*, items: List[Any], files: Files, config: MkDocsConfig) -> None:
+def resolve_files(*, items: list[Any], files: Files, config: MkDocsConfig) -> None:
     for item in items:
         if isinstance(item, str):
             resolve_file(item=item, files=files, config=config)
@@ -94,9 +94,9 @@ def on_files(files: Files, *, config: MkDocsConfig) -> Files:
 
 
 def generate_renamed_section_items(
-    items: List[Union[Page, Section, Link]], *, config: MkDocsConfig
-) -> List[Union[Page, Section, Link]]:
-    new_items: List[Union[Page, Section, Link]] = []
+    items: list[Union[Page, Section, Link]], *, config: MkDocsConfig
+) -> list[Union[Page, Section, Link]]:
+    new_items: list[Union[Page, Section, Link]] = []
     for item in items:
         if isinstance(item, Section):
             new_title = item.title
index c300624db271ea48e4535f17dafdeb9fcecec58b..2ca740a607e98278b550bef52261010d9594ae7d 100644 (file)
@@ -3,7 +3,7 @@ import random
 import sys
 import time
 from pathlib import Path
-from typing import Any, Dict, List, Union, cast
+from typing import Any, Union, cast
 
 import httpx
 from github import Github
@@ -120,7 +120,7 @@ class CommentsEdge(BaseModel):
 
 
 class Comments(BaseModel):
-    edges: List[CommentsEdge]
+    edges: list[CommentsEdge]
 
 
 class CommentsDiscussion(BaseModel):
@@ -149,7 +149,7 @@ class AllDiscussionsLabelsEdge(BaseModel):
 
 
 class AllDiscussionsDiscussionLabels(BaseModel):
-    edges: List[AllDiscussionsLabelsEdge]
+    edges: list[AllDiscussionsLabelsEdge]
 
 
 class AllDiscussionsDiscussionNode(BaseModel):
@@ -160,7 +160,7 @@ class AllDiscussionsDiscussionNode(BaseModel):
 
 
 class AllDiscussionsDiscussions(BaseModel):
-    nodes: List[AllDiscussionsDiscussionNode]
+    nodes: list[AllDiscussionsDiscussionNode]
 
 
 class AllDiscussionsRepository(BaseModel):
@@ -205,7 +205,7 @@ def get_graphql_response(
     discussion_id: Union[str, None] = None,
     comment_id: Union[str, None] = None,
     body: Union[str, None] = None,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
     headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"}
     variables = {
         "after": after,
@@ -233,12 +233,12 @@ def get_graphql_response(
         logging.error(data["errors"])
         logging.error(response.text)
         raise RuntimeError(response.text)
-    return cast(Dict[str, Any], data)
+    return cast(dict[str, Any], data)
 
 
 def get_graphql_translation_discussions(
     *, settings: Settings
-) -> List[AllDiscussionsDiscussionNode]:
+) -> list[AllDiscussionsDiscussionNode]:
     data = get_graphql_response(
         settings=settings,
         query=all_discussions_query,
@@ -250,7 +250,7 @@ def get_graphql_translation_discussions(
 
 def get_graphql_translation_discussion_comments_edges(
     *, settings: Settings, discussion_number: int, after: Union[str, None] = None
-) -> List[CommentsEdge]:
+) -> list[CommentsEdge]:
     data = get_graphql_response(
         settings=settings,
         query=translation_discussion_query,
@@ -264,7 +264,7 @@ def get_graphql_translation_discussion_comments_edges(
 def get_graphql_translation_discussion_comments(
     *, settings: Settings, discussion_number: int
 ) -> list[Comment]:
-    comment_nodes: List[Comment] = []
+    comment_nodes: list[Comment] = []
     discussion_edges = get_graphql_translation_discussion_comments_edges(
         settings=settings, discussion_number=discussion_number
     )
@@ -348,7 +348,7 @@ def main() -> None:
 
     # Generate translation map, lang ID to discussion
     discussions = get_graphql_translation_discussions(settings=settings)
-    lang_to_discussion_map: Dict[str, AllDiscussionsDiscussionNode] = {}
+    lang_to_discussion_map: dict[str, AllDiscussionsDiscussionNode] = {}
     for discussion in discussions:
         for edge in discussion.labels.edges:
             label = edge.node.name
index 65e009944c9c3656ec267bb2166f1834745e985e..207ab4649335b7bbeac4aa425ce7c6c97e75f8af 100644 (file)
@@ -3,9 +3,10 @@ import secrets
 import subprocess
 import time
 from collections import Counter
+from collections.abc import Container
 from datetime import datetime, timedelta, timezone
 from pathlib import Path
-from typing import Any, Container, Union
+from typing import Any, Union
 
 import httpx
 import yaml
index 2f1d6171155aca526ea2ed160e226d2524f7d1c8..7edb16c61565721d12994099da051de9b2d8fa48 100644 (file)
@@ -1,5 +1,5 @@
 import http
-from typing import FrozenSet, List, Optional
+from typing import Optional
 
 from fastapi import FastAPI, Path, Query
 
@@ -195,15 +195,15 @@ def get_enum_status_code():
 
 
 @app.get("/query/frozenset")
-def get_query_type_frozenset(query: FrozenSet[int] = Query(...)):
+def get_query_type_frozenset(query: frozenset[int] = Query(...)):
     return ",".join(map(str, sorted(query)))
 
 
 @app.get("/query/list")
-def get_query_list(device_ids: List[int] = Query()) -> List[int]:
+def get_query_list(device_ids: list[int] = Query()) -> list[int]:
     return device_ids
 
 
 @app.get("/query/list-default")
-def get_query_list_default(device_ids: List[int] = Query(default=[])) -> List[int]:
+def get_query_list_default(device_ids: list[int] = Query(default=[])) -> list[int]:
     return device_ids
index be14d10edc66e00d6b050803046400e79ceeafc6..2622366400243028c9386d804eea8fac345e5d66 100644 (file)
@@ -1,5 +1,3 @@
-from typing import Dict
-
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
@@ -8,7 +6,7 @@ app = FastAPI()
 
 
 class Items(BaseModel):
-    items: Dict[str, int]
+    items: dict[str, int]
 
 
 @app.post("/foo")
index 9fec5c96d4e17277ac0e9c8215bd499a00775411..8724e5ecb849d892f9484c255c9863136a1744a8 100644 (file)
@@ -1,5 +1,3 @@
-import typing
-
 from fastapi import FastAPI
 from fastapi.responses import JSONResponse
 from fastapi.testclient import TestClient
@@ -18,7 +16,7 @@ class Error(BaseModel):
 
 
 class JsonApiError(BaseModel):
-    errors: typing.List[Error]
+    errors: list[Error]
 
 
 @app.get(
index 68753561c9ecc983e74f9d0ac77b34bae31e0c4a..fecc3ee16b9dfb009c195f1d65ad20a2ea36844f 100644 (file)
@@ -1,5 +1,3 @@
-import typing
-
 from fastapi import FastAPI
 from fastapi.responses import JSONResponse
 from fastapi.testclient import TestClient
@@ -18,7 +16,7 @@ class Error(BaseModel):
 
 
 class JsonApiError(BaseModel):
-    errors: typing.List[Error]
+    errors: list[Error]
 
 
 @app.get(
index 9e855fdf81e34a43203f24470c9a3de112c63ece..083a024af0d0d6047e49b75d00ad0bf940629e12 100644 (file)
@@ -1,7 +1,8 @@
+from typing import Annotated
+
 import pytest
 from fastapi import Body, FastAPI, Query
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 8a31442eb0ca3fc9bd34ef6664c74fe35f04021e..5e48782f8ddc083dedfbfde2fc653a9e8679dac7 100644 (file)
@@ -1,9 +1,10 @@
+from typing import Annotated
+
 import pytest
 from fastapi import Depends, FastAPI, Path
 from fastapi.param_functions import Query
 from fastapi.testclient import TestClient
 from fastapi.utils import PYDANTIC_V2
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 473d33e52c36cba60bd8705b5196f49db59e494d..a9e7c78c992b9e6b27a27a93ad56b2fde942de02 100644 (file)
@@ -1,8 +1,9 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict
 from fastapi import APIRouter, FastAPI, Query
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index e5fa95ef222ca3cc92faef290f220ad1fd82c4b6..8b8417bae0f0927af3f7fa2e94de944ef17c0004 100644 (file)
@@ -1,10 +1,9 @@
-from typing import List
+from typing import Annotated
 
 import pytest
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
-from typing_extensions import Annotated
 
 from .utils import needs_pydanticv2
 
@@ -25,7 +24,7 @@ def get_client():
 
     FakeNumpyArrayPydantic = Annotated[
         FakeNumpyArray,
-        WithJsonSchema(TypeAdapter(List[float]).json_schema()),
+        WithJsonSchema(TypeAdapter(list[float]).json_schema()),
         PlainSerializer(lambda v: v.data),
     ]
 
@@ -66,7 +65,7 @@ def test_typeadapter():
 
     FakeNumpyArrayPydantic = Annotated[
         FakeNumpyArray,
-        WithJsonSchema(TypeAdapter(List[float]).json_schema()),
+        WithJsonSchema(TypeAdapter(list[float]).json_schema()),
         PlainSerializer(lambda v: v.data),
     ]
 
index 26537c5ab71a3a09d19308075d69ff9dfde1d262..3f9d84d894ec7b0b9fb86dbed9b4359914e18b36 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Any, Dict, List, Union
+from typing import Any, Union
 
 from fastapi import FastAPI, UploadFile
 from fastapi._compat import (
@@ -61,7 +61,7 @@ def test_complex():
     app = FastAPI()
 
     @app.post("/")
-    def foo(foo: Union[str, List[int]]):
+    def foo(foo: Union[str, list[int]]):
         return foo
 
     client = TestClient(app)
@@ -95,7 +95,7 @@ def test_propagates_pydantic2_model_config():
         embedded_model: EmbeddedModel = EmbeddedModel()
 
     @app.post("/")
-    def foo(req: Model) -> Dict[str, Union[str, None]]:
+    def foo(req: Model) -> dict[str, Union[str, None]]:
         return {
             "value": req.value or None,
             "embedded_value": req.embedded_model.value or None,
@@ -125,7 +125,7 @@ def test_is_bytes_sequence_annotation_union():
     # TODO: in theory this would allow declaring types that could be lists of bytes
     # to be read from files and other types, but I'm not even sure it's a good idea
     # to support it as a first class "feature"
-    assert is_bytes_sequence_annotation(Union[List[str], List[bytes]])
+    assert is_bytes_sequence_annotation(Union[list[str], list[bytes]])
 
 
 def test_is_uploadfile_sequence_annotation():
@@ -133,7 +133,7 @@ def test_is_uploadfile_sequence_annotation():
     # TODO: in theory this would allow declaring types that could be lists of UploadFile
     # and other types, but I'm not even sure it's a good idea to support it as a first
     # class "feature"
-    assert is_uploadfile_sequence_annotation(Union[List[str], List[UploadFile]])
+    assert is_uploadfile_sequence_annotation(Union[list[str], list[UploadFile]])
 
 
 @needs_pydanticv2
@@ -141,7 +141,7 @@ def test_serialize_sequence_value_with_optional_list():
     """Test that serialize_sequence_value handles optional lists correctly."""
     from fastapi._compat import v2
 
-    field_info = FieldInfo(annotation=Union[List[str], None])
+    field_info = FieldInfo(annotation=Union[list[str], None])
     field = v2.ModelField(name="items", field_info=field_info)
     result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"])
     assert result == ["a", "b", "c"]
@@ -166,7 +166,7 @@ def test_serialize_sequence_value_with_none_first_in_union():
     """Test that serialize_sequence_value handles Union[None, List[...]] correctly."""
     from fastapi._compat import v2
 
-    field_info = FieldInfo(annotation=Union[None, List[str]])
+    field_info = FieldInfo(annotation=Union[None, list[str]])
     field = v2.ModelField(name="items", field_info=field_info)
     result = v2.serialize_sequence_value(field=field, value=["x", "y"])
     assert result == ["x", "y"]
@@ -179,7 +179,7 @@ def test_is_pv1_scalar_field():
 
     # For coverage
     class Model(v1.BaseModel):
-        foo: Union[str, Dict[str, Any]]
+        foo: Union[str, dict[str, Any]]
 
     fields = v1.get_model_fields(Model)
     assert not is_scalar_field(fields[0])
index 7064761cb5af030dae1f8808ea6cefa305dcf72f..8829a0a611feccb4515c80510f30f61df0e17b10 100644 (file)
@@ -1,5 +1,5 @@
 import sys
-from typing import List, Optional
+from typing import Optional
 
 import pytest
 
@@ -8,6 +8,8 @@ from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314
 if sys.version_info >= (3, 14):
     skip_module_if_py_gte_314()
 
+from typing import Annotated
+
 from fastapi import FastAPI
 from fastapi._compat.v1 import BaseModel
 from fastapi.temp_pydantic_v1_params import (
@@ -21,7 +23,6 @@ from fastapi.temp_pydantic_v1_params import (
 )
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
-from typing_extensions import Annotated
 
 
 class Item(BaseModel):
@@ -112,7 +113,7 @@ def upload_file(
 
 @app.post("/upload-multiple/")
 def upload_multiple_files(
-    files: Annotated[List[bytes], File()],
+    files: Annotated[list[bytes], File()],
     note: Annotated[str, Form()] = "",
 ):
     return {
index d890291b199a21c5ed36783e98807b1b02f3946b..bc3e1c5ec3af394e1b87876dd8f2478f17f98469 100644 (file)
@@ -1,10 +1,9 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 from fastapi import FastAPI
 from fastapi._compat import PYDANTIC_V2
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
-from typing_extensions import Annotated
 
 if PYDANTIC_V2:
     from pydantic import WithJsonSchema
index 7e57d525ce800769f5432fc56916e50a134d5493..c175147bc3171153cc58792f100351af2599d801 100644 (file)
@@ -1,6 +1,5 @@
 import io
 from pathlib import Path
-from typing import List
 
 import pytest
 from fastapi import FastAPI, UploadFile
@@ -38,7 +37,7 @@ def test_upload_file_is_closed(tmp_path: Path):
     path.write_bytes(b"<file content>")
     app = FastAPI()
 
-    testing_file_store: List[UploadFile] = []
+    testing_file_store: list[UploadFile] = []
 
     @app.post("/uploadfile/")
     def create_upload_file(file: UploadFile):
index b560dc36f95cc933e92a9f7536a8bbd84aa3346c..b5614027723606211a60f12bda0da8bffe90f1ff 100644 (file)
@@ -1,9 +1,8 @@
-from typing import Any
+from typing import Annotated, Any
 
 import pytest
 from fastapi import Depends, FastAPI, HTTPException
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 class CustomError(Exception):
index 7e1c8822b8a4270e65ab49d9533ed67d8a7bcb82..cbadff8f8728a54a74f02d4d989813858be63ba7 100644 (file)
@@ -1,11 +1,11 @@
+from collections.abc import Generator
 from contextlib import contextmanager
-from typing import Any, Generator
+from typing import Annotated, Any
 
 import pytest
 from fastapi import Depends, FastAPI
 from fastapi.responses import StreamingResponse
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 class Session:
index 7c323c338b1ec14577b1add36aa69a029775d9e5..0fdf697b6ce66fead92a6673ba0f4aace6085dca 100644 (file)
@@ -1,10 +1,10 @@
+from collections.abc import Generator
 from contextlib import contextmanager
-from typing import Any, Generator
+from typing import Annotated, Any
 
 import pytest
 from fastapi import Depends, FastAPI, WebSocket
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 class Session:
index 75241b467ac9709e750df6c5c47e3ebbaf2fdc77..95ff3e9d9578cc657be76db0e55b4a6e78f72f3a 100644 (file)
@@ -1,4 +1,4 @@
-from typing import AsyncGenerator, Generator
+from collections.abc import AsyncGenerator, Generator
 
 import pytest
 from fastapi import Depends, FastAPI
index 02c10458cb3bb6a1679712986a7aa336858d9e57..5a8993474164cf144137576f791090faab5f5f2c 100644 (file)
@@ -1,5 +1,4 @@
 import json
-from typing import Dict
 
 import pytest
 from fastapi import BackgroundTasks, Depends, FastAPI
@@ -37,19 +36,19 @@ class OtherDependencyError(Exception):
     pass
 
 
-async def asyncgen_state(state: Dict[str, str] = Depends(get_state)):
+async def asyncgen_state(state: dict[str, str] = Depends(get_state)):
     state["/async"] = "asyncgen started"
     yield state["/async"]
     state["/async"] = "asyncgen completed"
 
 
-def generator_state(state: Dict[str, str] = Depends(get_state)):
+def generator_state(state: dict[str, str] = Depends(get_state)):
     state["/sync"] = "generator started"
     yield state["/sync"]
     state["/sync"] = "generator completed"
 
 
-async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)):
+async def asyncgen_state_try(state: dict[str, str] = Depends(get_state)):
     state["/async_raise"] = "asyncgen raise started"
     try:
         yield state["/async_raise"]
@@ -60,7 +59,7 @@ async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)):
         state["/async_raise"] = "asyncgen raise finalized"
 
 
-def generator_state_try(state: Dict[str, str] = Depends(get_state)):
+def generator_state_try(state: dict[str, str] = Depends(get_state)):
     state["/sync_raise"] = "generator raise started"
     try:
         yield state["/sync_raise"]
index 076802df8444cea0e402a46a7e2e4ab83f11f512..0c2e5594b6f1de890bdfa7b2fbc18da06b77f8e5 100644 (file)
@@ -1,10 +1,11 @@
+from collections.abc import Awaitable
 from contextvars import ContextVar
-from typing import Any, Awaitable, Callable, Dict, Optional
+from typing import Any, Callable, Optional
 
 from fastapi import Depends, FastAPI, Request, Response
 from fastapi.testclient import TestClient
 
-legacy_request_state_context_var: ContextVar[Optional[Dict[str, Any]]] = ContextVar(
+legacy_request_state_context_var: ContextVar[Optional[dict[str, Any]]] = ContextVar(
     "legacy_request_state_context_var", default=None
 )
 
index 8e8d07c2d61ab18355523d18625937156204d4dc..7c6717e2aa5fce23dee21a8a0f6c5daeb2ef9d0f 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from dirty_equals import IsDict
 from fastapi import Depends, FastAPI
 from fastapi.testclient import TestClient
@@ -40,7 +38,7 @@ async def no_duplicates(item: Item, item2: Item = Depends(dependency)):
 
 @app.post("/with-duplicates-sub")
 async def no_duplicates_sub(
-    item: Item, sub_items: List[Item] = Depends(sub_duplicate_dependency)
+    item: Item, sub_items: list[Item] = Depends(sub_duplicate_dependency)
 ):
     return [item, sub_items]
 
index 9c3cc3878b5210a80edea25168c81685fe2b75d3..1774196fe47e2a8a0baa45fbea369ada7ba59c8e 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Union
+from typing import Annotated, Union
 
 from fastapi import FastAPI, HTTPException, Security
 from fastapi.security import (
@@ -6,7 +6,6 @@ from fastapi.security import (
     SecurityScopes,
 )
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 61a76236f8dbd75c9af5548eaac94a2181291fc0..05a3cffa5a8ff623dec0efa3c448438040d67877 100644 (file)
@@ -1,10 +1,10 @@
+from collections.abc import AsyncGenerator, Generator
 from functools import partial
-from typing import AsyncGenerator, Generator
+from typing import Annotated
 
 import pytest
 from fastapi import Depends, FastAPI
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index b89d82db433fa5efc8c7372e99aa240861c7a7bc..14b65c7770c534dffe7271b044c5b60c82a48469 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List, Tuple
-
 from fastapi import Depends, FastAPI, Security
 from fastapi.security import SecurityScopes
 from fastapi.testclient import TestClient
@@ -25,8 +23,8 @@ def get_data_override():
 
 @app.get("/user")
 def read_user(
-    user_data: Tuple[str, List[str]] = Security(get_user, scopes=["foo", "bar"]),
-    data: List[int] = Depends(get_data),
+    user_data: tuple[str, list[str]] = Security(get_user, scopes=["foo", "bar"]),
+    data: list[int] = Depends(get_data),
 ):
     return {"user": user_data[0], "scopes": user_data[1], "data": data}
 
index 08356712d6932d40c10968d5ed9df61bc394bc0c..a4044112a21c9f223c73796eacdfd242ea6cc8b0 100644 (file)
@@ -1,7 +1,7 @@
 import inspect
 import sys
+from collections.abc import AsyncGenerator, Generator
 from functools import wraps
-from typing import AsyncGenerator, Generator
 
 import pytest
 from fastapi import Depends, FastAPI
index d87164fe80aacce0b0ed788f5981019cf55b5e1f..f3fc3cc94f8708230f4d8c08a3c0491c695cf9f6 100644 (file)
@@ -1,12 +1,11 @@
 import json
-from typing import Any, Tuple
+from typing import Annotated, Any
 
 import pytest
 from fastapi import APIRouter, Depends, FastAPI, HTTPException
 from fastapi.exceptions import FastAPIError
 from fastapi.responses import StreamingResponse
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 class Session:
@@ -43,7 +42,7 @@ def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep)
     named_session.open = False
 
 
-NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
+NamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)]
 
 
 def get_named_func_session(session: SessionFuncDep) -> Any:
@@ -58,14 +57,14 @@ def get_named_regular_func_session(session: SessionFuncDep) -> Any:
 
 
 BrokenSessionsDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_func_session)
+    tuple[NamedSession, Session], Depends(get_named_func_session)
 ]
 NamedSessionsFuncDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
+    tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
 ]
 
 RegularSessionsDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
+    tuple[NamedSession, Session], Depends(get_named_regular_func_session)
 ]
 
 app = FastAPI()
index 52a30ae7a755d2c8da52b82624fcede0a0dff830..dbe35e576c3615bf609eb59be90eec57fce00868 100644 (file)
@@ -1,13 +1,12 @@
 from contextvars import ContextVar
-from typing import Any, Dict, Tuple
+from typing import Annotated, Any
 
 import pytest
 from fastapi import Depends, FastAPI, WebSocket
 from fastapi.exceptions import FastAPIError
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
-global_context: ContextVar[Dict[str, Any]] = ContextVar("global_context", default={})  # noqa: B039
+global_context: ContextVar[dict[str, Any]] = ContextVar("global_context", default={})  # noqa: B039
 
 
 class Session:
@@ -43,7 +42,7 @@ def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep)
     global_state["named_session_closed"] = True
 
 
-NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
+NamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)]
 
 
 def get_named_func_session(session: SessionFuncDep) -> Any:
@@ -60,14 +59,14 @@ def get_named_regular_func_session(session: SessionFuncDep) -> Any:
 
 
 BrokenSessionsDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_func_session)
+    tuple[NamedSession, Session], Depends(get_named_func_session)
 ]
 NamedSessionsFuncDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
+    tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
 ]
 
 RegularSessionsDep = Annotated[
-    Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
+    tuple[NamedSession, Session], Depends(get_named_regular_func_session)
 ]
 
 app = FastAPI()
index cb9a31d314c5ca8e442299406364d6b27921ab6b..75290b60cdbbc396cfbcfa3e7070b8e89fbfd797 100644 (file)
@@ -4,12 +4,11 @@ See https://github.com/tiangolo/fastapi/discussions/9116
 """
 
 from pathlib import Path
-from typing import List
+from typing import Annotated
 
 import pytest
 from fastapi import FastAPI, File, Form
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
@@ -32,7 +31,7 @@ def file_after_form(
 
 @app.post("/file_list_before_form")
 def file_list_before_form(
-    files: Annotated[List[bytes], File()],
+    files: Annotated[list[bytes], File()],
     city: Annotated[str, Form()],
 ):
     return {"file_contents": files, "city": city}
@@ -41,7 +40,7 @@ def file_list_before_form(
 @app.post("/file_list_after_form")
 def file_list_after_form(
     city: Annotated[str, Form()],
-    files: Annotated[List[bytes], File()],
+    files: Annotated[list[bytes], File()],
 ):
     return {"file_contents": files, "city": city}
 
index 2a12049d1a36be87c6f9380b7960825d4da1a382..0b3eb8f2e2bb7a9002fdf6b3f3960de8d4ce6a42 100644 (file)
@@ -1,8 +1,7 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 from fastapi import FastAPI, File, Form
 from starlette.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 1db63f02148e3c7d20b6d54bf90b6c7bc1a63734..b149b76539e972248abc34e80f620eae976ee268 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
 from fastapi._compat import PYDANTIC_V2
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 app = FastAPI()
 
@@ -14,7 +13,7 @@ class FormModel(BaseModel):
     username: str
     lastname: str
     age: Optional[int] = None
-    tags: List[str] = ["foo", "bar"]
+    tags: list[str] = ["foo", "bar"]
     alias_with: str = Field(alias="with", default="nothing")
 
 
index 3bb951441f52c0c71d2044815cee005f055a68bb..67f054b34eb657e8750e9aa163301b7d43562828 100644 (file)
@@ -1,6 +1,7 @@
+from typing import Annotated
+
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 5aeec66367a7c1a6f4ee4f37a751cd38fa795cb1..62ebfbc964efc5db59c61604bd2db58505862ba6 100644 (file)
@@ -1,5 +1,4 @@
 import warnings
-from typing import List
 
 from fastapi import APIRouter, FastAPI
 from fastapi.routing import APIRoute
@@ -33,12 +32,12 @@ def test_top_level_generate_unique_id():
     app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
     router = APIRouter()
 
-    @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+    @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}})
     def post_root(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @router.post(
-        "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+        "/router", response_model=list[Item], responses={404: {"model": list[Message]}}
     )
     def post_router(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
@@ -234,12 +233,12 @@ def test_router_overrides_generate_unique_id():
     app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
     router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
 
-    @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+    @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}})
     def post_root(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @router.post(
-        "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+        "/router", response_model=list[Item], responses={404: {"model": list[Message]}}
     )
     def post_router(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
@@ -435,12 +434,12 @@ def test_router_include_overrides_generate_unique_id():
     app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
     router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
 
-    @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+    @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}})
     def post_root(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @router.post(
-        "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+        "/router", response_model=list[Item], responses={404: {"model": list[Message]}}
     )
     def post_router(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
@@ -637,20 +636,20 @@ def test_subrouter_top_level_include_overrides_generate_unique_id():
     router = APIRouter()
     sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
 
-    @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+    @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}})
     def post_root(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @router.post(
-        "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+        "/router", response_model=list[Item], responses={404: {"model": list[Message]}}
     )
     def post_router(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @sub_router.post(
         "/subrouter",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
     )
     def post_subrouter(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
@@ -910,14 +909,14 @@ def test_router_path_operation_overrides_generate_unique_id():
     app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
     router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
 
-    @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+    @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}})
     def post_root(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
 
     @router.post(
         "/router",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
         generate_unique_id_function=custom_generate_unique_id3,
     )
     def post_router(item1: Item, item2: Item):
@@ -1116,8 +1115,8 @@ def test_app_path_operation_overrides_generate_unique_id():
 
     @app.post(
         "/",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
         generate_unique_id_function=custom_generate_unique_id3,
     )
     def post_root(item1: Item, item2: Item):
@@ -1125,8 +1124,8 @@ def test_app_path_operation_overrides_generate_unique_id():
 
     @router.post(
         "/router",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
     )
     def post_router(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
@@ -1324,8 +1323,8 @@ def test_callback_override_generate_unique_id():
 
     @callback_router.post(
         "/post-callback",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
         generate_unique_id_function=custom_generate_unique_id3,
     )
     def post_callback(item1: Item, item2: Item):
@@ -1333,8 +1332,8 @@ def test_callback_override_generate_unique_id():
 
     @app.post(
         "/",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
         generate_unique_id_function=custom_generate_unique_id3,
         callbacks=callback_router.routes,
     )
@@ -1343,8 +1342,8 @@ def test_callback_override_generate_unique_id():
 
     @app.post(
         "/tocallback",
-        response_model=List[Item],
-        responses={404: {"model": List[Message]}},
+        response_model=list[Item],
+        responses={404: {"model": list[Message]}},
     )
     def post_with_callback(item1: Item, item2: Item):
         return item1, item2  # pragma: nocover
index 5aa35320c9bdb97733ea0cd7ea0d2bb167336ca5..93b72ad243468b4ba04a51b89ba65a1cfa3cc6b7 100644 (file)
@@ -1,8 +1,7 @@
-from typing import TypeVar
+from typing import Annotated, TypeVar
 
 from fastapi import Depends, FastAPI
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index 6601585ef04e02e3749d4a7a175e22df0f0b5f39..215d06a07262672021cb2cdd2eb1b386ad407626 100644 (file)
@@ -1,4 +1,5 @@
-from typing import Any, Iterator, Set, Type
+from collections.abc import Iterator
+from typing import Any
 
 import fastapi._compat
 import fastapi.openapi.utils
@@ -143,11 +144,11 @@ class SortedTypeSet(set):
     Set of Types whose `__iter__()` method yields results sorted by the type names
     """
 
-    def __init__(self, seq: Set[Type[Any]], *, sort_reversed: bool):
+    def __init__(self, seq: set[type[Any]], *, sort_reversed: bool):
         super().__init__(seq)
         self.sort_reversed = sort_reversed
 
-    def __iter__(self) -> Iterator[Type[Any]]:
+    def __iter__(self) -> Iterator[type[Any]]:
         members_sorted = sorted(
             super().__iter__(),
             key=lambda type_: type_.__name__,
index d5fa53c1fc25b9850bd22727a8475da8fb8d2c28..35c00363dac40f12ed156d6744d8113ace37de3b 100644 (file)
@@ -1,5 +1,3 @@
-from typing import Dict, List, Tuple
-
 import pytest
 from fastapi import FastAPI
 from pydantic import BaseModel
@@ -13,7 +11,7 @@ def test_invalid_sequence():
             title: str
 
         @app.get("/items/{id}")
-        def read_items(id: List[Item]):
+        def read_items(id: list[Item]):
             pass  # pragma: no cover
 
 
@@ -25,7 +23,7 @@ def test_invalid_tuple():
             title: str
 
         @app.get("/items/{id}")
-        def read_items(id: Tuple[Item, Item]):
+        def read_items(id: tuple[Item, Item]):
             pass  # pragma: no cover
 
 
@@ -37,7 +35,7 @@ def test_invalid_dict():
             title: str
 
         @app.get("/items/{id}")
-        def read_items(id: Dict[str, Item]):
+        def read_items(id: dict[str, Item]):
             pass  # pragma: no cover
 
 
index 475786adbf80dfc5c03234662eabdc60d30fac83..2b8fd059e1c192bc0766b7f92928acf35be893c1 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Dict, List, Optional, Tuple
+from typing import Optional
 
 import pytest
 from fastapi import FastAPI, Query
@@ -13,7 +13,7 @@ def test_invalid_sequence():
             title: str
 
         @app.get("/items/")
-        def read_items(q: List[Item] = Query(default=None)):
+        def read_items(q: list[Item] = Query(default=None)):
             pass  # pragma: no cover
 
 
@@ -25,7 +25,7 @@ def test_invalid_tuple():
             title: str
 
         @app.get("/items/")
-        def read_items(q: Tuple[Item, Item] = Query(default=None)):
+        def read_items(q: tuple[Item, Item] = Query(default=None)):
             pass  # pragma: no cover
 
 
@@ -37,7 +37,7 @@ def test_invalid_dict():
             title: str
 
         @app.get("/items/")
-        def read_items(q: Dict[str, Item] = Query(default=None)):
+        def read_items(q: dict[str, Item] = Query(default=None)):
             pass  # pragma: no cover
 
 
index 33304827a97f161b000ea78b6eb6c102862a4d4d..6ea405fe700fbd9097c7d1a4366511462e368c36 100644 (file)
@@ -1,5 +1,4 @@
 from decimal import Decimal
-from typing import List
 
 from dirty_equals import IsDict, IsOneOf
 from fastapi import FastAPI
@@ -15,7 +14,7 @@ class Item(BaseModel):
 
 
 @app.post("/items/")
-def save_item_no_body(item: List[Item]):
+def save_item_no_body(item: list[Item]):
     return {"item": item}
 
 
index 8162d986c577e887f143ae6cc3c009d3f0f56792..7387a81ddf1f0706555903b33464a08cf7f8e1d1 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from dirty_equals import IsDict
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
@@ -8,7 +6,7 @@ app = FastAPI()
 
 
 @app.get("/items/")
-def read_items(q: List[int] = Query(default=None)):
+def read_items(q: list[int] = Query(default=None)):
     return {"q": q}
 
 
index b0b5958c1b5fa015c8192ab19efee813494d5d66..6169867ba3a1337c9782a435f6a810f89bcb324b 100644 (file)
@@ -3,7 +3,6 @@
 # Made an issue in:
 # https://github.com/fastapi/fastapi/issues/14247
 from enum import Enum
-from typing import List
 
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
@@ -25,7 +24,7 @@ class MessageEvent(BaseModel):
 
 class MessageOutput(BaseModel):
     body: str = ""
-    events: List[MessageEvent] = []
+    events: list[MessageEvent] = []
 
 
 class Message(BaseModel):
index a45ea20c8c214163f9ba8303af91e072e8f3150e..98d9787455c08ab185d6298ef772d84e0b79a4ee 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional, Union
+from typing import Optional, Union
 
 import pytest
 from fastapi.openapi.models import Schema, SchemaType
@@ -13,7 +13,7 @@ from fastapi.openapi.models import Schema, SchemaType
     ],
 )
 def test_allowed_schema_type(
-    type_value: Optional[Union[SchemaType, List[SchemaType]]],
+    type_value: Optional[Union[SchemaType, list[SchemaType]]],
 ) -> None:
     """Test that Schema accepts SchemaType, List[SchemaType] and None for type field."""
     schema = Schema(type=type_value)
index c9a05418bf1ceec047355dfbd3081b079818fb6f..bfe5e9a712212524a5b909be6642998dfafb6277 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional
+from typing import Optional
 
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
@@ -11,7 +11,7 @@ from .utils import PYDANTIC_V2, needs_pydanticv2
 class SubItem(BaseModel):
     subname: str
     sub_description: Optional[str] = None
-    tags: List[str] = []
+    tags: list[str] = []
     if PYDANTIC_V2:
         model_config = {"json_schema_serialization_defaults_required": True}
 
@@ -44,11 +44,11 @@ def get_app_client(separate_input_output_schemas: bool = True) -> TestClient:
         return item
 
     @app.post("/items-list/")
-    def create_item_list(item: List[Item]):
+    def create_item_list(item: list[Item]):
         return item
 
     @app.get("/items/")
-    def read_items() -> List[Item]:
+    def read_items() -> list[Item]:
         return [
             Item(
                 name="Portal Gun",
index 0228900cf6cb5b9dcc055543a06f635ca6c18f4b..68602586434b4ccfc92bd722b42322ff5de313d1 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional
+from typing import Optional
 
 from fastapi import FastAPI, File
 from fastapi.testclient import TestClient
@@ -7,7 +7,7 @@ app = FastAPI()
 
 
 @app.post("/files")
-async def upload_files(files: Optional[List[bytes]] = File(None)):
+async def upload_files(files: Optional[list[bytes]] = File(None)):
     if files is None:
         return {"files_count": 0}
     return {"files_count": len(files), "sizes": [len(f) for f in files]}
index baa172497d3c810282ea8d1b23a05c792b045861..19c2e8d696de98ca6d22a4081a0a49fd4e9d7276 100644 (file)
@@ -1,9 +1,9 @@
-from typing import Any, List
+from typing import Any
 
 from dirty_equals import IsOneOf
 from fastapi.params import Body, Cookie, Header, Param, Path, Query
 
-test_data: List[Any] = ["teststr", None, ..., 1, []]
+test_data: list[Any] = ["teststr", None, ..., 1, []]
 
 
 def get_user():
index 769e5fab6272d068c56b5acb085b4aba05808ffe..ebf86b99f0ec6056350753058f643b3f0fd761d9 100644 (file)
@@ -1,5 +1,5 @@
 import sys
-from typing import Any, List, Union
+from typing import Any, Union
 
 from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314
 
@@ -21,7 +21,7 @@ class Item(BaseModel):
     size: int
     description: Union[str, None] = None
     sub: SubItem
-    multi: List[SubItem] = []
+    multi: list[SubItem] = []
 
 
 app = FastAPI()
index 64f3dd3446974918faf80bc2345164cfb8b1eefb..8879b010decc292d689c3a0a58afcd0182d247ed 100644 (file)
@@ -1,5 +1,5 @@
 import sys
-from typing import Any, List, Union
+from typing import Any, Union
 
 from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314
 
@@ -21,18 +21,18 @@ class Item(BaseModel):
     size: int
     description: Union[str, None] = None
     sub: SubItem
-    multi: List[SubItem] = []
+    multi: list[SubItem] = []
 
 
 app = FastAPI()
 
 
 @app.post("/item")
-def handle_item(data: Item) -> List[Item]:
+def handle_item(data: Item) -> list[Item]:
     return [data, data]
 
 
-@app.post("/item-filter", response_model=List[Item])
+@app.post("/item-filter", response_model=list[Item])
 def handle_item_filter(data: Item) -> Any:
     extended_data = data.dict()
     extended_data.update({"secret_data": "classified", "internal_id": 12345})
@@ -41,14 +41,14 @@ def handle_item_filter(data: Item) -> Any:
 
 
 @app.post("/item-list")
-def handle_item_list(data: List[Item]) -> Item:
+def handle_item_list(data: list[Item]) -> Item:
     if data:
         return data[0]
     return Item(title="", size=0, sub=SubItem(name=""))
 
 
 @app.post("/item-list-filter", response_model=Item)
-def handle_item_list_filter(data: List[Item]) -> Any:
+def handle_item_list_filter(data: list[Item]) -> Any:
     if data:
         extended_data = data[0].dict()
         extended_data.update({"secret_data": "classified", "internal_id": 12345})
@@ -58,12 +58,12 @@ def handle_item_list_filter(data: List[Item]) -> Any:
 
 
 @app.post("/item-list-to-list")
-def handle_item_list_to_list(data: List[Item]) -> List[Item]:
+def handle_item_list_to_list(data: list[Item]) -> list[Item]:
     return data
 
 
-@app.post("/item-list-to-list-filter", response_model=List[Item])
-def handle_item_list_to_list_filter(data: List[Item]) -> Any:
+@app.post("/item-list-to-list-filter", response_model=list[Item])
+def handle_item_list_to_list_filter(data: list[Item]) -> Any:
     if data:
         extended_data = data[0].dict()
         extended_data.update({"secret_data": "classified", "internal_id": 12345})
index 54d408827f62d4b6c371ecde248cfd68386cc4e6..e66583cd54d56aa966bad26cc56f8a3ac29c0396 100644 (file)
@@ -1,5 +1,5 @@
 import sys
-from typing import Any, List, Union
+from typing import Any, Union
 
 from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314
 
@@ -22,7 +22,7 @@ class Item(BaseModel):
     size: int
     description: Union[str, None] = None
     sub: SubItem
-    multi: List[SubItem] = []
+    multi: list[SubItem] = []
 
 
 class NewSubItem(NewBaseModel):
@@ -34,7 +34,7 @@ class NewItem(NewBaseModel):
     new_size: int
     new_description: Union[str, None] = None
     new_sub: NewSubItem
-    new_multi: List[NewSubItem] = []
+    new_multi: list[NewSubItem] = []
 
 
 app = FastAPI()
@@ -93,7 +93,7 @@ def handle_v2_item_to_v1_filter(data: NewItem) -> Any:
 
 
 @app.post("/v1-to-v2/item-to-list")
-def handle_v1_item_to_v2_list(data: Item) -> List[NewItem]:
+def handle_v1_item_to_v2_list(data: Item) -> list[NewItem]:
     converted = NewItem(
         new_title=data.title,
         new_size=data.size,
@@ -105,7 +105,7 @@ def handle_v1_item_to_v2_list(data: Item) -> List[NewItem]:
 
 
 @app.post("/v1-to-v2/list-to-list")
-def handle_v1_list_to_v2_list(data: List[Item]) -> List[NewItem]:
+def handle_v1_list_to_v2_list(data: list[Item]) -> list[NewItem]:
     result = []
     for item in data:
         result.append(
@@ -120,8 +120,8 @@ def handle_v1_list_to_v2_list(data: List[Item]) -> List[NewItem]:
     return result
 
 
-@app.post("/v1-to-v2/list-to-list-filter", response_model=List[NewItem])
-def handle_v1_list_to_v2_list_filter(data: List[Item]) -> Any:
+@app.post("/v1-to-v2/list-to-list-filter", response_model=list[NewItem])
+def handle_v1_list_to_v2_list_filter(data: list[Item]) -> Any:
     result = []
     for item in data:
         converted = {
@@ -140,7 +140,7 @@ def handle_v1_list_to_v2_list_filter(data: List[Item]) -> Any:
 
 
 @app.post("/v1-to-v2/list-to-item")
-def handle_v1_list_to_v2_item(data: List[Item]) -> NewItem:
+def handle_v1_list_to_v2_item(data: list[Item]) -> NewItem:
     if data:
         item = data[0]
         return NewItem(
@@ -154,7 +154,7 @@ def handle_v1_list_to_v2_item(data: List[Item]) -> NewItem:
 
 
 @app.post("/v2-to-v1/item-to-list")
-def handle_v2_item_to_v1_list(data: NewItem) -> List[Item]:
+def handle_v2_item_to_v1_list(data: NewItem) -> list[Item]:
     converted = Item(
         title=data.new_title,
         size=data.new_size,
@@ -166,7 +166,7 @@ def handle_v2_item_to_v1_list(data: NewItem) -> List[Item]:
 
 
 @app.post("/v2-to-v1/list-to-list")
-def handle_v2_list_to_v1_list(data: List[NewItem]) -> List[Item]:
+def handle_v2_list_to_v1_list(data: list[NewItem]) -> list[Item]:
     result = []
     for item in data:
         result.append(
@@ -181,8 +181,8 @@ def handle_v2_list_to_v1_list(data: List[NewItem]) -> List[Item]:
     return result
 
 
-@app.post("/v2-to-v1/list-to-list-filter", response_model=List[Item])
-def handle_v2_list_to_v1_list_filter(data: List[NewItem]) -> Any:
+@app.post("/v2-to-v1/list-to-list-filter", response_model=list[Item])
+def handle_v2_list_to_v1_list_filter(data: list[NewItem]) -> Any:
     result = []
     for item in data:
         converted = {
@@ -201,7 +201,7 @@ def handle_v2_list_to_v1_list_filter(data: List[NewItem]) -> Any:
 
 
 @app.post("/v2-to-v1/list-to-item")
-def handle_v2_list_to_v1_item(data: List[NewItem]) -> Item:
+def handle_v2_list_to_v1_item(data: list[NewItem]) -> Item:
     if data:
         item = data[0]
         return Item(
index 8985cb7b4cc69a0ad706e39710f3625f5fc500f7..9397368abf25e4e3ccd87d38e87ade3a0874b55d 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 
 from . import modelsv1, modelsv2, modelsv2b
@@ -30,7 +28,7 @@ def handle_v2_item_to_v1(data: modelsv2.Item) -> modelsv1.Item:
 
 
 @app.post("/v1-to-v2/item-to-list")
-def handle_v1_item_to_v2_list(data: modelsv1.Item) -> List[modelsv2.Item]:
+def handle_v1_item_to_v2_list(data: modelsv1.Item) -> list[modelsv2.Item]:
     converted = modelsv2.Item(
         new_title=data.title,
         new_size=data.size,
@@ -42,7 +40,7 @@ def handle_v1_item_to_v2_list(data: modelsv1.Item) -> List[modelsv2.Item]:
 
 
 @app.post("/v1-to-v2/list-to-list")
-def handle_v1_list_to_v2_list(data: List[modelsv1.Item]) -> List[modelsv2.Item]:
+def handle_v1_list_to_v2_list(data: list[modelsv1.Item]) -> list[modelsv2.Item]:
     result = []
     for item in data:
         result.append(
@@ -58,7 +56,7 @@ def handle_v1_list_to_v2_list(data: List[modelsv1.Item]) -> List[modelsv2.Item]:
 
 
 @app.post("/v1-to-v2/list-to-item")
-def handle_v1_list_to_v2_item(data: List[modelsv1.Item]) -> modelsv2.Item:
+def handle_v1_list_to_v2_item(data: list[modelsv1.Item]) -> modelsv2.Item:
     if data:
         item = data[0]
         return modelsv2.Item(
@@ -74,7 +72,7 @@ def handle_v1_list_to_v2_item(data: List[modelsv1.Item]) -> modelsv2.Item:
 
 
 @app.post("/v2-to-v1/item-to-list")
-def handle_v2_item_to_v1_list(data: modelsv2.Item) -> List[modelsv1.Item]:
+def handle_v2_item_to_v1_list(data: modelsv2.Item) -> list[modelsv1.Item]:
     converted = modelsv1.Item(
         title=data.new_title,
         size=data.new_size,
@@ -86,7 +84,7 @@ def handle_v2_item_to_v1_list(data: modelsv2.Item) -> List[modelsv1.Item]:
 
 
 @app.post("/v2-to-v1/list-to-list")
-def handle_v2_list_to_v1_list(data: List[modelsv2.Item]) -> List[modelsv1.Item]:
+def handle_v2_list_to_v1_list(data: list[modelsv2.Item]) -> list[modelsv1.Item]:
     result = []
     for item in data:
         result.append(
@@ -102,7 +100,7 @@ def handle_v2_list_to_v1_list(data: List[modelsv2.Item]) -> List[modelsv1.Item]:
 
 
 @app.post("/v2-to-v1/list-to-item")
-def handle_v2_list_to_v1_item(data: List[modelsv2.Item]) -> modelsv1.Item:
+def handle_v2_list_to_v1_item(data: list[modelsv2.Item]) -> modelsv1.Item:
     if data:
         item = data[0]
         return modelsv1.Item(
@@ -130,8 +128,8 @@ def handle_v2_same_name_to_v1(
 
 @app.post("/v2-to-v1/list-of-items-to-list-of-items")
 def handle_v2_items_in_list_to_v1_item_in_list(
-    data1: List[modelsv2.ItemInList], data2: List[modelsv2b.ItemInList]
-) -> List[modelsv1.ItemInList]:
+    data1: list[modelsv2.ItemInList], data2: list[modelsv2b.ItemInList]
+) -> list[modelsv1.ItemInList]:
     result = []
     item1 = data1[0]
     item2 = data2[0]
index 889291a1a7bc7630c21bb8a37e8402de732edc45..0cc8de45590c9fcd81dab12354f7c81832d77adb 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import Union
 
 from fastapi._compat.v1 import BaseModel
 
@@ -12,7 +12,7 @@ class Item(BaseModel):
     size: int
     description: Union[str, None] = None
     sub: SubItem
-    multi: List[SubItem] = []
+    multi: list[SubItem] = []
 
 
 class ItemInList(BaseModel):
index 2c8c6ea356e0668771f32fba0f1f7f79059f790b..d80b77e103585f184d7ffd31769bd499c92053b1 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import Union
 
 from pydantic import BaseModel
 
@@ -12,7 +12,7 @@ class Item(BaseModel):
     new_size: int
     new_description: Union[str, None] = None
     new_sub: SubItem
-    new_multi: List[SubItem] = []
+    new_multi: list[SubItem] = []
 
 
 class ItemInList(BaseModel):
index dc0c06c669a1f8a5f1f15d220d87a99ea66e81cd..e992bea2e11ff7bf13cb584408ca89cc37218c1d 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import Union
 
 from pydantic import BaseModel
 
@@ -12,7 +12,7 @@ class Item(BaseModel):
     dup_size: int
     dup_description: Union[str, None] = None
     dup_sub: SubItem
-    dup_multi: List[SubItem] = []
+    dup_multi: list[SubItem] = []
 
 
 class ItemInList(BaseModel):
index d2d6f6635b433e6385bf0a3344c123c4db59eb53..3e86469908f3a8f9604d9bc4c0622fffe225dab7 100644 (file)
@@ -1,5 +1,5 @@
 import sys
-from typing import Any, List, Union
+from typing import Any, Union
 
 from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314
 
@@ -22,7 +22,7 @@ class Item(BaseModel):
     size: int
     description: Union[str, None] = None
     sub: SubItem
-    multi: List[SubItem] = []
+    multi: list[SubItem] = []
 
 
 class NewSubItem(NewBaseModel):
@@ -34,7 +34,7 @@ class NewItem(NewBaseModel):
     new_size: int
     new_description: Union[str, None] = None
     new_sub: NewSubItem
-    new_multi: List[NewSubItem] = []
+    new_multi: list[NewSubItem] = []
 
 
 app = FastAPI()
index c9f94563bb98c03bfbc11c2e5d7e029525a5ff09..b72b0518a131e6446a097f64f2ac7e46e198c3a2 100644 (file)
@@ -2,7 +2,7 @@ from __future__ import annotations
 
 import uuid
 from dataclasses import dataclass, field
-from typing import List, Union
+from typing import Union
 
 from dirty_equals import IsUUID
 from fastapi import FastAPI
@@ -15,7 +15,7 @@ class Item:
     id: uuid.UUID
     name: str
     price: float
-    tags: List[str] = field(default_factory=list)
+    tags: list[str] = field(default_factory=list)
     description: Union[str, None] = None
     tax: Union[float, None] = None
 
index 74654ff3cedc7db2cba50464c9cd9f54a82cf666..cfbff19c87a86c7f340566e1b498d019bb3a0d4b 100644 (file)
@@ -1,8 +1,9 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from .utils import needs_py310
 
index 2ce64c6862a3e5b8cb7bb4a17f903c6ffa9a15eb..7d9988f9f8f6eec00fd0ea6816d8b2be6282f871 100644 (file)
@@ -1,8 +1,9 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from .utils import needs_py310
 
index 8c72fee54a4dfa3740428fa6904932892fea6abb..d1bff9ddf44d5a079ed4df453d2e8f54d04288a0 100644 (file)
@@ -1,5 +1,3 @@
-import typing
-
 from fastapi import Body, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
@@ -28,7 +26,7 @@ async def create_product(data: Product = Body(media_type=media_type, embed=True)
 @app.post("/shops")
 async def create_shop(
     data: Shop = Body(media_type=media_type),
-    included: typing.List[Product] = Body(default=[], media_type=media_type),
+    included: list[Product] = Body(default=[], media_type=media_type),
 ):
     pass  # pragma: no cover
 
index 18a2a2f308f6939e0d71e9488192398dbaadbc62..b2503a1c44f0c1d17e87d3facf0663718186f833 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Union
+from typing import Annotated, Union
 
 import pytest
 from dirty_equals import IsDict, IsOneOf, IsPartialDict
 from fastapi import Body, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -18,12 +17,12 @@ app = FastAPI()
 
 
 @app.post("/required-list-str", operation_id="required_list_str")
-async def read_required_list_str(p: Annotated[List[str], Body(embed=True)]):
+async def read_required_list_str(p: Annotated[list[str], Body(embed=True)]):
     return {"p": p}
 
 
 class BodyModelRequiredListStr(BaseModel):
-    p: List[str]
+    p: list[str]
 
 
 @app.post("/model-required-list-str", operation_id="model_required_list_str")
@@ -103,13 +102,13 @@ def test_required_list_str(path: str):
 
 @app.post("/required-list-alias", operation_id="required_list_alias")
 async def read_required_list_alias(
-    p: Annotated[List[str], Body(embed=True, alias="p_alias")],
+    p: Annotated[list[str], Body(embed=True, alias="p_alias")],
 ):
     return {"p": p}
 
 
 class BodyModelRequiredListAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias")
+    p: list[str] = Field(alias="p_alias")
 
 
 @app.post("/model-required-list-alias", operation_id="model_required_list_alias")
@@ -228,13 +227,13 @@ def test_required_list_alias_by_alias(path: str):
     "/required-list-validation-alias", operation_id="required_list_validation_alias"
 )
 def read_required_list_validation_alias(
-    p: Annotated[List[str], Body(embed=True, validation_alias="p_val_alias")],
+    p: Annotated[list[str], Body(embed=True, validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class BodyModelRequiredListValidationAlias(BaseModel):
-    p: List[str] = Field(validation_alias="p_val_alias")
+    p: list[str] = Field(validation_alias="p_val_alias")
 
 
 @app.post(
@@ -345,14 +344,14 @@ def test_required_list_validation_alias_by_validation_alias(path: str):
 )
 def read_required_list_alias_and_validation_alias(
     p: Annotated[
-        List[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
+        list[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
     ],
 ):
     return {"p": p}
 
 
 class BodyModelRequiredListAliasAndValidationAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias")
+    p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias")
 
 
 @app.post(
index e2ecdc7f43ca609578174078589758ae64ed7b35..ede635f840ac9cb0d2ae3bc669a89277d210f29f 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import Body, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -19,13 +18,13 @@ app = FastAPI()
 
 @app.post("/optional-list-str", operation_id="optional_list_str")
 async def read_optional_list_str(
-    p: Annotated[Optional[List[str]], Body(embed=True)] = None,
+    p: Annotated[Optional[list[str]], Body(embed=True)] = None,
 ):
     return {"p": p}
 
 
 class BodyModelOptionalListStr(BaseModel):
-    p: Optional[List[str]] = None
+    p: Optional[list[str]] = None
 
 
 @app.post("/model-optional-list-str", operation_id="model_optional_list_str")
@@ -131,13 +130,13 @@ def test_optional_list_str(path: str):
 
 @app.post("/optional-list-alias", operation_id="optional_list_alias")
 async def read_optional_list_alias(
-    p: Annotated[Optional[List[str]], Body(embed=True, alias="p_alias")] = None,
+    p: Annotated[Optional[list[str]], Body(embed=True, alias="p_alias")] = None,
 ):
     return {"p": p}
 
 
 class BodyModelOptionalListAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, alias="p_alias")
+    p: Optional[list[str]] = Field(None, alias="p_alias")
 
 
 @app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
@@ -264,14 +263,14 @@ def test_optional_list_alias_by_alias(path: str):
 )
 def read_optional_list_validation_alias(
     p: Annotated[
-        Optional[List[str]], Body(embed=True, validation_alias="p_val_alias")
+        Optional[list[str]], Body(embed=True, validation_alias="p_val_alias")
     ] = None,
 ):
     return {"p": p}
 
 
 class BodyModelOptionalListValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, validation_alias="p_val_alias")
+    p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
 
 
 @app.post(
@@ -410,7 +409,7 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
 )
 def read_optional_list_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[str]],
+        Optional[list[str]],
         Body(embed=True, alias="p_alias", validation_alias="p_val_alias"),
     ] = None,
 ):
@@ -418,7 +417,7 @@ def read_optional_list_alias_and_validation_alias(
 
 
 class BodyModelOptionalListAliasAndValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(
+    p: Optional[list[str]] = Field(
         None, alias="p_alias", validation_alias="p_val_alias"
     )
 
index a49f5a367542d8acffcb511736907aec5faad077..9e0c7217cc6ccd8c643dc1fcb9002952a0012d51 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import Body, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 18c660cad293336a39d558f6299ef9c21eaba9a8..aa47a4ede3300077e3aac7218ab9033e9958cff3 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Any, Dict, Union
+from typing import Annotated, Any, Union
 
 import pytest
 from dirty_equals import IsDict, IsOneOf
 from fastapi import Body, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -54,7 +53,7 @@ def test_required_str_schema(path: str):
     "path",
     ["/required-str", "/model-required-str"],
 )
-def test_required_str_missing(path: str, json: Union[Dict[str, Any], None]):
+def test_required_str_missing(path: str, json: Union[dict[str, Any], None]):
     client = TestClient(app)
     response = client.post(path, json=json)
     assert response.status_code == 422
@@ -140,7 +139,7 @@ def test_required_str_alias_schema(path: str):
     "path",
     ["/required-alias", "/model-required-alias"],
 )
-def test_required_alias_missing(path: str, json: Union[Dict[str, Any], None]):
+def test_required_alias_missing(path: str, json: Union[dict[str, Any], None]):
     client = TestClient(app)
     response = client.post(path, json=json)
     assert response.status_code == 422
@@ -266,7 +265,7 @@ def test_required_validation_alias_schema(path: str):
     ],
 )
 def test_required_validation_alias_missing(
-    path: str, json: Union[Dict[str, Any], None]
+    path: str, json: Union[dict[str, Any], None]
 ):
     client = TestClient(app)
     response = client.post(path, json=json)
@@ -386,7 +385,7 @@ def test_required_alias_and_validation_alias_schema(path: str):
     ],
 )
 def test_required_alias_and_validation_alias_missing(
-    path: str, json: Union[Dict[str, Any], None]
+    path: str, json: Union[dict[str, Any], None]
 ):
     client = TestClient(app)
     response = client.post(path, json=json)
index 5151a82d36cf65bc41d248623647807bd1a6167e..bf07394f90b4ca2516852cdff77084946dd9870d 100644 (file)
@@ -1,7 +1,7 @@
-from typing import Any, Dict
+from typing import Any
 
 
-def get_body_model_name(openapi: Dict[str, Any], path: str) -> str:
+def get_body_model_name(openapi: dict[str, Any], path: str) -> str:
     body = openapi["paths"][path]["post"]["requestBody"]
     body_schema = body["content"]["application/json"]["schema"]
     return body_schema.get("$ref", "").split("/")[-1]
index 1eec45689d0707806a08cf4eb445abbaf106afeb..f2d02dae545c17daf5375c27d8bacea03ef03a80 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import Cookie, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 6d0fa2ef29761c383b47193b54eb517ab9cae85f..3255857d448e44433db38c93bb21381dd7bb5853 100644 (file)
@@ -1,9 +1,10 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict, IsOneOf
 from fastapi import Cookie, FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 94a33967f3db38c214180199973c27e7a93f8581..52b032e4415419c05d7e20a525b21151a858c343 100644 (file)
@@ -1,10 +1,9 @@
-from typing import List
+from typing import Annotated
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, File, UploadFile
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -17,12 +16,12 @@ app = FastAPI()
 
 
 @app.post("/list-bytes", operation_id="list_bytes")
-async def read_list_bytes(p: Annotated[List[bytes], File()]):
+async def read_list_bytes(p: Annotated[list[bytes], File()]):
     return {"file_size": [len(file) for file in p]}
 
 
 @app.post("/list-uploadfile", operation_id="list_uploadfile")
-async def read_list_uploadfile(p: Annotated[List[UploadFile], File()]):
+async def read_list_uploadfile(p: Annotated[list[UploadFile], File()]):
     return {"file_size": [file.size for file in p]}
 
 
@@ -122,13 +121,13 @@ def test_list(path: str):
 
 
 @app.post("/list-bytes-alias", operation_id="list_bytes_alias")
-async def read_list_bytes_alias(p: Annotated[List[bytes], File(alias="p_alias")]):
+async def read_list_bytes_alias(p: Annotated[list[bytes], File(alias="p_alias")]):
     return {"file_size": [len(file) for file in p]}
 
 
 @app.post("/list-uploadfile-alias", operation_id="list_uploadfile_alias")
 async def read_list_uploadfile_alias(
-    p: Annotated[List[UploadFile], File(alias="p_alias")],
+    p: Annotated[list[UploadFile], File(alias="p_alias")],
 ):
     return {"file_size": [file.size for file in p]}
 
@@ -266,7 +265,7 @@ def test_list_alias_by_alias(path: str):
 
 @app.post("/list-bytes-validation-alias", operation_id="list_bytes_validation_alias")
 def read_list_bytes_validation_alias(
-    p: Annotated[List[bytes], File(validation_alias="p_val_alias")],
+    p: Annotated[list[bytes], File(validation_alias="p_val_alias")],
 ):
     return {"file_size": [len(file) for file in p]}
 
@@ -276,7 +275,7 @@ def read_list_bytes_validation_alias(
     operation_id="list_uploadfile_validation_alias",
 )
 def read_list_uploadfile_validation_alias(
-    p: Annotated[List[UploadFile], File(validation_alias="p_val_alias")],
+    p: Annotated[list[UploadFile], File(validation_alias="p_val_alias")],
 ):
     return {"file_size": [file.size for file in p]}
 
@@ -401,7 +400,7 @@ def test_list_validation_alias_by_validation_alias(path: str):
     operation_id="list_bytes_alias_and_validation_alias",
 )
 def read_list_bytes_alias_and_validation_alias(
-    p: Annotated[List[bytes], File(alias="p_alias", validation_alias="p_val_alias")],
+    p: Annotated[list[bytes], File(alias="p_alias", validation_alias="p_val_alias")],
 ):
     return {"file_size": [len(file) for file in p]}
 
@@ -412,7 +411,7 @@ def read_list_bytes_alias_and_validation_alias(
 )
 def read_list_uploadfile_alias_and_validation_alias(
     p: Annotated[
-        List[UploadFile], File(alias="p_alias", validation_alias="p_val_alias")
+        list[UploadFile], File(alias="p_alias", validation_alias="p_val_alias")
     ],
 ):
     return {"file_size": [file.size for file in p]}
index 2c1ca9530ed8ef4bd79fa5a4e9016ab8567d15f7..b7177e071dc8b0e75fe05214b90091766675b556 100644 (file)
@@ -1,10 +1,9 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, File, UploadFile
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 20e36501f8536babd1ca2c78a1a8ef9e774e9cab..af9fe552c915f53ebe2cd2fe840c698fdc047fe9 100644 (file)
@@ -1,10 +1,9 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, File, UploadFile
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -17,13 +16,13 @@ app = FastAPI()
 
 
 @app.post("/optional-list-bytes")
-async def read_optional_list_bytes(p: Annotated[Optional[List[bytes]], File()] = None):
+async def read_optional_list_bytes(p: Annotated[Optional[list[bytes]], File()] = None):
     return {"file_size": [len(file) for file in p] if p else None}
 
 
 @app.post("/optional-list-uploadfile")
 async def read_optional_list_uploadfile(
-    p: Annotated[Optional[List[UploadFile]], File()] = None,
+    p: Annotated[Optional[list[UploadFile]], File()] = None,
 ):
     return {"file_size": [file.size for file in p] if p else None}
 
@@ -103,14 +102,14 @@ def test_optional_list(path: str):
 
 @app.post("/optional-list-bytes-alias")
 async def read_optional_list_bytes_alias(
-    p: Annotated[Optional[List[bytes]], File(alias="p_alias")] = None,
+    p: Annotated[Optional[list[bytes]], File(alias="p_alias")] = None,
 ):
     return {"file_size": [len(file) for file in p] if p else None}
 
 
 @app.post("/optional-list-uploadfile-alias")
 async def read_optional_list_uploadfile_alias(
-    p: Annotated[Optional[List[UploadFile]], File(alias="p_alias")] = None,
+    p: Annotated[Optional[list[UploadFile]], File(alias="p_alias")] = None,
 ):
     return {"file_size": [file.size for file in p] if p else None}
 
@@ -204,7 +203,7 @@ def test_optional_list_alias_by_alias(path: str):
 
 @app.post("/optional-list-bytes-validation-alias")
 def read_optional_list_bytes_validation_alias(
-    p: Annotated[Optional[List[bytes]], File(validation_alias="p_val_alias")] = None,
+    p: Annotated[Optional[list[bytes]], File(validation_alias="p_val_alias")] = None,
 ):
     return {"file_size": [len(file) for file in p] if p else None}
 
@@ -212,7 +211,7 @@ def read_optional_list_bytes_validation_alias(
 @app.post("/optional-list-uploadfile-validation-alias")
 def read_optional_list_uploadfile_validation_alias(
     p: Annotated[
-        Optional[List[UploadFile]], File(validation_alias="p_val_alias")
+        Optional[list[UploadFile]], File(validation_alias="p_val_alias")
     ] = None,
 ):
     return {"file_size": [file.size for file in p] if p else None}
@@ -314,7 +313,7 @@ def test_optional_validation_alias_by_validation_alias(path: str):
 @app.post("/optional-list-bytes-alias-and-validation-alias")
 def read_optional_list_bytes_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[bytes]], File(alias="p_alias", validation_alias="p_val_alias")
+        Optional[list[bytes]], File(alias="p_alias", validation_alias="p_val_alias")
     ] = None,
 ):
     return {"file_size": [len(file) for file in p] if p else None}
@@ -323,7 +322,7 @@ def read_optional_list_bytes_alias_and_validation_alias(
 @app.post("/optional-list-uploadfile-alias-and-validation-alias")
 def read_optional_list_uploadfile_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[UploadFile]],
+        Optional[list[UploadFile]],
         File(alias="p_alias", validation_alias="p_val_alias"),
     ] = None,
 ):
index f041ac1ccfd8d746eb67422d907d46424feffd18..2979a1040a33c82b6d005ec960dd0d8a77b2ce78 100644 (file)
@@ -1,8 +1,9 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, File, UploadFile
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index e33f64385f2d67922c459fb4fb2700981d068bf4..e2a97ccd9b212b35cff8fc070713fcf1c17b356b 100644 (file)
@@ -1,7 +1,7 @@
-from typing import Any, Dict
+from typing import Any
 
 
-def get_body_model_name(openapi: Dict[str, Any], path: str) -> str:
+def get_body_model_name(openapi: dict[str, Any], path: str) -> str:
     body = openapi["paths"][path]["post"]["requestBody"]
     body_schema = body["content"]["multipart/form-data"]["schema"]
     return body_schema.get("$ref", "").split("/")[-1]
index 69a1b6a380c76326632f4ed36d35910dd06bcded..9f45aa755d52d39439b3f5cafc69a0dcbb3c5f95 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List
+from typing import Annotated
 
 import pytest
 from dirty_equals import IsDict, IsOneOf, IsPartialDict
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -18,12 +17,12 @@ app = FastAPI()
 
 
 @app.post("/required-list-str", operation_id="required_list_str")
-async def read_required_list_str(p: Annotated[List[str], Form()]):
+async def read_required_list_str(p: Annotated[list[str], Form()]):
     return {"p": p}
 
 
 class FormModelRequiredListStr(BaseModel):
-    p: List[str]
+    p: list[str]
 
 
 @app.post("/model-required-list-str", operation_id="model_required_list_str")
@@ -101,12 +100,12 @@ def test_required_list_str(path: str):
 
 
 @app.post("/required-list-alias", operation_id="required_list_alias")
-async def read_required_list_alias(p: Annotated[List[str], Form(alias="p_alias")]):
+async def read_required_list_alias(p: Annotated[list[str], Form(alias="p_alias")]):
     return {"p": p}
 
 
 class FormModelRequiredListAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias")
+    p: list[str] = Field(alias="p_alias")
 
 
 @app.post("/model-required-list-alias", operation_id="model_required_list_alias")
@@ -229,13 +228,13 @@ def test_required_list_alias_by_alias(path: str):
     "/required-list-validation-alias", operation_id="required_list_validation_alias"
 )
 def read_required_list_validation_alias(
-    p: Annotated[List[str], Form(validation_alias="p_val_alias")],
+    p: Annotated[list[str], Form(validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class FormModelRequiredListValidationAlias(BaseModel):
-    p: List[str] = Field(validation_alias="p_val_alias")
+    p: list[str] = Field(validation_alias="p_val_alias")
 
 
 @app.post(
@@ -345,13 +344,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str):
     operation_id="required_list_alias_and_validation_alias",
 )
 def read_required_list_alias_and_validation_alias(
-    p: Annotated[List[str], Form(alias="p_alias", validation_alias="p_val_alias")],
+    p: Annotated[list[str], Form(alias="p_alias", validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class FormModelRequiredListAliasAndValidationAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias")
+    p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias")
 
 
 @app.post(
index 1f779a7ed9eeed8a5da2a36e3a854527d4c57c86..0af6d3477788eb71d046180d492e5bd47b7750d6 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -19,13 +18,13 @@ app = FastAPI()
 
 @app.post("/optional-list-str", operation_id="optional_list_str")
 async def read_optional_list_str(
-    p: Annotated[Optional[List[str]], Form()] = None,
+    p: Annotated[Optional[list[str]], Form()] = None,
 ):
     return {"p": p}
 
 
 class FormModelOptionalListStr(BaseModel):
-    p: Optional[List[str]] = None
+    p: Optional[list[str]] = None
 
 
 @app.post("/model-optional-list-str", operation_id="model_optional_list_str")
@@ -95,13 +94,13 @@ def test_optional_list_str(path: str):
 
 @app.post("/optional-list-alias", operation_id="optional_list_alias")
 async def read_optional_list_alias(
-    p: Annotated[Optional[List[str]], Form(alias="p_alias")] = None,
+    p: Annotated[Optional[list[str]], Form(alias="p_alias")] = None,
 ):
     return {"p": p}
 
 
 class FormModelOptionalListAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, alias="p_alias")
+    p: Optional[list[str]] = Field(None, alias="p_alias")
 
 
 @app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
@@ -193,13 +192,13 @@ def test_optional_list_alias_by_alias(path: str):
     "/optional-list-validation-alias", operation_id="optional_list_validation_alias"
 )
 def read_optional_list_validation_alias(
-    p: Annotated[Optional[List[str]], Form(validation_alias="p_val_alias")] = None,
+    p: Annotated[Optional[list[str]], Form(validation_alias="p_val_alias")] = None,
 ):
     return {"p": p}
 
 
 class FormModelOptionalListValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, validation_alias="p_val_alias")
+    p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
 
 
 @app.post(
@@ -300,14 +299,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
 )
 def read_optional_list_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[str]], Form(alias="p_alias", validation_alias="p_val_alias")
+        Optional[list[str]], Form(alias="p_alias", validation_alias="p_val_alias")
     ] = None,
 ):
     return {"p": p}
 
 
 class FormModelOptionalListAliasAndValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(
+    p: Optional[list[str]] = Field(
         None, alias="p_alias", validation_alias="p_val_alias"
     )
 
index 969865945281ca8109cfbd99fe2b830a568a69de..92329216ec0b13283c6eb6211e7d49d711fca085 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index c901e7b44554f25325ff6c43884640dc4734b837..1e33038040e12f4f7c586e174662df9add8c9781 100644 (file)
@@ -1,9 +1,10 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict, IsOneOf
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index d200650dfdc12015663191e7db0e61bb2502edd1..913217311113b0aded7e0a2fb135f2bfb69901dc 100644 (file)
@@ -1,7 +1,7 @@
-from typing import Any, Dict
+from typing import Any
 
 
-def get_body_model_name(openapi: Dict[str, Any], path: str) -> str:
+def get_body_model_name(openapi: dict[str, Any], path: str) -> str:
     body = openapi["paths"][path]["post"]["requestBody"]
     body_schema = body["content"]["application/x-www-form-urlencoded"]["schema"]
     return body_schema.get("$ref", "").split("/")[-1]
index 4a5f4bb647c419981d6809cbf1c8d4357a0c3d7d..62f9f36ff643ce642b53611566b09d6fa1b0ecce 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List
+from typing import Annotated
 
 import pytest
 from dirty_equals import AnyThing, IsDict, IsOneOf, IsPartialDict
 from fastapi import FastAPI, Header
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -16,12 +15,12 @@ app = FastAPI()
 
 
 @app.get("/required-list-str")
-async def read_required_list_str(p: Annotated[List[str], Header()]):
+async def read_required_list_str(p: Annotated[list[str], Header()]):
     return {"p": p}
 
 
 class HeaderModelRequiredListStr(BaseModel):
-    p: List[str]
+    p: list[str]
 
 
 @app.get("/model-required-list-str")
@@ -96,12 +95,12 @@ def test_required_list_str(path: str):
 
 
 @app.get("/required-list-alias")
-async def read_required_list_alias(p: Annotated[List[str], Header(alias="p_alias")]):
+async def read_required_list_alias(p: Annotated[list[str], Header(alias="p_alias")]):
     return {"p": p}
 
 
 class HeaderModelRequiredListAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias")
+    p: list[str] = Field(alias="p_alias")
 
 
 @app.get("/model-required-list-alias")
@@ -219,13 +218,13 @@ def test_required_list_alias_by_alias(path: str):
 
 @app.get("/required-list-validation-alias")
 def read_required_list_validation_alias(
-    p: Annotated[List[str], Header(validation_alias="p_val_alias")],
+    p: Annotated[list[str], Header(validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class HeaderModelRequiredListValidationAlias(BaseModel):
-    p: List[str] = Field(validation_alias="p_val_alias")
+    p: list[str] = Field(validation_alias="p_val_alias")
 
 
 @app.get("/model-required-list-validation-alias")
@@ -328,13 +327,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str):
 
 @app.get("/required-list-alias-and-validation-alias")
 def read_required_list_alias_and_validation_alias(
-    p: Annotated[List[str], Header(alias="p_alias", validation_alias="p_val_alias")],
+    p: Annotated[list[str], Header(alias="p_alias", validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class HeaderModelRequiredListAliasAndValidationAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias")
+    p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias")
 
 
 @app.get("/model-required-list-alias-and-validation-alias")
index e81025c02be400d2f99e974531d24d06e299565a..88243f05a93247328f68450e0aebf480fb5294b6 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Header
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -17,13 +16,13 @@ app = FastAPI()
 
 @app.get("/optional-list-str")
 async def read_optional_list_str(
-    p: Annotated[Optional[List[str]], Header()] = None,
+    p: Annotated[Optional[list[str]], Header()] = None,
 ):
     return {"p": p}
 
 
 class HeaderModelOptionalListStr(BaseModel):
-    p: Optional[List[str]] = None
+    p: Optional[list[str]] = None
 
 
 @app.get("/model-optional-list-str")
@@ -93,13 +92,13 @@ def test_optional_list_str(path: str):
 
 @app.get("/optional-list-alias")
 async def read_optional_list_alias(
-    p: Annotated[Optional[List[str]], Header(alias="p_alias")] = None,
+    p: Annotated[Optional[list[str]], Header(alias="p_alias")] = None,
 ):
     return {"p": p}
 
 
 class HeaderModelOptionalListAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, alias="p_alias")
+    p: Optional[list[str]] = Field(None, alias="p_alias")
 
 
 @app.get("/model-optional-list-alias")
@@ -187,13 +186,13 @@ def test_optional_list_alias_by_alias(path: str):
 
 @app.get("/optional-list-validation-alias")
 def read_optional_list_validation_alias(
-    p: Annotated[Optional[List[str]], Header(validation_alias="p_val_alias")] = None,
+    p: Annotated[Optional[list[str]], Header(validation_alias="p_val_alias")] = None,
 ):
     return {"p": p}
 
 
 class HeaderModelOptionalListValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, validation_alias="p_val_alias")
+    p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
 
 
 @app.get("/model-optional-list-validation-alias")
@@ -273,14 +272,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
 @app.get("/optional-list-alias-and-validation-alias")
 def read_optional_list_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[str]], Header(alias="p_alias", validation_alias="p_val_alias")
+        Optional[list[str]], Header(alias="p_alias", validation_alias="p_val_alias")
     ] = None,
 ):
     return {"p": p}
 
 
 class HeaderModelOptionalListAliasAndValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(
+    p: Optional[list[str]] = Field(
         None, alias="p_alias", validation_alias="p_val_alias"
     )
 
index 5ae9f267017fe2b7d8306c3213caed1ad1c2a62f..e40b1669ee4618369b5330edcd33397b7ba1a191 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Header
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index d57c66919da06030c9a6432504ead56b11c57777..23554d3e4a0d0b5181d9e063ee2b383fd3ac13e1 100644 (file)
@@ -1,9 +1,10 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import AnyThing, IsDict, IsOneOf, IsPartialDict
 from fastapi import FastAPI, Header
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 64171996742e781d7759f9cb21d478e543e0551f..ecd4eb61cddd30bff400ffc64f11f1de651b8012 100644 (file)
@@ -1,7 +1,8 @@
+from typing import Annotated
+
 import pytest
 from fastapi import FastAPI, Path
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index 71cbca51fbda03c787f03a8cfe056d9e11a32a81..6a3000fbf65ca31868b4031f0867e2f394041d43 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List
+from typing import Annotated
 
 import pytest
 from dirty_equals import IsDict, IsOneOf
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -16,12 +15,12 @@ app = FastAPI()
 
 
 @app.get("/required-list-str")
-async def read_required_list_str(p: Annotated[List[str], Query()]):
+async def read_required_list_str(p: Annotated[list[str], Query()]):
     return {"p": p}
 
 
 class QueryModelRequiredListStr(BaseModel):
-    p: List[str]
+    p: list[str]
 
 
 @app.get("/model-required-list-str")
@@ -96,12 +95,12 @@ def test_required_list_str(path: str):
 
 
 @app.get("/required-list-alias")
-async def read_required_list_alias(p: Annotated[List[str], Query(alias="p_alias")]):
+async def read_required_list_alias(p: Annotated[list[str], Query(alias="p_alias")]):
     return {"p": p}
 
 
 class QueryModelRequiredListAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias")
+    p: list[str] = Field(alias="p_alias")
 
 
 @app.get("/model-required-list-alias")
@@ -219,13 +218,13 @@ def test_required_list_alias_by_alias(path: str):
 
 @app.get("/required-list-validation-alias")
 def read_required_list_validation_alias(
-    p: Annotated[List[str], Query(validation_alias="p_val_alias")],
+    p: Annotated[list[str], Query(validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class QueryModelRequiredListValidationAlias(BaseModel):
-    p: List[str] = Field(validation_alias="p_val_alias")
+    p: list[str] = Field(validation_alias="p_val_alias")
 
 
 @app.get("/model-required-list-validation-alias")
@@ -326,13 +325,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str):
 
 @app.get("/required-list-alias-and-validation-alias")
 def read_required_list_alias_and_validation_alias(
-    p: Annotated[List[str], Query(alias="p_alias", validation_alias="p_val_alias")],
+    p: Annotated[list[str], Query(alias="p_alias", validation_alias="p_val_alias")],
 ):
     return {"p": p}
 
 
 class QueryModelRequiredListAliasAndValidationAlias(BaseModel):
-    p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias")
+    p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias")
 
 
 @app.get("/model-required-list-alias-and-validation-alias")
index 56092133649e6ddc0432f3c5d7a6bd83de0ce659..f4b8ec6a823af1f56e1c0d59db08bfad2cb835ec 100644 (file)
@@ -1,11 +1,10 @@
-from typing import List, Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
@@ -17,13 +16,13 @@ app = FastAPI()
 
 @app.get("/optional-list-str")
 async def read_optional_list_str(
-    p: Annotated[Optional[List[str]], Query()] = None,
+    p: Annotated[Optional[list[str]], Query()] = None,
 ):
     return {"p": p}
 
 
 class QueryModelOptionalListStr(BaseModel):
-    p: Optional[List[str]] = None
+    p: Optional[list[str]] = None
 
 
 @app.get("/model-optional-list-str")
@@ -93,13 +92,13 @@ def test_optional_list_str(path: str):
 
 @app.get("/optional-list-alias")
 async def read_optional_list_alias(
-    p: Annotated[Optional[List[str]], Query(alias="p_alias")] = None,
+    p: Annotated[Optional[list[str]], Query(alias="p_alias")] = None,
 ):
     return {"p": p}
 
 
 class QueryModelOptionalListAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, alias="p_alias")
+    p: Optional[list[str]] = Field(None, alias="p_alias")
 
 
 @app.get("/model-optional-list-alias")
@@ -187,13 +186,13 @@ def test_optional_list_alias_by_alias(path: str):
 
 @app.get("/optional-list-validation-alias")
 def read_optional_list_validation_alias(
-    p: Annotated[Optional[List[str]], Query(validation_alias="p_val_alias")] = None,
+    p: Annotated[Optional[list[str]], Query(validation_alias="p_val_alias")] = None,
 ):
     return {"p": p}
 
 
 class QueryModelOptionalListValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(None, validation_alias="p_val_alias")
+    p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
 
 
 @app.get("/model-optional-list-validation-alias")
@@ -271,14 +270,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
 @app.get("/optional-list-alias-and-validation-alias")
 def read_optional_list_alias_and_validation_alias(
     p: Annotated[
-        Optional[List[str]], Query(alias="p_alias", validation_alias="p_val_alias")
+        Optional[list[str]], Query(alias="p_alias", validation_alias="p_val_alias")
     ] = None,
 ):
     return {"p": p}
 
 
 class QueryModelOptionalListAliasAndValidationAlias(BaseModel):
-    p: Optional[List[str]] = Field(
+    p: Optional[list[str]] = Field(
         None, alias="p_alias", validation_alias="p_val_alias"
     )
 
index 25e4ea42e60979d4dd0dad62006e494422dec83a..c7d20e37d1697fed2b808b7abec293bf83e249a2 100644 (file)
@@ -1,11 +1,10 @@
-from typing import Optional
+from typing import Annotated, Optional
 
 import pytest
 from dirty_equals import IsDict
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index aa0731e2c61098918eeca2b3a5deea2438940d97..ce30f3b1f8fcf4be3f51c088f89ad060628ab02d 100644 (file)
@@ -1,9 +1,10 @@
+from typing import Annotated
+
 import pytest
 from dirty_equals import IsDict, IsOneOf
 from fastapi import FastAPI, Query
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated
 
 from tests.utils import needs_pydanticv2
 
index e162cd39b5e854ba3f462b8c7fa268afb17d211b..5b241c76b6d73860d267da33e3fcc722efb8ac15 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 from fastapi._compat import PYDANTIC_V2
 from fastapi.testclient import TestClient
@@ -45,7 +43,7 @@ def read_model():
     return Model(alias="Foo")
 
 
-@app.get("/list", response_model=List[Model], response_model_by_alias=False)
+@app.get("/list", response_model=list[Model], response_model_by_alias=False)
 def read_list():
     return [{"alias": "Foo"}, {"alias": "Bar"}]
 
@@ -60,7 +58,7 @@ def by_alias_model():
     return Model(alias="Foo")
 
 
-@app.get("/by-alias/list", response_model=List[Model])
+@app.get("/by-alias/list", response_model=list[Model])
 def by_alias_list():
     return [{"alias": "Foo"}, {"alias": "Bar"}]
 
@@ -75,7 +73,7 @@ def no_alias_model():
     return ModelNoAlias(name="Foo")
 
 
-@app.get("/no-alias/list", response_model=List[ModelNoAlias])
+@app.get("/no-alias/list", response_model=list[ModelNoAlias])
 def no_alias_list():
     return [{"name": "Foo"}, {"name": "Bar"}]
 
index 706929ac3673c320fcc9d8a4e15b4ca9f167640e..4dc164bf92120c2e5ae06ea3587681b0ea77b9e0 100644 (file)
@@ -1,5 +1,3 @@
-import typing
-
 from fastapi import FastAPI, Response
 from fastapi.responses import JSONResponse
 from fastapi.testclient import TestClient
@@ -18,7 +16,7 @@ class Error(BaseModel):
 
 
 class JsonApiError(BaseModel):
-    errors: typing.List[Error]
+    errors: list[Error]
 
 
 @app.get(
index 3ca8708f1263a7c47c9cb78c0e0c933b3f70aa60..70456a7462c7fcc22da90a8ddd82ba196379f309 100644 (file)
@@ -1,5 +1,3 @@
-import typing
-
 from fastapi import FastAPI
 from fastapi.responses import JSONResponse
 from fastapi.testclient import TestClient
@@ -18,7 +16,7 @@ class Error(BaseModel):
 
 
 class JsonApiError(BaseModel):
-    errors: typing.List[Error]
+    errors: list[Error]
 
 
 @app.get(
index 1745c69b60985965192a3aedfdce222caa82fa93..44e882a76e24b268ca1367e3ae1b75fd6be246f6 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import Union
 
 import pytest
 from fastapi import FastAPI
@@ -191,7 +191,7 @@ def response_model_filtering_model_annotation_submodel_return_submodel() -> DBUs
     return DBUser(name="John", surname="Doe", password_hash="secret")
 
 
-@app.get("/response_model_list_of_model-no_annotation", response_model=List[User])
+@app.get("/response_model_list_of_model-no_annotation", response_model=list[User])
 def response_model_list_of_model_no_annotation():
     return [
         DBUser(name="John", surname="Doe", password_hash="secret"),
@@ -200,7 +200,7 @@ def response_model_list_of_model_no_annotation():
 
 
 @app.get("/no_response_model-annotation_list_of_model")
-def no_response_model_annotation_list_of_model() -> List[User]:
+def no_response_model_annotation_list_of_model() -> list[User]:
     return [
         DBUser(name="John", surname="Doe", password_hash="secret"),
         DBUser(name="Jane", surname="Does", password_hash="secret2"),
@@ -208,7 +208,7 @@ def no_response_model_annotation_list_of_model() -> List[User]:
 
 
 @app.get("/no_response_model-annotation_forward_ref_list_of_model")
-def no_response_model_annotation_forward_ref_list_of_model() -> "List[User]":
+def no_response_model_annotation_forward_ref_list_of_model() -> "list[User]":
     return [
         DBUser(name="John", surname="Doe", password_hash="secret"),
         DBUser(name="Jane", surname="Does", password_hash="secret2"),
index a3e0f95f0438c2b562042d9fbbd78e2463a392b5..358697d6dfac7fe1df7af526b989ac4e693a557d 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
@@ -44,7 +42,7 @@ async def read_pet(pet_id: int):
     return pet
 
 
-@app.get("/pets/", response_model=List[PetOut])
+@app.get("/pets/", response_model=list[PetOut])
 async def read_pets():
     user = UserDB(
         email="johndoe@example.com",
index 64003a8417f2af54c5cb757641c8c4a6aafadad0..c0c2f3a9dcad36b90d5d9724861768377fe7dd1d 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
@@ -46,7 +44,7 @@ async def read_pet(pet_id: int):
     return pet
 
 
-@app.get("/pets/", response_model=List[PetOut])
+@app.get("/pets/", response_model=list[PetOut])
 async def read_pets():
     user = UserDB(
         email="johndoe@example.com",
index 88b55a436d97f609e7becdd5cf922203f1eab3db..f884b5c74ab7fefd73d1e28025e1de83a4a7139e 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 import pytest
 from fastapi import FastAPI
 from fastapi.exceptions import FastAPIError
@@ -22,7 +20,7 @@ def test_invalid_response_model_sub_type_raises():
     with pytest.raises(FastAPIError):
         app = FastAPI()
 
-        @app.get("/", response_model=List[NonPydanticModel])
+        @app.get("/", response_model=list[NonPydanticModel])
         def read_root():
             pass  # pragma: nocover
 
@@ -40,6 +38,6 @@ def test_invalid_response_model_sub_type_in_responses_raises():
     with pytest.raises(FastAPIError):
         app = FastAPI()
 
-        @app.get("/", responses={"500": {"model": List[NonPydanticModel]}})
+        @app.get("/", responses={"500": {"model": list[NonPydanticModel]}})
         def read_root():
             pass  # pragma: nocover
index 660bcee1bb7eb53457b6021b959fda109d6e79e7..8036bcb07d38bca11c8b11efdb941dd53965c09c 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
@@ -17,7 +15,7 @@ def valid1():
     pass
 
 
-@app.get("/valid2", responses={"500": {"model": List[int]}})
+@app.get("/valid2", responses={"500": {"model": list[int]}})
 def valid2():
     pass
 
@@ -27,7 +25,7 @@ def valid3():
     pass
 
 
-@app.get("/valid4", responses={"500": {"model": List[Model]}})
+@app.get("/valid4", responses={"500": {"model": list[Model]}})
 def valid4():
     pass
 
index dd7ff3314b8777d70062036f16b42a4c6c9796d4..9df299cdaa6098d5211cd4f86a5d3f62825a6741 100644 (file)
@@ -1,5 +1,6 @@
+from collections.abc import AsyncGenerator
 from contextlib import asynccontextmanager
-from typing import AsyncGenerator, Dict, Union
+from typing import Union
 
 import pytest
 from fastapi import APIRouter, FastAPI, Request
@@ -28,7 +29,7 @@ def test_router_events(state: State) -> None:
     app = FastAPI()
 
     @app.get("/")
-    def main() -> Dict[str, str]:
+    def main() -> dict[str, str]:
         return {"message": "Hello World"}
 
     @app.on_event("startup")
@@ -96,7 +97,7 @@ def test_app_lifespan_state(state: State) -> None:
     app = FastAPI(lifespan=lifespan)
 
     @app.get("/")
-    def main() -> Dict[str, str]:
+    def main() -> dict[str, str]:
         return {"message": "Hello World"}
 
     assert state.app_startup is False
@@ -113,19 +114,19 @@ def test_app_lifespan_state(state: State) -> None:
 
 def test_router_nested_lifespan_state(state: State) -> None:
     @asynccontextmanager
-    async def lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]:
+    async def lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:
         state.app_startup = True
         yield {"app": True}
         state.app_shutdown = True
 
     @asynccontextmanager
-    async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]:
+    async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:
         state.router_startup = True
         yield {"router": True}
         state.router_shutdown = True
 
     @asynccontextmanager
-    async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]:
+    async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:
         state.sub_router_startup = True
         yield {"sub_router": True}
         state.sub_router_shutdown = True
@@ -139,7 +140,7 @@ def test_router_nested_lifespan_state(state: State) -> None:
     app.include_router(router)
 
     @app.get("/")
-    def main(request: Request) -> Dict[str, str]:
+    def main(request: Request) -> dict[str, str]:
         assert request.state.app
         assert request.state.router
         assert request.state.sub_router
@@ -175,7 +176,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
     @asynccontextmanager
     async def lifespan(
         app: FastAPI,
-    ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]:
+    ) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
         yield {
             "app_specific": True,
             "overridden": "app",
@@ -184,7 +185,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
     @asynccontextmanager
     async def router_lifespan(
         app: FastAPI,
-    ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]:
+    ) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
         yield {
             "router_specific": True,
             "overridden": "router",  # should override parent
@@ -225,7 +226,7 @@ def test_merged_mixed_state_lifespans() -> None:
         yield
 
     @asynccontextmanager
-    async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]:
+    async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:
         yield {"router": True}
 
     @asynccontextmanager
index d41f1dc1f038cb10a1c98fca222decd076f45301..583007c8b77d3b1805afe4253727a470b73d5916 100644 (file)
@@ -1,12 +1,11 @@
 # Ref: https://github.com/fastapi/fastapi/issues/14454
 
-from typing import Optional
+from typing import Annotated, Optional
 
 from fastapi import APIRouter, Depends, FastAPI, Security
 from fastapi.security import OAuth2AuthorizationCodeBearer
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
-from typing_extensions import Annotated
 
 oauth2_scheme = OAuth2AuthorizationCodeBearer(
     authorizationUrl="authorize",
index ff866d4fc972859ad34ca5ee557a898860c6ab58..1c21369d33f0691b15596d6a0f4ba4158809aa7a 100644 (file)
@@ -1,10 +1,11 @@
 # Ref: https://github.com/fastapi/fastapi/issues/14454
 
+from typing import Annotated
+
 from fastapi import Depends, FastAPI, Security
 from fastapi.security import OAuth2AuthorizationCodeBearer
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
-from typing_extensions import Annotated
 
 oauth2_scheme = OAuth2AuthorizationCodeBearer(
     authorizationUrl="api/oauth/authorize",
index 248fd2bcc29a4fb663267ccd786ab0fce52f287d..fccb026fe2775ce6de1618ff49cfe416c990edb8 100644 (file)
@@ -1,9 +1,8 @@
-from typing import Dict
+from typing import Annotated
 
 import pytest
 from fastapi import Depends, FastAPI, Security
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 @pytest.fixture(name="call_counter")
@@ -12,7 +11,7 @@ def call_counter_fixture():
 
 
 @pytest.fixture(name="app")
-def app_fixture(call_counter: Dict[str, int]):
+def app_fixture(call_counter: dict[str, int]):
     def get_db():
         call_counter["count"] += 1
         return f"db_{call_counter['count']}"
@@ -38,7 +37,7 @@ def client_fixture(app: FastAPI):
 
 
 def test_security_scopes_dependency_called_once(
-    client: TestClient, call_counter: Dict[str, int]
+    client: TestClient, call_counter: dict[str, int]
 ):
     response = client.get("/")
 
index 2bbcc749d30f403f005e5676eecec520f8386b39..c306ed0590cc28a5c03d495688fafd040f02de05 100644 (file)
@@ -1,11 +1,10 @@
 # Ref: https://github.com/tiangolo/fastapi/issues/5623
 
-from typing import Any, Dict, List
+from typing import Annotated, Any
 
 from fastapi import FastAPI, Security
 from fastapi.security import SecurityScopes
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 async def security1(scopes: SecurityScopes):
@@ -17,8 +16,8 @@ async def security2(scopes: SecurityScopes):
 
 
 async def dep3(
-    dep1: Annotated[List[str], Security(security1, scopes=["scope1"])],
-    dep2: Annotated[List[str], Security(security2, scopes=["scope2"])],
+    dep1: Annotated[list[str], Security(security1, scopes=["scope1"])],
+    dep2: Annotated[list[str], Security(security2, scopes=["scope2"])],
 ):
     return {"dep1": dep1, "dep2": dep2}
 
@@ -28,7 +27,7 @@ app = FastAPI()
 
 @app.get("/scopes")
 def get_scopes(
-    dep3: Annotated[Dict[str, Any], Security(dep3, scopes=["scope3"])],
+    dep3: Annotated[dict[str, Any], Security(dep3, scopes=["scope3"])],
 ):
     return dep3
 
index 9cc668d8e77d1df05ee0f27dbe31a19b7c554da1..2c64d5f3d5398bb81e1703eeab8db2850f79de37 100644 (file)
@@ -1,12 +1,12 @@
 # Ref: https://github.com/fastapi/fastapi/discussions/6024#discussioncomment-8541913
 
-from typing import Dict
+
+from typing import Annotated
 
 import pytest
 from fastapi import Depends, FastAPI, Security
 from fastapi.security import SecurityScopes
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
 @pytest.fixture(name="call_counts")
@@ -20,7 +20,7 @@ def call_counts_fixture():
 
 
 @pytest.fixture(name="app")
-def app_fixture(call_counts: Dict[str, int]):
+def app_fixture(call_counts: dict[str, int]):
     def get_db_session():
         call_counts["get_db_session"] += 1
         return f"db_session_{call_counts['get_db_session']}"
@@ -75,7 +75,7 @@ def client_fixture(app: FastAPI):
 
 
 def test_security_scopes_sub_dependency_caching(
-    client: TestClient, call_counts: Dict[str, int]
+    client: TestClient, call_counts: dict[str, int]
 ):
     response = client.get("/")
 
index d823e5e04a580e09e2d33b260e0c7ebd041ea6ff..14f88dd931f4e1caf10b2b99e1202a2bc0e15c74 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional
+from typing import Optional
 
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
@@ -10,7 +10,7 @@ app = FastAPI()
 class Item(BaseModel):
     name: str
     price: Optional[float] = None
-    owner_ids: Optional[List[int]] = None
+    owner_ids: Optional[list[int]] = None
 
 
 @app.get("/items/valid", response_model=Item)
@@ -23,7 +23,7 @@ def get_coerce():
     return {"name": "coerce", "price": "1.0"}
 
 
-@app.get("/items/validlist", response_model=List[Item])
+@app.get("/items/validlist", response_model=list[Item])
 def get_validlist():
     return [
         {"name": "foo"},
index 1e3bf3b28bcc3743f69802545fa4c103de22c566..ee695368b897ae83c620dab3a9662c8fc5b54c9d 100644 (file)
@@ -1,6 +1,6 @@
 from dataclasses import dataclass
 from datetime import datetime
-from typing import List, Optional
+from typing import Optional
 
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
@@ -13,7 +13,7 @@ class Item:
     name: str
     date: datetime
     price: Optional[float] = None
-    owner_ids: Optional[List[int]] = None
+    owner_ids: Optional[list[int]] = None
 
 
 @app.get("/items/valid", response_model=Item)
@@ -33,7 +33,7 @@ def get_coerce():
     return {"name": "coerce", "date": datetime(2021, 7, 26).isoformat(), "price": "1.0"}
 
 
-@app.get("/items/validlist", response_model=List[Item])
+@app.get("/items/validlist", response_model=list[Item])
 def get_validlist():
     return [
         {"name": "foo", "date": datetime(2021, 7, 26)},
@@ -47,7 +47,7 @@ def get_validlist():
     ]
 
 
-@app.get("/items/objectlist", response_model=List[Item])
+@app.get("/items/objectlist", response_model=list[Item])
 def get_objectlist():
     return [
         Item(name="foo", date=datetime(2021, 7, 26)),
index 3bb46b2e9bcd6d08f08d82f81d3612fe66f6fb9e..79c90c9c2912db9766c37156e8d772ed4f41d6a9 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Dict, List, Optional
+from typing import Optional
 
 from fastapi import FastAPI
 from pydantic import BaseModel, Field
@@ -10,7 +10,7 @@ app = FastAPI()
 class Item(BaseModel):
     name: str = Field(alias="aliased_name")
     price: Optional[float] = None
-    owner_ids: Optional[List[int]] = None
+    owner_ids: Optional[list[int]] = None
 
 
 @app.get("/items/valid", response_model=Item)
@@ -23,7 +23,7 @@ def get_coerce():
     return Item(aliased_name="coerce", price="1.0")
 
 
-@app.get("/items/validlist", response_model=List[Item])
+@app.get("/items/validlist", response_model=list[Item])
 def get_validlist():
     return [
         Item(aliased_name="foo"),
@@ -32,7 +32,7 @@ def get_validlist():
     ]
 
 
-@app.get("/items/validdict", response_model=Dict[str, Item])
+@app.get("/items/validdict", response_model=dict[str, Item])
 def get_validdict():
     return {
         "k1": Item(aliased_name="foo"),
@@ -59,7 +59,7 @@ def get_coerce_exclude_unset():
 
 @app.get(
     "/items/validlist-exclude-unset",
-    response_model=List[Item],
+    response_model=list[Item],
     response_model_exclude_unset=True,
 )
 def get_validlist_exclude_unset():
@@ -72,7 +72,7 @@ def get_validlist_exclude_unset():
 
 @app.get(
     "/items/validdict-exclude-unset",
-    response_model=Dict[str, Item],
+    response_model=dict[str, Item],
     response_model_exclude_unset=True,
 )
 def get_validdict_exclude_unset():
index 89bb884b5c434c808b6ef690230f079afafe9d99..ce880749575bde96f8b9252af976f9ef3f7da567 100644 (file)
@@ -1,12 +1,11 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Annotated
 
 import pytest
 from fastapi import Depends, FastAPI
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
-from typing_extensions import Annotated
 
 if TYPE_CHECKING:  # pragma: no cover
     from collections.abc import AsyncGenerator
index 9bd6d09d6336a537aa923962973e31f9f42fd423..6e037fb21fda60b5f18108cc22252d49407aced5 100644 (file)
@@ -1,8 +1,9 @@
 from __future__ import annotations
 
+from typing import Annotated
+
 from fastapi import Depends, FastAPI, Request
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 from .utils import needs_py310
 
index ca33d2580c2f9fe1db051b7740b6c49b16e1bdcf..fbc69a61451b6f035dbda508d11b6ca0512e7b4a 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List, Tuple
-
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
@@ -9,7 +7,7 @@ app = FastAPI()
 
 
 class ItemGroup(BaseModel):
-    items: List[Tuple[str, str]]
+    items: list[tuple[str, str]]
 
 
 class Coordinate(BaseModel):
@@ -23,12 +21,12 @@ def post_model_with_tuple(item_group: ItemGroup):
 
 
 @app.post("/tuple-of-models/")
-def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]):
+def post_tuple_of_models(square: tuple[Coordinate, Coordinate]):
     return square
 
 
 @app.post("/tuple-form/")
-def hello(values: Tuple[int, int] = Form()):
+def hello(values: tuple[int, int] = Form()):
     return values
 
 
index f303990f03d5db85ea9256df9b353650402ac137..0be1fc81d63de64453feb4ef885695cb5979e539 100644 (file)
@@ -35,9 +35,10 @@ def test_get(client: TestClient, html: str):
 
 
 def test_websocket_handle_disconnection(client: TestClient):
-    with client.websocket_connect("/ws/1234") as connection, client.websocket_connect(
-        "/ws/5678"
-    ) as connection_two:
+    with (
+        client.websocket_connect("/ws/1234") as connection,
+        client.websocket_connect("/ws/5678") as connection_two,
+    ):
         connection.send_text("Hello from 1234")
         data1 = connection.receive_text()
         assert data1 == "You wrote: Hello from 1234"
index 6af9e1d226323582006b367fd6d150411ce3cf4f..bf41a72915c5c7027afef19cedca7c03779de996 100644 (file)
@@ -1,11 +1,11 @@
-from typing import Any, Dict, Union
+from typing import Annotated, Any, Union
 
 from dirty_equals import IsDict
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
 from pydantic import BaseModel, Field
-from typing_extensions import Annotated, Literal
+from typing_extensions import Literal
 
 from .utils import needs_pydanticv2
 
@@ -32,7 +32,7 @@ def test_discriminator_pydantic_v2() -> None:
     @app.post("/items/")
     def save_union_body_discriminator(
         item: Item, q: Annotated[str, Field(description="Query string")]
-    ) -> Dict[str, Any]:
+    ) -> dict[str, Any]:
         return {"item": item}
 
     client = TestClient(app)
index 14145e6f60dcd07ce7a0b0ca14e979ff591ff762..f8108c8df4a2b120b40319d82befdbf3c5ba3996 100644 (file)
@@ -1,13 +1,12 @@
 # Ref: https://github.com/fastapi/fastapi/discussions/14495
 
-from typing import Union
+from typing import Annotated, Union
 
 import pytest
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from inline_snapshot import snapshot
 from pydantic import BaseModel
-from typing_extensions import Annotated
 
 from .utils import needs_pydanticv2
 
index cbe98ea825cc7501f49cc4fc13f6d7641305835e..018949f0c7da5d1a1be5a35a75a831539648e82f 100644 (file)
@@ -1,9 +1,8 @@
-from typing import Union
+from typing import Annotated, Union
 
 from fastapi import FastAPI, Form
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index cd97007a44814206efb6da03e9254a3373f4d856..938d41956634a01e3037075c7dcf453300d3f0a7 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional, Union
+from typing import Optional, Union
 
 import pytest
 from fastapi import FastAPI
@@ -12,7 +12,7 @@ app = FastAPI()
 class Item(BaseModel):
     name: str
     price: Optional[float] = None
-    owner_ids: Optional[List[int]] = None
+    owner_ids: Optional[list[int]] = None
 
 
 @app.get("/items/invalid", response_model=Item)
@@ -38,7 +38,7 @@ def get_innerinvalid():
     return {"name": "double invalid", "price": "foo", "owner_ids": ["foo", "bar"]}
 
 
-@app.get("/items/invalidlist", response_model=List[Item])
+@app.get("/items/invalidlist", response_model=list[Item])
 def get_invalidlist():
     return [
         {"name": "foo"},
index 0415988a0b8b5ad62e8dcc0a192fa3ea373baa96..67282bcde1b188898b22f79529b24225ddf053f0 100644 (file)
@@ -1,4 +1,4 @@
-from typing import List, Optional
+from typing import Optional
 
 import pytest
 from fastapi import FastAPI
@@ -13,7 +13,7 @@ app = FastAPI()
 class Item:
     name: str
     price: Optional[float] = None
-    owner_ids: Optional[List[int]] = None
+    owner_ids: Optional[list[int]] = None
 
 
 @app.get("/items/invalid", response_model=Item)
@@ -26,7 +26,7 @@ def get_innerinvalid():
     return {"name": "double invalid", "price": "foo", "owner_ids": ["foo", "bar"]}
 
 
-@app.get("/items/invalidlist", response_model=List[Item])
+@app.get("/items/invalidlist", response_model=list[Item])
 def get_invalidlist():
     return [
         {"name": "foo"},
index d23d279808d7fee784ba4c57ab9038e1850cb49f..8f76572ba6ad82a4f4ec9c4e9fe28d8c860c6994 100644 (file)
@@ -1,5 +1,3 @@
-from typing import List
-
 from fastapi import FastAPI
 from fastapi._compat import PYDANTIC_V2
 from pydantic import BaseModel
@@ -8,17 +6,17 @@ app = FastAPI()
 
 
 class RecursiveItem(BaseModel):
-    sub_items: List["RecursiveItem"] = []
+    sub_items: list["RecursiveItem"] = []
     name: str
 
 
 class RecursiveSubitemInSubmodel(BaseModel):
-    sub_items2: List["RecursiveItemViaSubmodel"] = []
+    sub_items2: list["RecursiveItemViaSubmodel"] = []
     name: str
 
 
 class RecursiveItemViaSubmodel(BaseModel):
-    sub_items1: List[RecursiveSubitemInSubmodel] = []
+    sub_items1: list[RecursiveSubitemInSubmodel] = []
     name: str
 
 
index 21a694cb5420fce696d7e430196517e380dbb08b..982ae1e21d690630739e0a7165a09e6b8098df6c 100644 (file)
@@ -1,10 +1,10 @@
 from datetime import datetime
+from typing import Annotated
 
 from fastapi import FastAPI, Security
 from fastapi.security import HTTPBearer
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
-from typing_extensions import Annotated
 
 app = FastAPI()
 
index ccb1c4b7da2e896fe4e693f3cabc8d03ea377545..51b982c00e51c346c508e0881eec69e1388073fb 100644 (file)
@@ -1,16 +1,15 @@
 import json
-from typing import List
+from typing import Annotated
 
 from fastapi import APIRouter, Depends, FastAPI, WebSocket
 from fastapi.testclient import TestClient
-from typing_extensions import Annotated
 
 
-def dependency_list() -> List[str]:
+def dependency_list() -> list[str]:
     return []
 
 
-DepList = Annotated[List[str], Depends(dependency_list)]
+DepList = Annotated[list[str], Depends(dependency_list)]
 
 
 def create_dependency(name: str):