7 changed files with 15 additions and 505 deletions
@ -1,50 +0,0 @@ |
|||
from typing import ( |
|||
Any, |
|||
Union, |
|||
) |
|||
|
|||
from fastapi.types import IncEx |
|||
from pydantic.fields import FieldInfo |
|||
from typing_extensions import Literal, Protocol |
|||
|
|||
|
|||
class ModelField(Protocol): |
|||
field_info: "FieldInfo" |
|||
name: str |
|||
mode: Literal["validation", "serialization"] = "validation" |
|||
_version: Literal["v1", "v2"] = "v1" |
|||
|
|||
@property |
|||
def alias(self) -> str: ... |
|||
|
|||
@property |
|||
def required(self) -> bool: ... |
|||
|
|||
@property |
|||
def default(self) -> Any: ... |
|||
|
|||
@property |
|||
def type_(self) -> Any: ... |
|||
|
|||
def get_default(self) -> Any: ... |
|||
|
|||
def validate( |
|||
self, |
|||
value: Any, |
|||
values: dict[str, Any] = {}, # noqa: B006 |
|||
*, |
|||
loc: tuple[Union[int, str], ...] = (), |
|||
) -> tuple[Any, Union[list[dict[str, Any]], None]]: ... |
|||
|
|||
def serialize( |
|||
self, |
|||
value: Any, |
|||
*, |
|||
mode: Literal["json", "python"] = "json", |
|||
include: Union[IncEx, None] = None, |
|||
exclude: Union[IncEx, None] = None, |
|||
by_alias: bool = True, |
|||
exclude_unset: bool = False, |
|||
exclude_defaults: bool = False, |
|||
exclude_none: bool = False, |
|||
) -> Any: ... |
|||
@ -1,222 +0,0 @@ |
|||
from collections.abc import Sequence |
|||
from copy import copy |
|||
from dataclasses import dataclass, is_dataclass |
|||
from enum import Enum |
|||
from typing import ( |
|||
Any, |
|||
Callable, |
|||
Union, |
|||
) |
|||
|
|||
from fastapi._compat import shared |
|||
from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX |
|||
from fastapi.types import ModelNameMap |
|||
from pydantic.v1 import BaseConfig as BaseConfig |
|||
from pydantic.v1 import BaseModel as BaseModel |
|||
from pydantic.v1 import ValidationError as ValidationError |
|||
from pydantic.v1 import create_model as create_model |
|||
from pydantic.v1.class_validators import Validator as Validator |
|||
from pydantic.v1.color import Color as Color |
|||
from pydantic.v1.error_wrappers import ErrorWrapper as ErrorWrapper |
|||
from pydantic.v1.fields import ( |
|||
SHAPE_FROZENSET, |
|||
SHAPE_LIST, |
|||
SHAPE_SEQUENCE, |
|||
SHAPE_SET, |
|||
SHAPE_SINGLETON, |
|||
SHAPE_TUPLE, |
|||
SHAPE_TUPLE_ELLIPSIS, |
|||
) |
|||
from pydantic.v1.fields import FieldInfo as FieldInfo |
|||
from pydantic.v1.fields import ModelField as ModelField |
|||
from pydantic.v1.fields import Undefined as Undefined |
|||
from pydantic.v1.fields import UndefinedType as UndefinedType |
|||
from pydantic.v1.networks import AnyUrl as AnyUrl |
|||
from pydantic.v1.networks import NameEmail as NameEmail |
|||
from pydantic.v1.schema import TypeModelSet as TypeModelSet |
|||
from pydantic.v1.schema import field_schema, model_process_schema |
|||
from pydantic.v1.schema import ( |
|||
get_annotation_from_field_info as get_annotation_from_field_info, |
|||
) |
|||
from pydantic.v1.schema import ( |
|||
get_flat_models_from_field as get_flat_models_from_field, |
|||
) |
|||
from pydantic.v1.schema import ( |
|||
get_flat_models_from_fields as get_flat_models_from_fields, |
|||
) |
|||
from pydantic.v1.schema import get_model_name_map as get_model_name_map |
|||
from pydantic.v1.types import SecretBytes as SecretBytes |
|||
from pydantic.v1.types import SecretStr as SecretStr |
|||
from pydantic.v1.typing import evaluate_forwardref as evaluate_forwardref |
|||
from pydantic.v1.utils import lenient_issubclass as lenient_issubclass |
|||
from pydantic.version import VERSION as PYDANTIC_VERSION |
|||
from typing_extensions import Literal |
|||
|
|||
PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2]) |
|||
PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2 |
|||
# Keeping old "Required" functionality from Pydantic V1, without |
|||
# shadowing typing.Required. |
|||
RequiredParam: Any = Ellipsis |
|||
|
|||
|
|||
GetJsonSchemaHandler = Any |
|||
JsonSchemaValue = dict[str, Any] |
|||
CoreSchema = Any |
|||
Url = AnyUrl |
|||
|
|||
sequence_shapes = { |
|||
SHAPE_LIST, |
|||
SHAPE_SET, |
|||
SHAPE_FROZENSET, |
|||
SHAPE_TUPLE, |
|||
SHAPE_SEQUENCE, |
|||
SHAPE_TUPLE_ELLIPSIS, |
|||
} |
|||
sequence_shape_to_type = { |
|||
SHAPE_LIST: list, |
|||
SHAPE_SET: set, |
|||
SHAPE_TUPLE: tuple, |
|||
SHAPE_SEQUENCE: list, |
|||
SHAPE_TUPLE_ELLIPSIS: list, |
|||
} |
|||
|
|||
|
|||
@dataclass |
|||
class GenerateJsonSchema: |
|||
ref_template: str |
|||
|
|||
|
|||
class PydanticSchemaGenerationError(Exception): |
|||
pass |
|||
|
|||
|
|||
RequestErrorModel: type[BaseModel] = create_model("Request") |
|||
|
|||
|
|||
def with_info_plain_validator_function( |
|||
function: Callable[..., Any], |
|||
*, |
|||
ref: Union[str, None] = None, |
|||
metadata: Any = None, |
|||
serialization: Any = None, |
|||
) -> Any: |
|||
return {} |
|||
|
|||
|
|||
def get_model_definitions( |
|||
*, |
|||
flat_models: set[Union[type[BaseModel], type[Enum]]], |
|||
model_name_map: dict[Union[type[BaseModel], type[Enum]], str], |
|||
) -> dict[str, Any]: |
|||
definitions: dict[str, dict[str, Any]] = {} |
|||
for model in flat_models: |
|||
m_schema, m_definitions, m_nested_models = model_process_schema( |
|||
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX |
|||
) |
|||
definitions.update(m_definitions) |
|||
model_name = model_name_map[model] |
|||
definitions[model_name] = m_schema |
|||
for m_schema in definitions.values(): |
|||
if "description" in m_schema: |
|||
m_schema["description"] = m_schema["description"].split("\f")[0] |
|||
return definitions |
|||
|
|||
|
|||
def is_pv1_scalar_field(field: ModelField) -> bool: |
|||
from fastapi import params |
|||
|
|||
field_info = field.field_info |
|||
if not ( |
|||
field.shape == SHAPE_SINGLETON |
|||
and not lenient_issubclass(field.type_, BaseModel) |
|||
and not lenient_issubclass(field.type_, dict) |
|||
and not shared.field_annotation_is_sequence(field.type_) |
|||
and not is_dataclass(field.type_) |
|||
and not isinstance(field_info, params.Body) |
|||
): |
|||
return False |
|||
if field.sub_fields: |
|||
if not all(is_pv1_scalar_field(f) for f in field.sub_fields): |
|||
return False |
|||
return True |
|||
|
|||
|
|||
def _model_dump( |
|||
model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any |
|||
) -> Any: |
|||
return model.dict(**kwargs) |
|||
|
|||
|
|||
def _get_model_config(model: BaseModel) -> Any: |
|||
return model.__config__ |
|||
|
|||
|
|||
def get_schema_from_model_field( |
|||
*, |
|||
field: ModelField, |
|||
model_name_map: ModelNameMap, |
|||
field_mapping: dict[ |
|||
tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue |
|||
], |
|||
separate_input_output_schemas: bool = True, |
|||
) -> dict[str, Any]: |
|||
return field_schema( |
|||
field, |
|||
model_name_map=model_name_map, # type: ignore[arg-type] |
|||
ref_prefix=REF_PREFIX, |
|||
)[0] |
|||
|
|||
|
|||
# def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: |
|||
# models = get_flat_models_from_fields(fields, known_models=set()) |
|||
# return get_model_name_map(models) # type: ignore[no-any-return] |
|||
|
|||
|
|||
def get_definitions( |
|||
*, |
|||
fields: list[ModelField], |
|||
model_name_map: ModelNameMap, |
|||
separate_input_output_schemas: bool = True, |
|||
) -> tuple[ |
|||
dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], |
|||
dict[str, dict[str, Any]], |
|||
]: |
|||
models = get_flat_models_from_fields(fields, known_models=set()) |
|||
return {}, get_model_definitions(flat_models=models, model_name_map=model_name_map) # type: ignore[arg-type] |
|||
|
|||
|
|||
def is_scalar_field(field: ModelField) -> bool: |
|||
return is_pv1_scalar_field(field) |
|||
|
|||
|
|||
def is_sequence_field(field: ModelField) -> bool: |
|||
return field.shape in sequence_shapes or shared._annotation_is_sequence(field.type_) |
|||
|
|||
|
|||
def is_bytes_field(field: ModelField) -> bool: |
|||
return lenient_issubclass(field.type_, bytes) |
|||
|
|||
|
|||
def is_bytes_sequence_field(field: ModelField) -> bool: |
|||
return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) |
|||
|
|||
|
|||
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: |
|||
return copy(field_info) |
|||
|
|||
|
|||
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: |
|||
return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return] |
|||
|
|||
|
|||
def create_body_model( |
|||
*, fields: Sequence[ModelField], model_name: str |
|||
) -> type[BaseModel]: |
|||
BodyModel = create_model(model_name) |
|||
for f in fields: |
|||
BodyModel.__fields__[f.name] = f |
|||
return BodyModel |
|||
|
|||
|
|||
def get_model_fields(model: type[BaseModel]) -> list[ModelField]: |
|||
return list(model.__fields__.values()) |
|||
Loading…
Reference in new issue