|
|
|
@ -189,16 +189,32 @@ def get_flat_dependant( |
|
|
|
return flat_dependant |
|
|
|
|
|
|
|
|
|
|
|
@dataclass |
|
|
|
class _FlatParamField: |
|
|
|
field: ModelField |
|
|
|
original_field: ModelField |
|
|
|
|
|
|
|
|
|
|
|
def _is_model_param(field: ModelField) -> bool: |
|
|
|
return lenient_issubclass(field.field_info.annotation, BaseModel) |
|
|
|
|
|
|
|
|
|
|
|
def _get_flat_param_fields(fields: Sequence[ModelField]) -> list[_FlatParamField]: |
|
|
|
flat_fields: list[_FlatParamField] = [] |
|
|
|
for field in fields: |
|
|
|
if _is_model_param(field): |
|
|
|
annotation = cast(type[BaseModel], field.field_info.annotation) |
|
|
|
flat_fields.extend( |
|
|
|
_FlatParamField(field=sub_field, original_field=field) |
|
|
|
for sub_field in get_cached_model_fields(annotation) |
|
|
|
) |
|
|
|
else: |
|
|
|
flat_fields.append(_FlatParamField(field=field, original_field=field)) |
|
|
|
return flat_fields |
|
|
|
|
|
|
|
|
|
|
|
def _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]: |
|
|
|
if not fields: |
|
|
|
return fields |
|
|
|
first_field = fields[0] |
|
|
|
if len(fields) == 1 and lenient_issubclass( |
|
|
|
first_field.field_info.annotation, BaseModel |
|
|
|
): |
|
|
|
fields_to_extract = get_cached_model_fields(first_field.field_info.annotation) |
|
|
|
return fields_to_extract |
|
|
|
return fields |
|
|
|
return [flat_field.field for flat_field in _get_flat_param_fields(fields)] |
|
|
|
|
|
|
|
|
|
|
|
def get_flat_params(dependant: Dependant) -> list[ModelField]: |
|
|
|
@ -791,32 +807,25 @@ def request_params_to_args( |
|
|
|
if not fields: |
|
|
|
return values, errors |
|
|
|
|
|
|
|
first_field = fields[0] |
|
|
|
fields_to_extract = fields |
|
|
|
single_not_embedded_field = False |
|
|
|
default_convert_underscores = True |
|
|
|
if len(fields) == 1 and lenient_issubclass( |
|
|
|
first_field.field_info.annotation, BaseModel |
|
|
|
): |
|
|
|
fields_to_extract = get_cached_model_fields(first_field.field_info.annotation) |
|
|
|
single_not_embedded_field = True |
|
|
|
# If headers are in a Pydantic model, the way to disable convert_underscores |
|
|
|
# would be with Header(convert_underscores=False) at the Pydantic model level |
|
|
|
default_convert_underscores = getattr( |
|
|
|
first_field.field_info, "convert_underscores", True |
|
|
|
) |
|
|
|
|
|
|
|
params_to_process: dict[str, Any] = {} |
|
|
|
|
|
|
|
flat_fields = _get_flat_param_fields(fields) |
|
|
|
model_fields = [field for field in fields if _is_model_param(field)] |
|
|
|
processed_extras: dict[str, Any] = {} |
|
|
|
params_by_field: dict[int, dict[str, Any]] = { |
|
|
|
id(field): {} for field in model_fields |
|
|
|
} |
|
|
|
processed_keys = set() |
|
|
|
|
|
|
|
for field in fields_to_extract: |
|
|
|
for flat_field in flat_fields: |
|
|
|
field = flat_field.field |
|
|
|
original_field = flat_field.original_field |
|
|
|
alias = None |
|
|
|
if isinstance(received_params, Headers): |
|
|
|
# Handle fields extracted from a Pydantic Model for a header, each field |
|
|
|
# doesn't have a FieldInfo of type Header with the default convert_underscores=True |
|
|
|
convert_underscores = getattr( |
|
|
|
field.field_info, "convert_underscores", default_convert_underscores |
|
|
|
field.field_info, |
|
|
|
"convert_underscores", |
|
|
|
getattr(original_field.field_info, "convert_underscores", True), |
|
|
|
) |
|
|
|
if convert_underscores: |
|
|
|
alias = get_validation_alias(field) |
|
|
|
@ -824,7 +833,8 @@ def request_params_to_args( |
|
|
|
alias = alias.replace("_", "-") |
|
|
|
value = _get_multidict_value(field, received_params, alias=alias) |
|
|
|
if value is not None: |
|
|
|
params_to_process[get_validation_alias(field)] = value |
|
|
|
if _is_model_param(original_field): |
|
|
|
params_by_field[id(original_field)][get_validation_alias(field)] = value |
|
|
|
processed_keys.add(alias or get_validation_alias(field)) |
|
|
|
|
|
|
|
for key in received_params.keys(): |
|
|
|
@ -832,30 +842,27 @@ def request_params_to_args( |
|
|
|
if isinstance(received_params, (ImmutableMultiDict, Headers)): |
|
|
|
value = received_params.getlist(key) |
|
|
|
if isinstance(value, list) and (len(value) == 1): |
|
|
|
params_to_process[key] = value[0] |
|
|
|
processed_extras[key] = value[0] |
|
|
|
else: |
|
|
|
params_to_process[key] = value |
|
|
|
processed_extras[key] = value |
|
|
|
else: |
|
|
|
params_to_process[key] = received_params.get(key) |
|
|
|
processed_extras[key] = received_params.get(key) |
|
|
|
|
|
|
|
if single_not_embedded_field: |
|
|
|
field_info = first_field.field_info |
|
|
|
assert isinstance(field_info, params.Param), ( |
|
|
|
"Params must be subclasses of Param" |
|
|
|
) |
|
|
|
loc: tuple[str, ...] = (field_info.in_.value,) |
|
|
|
v_, errors_ = _validate_value_with_model_field( |
|
|
|
field=first_field, value=params_to_process, values=values, loc=loc |
|
|
|
) |
|
|
|
return {first_field.name: v_}, errors_ |
|
|
|
if len(model_fields) == 1: |
|
|
|
params_by_field[id(model_fields[0])].update(processed_extras) |
|
|
|
|
|
|
|
for field in fields: |
|
|
|
value = _get_multidict_value(field, received_params) |
|
|
|
field_info = field.field_info |
|
|
|
assert isinstance(field_info, params.Param), ( |
|
|
|
"Params must be subclasses of Param" |
|
|
|
) |
|
|
|
loc = (field_info.in_.value, get_validation_alias(field)) |
|
|
|
loc: tuple[str, ...] |
|
|
|
if _is_model_param(field): |
|
|
|
loc = (field_info.in_.value,) |
|
|
|
value = params_by_field[id(field)] |
|
|
|
else: |
|
|
|
loc = (field_info.in_.value, get_validation_alias(field)) |
|
|
|
value = _get_multidict_value(field, received_params) |
|
|
|
v_, errors_ = _validate_value_with_model_field( |
|
|
|
field=field, value=value, values=values, loc=loc |
|
|
|
) |
|
|
|
|