diff --git a/fastapi/_compat/__init__.py b/fastapi/_compat/__init__.py index 4581c38c88..84076e164b 100644 --- a/fastapi/_compat/__init__.py +++ b/fastapi/_compat/__init__.py @@ -23,6 +23,7 @@ from .v2 import ModelField as ModelField from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError from .v2 import RequiredParam as RequiredParam from .v2 import Undefined as Undefined +from .v2 import UndefinedType as UndefinedType from .v2 import Url as Url from .v2 import copy_field_info as copy_field_info from .v2 import create_body_model as create_body_model diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index 79fba93188..b68ab9904c 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -30,7 +30,7 @@ from pydantic.fields import FieldInfo as FieldInfo from pydantic.json_schema import GenerateJsonSchema as _GenerateJsonSchema from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue from pydantic_core import CoreSchema as CoreSchema -from pydantic_core import PydanticUndefined +from pydantic_core import PydanticUndefined, PydanticUndefinedType from pydantic_core import Url as Url from pydantic_core.core_schema import ( with_info_plain_validator_function as with_info_plain_validator_function, @@ -38,6 +38,7 @@ from pydantic_core.core_schema import ( RequiredParam = PydanticUndefined Undefined = PydanticUndefined +UndefinedType = PydanticUndefinedType evaluate_forwardref = eval_type_lenient diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 7283ea179e..3e2098a684 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -734,30 +734,26 @@ async def solve_dependencies( ) -if PYDANTIC_V2: - if sys.hexversion >= 0x30A0000: - - def _allows_none(field: ModelField) -> bool: - origin = get_origin(field.type_) - return (origin is Union or origin is types.UnionType) and type( - None - ) in get_args(field.type_) - else: +if sys.hexversion >= 0x030A0000 and sys.hexversion < 0x030E0000: + + def _allows_none(field: ModelField) -> bool: + origin = get_origin(field.field_info.annotation) + return (origin is Union or origin is types.UnionType) and type( + None + ) in get_args(field.field_info.annotation) - def _allows_none(field: ModelField) -> bool: - origin = get_origin(field.type_) - return origin is Union and type(None) in get_args(field.type_) else: def _allows_none(field: ModelField) -> bool: - return field.allow_none # type: ignore + origin = get_origin(field.field_info.annotation) + return origin is Union and type(None) in get_args(field.field_info.annotation) def _validate_value_with_model_field( *, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] ) -> tuple[Any, list[Any]]: if value is Undefined: - if field.required: + if field.field_info.is_required(): return None, [get_missing_field_error(loc=loc)] else: return deepcopy(field.default), [] @@ -779,6 +775,7 @@ def _get_multidict_value( field: ModelField, values: Mapping[str, Any], alias: str | None = None ) -> Any: alias = alias or get_validation_alias(field) + value: Any if ( (not _is_json_field(field)) and field_annotation_is_sequence(field.field_info.annotation) @@ -848,7 +845,7 @@ def request_params_to_args( if alias == field.name: alias = alias.replace("_", "-") value = _get_multidict_value(field, received_params, alias=alias) - if value is not None: + if value is not Undefined and value is not None: params_to_process[get_validation_alias(field)] = value processed_keys.add(alias or get_validation_alias(field))