Browse Source

🎨 Tweak types

pull/14168/head
Sebastián Ramírez 10 months ago
parent
commit
3d14dda1c4
  1. 20
      fastapi/_compat/_params_v1.py
  2. 42
      fastapi/_compat/main.py
  3. 12
      fastapi/_compat/shared.py
  4. 128
      fastapi/_compat/v1.py
  5. 4
      fastapi/dependencies/utils.py
  6. 6
      fastapi/encoders.py
  7. 12
      fastapi/utils.py

20
fastapi/_compat/_params_v1.py

@ -5,9 +5,7 @@ from typing import Any, Callable, Dict, List, Optional, Union
from fastapi.openapi.models import Example from fastapi.openapi.models import Example
from typing_extensions import Annotated, deprecated from typing_extensions import Annotated, deprecated
from .shared import ( from .shared import PYDANTIC_VERSION_MINOR_TUPLE
PYDANTIC_VERSION_MINOR_TUPLE,
)
from .v1 import FieldInfo, Undefined from .v1 import FieldInfo, Undefined
_Unset: Any = Undefined _Unset: Any = Undefined
@ -20,7 +18,7 @@ class ParamTypes(Enum):
cookie = "cookie" cookie = "cookie"
class Param(FieldInfo): class Param(FieldInfo): # type: ignore[misc]
in_: ParamTypes in_: ParamTypes
def __init__( def __init__(
@ -121,7 +119,7 @@ class Param(FieldInfo):
return f"{self.__class__.__name__}({self.default})" return f"{self.__class__.__name__}({self.default})"
class Path(Param): class Path(Param): # type: ignore[misc]
in_ = ParamTypes.path in_ = ParamTypes.path
def __init__( def __init__(
@ -207,7 +205,7 @@ class Path(Param):
) )
class Query(Param): class Query(Param): # type: ignore[misc]
in_ = ParamTypes.query in_ = ParamTypes.query
def __init__( def __init__(
@ -291,7 +289,7 @@ class Query(Param):
) )
class Header(Param): class Header(Param): # type: ignore[misc]
in_ = ParamTypes.header in_ = ParamTypes.header
def __init__( def __init__(
@ -377,7 +375,7 @@ class Header(Param):
) )
class Cookie(Param): class Cookie(Param): # type: ignore[misc]
in_ = ParamTypes.cookie in_ = ParamTypes.cookie
def __init__( def __init__(
@ -461,7 +459,7 @@ class Cookie(Param):
) )
class Body(FieldInfo): class Body(FieldInfo): # type: ignore[misc]
def __init__( def __init__(
self, self,
default: Any = Undefined, default: Any = Undefined,
@ -565,7 +563,7 @@ class Body(FieldInfo):
return f"{self.__class__.__name__}({self.default})" return f"{self.__class__.__name__}({self.default})"
class Form(Body): class Form(Body): # type: ignore[misc]
def __init__( def __init__(
self, self,
default: Any = Undefined, default: Any = Undefined,
@ -649,7 +647,7 @@ class Form(Body):
) )
class File(Form): class File(Form): # type: ignore[misc]
def __init__( def __init__(
self, self,
default: Any = Undefined, default: Any = Undefined,

42
fastapi/_compat/main.py

@ -48,8 +48,8 @@ else:
@lru_cache @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, v1.BaseModel): if lenient_issubclass(model, v1.BaseModel): # type: ignore[attr-defined]
return v1.get_model_fields(model) # type: ignore[return-value] return v1.get_model_fields(model)
else: else:
from . import v2 from . import v2
@ -67,7 +67,7 @@ def _is_undefined(value: object) -> bool:
def _get_model_config(model: BaseModel) -> Any: def _get_model_config(model: BaseModel) -> Any:
if isinstance(model, v1.BaseModel): if isinstance(model, v1.BaseModel): # type: ignore[attr-defined]
return v1._get_model_config(model) return v1._get_model_config(model)
elif PYDANTIC_V2: elif PYDANTIC_V2:
from . import v2 from . import v2
@ -78,7 +78,7 @@ def _get_model_config(model: BaseModel) -> Any:
def _model_dump( def _model_dump(
model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
) -> Any: ) -> Any:
if isinstance(model, v1.BaseModel): if isinstance(model, v1.BaseModel): # type: ignore[attr-defined]
return v1._model_dump(model, mode=mode, **kwargs) return v1._model_dump(model, mode=mode, **kwargs)
elif PYDANTIC_V2: elif PYDANTIC_V2:
from . import v2 from . import v2
@ -110,12 +110,12 @@ def create_body_model(
*, fields: Sequence[ModelField], model_name: str *, fields: Sequence[ModelField], model_name: str
) -> Type[BaseModel]: ) -> Type[BaseModel]:
if fields and isinstance(fields[0], v1.ModelField): if fields and isinstance(fields[0], v1.ModelField):
return v1.create_body_model(fields=fields, model_name=model_name) # type: ignore[return-value] return v1.create_body_model(fields=fields, model_name=model_name)
else: else:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.create_body_model(fields=fields, model_name=model_name) # type: ignore[return-value] return v2.create_body_model(fields=fields, model_name=model_name) # type: ignore[arg-type]
def get_annotation_from_field_info( def get_annotation_from_field_info(
@ -141,7 +141,7 @@ def is_bytes_field(field: ModelField) -> bool:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.is_bytes_field(field) # type: ignore[return-value] return v2.is_bytes_field(field) # type: ignore[arg-type]
def is_bytes_sequence_field(field: ModelField) -> bool: def is_bytes_sequence_field(field: ModelField) -> bool:
@ -151,7 +151,7 @@ def is_bytes_sequence_field(field: ModelField) -> bool:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.is_bytes_sequence_field(field) # type: ignore[return-value] return v2.is_bytes_sequence_field(field) # type: ignore[arg-type]
def is_scalar_field(field: ModelField) -> bool: def is_scalar_field(field: ModelField) -> bool:
@ -161,7 +161,7 @@ def is_scalar_field(field: ModelField) -> bool:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.is_scalar_field(field) # type: ignore[return-value] return v2.is_scalar_field(field) # type: ignore[arg-type]
def is_scalar_sequence_field(field: ModelField) -> bool: def is_scalar_sequence_field(field: ModelField) -> bool:
@ -171,7 +171,7 @@ def is_scalar_sequence_field(field: ModelField) -> bool:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.is_scalar_sequence_field(field) # type: ignore[return-value] return v2.is_scalar_sequence_field(field) # type: ignore[arg-type]
def is_sequence_field(field: ModelField) -> bool: def is_sequence_field(field: ModelField) -> bool:
@ -181,7 +181,7 @@ def is_sequence_field(field: ModelField) -> bool:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.is_sequence_field(field) # type: ignore[return-value] return v2.is_sequence_field(field) # type: ignore[arg-type]
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
@ -191,11 +191,11 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
assert PYDANTIC_V2 assert PYDANTIC_V2
from . import v2 from . import v2
return v2.serialize_sequence_value(field=field, value=value) # type: ignore[return-value] 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, v1.BaseModel): if lenient_issubclass(model, v1.BaseModel): # type: ignore[attr-defined]
v1._model_rebuild(model) v1._model_rebuild(model)
elif PYDANTIC_V2: elif PYDANTIC_V2:
from . import v2 from . import v2
@ -205,7 +205,7 @@ def _model_rebuild(model: Type[BaseModel]) -> None:
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, v1.ModelField)] v1_model_fields = [field for field in fields if isinstance(field, v1.ModelField)]
v1_flat_models = v1.get_flat_models_from_fields(v1_model_fields, known_models=set()) v1_flat_models = v1.get_flat_models_from_fields(v1_model_fields, known_models=set()) # type: ignore[attr-defined]
all_flat_models = v1_flat_models all_flat_models = v1_flat_models
if PYDANTIC_V2: if PYDANTIC_V2:
from . import v2 from . import v2
@ -218,10 +218,10 @@ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
) )
all_flat_models = all_flat_models.union(v2_flat_models) all_flat_models = all_flat_models.union(v2_flat_models)
model_name_map = v2.get_model_name_map(all_flat_models) # type: ignore[no-any-return] model_name_map = v2.get_model_name_map(all_flat_models)
return model_name_map return model_name_map
model_name_map = v1.get_model_name_map(all_flat_models) # type: ignore[no-any-return] model_name_map = v1.get_model_name_map(all_flat_models)
return model_name_map # type: ignore[return-value] return model_name_map
def get_definitions( def get_definitions(
@ -269,7 +269,7 @@ def get_schema_from_model_field(
return v1.get_schema_from_model_field( return v1.get_schema_from_model_field(
field=field, field=field,
model_name_map=model_name_map, model_name_map=model_name_map,
field_mapping=field_mapping, # type: ignore[arg-type] field_mapping=field_mapping,
separate_input_output_schemas=separate_input_output_schemas, separate_input_output_schemas=separate_input_output_schemas,
) )
else: else:
@ -277,7 +277,7 @@ def get_schema_from_model_field(
from . import v2 from . import v2
return v2.get_schema_from_model_field( return v2.get_schema_from_model_field(
field=field, field=field, # type: ignore[arg-type]
model_name_map=model_name_map, model_name_map=model_name_map,
field_mapping=field_mapping, # type: ignore[arg-type] field_mapping=field_mapping, # type: ignore[arg-type]
separate_input_output_schemas=separate_input_output_schemas, separate_input_output_schemas=separate_input_output_schemas,
@ -295,10 +295,10 @@ def _is_model_field(value: Any) -> bool:
def _is_model_class(value: Any) -> bool: def _is_model_class(value: Any) -> bool:
if lenient_issubclass(value, v1.BaseModel): if lenient_issubclass(value, v1.BaseModel): # type: ignore[attr-defined]
return True return True
elif PYDANTIC_V2: elif PYDANTIC_V2:
from . import v2 from . import v2
return lenient_issubclass(value, v2.BaseModel) return lenient_issubclass(value, v2.BaseModel) # type: ignore[attr-defined]
return False return False

12
fastapi/_compat/shared.py

@ -31,10 +31,10 @@ if sys.version_info < (3, 9):
# TODO: remove when dropping support for Python 3.8 # TODO: remove when dropping support for Python 3.8
WithArgsTypes: Tuple[Any, ...] = () WithArgsTypes: Tuple[Any, ...] = ()
elif sys.version_info < (3, 10): elif sys.version_info < (3, 10):
WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # pyright: ignore[reportAttributeAccessIssue] WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # type: ignore[attr-defined]
else: else:
WithArgsTypes: tuple[Any, ...] = ( WithArgsTypes: tuple[Any, ...] = (
typing._GenericAlias, typing._GenericAlias, # type: ignore[attr-defined]
types.GenericAlias, types.GenericAlias,
types.UnionType, types.UnionType,
) # pyright: ignore[reportAttributeAccessIssue] ) # pyright: ignore[reportAttributeAccessIssue]
@ -77,7 +77,7 @@ def lenient_issubclass(
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)): if lenient_issubclass(annotation, (str, bytes)):
return False return False
return lenient_issubclass(annotation, sequence_types) return lenient_issubclass(annotation, sequence_types) # type: ignore[arg-type]
def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool: def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
@ -98,7 +98,7 @@ def value_is_sequence(value: Any) -> bool:
def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool: def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
return ( return (
lenient_issubclass(annotation, (BaseModel, v1.BaseModel, Mapping, UploadFile)) lenient_issubclass(annotation, (BaseModel, v1.BaseModel, Mapping, UploadFile)) # type: ignore[attr-defined]
or _annotation_is_sequence(annotation) or _annotation_is_sequence(annotation)
or is_dataclass(annotation) or is_dataclass(annotation)
) )
@ -195,12 +195,12 @@ def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
def annotation_is_pydantic_v1(annotation: Any) -> bool: def annotation_is_pydantic_v1(annotation: Any) -> bool:
if lenient_issubclass(annotation, v1.BaseModel): if lenient_issubclass(annotation, v1.BaseModel): # type: ignore[attr-defined]
return True return True
origin = get_origin(annotation) origin = get_origin(annotation)
if origin is Union or origin is UnionType: if origin is Union or origin is UnionType:
for arg in get_args(annotation): for arg in get_args(annotation):
if lenient_issubclass(arg, v1.BaseModel): if lenient_issubclass(arg, v1.BaseModel): # type: ignore[attr-defined]
return True return True
if field_annotation_is_sequence(annotation): if field_annotation_is_sequence(annotation):
for sub_annotation in get_args(annotation): for sub_annotation in get_args(annotation):

128
fastapi/_compat/v1.py

@ -23,20 +23,20 @@ PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")
PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2 PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
# Keeping old "Required" functionality from Pydantic V1, without # Keeping old "Required" functionality from Pydantic V1, without
# shadowing typing.Required. # shadowing typing.Required.
RequiredParam: Any = Ellipsis # type: ignore[no-redef] RequiredParam: Any = Ellipsis
if not PYDANTIC_V2: if not PYDANTIC_V2:
from pydantic import AnyUrl as Url # noqa: F401 from pydantic import AnyUrl as Url # noqa: F401
from pydantic import ( # type: ignore[assignment] from pydantic import (
BaseConfig as BaseConfig, # noqa: F401 BaseConfig as BaseConfig, # noqa: F401
) )
from pydantic import BaseModel, create_model from pydantic import BaseModel, create_model
from pydantic import ValidationError as ValidationError # noqa: F401 from pydantic import ValidationError as ValidationError # noqa: F401
from pydantic.class_validators import ( # type: ignore[no-redef] from pydantic.class_validators import (
Validator as Validator, # noqa: F401 Validator as Validator, # noqa: F401
) )
from pydantic.color import Color as Color # noqa: F401 from pydantic.color import Color as Color # noqa: F401
from pydantic.error_wrappers import ( # type: ignore[no-redef] from pydantic.error_wrappers import (
ErrorWrapper as ErrorWrapper, # noqa: F401 ErrorWrapper as ErrorWrapper, # noqa: F401
) )
from pydantic.errors import MissingError from pydantic.errors import MissingError
@ -50,14 +50,10 @@ if not PYDANTIC_V2:
SHAPE_TUPLE_ELLIPSIS, SHAPE_TUPLE_ELLIPSIS,
) )
from pydantic.fields import FieldInfo as FieldInfo from pydantic.fields import FieldInfo as FieldInfo
from pydantic.fields import ( # type: ignore[no-redef,attr-defined] from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined]
ModelField as ModelField, # noqa: F401 from pydantic.fields import Undefined as Undefined # type: ignore[attr-defined]
) from pydantic.fields import (
from pydantic.fields import ( # type: ignore[no-redef,attr-defined] UndefinedType as UndefinedType, # type: ignore[attr-defined] # noqa: F401
Undefined as Undefined,
)
from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
UndefinedType as UndefinedType, # noqa: F401
) )
from pydantic.networks import AnyUrl as AnyUrl # noqa: F401 from pydantic.networks import AnyUrl as AnyUrl # noqa: F401
from pydantic.networks import NameEmail as NameEmail # noqa: F401 from pydantic.networks import NameEmail as NameEmail # noqa: F401
@ -67,37 +63,36 @@ if not PYDANTIC_V2:
get_flat_models_from_fields, get_flat_models_from_fields,
model_process_schema, model_process_schema,
) )
from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401 from pydantic.schema import (
get_annotation_from_field_info as get_annotation_from_field_info, get_annotation_from_field_info as get_annotation_from_field_info, # noqa: F401
) )
from pydantic.schema import get_flat_models_from_field as get_flat_models_from_field from pydantic.schema import get_flat_models_from_field as get_flat_models_from_field
from pydantic.schema import get_model_name_map as get_model_name_map # noqa: F401 from pydantic.schema import get_model_name_map as get_model_name_map # noqa: F401
from pydantic.types import SecretBytes as SecretBytes # noqa: F401 from pydantic.types import SecretBytes as SecretBytes # noqa: F401
from pydantic.types import SecretStr as SecretStr # noqa: F401 from pydantic.types import SecretStr as SecretStr # noqa: F401
from pydantic.typing import ( # type: ignore[no-redef] from pydantic.typing import evaluate_forwardref as evaluate_forwardref # noqa: F401
evaluate_forwardref as evaluate_forwardref, # noqa: F401 from pydantic.utils import lenient_issubclass as lenient_issubclass # noqa: F401
)
from pydantic.utils import ( # type: ignore[no-redef]
lenient_issubclass as lenient_issubclass, # noqa: F401
)
else: else:
from pydantic.v1 import AnyUrl as Url # noqa: F401 from pydantic.v1 import AnyUrl as Url # noqa: F401
from pydantic.v1 import ( # type: ignore[assignment] from pydantic.v1 import (
BaseConfig as BaseConfig, # noqa: F401 BaseConfig as BaseConfig, # type: ignore[assignment] # noqa: F401
) )
from pydantic.v1 import BaseModel, create_model from pydantic.v1 import (
from pydantic.v1 import ValidationError as ValidationError # noqa: F401 BaseModel as BaseModel, # type: ignore[assignment] # noqa: F401
from pydantic.v1.class_validators import ( # type: ignore[no-redef]
Validator as Validator, # noqa: F401
) )
from pydantic.v1.color import Color as Color # noqa: F401 from pydantic.v1 import (
from pydantic.v1.error_wrappers import ( # type: ignore[no-redef] ValidationError as ValidationError, # type: ignore[assignment] # noqa: F401
ErrorWrapper as ErrorWrapper, # noqa: F401
) )
from pydantic.v1 import create_model as create_model # noqa: F401
from pydantic.v1.class_validators import Validator as Validator # noqa: F401
from pydantic.v1.color import (
Color as Color, # type: ignore[assignment] # noqa: F401
)
from pydantic.v1.error_wrappers import ErrorWrapper as ErrorWrapper # noqa: F401
from pydantic.v1.errors import MissingError from pydantic.v1.errors import MissingError
from pydantic.v1.fields import ( # type: ignore[attr-defined] from pydantic.v1.fields import (
SHAPE_FROZENSET, SHAPE_FROZENSET,
SHAPE_LIST, SHAPE_LIST,
SHAPE_SEQUENCE, SHAPE_SEQUENCE,
@ -106,26 +101,22 @@ else:
SHAPE_TUPLE, SHAPE_TUPLE,
SHAPE_TUPLE_ELLIPSIS, SHAPE_TUPLE_ELLIPSIS,
) )
from pydantic.v1.fields import FieldInfo as FieldInfo from pydantic.v1.fields import FieldInfo as FieldInfo # type: ignore[assignment]
from pydantic.v1.fields import ( # type: ignore[no-redef,attr-defined] from pydantic.v1.fields import ModelField as ModelField # noqa: F401
ModelField as ModelField, # noqa: F401 from pydantic.v1.fields import Undefined as Undefined
) from pydantic.v1.fields import UndefinedType as UndefinedType # noqa: F401
from pydantic.v1.fields import ( # type: ignore[no-redef,attr-defined]
Undefined as Undefined,
)
from pydantic.v1.fields import ( # type: ignore[no-redef, attr-defined]
UndefinedType as UndefinedType, # noqa: F401
)
from pydantic.v1.networks import AnyUrl as AnyUrl # noqa: F401 from pydantic.v1.networks import AnyUrl as AnyUrl # noqa: F401
from pydantic.v1.networks import NameEmail as NameEmail # noqa: F401 from pydantic.v1.networks import (
NameEmail as NameEmail, # type: ignore[assignment] # noqa: F401
)
from pydantic.v1.schema import TypeModelSet as TypeModelSet from pydantic.v1.schema import TypeModelSet as TypeModelSet
from pydantic.v1.schema import ( from pydantic.v1.schema import (
field_schema, field_schema,
get_flat_models_from_fields, get_flat_models_from_fields,
model_process_schema, model_process_schema,
) )
from pydantic.v1.schema import ( # type: ignore[no-redef] # noqa: F401 from pydantic.v1.schema import (
get_annotation_from_field_info as get_annotation_from_field_info, get_annotation_from_field_info as get_annotation_from_field_info, # noqa: F401
) )
from pydantic.v1.schema import ( from pydantic.v1.schema import (
get_flat_models_from_field as get_flat_models_from_field, # noqa: F401 get_flat_models_from_field as get_flat_models_from_field, # noqa: F401
@ -133,19 +124,21 @@ else:
from pydantic.v1.schema import ( from pydantic.v1.schema import (
get_model_name_map as get_model_name_map, # noqa: F401 get_model_name_map as get_model_name_map, # noqa: F401
) )
from pydantic.v1.types import SecretBytes as SecretBytes # noqa: F401 from pydantic.v1.types import (
from pydantic.v1.types import SecretStr as SecretStr # noqa: F401 SecretBytes as SecretBytes, # type: ignore[assignment] # noqa: F401
from pydantic.v1.typing import ( # type: ignore[no-redef]
evaluate_forwardref as evaluate_forwardref, # noqa: F401
) )
from pydantic.v1.utils import ( # type: ignore[no-redef] from pydantic.v1.types import (
lenient_issubclass as lenient_issubclass, # noqa: F401 SecretStr as SecretStr, # type: ignore[assignment] # noqa: F401
)
from pydantic.v1.typing import (
evaluate_forwardref as evaluate_forwardref, # noqa: F401
) )
from pydantic.v1.utils import lenient_issubclass as lenient_issubclass # noqa: F401
GetJsonSchemaHandler = Any # type: ignore[assignment,misc] GetJsonSchemaHandler = Any
JsonSchemaValue = Dict[str, Any] # type: ignore[misc] JsonSchemaValue = Dict[str, Any]
CoreSchema = Any # type: ignore[assignment,misc] CoreSchema = Any
sequence_shapes = { sequence_shapes = {
@ -166,18 +159,18 @@ sequence_shape_to_type = {
@dataclass @dataclass
class GenerateJsonSchema: # type: ignore[no-redef] class GenerateJsonSchema:
ref_template: str ref_template: str
class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef] class PydanticSchemaGenerationError(Exception):
pass pass
RequestErrorModel: Type[BaseModel] = create_model("Request") RequestErrorModel: Type[BaseModel] = create_model("Request")
def with_info_plain_validator_function( # type: ignore[misc] def with_info_plain_validator_function(
function: Callable[..., Any], function: Callable[..., Any],
*, *,
ref: Union[str, None] = None, ref: Union[str, None] = None,
@ -211,7 +204,7 @@ def is_pv1_scalar_field(field: ModelField) -> bool:
field_info = field.field_info field_info = field.field_info
if not ( if not (
field.shape == SHAPE_SINGLETON # type: ignore[attr-defined] field.shape == SHAPE_SINGLETON
and not lenient_issubclass(field.type_, BaseModel) and not lenient_issubclass(field.type_, BaseModel)
and not lenient_issubclass(field.type_, dict) and not lenient_issubclass(field.type_, dict)
and not shared.field_annotation_is_sequence(field.type_) and not shared.field_annotation_is_sequence(field.type_)
@ -219,21 +212,18 @@ def is_pv1_scalar_field(field: ModelField) -> bool:
and not isinstance(field_info, params.Body) and not isinstance(field_info, params.Body)
): ):
return False return False
if field.sub_fields: # type: ignore[attr-defined] if field.sub_fields:
if not all( if not all(is_pv1_scalar_field(f) for f in field.sub_fields):
is_pv1_scalar_field(f)
for f in field.sub_fields # type: ignore[attr-defined]
):
return False return False
return True return True
def is_pv1_scalar_sequence_field(field: ModelField) -> bool: def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
if (field.shape in sequence_shapes) and not lenient_issubclass( # type: ignore[attr-defined] if (field.shape in sequence_shapes) and not lenient_issubclass(
field.type_, BaseModel field.type_, BaseModel
): ):
if field.sub_fields is not None: # type: ignore[attr-defined] if field.sub_fields is not None:
for sub_field in field.sub_fields: # type: ignore[attr-defined] for sub_field in field.sub_fields:
if not is_pv1_scalar_field(sub_field): if not is_pv1_scalar_field(sub_field):
return False return False
return True return True
@ -319,7 +309,7 @@ def is_scalar_field(field: ModelField) -> bool:
def is_sequence_field(field: ModelField) -> bool: def is_sequence_field(field: ModelField) -> bool:
return field.shape in sequence_shapes or shared._annotation_is_sequence(field.type_) # type: ignore[attr-defined] return field.shape in sequence_shapes or shared._annotation_is_sequence(field.type_)
def is_scalar_sequence_field(field: ModelField) -> bool: def is_scalar_sequence_field(field: ModelField) -> bool:
@ -327,11 +317,11 @@ def is_scalar_sequence_field(field: ModelField) -> bool:
def is_bytes_field(field: ModelField) -> bool: def is_bytes_field(field: ModelField) -> bool:
return lenient_issubclass(field.type_, bytes) return lenient_issubclass(field.type_, bytes) # type: ignore[no-any-return]
def is_bytes_sequence_field(field: ModelField) -> bool: def is_bytes_sequence_field(field: ModelField) -> bool:
return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) # type: ignore[attr-defined] return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes)
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
@ -339,11 +329,11 @@ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return,attr-defined] 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) # type: ignore[call-arg] missing_field_error = ErrorWrapper(MissingError(), loc=loc)
new_error = ValidationError([missing_field_error], RequestErrorModel) new_error = ValidationError([missing_field_error], RequestErrorModel)
return new_error.errors()[0] # type: ignore[return-value] return new_error.errors()[0] # type: ignore[return-value]

4
fastapi/dependencies/utils.py

@ -733,7 +733,7 @@ def _validate_value_with_model_field(
else: else:
return deepcopy(field.default), [] return deepcopy(field.default), []
v_, errors_ = field.validate(value, values, loc=loc) v_, errors_ = field.validate(value, values, loc=loc)
if _is_error_wrapper(errors_): if _is_error_wrapper(errors_): # type: ignore[arg-type]
return None, [errors_] return None, [errors_]
elif isinstance(errors_, list): elif isinstance(errors_, list):
new_errors = v1._regenerate_error_with_loc(errors=errors_, loc_prefix=()) new_errors = v1._regenerate_error_with_loc(errors=errors_, loc_prefix=())
@ -1015,7 +1015,7 @@ def get_body_field(
BodyFieldInfo = params.Form BodyFieldInfo = params.Form
else: else:
if annotation_is_pydantic_v1(BodyModel): if annotation_is_pydantic_v1(BodyModel):
BodyFieldInfo = _params_v1.Body BodyFieldInfo = _params_v1.Body # type: ignore[assignment]
else: else:
BodyFieldInfo = params.Body BodyFieldInfo = params.Body

6
fastapi/encoders.py

@ -86,7 +86,7 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
set: list, set: list,
UUID: str, UUID: str,
Url: str, Url: str,
v1.Url: str, v1.Url: str, # type: ignore[attr-defined]
AnyUrl: str, AnyUrl: str,
v1.AnyUrl: str, v1.AnyUrl: str,
} }
@ -220,10 +220,10 @@ def jsonable_encoder(
include = set(include) include = set(include)
if exclude is not None and not isinstance(exclude, (set, dict)): if exclude is not None and not isinstance(exclude, (set, dict)):
exclude = set(exclude) exclude = set(exclude)
if isinstance(obj, (BaseModel, v1.BaseModel)): if isinstance(obj, (BaseModel, v1.BaseModel)): # type: ignore[attr-defined]
# TODO: remove when deprecating Pydantic v1 # TODO: remove when deprecating Pydantic v1
encoders: Dict[Any, Any] = {} encoders: Dict[Any, Any] = {}
if isinstance(obj, v1.BaseModel): if isinstance(obj, v1.BaseModel): # type: ignore[attr-defined]
encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined] encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
if custom_encoder: if custom_encoder:
encoders = {**encoders, **custom_encoder} encoders = {**encoders, **custom_encoder}

12
fastapi/utils.py

@ -102,7 +102,7 @@ def create_model_field(
if annotation_is_pydantic_v1(type_) or version == "1": if annotation_is_pydantic_v1(type_) or version == "1":
try: try:
return v1.ModelField(**v1_kwargs) # type: ignore[arg-type] return v1.ModelField(**v1_kwargs) # type: ignore[no-any-return]
except RuntimeError: except RuntimeError:
raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None
elif PYDANTIC_V2: elif PYDANTIC_V2:
@ -113,13 +113,13 @@ def create_model_field(
) )
kwargs = {"mode": mode, "name": name, "field_info": field_info} kwargs = {"mode": mode, "name": name, "field_info": field_info}
try: try:
return v2.ModelField(**kwargs) # type: ignore[arg-type] return v2.ModelField(**kwargs) # type: ignore[return-value,arg-type]
except PydanticSchemaGenerationError: except PydanticSchemaGenerationError:
raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None
# Pydantic v2 is not installed, but it's not a Pydantic v1 ModelField, it could be # Pydantic v2 is not installed, but it's not a Pydantic v1 ModelField, it could be
# a Pydantic v1 type, like a constrained int # a Pydantic v1 type, like a constrained int
try: try:
return v1.ModelField(**v1_kwargs) # type: ignore[arg-type] return v1.ModelField(**v1_kwargs) # type: ignore[no-any-return]
except RuntimeError: except RuntimeError:
raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None
@ -132,7 +132,7 @@ def create_cloned_field(
if PYDANTIC_V2: if PYDANTIC_V2:
from ._compat import v2 from ._compat import v2
if isinstance(field, v2.ModelField): # type: ignore[name-defined] if isinstance(field, v2.ModelField):
return field return field
# cloned_types caches already cloned types to support recursive models and improve # cloned_types caches already cloned types to support recursive models and improve
# performance by avoiding unnecessary cloning # performance by avoiding unnecessary cloning
@ -144,10 +144,10 @@ def create_cloned_field(
original_type = original_type.__pydantic_model__ original_type = original_type.__pydantic_model__
use_type = original_type use_type = original_type
if lenient_issubclass(original_type, v1.BaseModel): if lenient_issubclass(original_type, v1.BaseModel):
original_type = cast(Type[v1.BaseModel], original_type) original_type = cast(Type[v1.BaseModel], original_type) # type: ignore[name-defined]
use_type = cloned_types.get(original_type) use_type = cloned_types.get(original_type)
if use_type is None: if use_type is None:
use_type = v1.create_model(original_type.__name__, __base__=original_type) use_type = v1.create_model(original_type.__name__, __base__=original_type) # type: ignore[attr-defined]
cloned_types[original_type] = use_type cloned_types[original_type] = use_type
for f in original_type.__fields__.values(): for f in original_type.__fields__.values():
use_type.__fields__[f.name] = create_cloned_field( use_type.__fields__[f.name] = create_cloned_field(

Loading…
Cancel
Save