Figured it out. I can use .param.add_parameter
.
Which means I’m able to do basic conversions between Param models and Pydantic Models via the functions param_to_pydantic_class
and pydantic_to_param_class
.
import datetime
from typing import Container, Dict, List, Optional, Type, Union
import param
import pydantic
import pytest
from pydantic import BaseConfig, BaseModel, create_model
try:
import numpy as np
DATE_TYPE = Union[datetime.datetime, datetime.date, np.datetime64]
except:
DATE_TYPE = Union[datetime.datetime, datetime.date]
PARAM_TO_PYTHON_TYPE: Dict[param.Parameter, Type] = {
param.String: str,
param.Integer: int,
param.Number: float,
param.Date: DATE_TYPE,
param.List: List,
}
PYTHON_TYPE_TO_PARAM = {value: key for key, value in PARAM_TO_PYTHON_TYPE.items()}
def _get_python_type_from_parameter(parameter: param.Parameter):
if isinstance(parameter, param.List) and parameter.item_type:
python_type: Type = List[parameter.item_type]
else:
python_type = PARAM_TO_PYTHON_TYPE[parameter.__class__]
if parameter.allow_None:
python_type = Union[python_type, None]
return python_type
def _get_parameter_type_from_python_type(type_: Type) -> Type[param.Parameter]:
return PYTHON_TYPE_TO_PARAM[type_]
def _get_parameter_type_from_pydantic_field(
field: pydantic.fields.ModelField,
) -> Type[param.Parameter]:
return _get_parameter_type_from_python_type(field.type_)
def param_to_pydantic_class(
parameterized: Type[param.Parameterized],
*,
config: Type = BaseConfig,
exclude: Container[str] = []
) -> Type[BaseModel]:
fields = {}
parameters = [
parameterized.param[key]
for key in parameterized.param
if not parameterized.param[key].name in exclude
]
for parameter in parameters:
python_type = _get_python_type_from_parameter(parameter)
fields[parameter.name] = (python_type, parameter.default)
pydantic_model = create_model(parameterized.__name__, __config__=config, **fields) # type: ignore
return pydantic_model
def pydantic_to_param_class(value) -> param.Parameterized:
new_class: param.Parameterized = type(value.__name__, (param.Parameterized,), {})
for name, field in value.__fields__.items():
parameter_type = _get_parameter_type_from_pydantic_field(field)
parameter = parameter_type(default=field.default, allow_None=field.allow_none)
new_class.param.add_parameter(name, parameter)
return new_class