Browse Source

persuing 'on_error="omit"'

pull/9837/head
JONEMI21 8 months ago
parent
commit
d90b39a60a
  1. 2
      fastapi/_compat/main.py
  2. 27
      fastapi/_compat/shared.py
  3. 3
      fastapi/_compat/v1.py
  4. 7
      fastapi/_compat/v2.py
  5. 13
      fastapi/dependencies/utils.py

2
fastapi/_compat/main.py

@ -28,7 +28,6 @@ if PYDANTIC_V2:
from .v2 import Validator as Validator from .v2 import Validator as Validator
from .v2 import evaluate_forwardref as evaluate_forwardref from .v2 import evaluate_forwardref as evaluate_forwardref
from .v2 import get_missing_field_error as get_missing_field_error from .v2 import get_missing_field_error as get_missing_field_error
from .v2 import ignore_invalid as ignore_invalid
from .v2 import ( from .v2 import (
with_info_plain_validator_function as with_info_plain_validator_function, with_info_plain_validator_function as with_info_plain_validator_function,
) )
@ -45,7 +44,6 @@ else:
from .v1 import Validator as Validator from .v1 import Validator as Validator
from .v1 import evaluate_forwardref as evaluate_forwardref from .v1 import evaluate_forwardref as evaluate_forwardref
from .v1 import get_missing_field_error as get_missing_field_error from .v1 import get_missing_field_error as get_missing_field_error
from .v1 import ignore_invalid as ignore_invalid
from .v1 import ( # type: ignore[assignment] from .v1 import ( # type: ignore[assignment]
with_info_plain_validator_function as with_info_plain_validator_function, with_info_plain_validator_function as with_info_plain_validator_function,
) )

27
fastapi/_compat/shared.py

@ -252,30 +252,3 @@ def annotation_is_pydantic_v1(annotation: Any) -> bool:
if annotation_is_pydantic_v1(sub_annotation): if annotation_is_pydantic_v1(sub_annotation):
return True return True
return False return False
def remove_invalid(v: Any, handler: Callable[[Any], Any]) -> Any:
try:
return handler(v)
except ValidationError as exc:
if not isinstance(v, dict):
raise exc
# remove invalid values from invalid keys and revalidate
errors = may_v1._regenerate_error_with_loc(errors=[exc.errors()], loc_prefix=())
for err in errors:
loc = err.get("loc", ())
if len(loc) == 1:
v.pop(loc[0], None)
elif len(loc) == 2 and isinstance(v.get(loc[0]), list):
try:
v[loc[0]][loc[1]] = None
except (ValueError, IndexError):
pass
# remove the None values from lists
for key in list(v.keys()):
if isinstance(v[key], list):
v[key] = [item for item in v[key] if item is not None]
# remove empty lists
if v[key] == []:
v.pop(key)
return handler(v)

3
fastapi/_compat/v1.py

@ -349,6 +349,3 @@ def create_body_model(
def get_model_fields(model: Type[BaseModel]) -> List[ModelField]: def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
return list(model.__fields__.values()) # type: ignore[attr-defined] return list(model.__fields__.values()) # type: ignore[attr-defined]
def ignore_invalid(field_info: FieldInfo) -> FieldInfo:
return field_info

7
fastapi/_compat/v2.py

@ -488,10 +488,3 @@ def get_flat_models_from_fields(
def get_long_model_name(model: TypeModelOrEnum) -> str: def get_long_model_name(model: TypeModelOrEnum) -> str:
return f"{model.__module__}__{model.__qualname__}".replace(".", "__") return f"{model.__module__}__{model.__qualname__}".replace(".", "__")
def ignore_invalid(field_info: FieldInfo) -> FieldInfo:
new_field_info = copy(field_info)
new_field_info.metadata = getattr(field_info, "metadata", []) + [
WrapValidator(shared.remove_invalid)
]
return new_field_info

13
fastapi/dependencies/utils.py

@ -34,7 +34,6 @@ from fastapi._compat import (
get_annotation_from_field_info, get_annotation_from_field_info,
get_cached_model_fields, get_cached_model_fields,
get_missing_field_error, get_missing_field_error,
ignore_invalid,
is_bytes_field, is_bytes_field,
is_bytes_sequence_field, is_bytes_sequence_field,
is_scalar_field, is_scalar_field,
@ -64,7 +63,7 @@ from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.types import DependencyCacheKey from fastapi.types import DependencyCacheKey
from fastapi.utils import create_model_field, get_path_param_names from fastapi.utils import create_model_field, get_path_param_names
from pydantic import BaseModel from pydantic import BaseModel, TypeAdapter
from pydantic.fields import FieldInfo from pydantic.fields import FieldInfo
from starlette.background import BackgroundTasks as StarletteBackgroundTasks from starlette.background import BackgroundTasks as StarletteBackgroundTasks
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
@ -527,15 +526,7 @@ def analyze_param(
if is_scalar_sequence_field(field) or is_scalar_sequence_mapping_field( if is_scalar_sequence_field(field) or is_scalar_sequence_mapping_field(
field field
): ):
field = create_model_field( field._type_adapter.core_schema["on_error"] = "omit"
name=param_name,
type_=use_annotation_from_field_info,
default=field_info.default,
alias=alias,
required=field_info.default
in (RequiredParam, may_v1.RequiredParam, Undefined),
field_info=ignore_invalid(field_info),
)
return ParamDetails(type_annotation=type_annotation, depends=depends, field=field) return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)

Loading…
Cancel
Save