Source code for paidiverpy.frontend.parse

"""Parse Pydantic models to a dictionary format for frontend use."""

from pathlib import Path
from typing import get_args
from typing import get_origin
import pydantic.fields
from pydantic_core import PydanticUndefinedType

OPTIONAL = 2


[docs] def define_default_value(field: pydantic.fields.FieldInfo) -> any: """Define the default value for a Pydantic field. Args: field (pydantic.fields.FieldInfo): The Pydantic field to parse. Returns: any: The default value of the field, or None if no default is set. """ if field.default_factory is not None: return field.default_factory() if callable(field.default_factory) else field.default_factory if type(field.default) is PydanticUndefinedType: return None return field.default if field.default is not None else None
[docs] def parse_default_params(model: pydantic.BaseModel, steps: bool = False) -> dict: """Parse the default parameters from a Pydantic model. Args: model (pydantic.BaseModel): The Pydantic model to parse. steps (bool): If True, the parameters will be parsed for steps. Returns: dict: A dictionary containing the parsed parameters. """ params = parse_fields_from_pydantic_model(model) if "name" in params and not steps: del params["name"] if "step_name" in params: del params["step_name"] if "test" in params and not steps: del params["test"] if "input_path" in params and not steps: input_path = {} input_path["type"] = "str" input_path["default"] = "" input_path["description"] = params["input_path"]["description"] params["input_path"] = input_path if "metadata_path" in params and not steps: metadata_path = {} metadata_path["type"] = "str" metadata_path["default"] = "" metadata_path["description"] = params["metadata_path"]["description"] params["metadata_path"] = metadata_path if "metadata_type" in params and not steps: metadata_type = {} metadata_type["type"] = "literal" metadata_type["default"] = None metadata_type["options"] = params["metadata_type"]["field_options"]["literal"] metadata_type["description"] = params["metadata_type"]["description"] params["metadata_type"] = metadata_type return params
[docs] def parse_get_origin_field(field: pydantic.fields.FieldInfo, origin_field: type) -> dict: """Parse the origin field of a Pydantic field. Args: field (pydantic.fields.FieldInfo): The Pydantic field to parse. origin_field (type): The origin type of the field. Returns: dict: A dictionary containing the parsed field information. """ output = {} output["default"] = define_default_value(field) output["description"] = field.description if field.description else "" if origin_field.__name__ in ["Literal", "LiteralType", "literal"]: output["type"] = "literal" output["options"] = list(get_args(field.annotation)) elif origin_field.__name__ in ["UnionType", "Union"]: output = parse_union_field(field, output) elif origin_field.__name__ == "list": output["type"] = "list" output["item_type"] = get_args(field.annotation)[0] if get_args(field.annotation) else "str" output["item_default"] = define_default_value(field) else: output["type"] = origin_field.__name__ if origin_field else "Any" if hasattr(origin_field, "__name__"): output["type"] = origin_field.__name__ elif hasattr(origin_field, "__origin__"): output["type"] = origin_field.__origin__.__name__ return output
[docs] def parse_union_field(field: pydantic.fields.FieldInfo, output: dict) -> dict: """Parse a Pydantic field that is a union type. Args: field (pydantic.fields.FieldInfo): The Pydantic field to parse. output (dict): The output dictionary to populate with parsed information. Returns: dict: The updated output dictionary with union field information. """ arguments = get_args(field.annotation) if len(arguments) == OPTIONAL and Path in arguments: output["type"] = "str" output["default"] = output["default"] if output["default"] is not None else "" else: output["type"] = "union" output["field_options"] = {} for argument in get_args(field.annotation): if argument is Path: continue if argument is None: output["field_options"]["None"] = "null" elif argument.__name__ in ["Literal", "LiteralType", "literal"]: output["field_options"]["literal"] = list(get_args(argument)) elif argument.__name__ == "list": output["field_options"]["list"] = get_args(argument)[0] elif hasattr(argument, "model_json_schema"): output["field_options"][argument.__name__] = argument.model_json_schema()["description"] else: output["field_options"][argument.__name__] = argument.__name__ return output
[docs] def parse_fields_from_pydantic_model(model: pydantic.BaseModel) -> dict: """Parse fields from a Pydantic model into a dictionary format. Args: model (pydantic.BaseModel): The Pydantic model to parse. Returns: dict: A dictionary containing the parsed fields with their default values and types. """ output = {} for name, field in model.model_fields.items(): default_value = define_default_value(field) output[name] = {"default": default_value, "description": field.description} origin_field = get_origin(field.annotation) if not origin_field: field_type = field.annotation.__name__ if field.annotation else "Any" output[name]["type"] = field_type continue output[name] = parse_get_origin_field(field, origin_field) return output