|
|
@ -1,6 +1,7 @@ |
|
|
import dataclasses |
|
|
import dataclasses |
|
|
import inspect |
|
|
import inspect |
|
|
import sys |
|
|
import sys |
|
|
|
|
|
import types |
|
|
from collections.abc import ( |
|
|
from collections.abc import ( |
|
|
AsyncGenerator, |
|
|
AsyncGenerator, |
|
|
AsyncIterable, |
|
|
AsyncIterable, |
|
|
@ -31,6 +32,7 @@ from fastapi._compat import ( |
|
|
ModelField, |
|
|
ModelField, |
|
|
RequiredParam, |
|
|
RequiredParam, |
|
|
Undefined, |
|
|
Undefined, |
|
|
|
|
|
UndefinedType, |
|
|
copy_field_info, |
|
|
copy_field_info, |
|
|
create_body_model, |
|
|
create_body_model, |
|
|
evaluate_forwardref, |
|
|
evaluate_forwardref, |
|
|
@ -596,7 +598,7 @@ async def solve_dependencies( |
|
|
*, |
|
|
*, |
|
|
request: Request | WebSocket, |
|
|
request: Request | WebSocket, |
|
|
dependant: Dependant, |
|
|
dependant: Dependant, |
|
|
body: dict[str, Any] | FormData | None = None, |
|
|
body: dict[str, Any] | FormData | UndefinedType | None = None, |
|
|
background_tasks: StarletteBackgroundTasks | None = None, |
|
|
background_tasks: StarletteBackgroundTasks | None = None, |
|
|
response: Response | None = None, |
|
|
response: Response | None = None, |
|
|
dependency_overrides_provider: Any | None = None, |
|
|
dependency_overrides_provider: Any | None = None, |
|
|
@ -732,10 +734,24 @@ async def solve_dependencies( |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_ |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _validate_value_with_model_field( |
|
|
def _validate_value_with_model_field( |
|
|
*, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] |
|
|
*, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] |
|
|
) -> tuple[Any, list[Any]]: |
|
|
) -> tuple[Any, list[Any]]: |
|
|
|
|
|
if value is Undefined: |
|
|
|
|
|
if field.required: |
|
|
|
|
|
return None, [get_missing_field_error(loc=loc)] |
|
|
|
|
|
else: |
|
|
|
|
|
return deepcopy(field.default), [] |
|
|
if value is None: |
|
|
if value is None: |
|
|
|
|
|
if _allows_none(field): |
|
|
|
|
|
return value, [] |
|
|
if field.field_info.is_required(): |
|
|
if field.field_info.is_required(): |
|
|
return None, [get_missing_field_error(loc=loc)] |
|
|
return None, [get_missing_field_error(loc=loc)] |
|
|
else: |
|
|
else: |
|
|
@ -758,9 +774,9 @@ def _get_multidict_value( |
|
|
): |
|
|
): |
|
|
value = values.getlist(alias) |
|
|
value = values.getlist(alias) |
|
|
else: |
|
|
else: |
|
|
value = values.get(alias, None) |
|
|
value = values.get(alias, Undefined) |
|
|
if ( |
|
|
if ( |
|
|
value is None |
|
|
value is Undefined |
|
|
or ( |
|
|
or ( |
|
|
isinstance(field.field_info, params.Form) |
|
|
isinstance(field.field_info, params.Form) |
|
|
and isinstance(value, str) # For type checks |
|
|
and isinstance(value, str) # For type checks |
|
|
@ -772,7 +788,7 @@ def _get_multidict_value( |
|
|
) |
|
|
) |
|
|
): |
|
|
): |
|
|
if field.field_info.is_required(): |
|
|
if field.field_info.is_required(): |
|
|
return |
|
|
return Undefined |
|
|
else: |
|
|
else: |
|
|
return deepcopy(field.default) |
|
|
return deepcopy(field.default) |
|
|
return value |
|
|
return value |
|
|
@ -932,7 +948,7 @@ async def _extract_form_body( |
|
|
for sub_value in value: |
|
|
for sub_value in value: |
|
|
results.append(await sub_value.read()) |
|
|
results.append(await sub_value.read()) |
|
|
value = serialize_sequence_value(field=field, value=results) |
|
|
value = serialize_sequence_value(field=field, value=results) |
|
|
if value is not None: |
|
|
if value is not Undefined and value is not None: |
|
|
values[get_validation_alias(field)] = value |
|
|
values[get_validation_alias(field)] = value |
|
|
field_aliases = {get_validation_alias(field) for field in body_fields} |
|
|
field_aliases = {get_validation_alias(field) for field in body_fields} |
|
|
for key in received_body.keys(): |
|
|
for key in received_body.keys(): |
|
|
@ -947,7 +963,7 @@ async def _extract_form_body( |
|
|
|
|
|
|
|
|
async def request_body_to_args( |
|
|
async def request_body_to_args( |
|
|
body_fields: list[ModelField], |
|
|
body_fields: list[ModelField], |
|
|
received_body: dict[str, Any] | FormData | None, |
|
|
received_body: dict[str, Any] | FormData | UndefinedType | None, |
|
|
embed_body_fields: bool, |
|
|
embed_body_fields: bool, |
|
|
) -> tuple[dict[str, Any], list[dict[str, Any]]]: |
|
|
) -> tuple[dict[str, Any], list[dict[str, Any]]]: |
|
|
values: dict[str, Any] = {} |
|
|
values: dict[str, Any] = {} |
|
|
@ -977,10 +993,12 @@ async def request_body_to_args( |
|
|
return {first_field.name: v_}, errors_ |
|
|
return {first_field.name: v_}, errors_ |
|
|
for field in body_fields: |
|
|
for field in body_fields: |
|
|
loc = ("body", get_validation_alias(field)) |
|
|
loc = ("body", get_validation_alias(field)) |
|
|
value: Any | None = None |
|
|
value: Any | None = Undefined |
|
|
if body_to_process is not None: |
|
|
if body_to_process is not None and not isinstance( |
|
|
|
|
|
body_to_process, UndefinedType |
|
|
|
|
|
): |
|
|
try: |
|
|
try: |
|
|
value = body_to_process.get(get_validation_alias(field)) |
|
|
value = body_to_process.get(get_validation_alias(field), Undefined) |
|
|
# If the received body is a list, not a dict |
|
|
# If the received body is a list, not a dict |
|
|
except AttributeError: |
|
|
except AttributeError: |
|
|
errors.append(get_missing_field_error(loc)) |
|
|
errors.append(get_missing_field_error(loc)) |
|
|
|