🎨 Update internal types for Python 3.10 (#14898)

This commit is contained in:
Sebastián Ramírez 2026-02-11 10:41:21 -08:00 committed by GitHub
parent cc903bd440
commit 3da206c06d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 1087 additions and 1110 deletions

View File

@ -8,8 +8,11 @@ from functools import lru_cache
from typing import (
Annotated,
Any,
Literal,
Union,
cast,
get_args,
get_origin,
)
from fastapi._compat import lenient_issubclass, shared
@ -32,7 +35,6 @@ from pydantic_core import Url as Url
from pydantic_core.core_schema import (
with_info_plain_validator_function as with_info_plain_validator_function,
)
from typing_extensions import Literal, get_args, get_origin
RequiredParam = PydanticUndefined
Undefined = PydanticUndefined
@ -83,7 +85,7 @@ class ModelField:
field_info: FieldInfo
name: str
mode: Literal["validation", "serialization"] = "validation"
config: Union[ConfigDict, None] = None
config: ConfigDict | None = None
@property
def alias(self) -> str:
@ -91,14 +93,14 @@ class ModelField:
return a if a is not None else self.name
@property
def validation_alias(self) -> Union[str, None]:
def validation_alias(self) -> str | None:
va = self.field_info.validation_alias
if isinstance(va, str) and va:
return va
return None
@property
def serialization_alias(self) -> Union[str, None]:
def serialization_alias(self) -> str | None:
sa = self.field_info.serialization_alias
return sa or None
@ -143,7 +145,7 @@ class ModelField:
value: Any,
values: dict[str, Any] = {}, # noqa: B006
*,
loc: tuple[Union[int, str], ...] = (),
loc: tuple[int | str, ...] = (),
) -> tuple[Any, list[dict[str, Any]]]:
try:
return (
@ -160,8 +162,8 @@ class ModelField:
value: Any,
*,
mode: Literal["json", "python"] = "json",
include: Union[IncEx, None] = None,
exclude: Union[IncEx, None] = None,
include: IncEx | None = None,
exclude: IncEx | None = None,
by_alias: bool = True,
exclude_unset: bool = False,
exclude_defaults: bool = False,
@ -202,7 +204,7 @@ def get_schema_from_model_field(
],
separate_input_output_schemas: bool = True,
) -> dict[str, Any]:
override_mode: Union[Literal["validation"], None] = (
override_mode: Literal["validation"] | None = (
None
if (separate_input_output_schemas or _has_computed_fields(field))
else "validation"
@ -318,7 +320,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index]
def get_missing_field_error(loc: tuple[Union[int, str], ...]) -> dict[str, Any]:
def get_missing_field_error(loc: tuple[int | str, ...]) -> dict[str, Any]:
error = ValidationError.from_exception_data(
"Field required", [{"type": "missing", "loc": loc, "input": {}}]
).errors(include_url=False)[0]
@ -360,7 +362,7 @@ def get_cached_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]]
TypeModelOrEnum = type["BaseModel"] | type[Enum]
TypeModelSet = set[TypeModelOrEnum]
@ -377,7 +379,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: TypeModelSet | None = None
) -> TypeModelSet:
known_models = known_models or set()
fields = get_model_fields(model)
@ -426,7 +428,7 @@ def get_flat_models_from_fields(
def _regenerate_error_with_loc(
*, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...]
*, errors: Sequence[Any], loc_prefix: tuple[str | int, ...]
) -> list[dict[str, Any]]:
updated_loc_errors: list[Any] = [
{**err, "loc": loc_prefix + err.get("loc", ())} for err in errors

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
from typing import Annotated, Any, Callable
from collections.abc import Callable
from typing import Annotated, Any
from annotated_doc import Doc
from starlette.background import BackgroundTasks as StarletteBackgroundTasks

View File

@ -1,10 +1,8 @@
from collections.abc import Mapping
from collections.abc import Callable, Mapping
from typing import (
Annotated,
Any,
BinaryIO,
Callable,
Optional,
TypeVar,
cast,
)
@ -58,11 +56,11 @@ class UploadFile(StarletteUploadFile):
BinaryIO,
Doc("The standard Python file object (non-async)."),
]
filename: Annotated[Optional[str], Doc("The original file name.")]
size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
filename: Annotated[str | None, Doc("The original file name.")]
size: Annotated[int | None, Doc("The size of the file in bytes.")]
headers: Annotated[Headers, Doc("The headers of the request.")]
content_type: Annotated[
Optional[str], Doc("The content type of the request, from the headers.")
str | None, Doc("The content type of the request, from the headers.")
]
async def write(

View File

@ -1,13 +1,13 @@
import inspect
import sys
from collections.abc import Callable
from dataclasses import dataclass, field
from functools import cached_property, partial
from typing import Any, Callable, Optional, Union
from typing import Any, Literal
from fastapi._compat import ModelField
from fastapi.security.base import SecurityBase
from fastapi.types import DependencyCacheKey
from typing_extensions import Literal
if sys.version_info >= (3, 13): # pragma: no cover
from inspect import iscoroutinefunction
@ -15,7 +15,7 @@ else: # pragma: no cover
from asyncio import iscoroutinefunction
def _unwrapped_call(call: Optional[Callable[..., Any]]) -> Any:
def _unwrapped_call(call: Callable[..., Any] | None) -> Any:
if call is None:
return call # pragma: no cover
unwrapped = inspect.unwrap(_impartial(call))
@ -36,19 +36,19 @@ class Dependant:
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
websocket_param_name: Optional[str] = None
http_connection_param_name: Optional[str] = None
response_param_name: Optional[str] = None
background_tasks_param_name: Optional[str] = None
security_scopes_param_name: Optional[str] = None
own_oauth_scopes: Optional[list[str]] = None
parent_oauth_scopes: Optional[list[str]] = None
name: str | None = None
call: Callable[..., Any] | None = None
request_param_name: str | None = None
websocket_param_name: str | None = None
http_connection_param_name: str | None = None
response_param_name: str | None = None
background_tasks_param_name: str | None = None
security_scopes_param_name: str | None = None
own_oauth_scopes: list[str] | None = None
parent_oauth_scopes: list[str] | None = None
use_cache: bool = True
path: Optional[str] = None
scope: Union[Literal["function", "request"], None] = None
path: str | None = None
scope: Literal["function", "request"] | None = None
@cached_property
def oauth_scopes(self) -> list[str]:
@ -185,7 +185,7 @@ class Dependant:
return False
@cached_property
def computed_scope(self) -> Union[str, None]:
def computed_scope(self) -> str | None:
if self.scope:
return self.scope
if self.is_gen_callable or self.is_async_gen_callable:

View File

@ -1,6 +1,7 @@
import dataclasses
import datetime
from collections import defaultdict, deque
from collections.abc import Callable
from decimal import Decimal
from enum import Enum
from ipaddress import (
@ -14,7 +15,7 @@ from ipaddress import (
from pathlib import Path, PurePath
from re import Pattern
from types import GeneratorType
from typing import Annotated, Any, Callable, Optional, Union
from typing import Annotated, Any
from uuid import UUID
from annotated_doc import Doc
@ -33,13 +34,13 @@ from ._compat import (
# Taken from Pydantic v1 as is
def isoformat(o: Union[datetime.date, datetime.time]) -> str:
def isoformat(o: datetime.date | datetime.time) -> str:
return o.isoformat()
# Adapted from Pydantic v1
# TODO: pv2 should this return strings instead?
def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
def decimal_encoder(dec_value: Decimal) -> int | float:
"""
Encodes a Decimal as int if there's no exponent, otherwise float
@ -118,7 +119,7 @@ def jsonable_encoder(
),
],
include: Annotated[
Optional[IncEx],
IncEx | None,
Doc(
"""
Pydantic's `include` parameter, passed to Pydantic models to set the
@ -127,7 +128,7 @@ def jsonable_encoder(
),
] = None,
exclude: Annotated[
Optional[IncEx],
IncEx | None,
Doc(
"""
Pydantic's `exclude` parameter, passed to Pydantic models to set the
@ -177,7 +178,7 @@ def jsonable_encoder(
),
] = False,
custom_encoder: Annotated[
Optional[dict[Any, Callable[[Any], Any]]],
dict[Any, Callable[[Any], Any]] | None,
Doc(
"""
Pydantic's `custom_encoder` parameter, passed to Pydantic models to define

View File

@ -1,5 +1,5 @@
from collections.abc import Mapping, Sequence
from typing import Annotated, Any, Optional, TypedDict, Union
from typing import Annotated, Any, TypedDict
from annotated_doc import Doc
from pydantic import BaseModel, create_model
@ -68,7 +68,7 @@ class HTTPException(StarletteHTTPException):
),
] = None,
headers: Annotated[
Optional[Mapping[str, str]],
Mapping[str, str] | None,
Doc(
"""
Any headers to send to the client in the response.
@ -137,7 +137,7 @@ class WebSocketException(StarletteWebSocketException):
),
],
reason: Annotated[
Union[str, None],
str | None,
Doc(
"""
The reason to close the WebSocket connection.
@ -176,7 +176,7 @@ class ValidationException(Exception):
self,
errors: Sequence[Any],
*,
endpoint_ctx: Optional[EndpointContext] = None,
endpoint_ctx: EndpointContext | None = None,
) -> None:
self._errors = errors
self.endpoint_ctx = endpoint_ctx
@ -215,7 +215,7 @@ class RequestValidationError(ValidationException):
errors: Sequence[Any],
*,
body: Any = None,
endpoint_ctx: Optional[EndpointContext] = None,
endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
self.body = body
@ -226,7 +226,7 @@ class WebSocketRequestValidationError(ValidationException):
self,
errors: Sequence[Any],
*,
endpoint_ctx: Optional[EndpointContext] = None,
endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
@ -237,7 +237,7 @@ class ResponseValidationError(ValidationException):
errors: Sequence[Any],
*,
body: Any = None,
endpoint_ctx: Optional[EndpointContext] = None,
endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
self.body = body

View File

@ -1,5 +1,5 @@
import json
from typing import Annotated, Any, Optional
from typing import Annotated, Any
from annotated_doc import Doc
from fastapi.encoders import jsonable_encoder
@ -85,7 +85,7 @@ def get_swagger_ui_html(
),
] = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Annotated[
Optional[str],
str | None,
Doc(
"""
The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
@ -96,7 +96,7 @@ def get_swagger_ui_html(
),
] = None,
init_oauth: Annotated[
Optional[dict[str, Any]],
dict[str, Any] | None,
Doc(
"""
A dictionary with Swagger UI OAuth2 initialization configurations.
@ -107,7 +107,7 @@ def get_swagger_ui_html(
),
] = None,
swagger_ui_parameters: Annotated[
Optional[dict[str, Any]],
dict[str, Any] | None,
Doc(
"""
Configuration parameters for Swagger UI.

View File

@ -1,6 +1,6 @@
from collections.abc import Iterable, Mapping
from collections.abc import Callable, Iterable, Mapping
from enum import Enum
from typing import Annotated, Any, Callable, Optional, Union
from typing import Annotated, Any, Literal, Optional, Union
from fastapi._compat import with_info_plain_validator_function
from fastapi.logger import logger
@ -10,7 +10,7 @@ from pydantic import (
Field,
GetJsonSchemaHandler,
)
from typing_extensions import Literal, TypedDict
from typing_extensions import TypedDict
from typing_extensions import deprecated as typing_deprecated
try:
@ -59,37 +59,37 @@ class BaseModelWithConfig(BaseModel):
class Contact(BaseModelWithConfig):
name: Optional[str] = None
url: Optional[AnyUrl] = None
email: Optional[EmailStr] = None
name: str | None = None
url: AnyUrl | None = None
email: EmailStr | None = None
class License(BaseModelWithConfig):
name: str
identifier: Optional[str] = None
url: Optional[AnyUrl] = None
identifier: str | None = None
url: AnyUrl | None = None
class Info(BaseModelWithConfig):
title: str
summary: Optional[str] = None
description: Optional[str] = None
termsOfService: Optional[str] = None
contact: Optional[Contact] = None
license: Optional[License] = None
summary: str | None = None
description: str | None = None
termsOfService: str | None = None
contact: Contact | None = None
license: License | None = None
version: str
class ServerVariable(BaseModelWithConfig):
enum: Annotated[Optional[list[str]], Field(min_length=1)] = None
enum: Annotated[list[str] | None, Field(min_length=1)] = None
default: str
description: Optional[str] = None
description: str | None = None
class Server(BaseModelWithConfig):
url: Union[AnyUrl, str]
description: Optional[str] = None
variables: Optional[dict[str, ServerVariable]] = None
url: AnyUrl | str
description: str | None = None
variables: dict[str, ServerVariable] | None = None
class Reference(BaseModel):
@ -98,19 +98,19 @@ class Reference(BaseModel):
class Discriminator(BaseModel):
propertyName: str
mapping: Optional[dict[str, str]] = None
mapping: dict[str, str] | None = None
class XML(BaseModelWithConfig):
name: Optional[str] = None
namespace: Optional[str] = None
prefix: Optional[str] = None
attribute: Optional[bool] = None
wrapped: Optional[bool] = None
name: str | None = None
namespace: str | None = None
prefix: str | None = None
attribute: bool | None = None
wrapped: bool | None = None
class ExternalDocumentation(BaseModelWithConfig):
description: Optional[str] = None
description: str | None = None
url: AnyUrl
@ -123,80 +123,80 @@ SchemaType = Literal[
class Schema(BaseModelWithConfig):
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
# Core Vocabulary
schema_: Optional[str] = Field(default=None, alias="$schema")
vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
id: Optional[str] = Field(default=None, alias="$id")
anchor: Optional[str] = Field(default=None, alias="$anchor")
dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
ref: Optional[str] = Field(default=None, alias="$ref")
dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs")
comment: Optional[str] = Field(default=None, alias="$comment")
schema_: str | None = Field(default=None, alias="$schema")
vocabulary: str | None = Field(default=None, alias="$vocabulary")
id: str | None = Field(default=None, alias="$id")
anchor: str | None = Field(default=None, alias="$anchor")
dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor")
ref: str | None = Field(default=None, alias="$ref")
dynamicRef: str | None = Field(default=None, alias="$dynamicRef")
defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs")
comment: str | None = 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: list["SchemaOrBool"] | None = None
anyOf: list["SchemaOrBool"] | None = None
oneOf: list["SchemaOrBool"] | None = 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: dict[str, "SchemaOrBool"] | None = None
prefixItems: list["SchemaOrBool"] | None = None
items: Optional["SchemaOrBool"] = None
contains: Optional["SchemaOrBool"] = None
properties: Optional[dict[str, "SchemaOrBool"]] = None
patternProperties: Optional[dict[str, "SchemaOrBool"]] = None
properties: dict[str, "SchemaOrBool"] | None = None
patternProperties: dict[str, "SchemaOrBool"] | None = 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
const: Optional[Any] = None
multipleOf: Optional[float] = Field(default=None, gt=0)
maximum: Optional[float] = None
exclusiveMaximum: Optional[float] = None
minimum: Optional[float] = None
exclusiveMinimum: Optional[float] = None
maxLength: Optional[int] = Field(default=None, ge=0)
minLength: Optional[int] = Field(default=None, ge=0)
pattern: Optional[str] = None
maxItems: Optional[int] = Field(default=None, ge=0)
minItems: Optional[int] = Field(default=None, ge=0)
uniqueItems: Optional[bool] = None
maxContains: Optional[int] = Field(default=None, ge=0)
minContains: Optional[int] = Field(default=None, ge=0)
maxProperties: Optional[int] = Field(default=None, ge=0)
minProperties: Optional[int] = Field(default=None, ge=0)
required: Optional[list[str]] = None
dependentRequired: Optional[dict[str, set[str]]] = None
type: SchemaType | list[SchemaType] | None = None
enum: list[Any] | None = None
const: Any | None = None
multipleOf: float | None = Field(default=None, gt=0)
maximum: float | None = None
exclusiveMaximum: float | None = None
minimum: float | None = None
exclusiveMinimum: float | None = None
maxLength: int | None = Field(default=None, ge=0)
minLength: int | None = Field(default=None, ge=0)
pattern: str | None = None
maxItems: int | None = Field(default=None, ge=0)
minItems: int | None = Field(default=None, ge=0)
uniqueItems: bool | None = None
maxContains: int | None = Field(default=None, ge=0)
minContains: int | None = Field(default=None, ge=0)
maxProperties: int | None = Field(default=None, ge=0)
minProperties: int | None = Field(default=None, ge=0)
required: list[str] | None = None
dependentRequired: dict[str, set[str]] | None = 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
format: str | None = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
# A Vocabulary for the Contents of String-Encoded Data
contentEncoding: Optional[str] = None
contentMediaType: Optional[str] = None
contentEncoding: str | None = None
contentMediaType: str | None = None
contentSchema: Optional["SchemaOrBool"] = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
# A Vocabulary for Basic Meta-Data Annotations
title: Optional[str] = None
description: Optional[str] = None
default: Optional[Any] = None
deprecated: Optional[bool] = None
readOnly: Optional[bool] = None
writeOnly: Optional[bool] = None
examples: Optional[list[Any]] = None
title: str | None = None
description: str | None = None
default: Any | None = None
deprecated: bool | None = None
readOnly: bool | None = None
writeOnly: bool | None = None
examples: list[Any] | None = None
# Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
# Schema Object
discriminator: Optional[Discriminator] = None
xml: Optional[XML] = None
externalDocs: Optional[ExternalDocumentation] = None
discriminator: Discriminator | None = None
xml: XML | None = None
externalDocs: ExternalDocumentation | None = None
example: Annotated[
Optional[Any],
Any | None,
typing_deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
@ -206,14 +206,14 @@ class Schema(BaseModelWithConfig):
# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
# A JSON Schema MUST be an object or a boolean.
SchemaOrBool = Union[Schema, bool]
SchemaOrBool = Schema | bool
class Example(TypedDict, total=False):
summary: Optional[str]
description: Optional[str]
value: Optional[Any]
externalValue: Optional[AnyUrl]
summary: str | None
description: str | None
value: Any | None
externalValue: AnyUrl | None
__pydantic_config__ = {"extra": "allow"} # type: ignore[misc]
@ -226,33 +226,33 @@ class ParameterInType(Enum):
class Encoding(BaseModelWithConfig):
contentType: Optional[str] = None
headers: Optional[dict[str, Union["Header", Reference]]] = None
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
contentType: str | None = None
headers: dict[str, Union["Header", Reference]] | None = None
style: str | None = None
explode: bool | None = None
allowReserved: bool | None = None
class MediaType(BaseModelWithConfig):
schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
example: Optional[Any] = None
examples: Optional[dict[str, Union[Example, Reference]]] = None
encoding: Optional[dict[str, Encoding]] = None
schema_: Schema | Reference | None = Field(default=None, alias="schema")
example: Any | None = None
examples: dict[str, Example | Reference] | None = None
encoding: dict[str, Encoding] | None = None
class ParameterBase(BaseModelWithConfig):
description: Optional[str] = None
required: Optional[bool] = None
deprecated: Optional[bool] = None
description: str | None = None
required: bool | None = None
deprecated: bool | None = None
# Serialization rules for simple scenarios
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
example: Optional[Any] = None
examples: Optional[dict[str, Union[Example, Reference]]] = None
style: str | None = None
explode: bool | None = None
allowReserved: bool | None = None
schema_: Schema | Reference | None = Field(default=None, alias="schema")
example: Any | None = None
examples: dict[str, Example | Reference] | None = None
# Serialization rules for more complex scenarios
content: Optional[dict[str, MediaType]] = None
content: dict[str, MediaType] | None = None
class Parameter(ParameterBase):
@ -265,57 +265,57 @@ class Header(ParameterBase):
class RequestBody(BaseModelWithConfig):
description: Optional[str] = None
description: str | None = None
content: dict[str, MediaType]
required: Optional[bool] = None
required: bool | None = None
class Link(BaseModelWithConfig):
operationRef: Optional[str] = None
operationId: Optional[str] = None
parameters: Optional[dict[str, Union[Any, str]]] = None
requestBody: Optional[Union[Any, str]] = None
description: Optional[str] = None
server: Optional[Server] = None
operationRef: str | None = None
operationId: str | None = None
parameters: dict[str, Any | str] | None = None
requestBody: Any | str | None = None
description: str | None = None
server: Server | None = None
class Response(BaseModelWithConfig):
description: str
headers: Optional[dict[str, Union[Header, Reference]]] = None
content: Optional[dict[str, MediaType]] = None
links: Optional[dict[str, Union[Link, Reference]]] = None
headers: dict[str, Header | Reference] | None = None
content: dict[str, MediaType] | None = None
links: dict[str, Link | Reference] | None = None
class Operation(BaseModelWithConfig):
tags: Optional[list[str]] = None
summary: Optional[str] = None
description: Optional[str] = None
externalDocs: Optional[ExternalDocumentation] = None
operationId: Optional[str] = None
parameters: Optional[list[Union[Parameter, Reference]]] = None
requestBody: Optional[Union[RequestBody, Reference]] = None
tags: list[str] | None = None
summary: str | None = None
description: str | None = None
externalDocs: ExternalDocumentation | None = None
operationId: str | None = None
parameters: list[Parameter | Reference] | None = None
requestBody: RequestBody | Reference | None = None
# Using Any for Specification Extensions
responses: Optional[dict[str, Union[Response, Any]]] = None
callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None
deprecated: Optional[bool] = None
security: Optional[list[dict[str, list[str]]]] = None
servers: Optional[list[Server]] = None
responses: dict[str, Response | Any] | None = None
callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None
deprecated: bool | None = None
security: list[dict[str, list[str]]] | None = None
servers: list[Server] | None = None
class PathItem(BaseModelWithConfig):
ref: Optional[str] = Field(default=None, alias="$ref")
summary: Optional[str] = None
description: Optional[str] = None
get: Optional[Operation] = None
put: Optional[Operation] = None
post: Optional[Operation] = None
delete: Optional[Operation] = None
options: Optional[Operation] = None
head: Optional[Operation] = None
patch: Optional[Operation] = None
trace: Optional[Operation] = None
servers: Optional[list[Server]] = None
parameters: Optional[list[Union[Parameter, Reference]]] = None
ref: str | None = Field(default=None, alias="$ref")
summary: str | None = None
description: str | None = None
get: Operation | None = None
put: Operation | None = None
post: Operation | None = None
delete: Operation | None = None
options: Operation | None = None
head: Operation | None = None
patch: Operation | None = None
trace: Operation | None = None
servers: list[Server] | None = None
parameters: list[Parameter | Reference] | None = None
class SecuritySchemeType(Enum):
@ -327,7 +327,7 @@ class SecuritySchemeType(Enum):
class SecurityBase(BaseModelWithConfig):
type_: SecuritySchemeType = Field(alias="type")
description: Optional[str] = None
description: str | None = None
class APIKeyIn(Enum):
@ -349,11 +349,11 @@ class HTTPBase(SecurityBase):
class HTTPBearer(HTTPBase):
scheme: Literal["bearer"] = "bearer"
bearerFormat: Optional[str] = None
bearerFormat: str | None = None
class OAuthFlow(BaseModelWithConfig):
refreshUrl: Optional[str] = None
refreshUrl: str | None = None
scopes: dict[str, str] = {}
@ -375,10 +375,10 @@ class OAuthFlowAuthorizationCode(OAuthFlow):
class OAuthFlows(BaseModelWithConfig):
implicit: Optional[OAuthFlowImplicit] = None
password: Optional[OAuthFlowPassword] = None
clientCredentials: Optional[OAuthFlowClientCredentials] = None
authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
implicit: OAuthFlowImplicit | None = None
password: OAuthFlowPassword | None = None
clientCredentials: OAuthFlowClientCredentials | None = None
authorizationCode: OAuthFlowAuthorizationCode | None = None
class OAuth2(SecurityBase):
@ -393,41 +393,41 @@ class OpenIdConnect(SecurityBase):
openIdConnectUrl: str
SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
SecurityScheme = 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: dict[str, Schema | Reference] | None = None
responses: dict[str, Response | Reference] | None = None
parameters: dict[str, Parameter | Reference] | None = None
examples: dict[str, Example | Reference] | None = None
requestBodies: dict[str, RequestBody | Reference] | None = None
headers: dict[str, Header | Reference] | None = None
securitySchemes: dict[str, SecurityScheme | Reference] | None = None
links: dict[str, Link | Reference] | None = 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: dict[str, dict[str, PathItem] | Reference | Any] | None = None
pathItems: dict[str, PathItem | Reference] | None = None
class Tag(BaseModelWithConfig):
name: str
description: Optional[str] = None
externalDocs: Optional[ExternalDocumentation] = None
description: str | None = None
externalDocs: ExternalDocumentation | None = None
class OpenAPI(BaseModelWithConfig):
openapi: str
info: Info
jsonSchemaDialect: Optional[str] = None
servers: Optional[list[Server]] = None
jsonSchemaDialect: str | None = None
servers: list[Server] | None = None
# Using Any for Specification Extensions
paths: Optional[dict[str, Union[PathItem, Any]]] = None
webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None
components: Optional[Components] = None
security: Optional[list[dict[str, list[str]]]] = None
tags: Optional[list[Tag]] = None
externalDocs: Optional[ExternalDocumentation] = None
paths: dict[str, PathItem | Any] | None = None
webhooks: dict[str, PathItem | Reference] | None = None
components: Components | None = None
security: list[dict[str, list[str]]] | None = None
tags: list[Tag] | None = None
externalDocs: ExternalDocumentation | None = None
Schema.model_rebuild()

View File

@ -3,7 +3,7 @@ import http.client
import inspect
import warnings
from collections.abc import Sequence
from typing import Any, Optional, Union, cast
from typing import Any, Literal, cast
from fastapi import routing
from fastapi._compat import (
@ -38,7 +38,6 @@ from fastapi.utils import (
from pydantic import BaseModel
from starlette.responses import JSONResponse
from starlette.routing import BaseRoute
from typing_extensions import Literal
validation_error_definition = {
"title": "ValidationError",
@ -180,13 +179,13 @@ def _get_openapi_operation_parameters(
def get_openapi_operation_request_body(
*,
body_field: Optional[ModelField],
body_field: ModelField | None,
model_name_map: ModelNameMap,
field_mapping: dict[
tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any]
],
separate_input_output_schemas: bool = True,
) -> Optional[dict[str, Any]]:
) -> dict[str, Any] | None:
if not body_field:
return None
assert isinstance(body_field, ModelField)
@ -279,7 +278,7 @@ def get_openapi_path(
else:
current_response_class = route.response_class
assert current_response_class, "A response class is needed to generate OpenAPI"
route_response_media_type: Optional[str] = current_response_class.media_type
route_response_media_type: str | None = current_response_class.media_type
if route.include_in_schema:
for method in route.methods:
operation = get_openapi_operation_metadata(
@ -393,7 +392,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: dict[str, Any] | None = None
if field:
additional_field_schema = get_schema_from_model_field(
field=field,
@ -408,7 +407,7 @@ def get_openapi_path(
.setdefault("schema", {})
)
deep_dict_update(additional_schema, additional_field_schema)
status_text: Optional[str] = status_code_ranges.get(
status_text: str | None = status_code_ranges.get(
str(additional_status_code).upper()
) or http.client.responses.get(int(additional_status_code))
description = (
@ -482,17 +481,17 @@ def get_openapi(
title: str,
version: str,
openapi_version: str = "3.1.0",
summary: Optional[str] = None,
description: Optional[str] = None,
summary: str | None = None,
description: str | None = None,
routes: Sequence[BaseRoute],
webhooks: Optional[Sequence[BaseRoute]] = None,
tags: Optional[list[dict[str, Any]]] = None,
servers: Optional[list[dict[str, Union[str, Any]]]] = None,
terms_of_service: Optional[str] = None,
contact: Optional[dict[str, Union[str, Any]]] = None,
license_info: Optional[dict[str, Union[str, Any]]] = None,
webhooks: Sequence[BaseRoute] | None = None,
tags: list[dict[str, Any]] | None = None,
servers: list[dict[str, str | Any]] | None = None,
terms_of_service: str | None = None,
contact: dict[str, str | Any] | None = None,
license_info: dict[str, str | Any] | None = None,
separate_input_output_schemas: bool = True,
external_docs: Optional[dict[str, Any]] = None,
external_docs: dict[str, Any] | None = None,
) -> dict[str, Any]:
info: dict[str, Any] = {"title": title, "version": version}
if summary:

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
import warnings
from collections.abc import Sequence
from collections.abc import Callable, Sequence
from dataclasses import dataclass
from enum import Enum
from typing import Annotated, Any, Callable, Optional, Union
from typing import Annotated, Any, Literal
from fastapi.exceptions import FastAPIDeprecationWarning
from fastapi.openapi.models import Example
from pydantic import AliasChoices, AliasPath
from pydantic.fields import FieldInfo
from typing_extensions import Literal, deprecated
from typing_extensions import deprecated
from ._compat import (
Undefined,
@ -31,45 +31,45 @@ class Param(FieldInfo): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
if example is not _Unset:
@ -142,45 +142,45 @@ class Path(Param): # type: ignore[misc]
self,
default: Any = ...,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
assert default is ..., "Path parameters cannot have a default value"
@ -226,45 +226,45 @@ class Query(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@ -308,46 +308,46 @@ class Header(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
convert_underscores: bool = True,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
self.convert_underscores = convert_underscores
@ -392,45 +392,45 @@ class Cookie(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@ -472,47 +472,47 @@ class Body(FieldInfo): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
embed: Union[bool, None] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
embed: bool | None = None,
media_type: str = "application/json",
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
self.embed = embed
@ -584,46 +584,46 @@ class Form(Body): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
media_type: str = "application/x-www-form-urlencoded",
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@ -666,46 +666,46 @@ class File(Form): # type: ignore[misc]
self,
default: Any = Undefined,
*,
default_factory: Union[Callable[[], Any], None] = _Unset,
annotation: Optional[Any] = None,
default_factory: Callable[[], Any] | None = _Unset,
annotation: Any | None = None,
media_type: str = "multipart/form-data",
alias: Optional[str] = None,
alias_priority: Union[int, None] = _Unset,
validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
serialization_alias: Union[str, None] = None,
title: Optional[str] = None,
description: Optional[str] = None,
gt: Optional[float] = None,
ge: Optional[float] = None,
lt: Optional[float] = None,
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
pattern: Optional[str] = None,
alias: str | None = None,
alias_priority: int | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = None,
serialization_alias: str | None = None,
title: str | None = None,
description: str | None = None,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
min_length: int | None = None,
max_length: int | None = None,
pattern: str | None = None,
regex: Annotated[
Optional[str],
str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
discriminator: Union[str, None] = None,
strict: Union[bool, None] = _Unset,
multiple_of: Union[float, None] = _Unset,
allow_inf_nan: Union[bool, None] = _Unset,
max_digits: Union[int, None] = _Unset,
decimal_places: Union[int, None] = _Unset,
examples: Optional[list[Any]] = None,
discriminator: str | None = None,
strict: bool | None = _Unset,
multiple_of: float | None = _Unset,
allow_inf_nan: bool | None = _Unset,
max_digits: int | None = _Unset,
decimal_places: int | None = _Unset,
examples: list[Any] | None = None,
example: Annotated[
Optional[Any],
Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Optional[dict[str, Example]] = None,
deprecated: Union[deprecated, str, bool, None] = None,
openapi_examples: dict[str, Example] | None = None,
deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
json_schema_extra: Union[dict[str, Any], None] = None,
json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@ -745,11 +745,11 @@ class File(Form): # type: ignore[misc]
@dataclass(frozen=True)
class Depends:
dependency: Optional[Callable[..., Any]] = None
dependency: Callable[..., Any] | None = None
use_cache: bool = True
scope: Union[Literal["function", "request"], None] = None
scope: Literal["function", "request"] | None = None
@dataclass(frozen=True)
class Security(Depends):
scopes: Optional[Sequence[str]] = None
scopes: Sequence[str] | None = None

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
from typing import Annotated, Optional, Union
from typing import Annotated
from annotated_doc import Doc
from fastapi.openapi.models import APIKey, APIKeyIn
@ -13,8 +13,8 @@ class APIKeyBase(SecurityBase):
self,
location: APIKeyIn,
name: str,
description: Union[str, None],
scheme_name: Union[str, None],
description: str | None,
scheme_name: str | None,
auto_error: bool,
):
self.auto_error = auto_error
@ -42,7 +42,7 @@ class APIKeyBase(SecurityBase):
headers={"WWW-Authenticate": "APIKey"},
)
def check_api_key(self, api_key: Optional[str]) -> Optional[str]:
def check_api_key(self, api_key: str | None) -> str | None:
if not api_key:
if self.auto_error:
raise self.make_not_authenticated_error()
@ -90,7 +90,7 @@ class APIKeyQuery(APIKeyBase):
Doc("Query parameter name."),
],
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -100,7 +100,7 @@ class APIKeyQuery(APIKeyBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -137,7 +137,7 @@ class APIKeyQuery(APIKeyBase):
auto_error=auto_error,
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
api_key = request.query_params.get(self.model.name)
return self.check_api_key(api_key)
@ -179,7 +179,7 @@ class APIKeyHeader(APIKeyBase):
*,
name: Annotated[str, Doc("Header name.")],
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -189,7 +189,7 @@ class APIKeyHeader(APIKeyBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -225,7 +225,7 @@ class APIKeyHeader(APIKeyBase):
auto_error=auto_error,
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
api_key = request.headers.get(self.model.name)
return self.check_api_key(api_key)
@ -267,7 +267,7 @@ class APIKeyCookie(APIKeyBase):
*,
name: Annotated[str, Doc("Cookie name.")],
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -277,7 +277,7 @@ class APIKeyCookie(APIKeyBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -313,6 +313,6 @@ class APIKeyCookie(APIKeyBase):
auto_error=auto_error,
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
api_key = request.cookies.get(self.model.name)
return self.check_api_key(api_key)

View File

@ -1,6 +1,6 @@
import binascii
from base64 import b64decode
from typing import Annotated, Optional
from typing import Annotated
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
@ -71,8 +71,8 @@ class HTTPBase(SecurityBase):
self,
*,
scheme: str,
scheme_name: Optional[str] = None,
description: Optional[str] = None,
scheme_name: str | None = None,
description: str | None = None,
auto_error: bool = True,
):
self.model: HTTPBaseModel = HTTPBaseModel(
@ -91,9 +91,7 @@ class HTTPBase(SecurityBase):
headers=self.make_authenticate_headers(),
)
async def __call__(
self, request: Request
) -> Optional[HTTPAuthorizationCredentials]:
async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):
@ -143,7 +141,7 @@ class HTTPBasic(HTTPBase):
self,
*,
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -153,7 +151,7 @@ class HTTPBasic(HTTPBase):
),
] = None,
realm: Annotated[
Optional[str],
str | None,
Doc(
"""
HTTP Basic authentication realm.
@ -161,7 +159,7 @@ class HTTPBasic(HTTPBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -203,7 +201,7 @@ class HTTPBasic(HTTPBase):
async def __call__( # type: ignore
self, request: Request
) -> Optional[HTTPBasicCredentials]:
) -> HTTPBasicCredentials | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "basic":
@ -256,9 +254,9 @@ class HTTPBearer(HTTPBase):
def __init__(
self,
*,
bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None,
bearerFormat: Annotated[str | None, Doc("Bearer token format.")] = None,
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -268,7 +266,7 @@ class HTTPBearer(HTTPBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -302,9 +300,7 @@ class HTTPBearer(HTTPBase):
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
async def __call__(
self, request: Request
) -> Optional[HTTPAuthorizationCredentials]:
async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):
@ -362,7 +358,7 @@ class HTTPDigest(HTTPBase):
self,
*,
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -372,7 +368,7 @@ class HTTPDigest(HTTPBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -405,9 +401,7 @@ class HTTPDigest(HTTPBase):
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
async def __call__(
self, request: Request
) -> Optional[HTTPAuthorizationCredentials]:
async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):

View File

@ -1,4 +1,4 @@
from typing import Annotated, Any, Optional, Union, cast
from typing import Annotated, Any, cast
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
@ -60,7 +60,7 @@ class OAuth2PasswordRequestForm:
self,
*,
grant_type: Annotated[
Union[str, None],
str | None,
Form(pattern="^password$"),
Doc(
"""
@ -128,7 +128,7 @@ class OAuth2PasswordRequestForm:
),
] = "",
client_id: Annotated[
Union[str, None],
str | None,
Form(),
Doc(
"""
@ -139,7 +139,7 @@ class OAuth2PasswordRequestForm:
),
] = None,
client_secret: Annotated[
Union[str, None],
str | None,
Form(json_schema_extra={"format": "password"}),
Doc(
"""
@ -294,7 +294,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
),
] = "",
client_id: Annotated[
Union[str, None],
str | None,
Form(),
Doc(
"""
@ -305,7 +305,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
),
] = None,
client_secret: Annotated[
Union[str, None],
str | None,
Form(),
Doc(
"""
@ -344,7 +344,7 @@ class OAuth2(SecurityBase):
self,
*,
flows: Annotated[
Union[OAuthFlowsModel, dict[str, dict[str, Any]]],
OAuthFlowsModel | dict[str, dict[str, Any]],
Doc(
"""
The dictionary of OAuth2 flows.
@ -352,7 +352,7 @@ class OAuth2(SecurityBase):
),
] = OAuthFlowsModel(),
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -362,7 +362,7 @@ class OAuth2(SecurityBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -420,7 +420,7 @@ class OAuth2(SecurityBase):
headers={"WWW-Authenticate": "Bearer"},
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
if not authorization:
if self.auto_error:
@ -454,7 +454,7 @@ class OAuth2PasswordBearer(OAuth2):
),
],
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -464,7 +464,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = None,
scopes: Annotated[
Optional[dict[str, str]],
dict[str, str] | None,
Doc(
"""
The OAuth2 scopes that would be required by the *path operations* that
@ -476,7 +476,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -506,7 +506,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = True,
refreshUrl: Annotated[
Optional[str],
str | None,
Doc(
"""
The URL to refresh the token and obtain a new one.
@ -533,7 +533,7 @@ class OAuth2PasswordBearer(OAuth2):
auto_error=auto_error,
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
@ -562,7 +562,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
],
refreshUrl: Annotated[
Optional[str],
str | None,
Doc(
"""
The URL to refresh the token and obtain a new one.
@ -570,7 +570,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -580,7 +580,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
scopes: Annotated[
Optional[dict[str, str]],
dict[str, str] | None,
Doc(
"""
The OAuth2 scopes that would be required by the *path operations* that
@ -589,7 +589,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -639,7 +639,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
auto_error=auto_error,
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
@ -666,7 +666,7 @@ class SecurityScopes:
def __init__(
self,
scopes: Annotated[
Optional[list[str]],
list[str] | None,
Doc(
"""
This will be filled by FastAPI.

View File

@ -1,4 +1,4 @@
from typing import Annotated, Optional
from typing import Annotated
from annotated_doc import Doc
from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
@ -31,7 +31,7 @@ class OpenIdConnect(SecurityBase):
),
],
scheme_name: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme name.
@ -41,7 +41,7 @@ class OpenIdConnect(SecurityBase):
),
] = None,
description: Annotated[
Optional[str],
str | None,
Doc(
"""
Security scheme description.
@ -84,7 +84,7 @@ class OpenIdConnect(SecurityBase):
headers={"WWW-Authenticate": "Bearer"},
)
async def __call__(self, request: Request) -> Optional[str]:
async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
if not authorization:
if self.auto_error:

View File

@ -1,8 +1,5 @@
from typing import Optional
def get_authorization_scheme_param(
authorization_header_value: Optional[str],
authorization_header_value: str | None,
) -> tuple[str, str]:
if not authorization_header_value:
return "", ""

View File

@ -1,11 +1,12 @@
import types
from collections.abc import Callable
from enum import Enum
from typing import Any, Callable, Optional, TypeVar, Union
from typing import Any, TypeVar, Union
from pydantic import BaseModel
from pydantic.main import IncEx as IncEx
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
UnionType = getattr(types, "UnionType", Union)
ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str]
DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str]
ModelNameMap = dict[type[BaseModel] | type[Enum], str]
DependencyCacheKey = tuple[Callable[..., Any] | None, tuple[str, ...], str]

View File

@ -3,8 +3,7 @@ import warnings
from typing import (
TYPE_CHECKING,
Any,
Optional,
Union,
Literal,
)
import fastapi
@ -17,7 +16,6 @@ from fastapi._compat import (
from fastapi.datastructures import DefaultPlaceholder, DefaultType
from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError
from pydantic.fields import FieldInfo
from typing_extensions import Literal
from ._compat import v2
@ -25,7 +23,7 @@ if TYPE_CHECKING: # pragma: nocover
from .routing import APIRoute
def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
def is_body_allowed_for_status_code(status_code: int | str | None) -> bool:
if status_code is None:
return True
# Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1
@ -60,9 +58,9 @@ _invalid_args_message = (
def create_model_field(
name: str,
type_: Any,
default: Optional[Any] = Undefined,
field_info: Optional[FieldInfo] = None,
alias: Optional[str] = None,
default: Any | None = Undefined,
field_info: FieldInfo | None = None,
alias: str | None = None,
mode: Literal["validation", "serialization"] = "validation",
) -> ModelField:
if annotation_is_pydantic_v1(type_):
@ -121,9 +119,9 @@ def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) ->
def get_value_or_default(
first_item: Union[DefaultPlaceholder, DefaultType],
*extra_items: Union[DefaultPlaceholder, DefaultType],
) -> Union[DefaultPlaceholder, DefaultType]:
first_item: DefaultPlaceholder | DefaultType,
*extra_items: DefaultPlaceholder | DefaultType,
) -> DefaultPlaceholder | DefaultType:
"""
Pass items or `DefaultPlaceholder`s by descending priority.