I am trying to create a dynamic model using Python's pydantic library. My input data is a regular dict. However, the content of the dict (read: its keys) may vary.
I am wondering how to dynamically create a pydantic model which is dependent on the dict's content?
I created a toy example with two different dicts (inputs1 and inputs2). Let's assume the nested dict called strategy may be different. Based on strategy/name I know in advance which fields will exist in strategy. I need to create the pydantic model based on strategy/name.
from pydantic import BaseModel
inputs1 = {
"universe": {"name": "test_universe", "ccy": "USD"},
"price_src": "csv",
"strategy": {"name": "test_strat1"},
}
inputs2 = {
"universe": {"name": "test_universe", "ccy": "USD"},
"price_src": "csv",
"strategy": {"name": "test_strat2", "periods": 10},
}
class Universe(BaseModel):
name: str
ccy: str = "EUR"
strategy_name = "test_strat2"
if strategy_name == "test_strat1":
inputs = inputs1
class Strategy(BaseModel):
name: str
elif strategy_name == "test_strat2":
inputs = inputs2
class Strategy(BaseModel):
name: str
periods: int
class StaticModel(BaseModel):
universe: Universe
price_src: str = "csv"
strategy: Strategy
static_model = StaticModel(**inputs)
My expected output if ``strategy_name == "test_strat1":
universe=Universe(name='test_universe', ccy='USD') price_src='csv' strategy=Strategy(name='test_strat1')
My expected output if ``strategy_name == "test_strat2":
universe=Universe(name='test_universe', ccy='USD') price_src='csv' strategy=Strategy(name='test_strat2', periods=10)
I was thinking about using pydantic's create_model function. However, I don't understand how to dynamically define the fields.
For the dynamic creation of pydantic models, you can use create_model. Like so:
from pydantic import create_model
d = {"strategy": {"name": "test_strat2", "periods": 10}}
Strategy = create_model("Strategy", **d["strategy"])
print(Strategy.schema_json(indent=2))
Output:
{
"title": "Strategy",
"type": "object",
"properties": {
"name": {
"title": "Name",
"default": "test_strat2",
"type": "string"
},
"periods": {
"title": "Periods",
"default": 10,
"type": "integer"
}
}
}
You can use create_model with key=(type, ...) (3 dots) to declare a field without default value. For example:
from pydantic import BaseModel, create_model
...
if strategy_name == "test_strat1":
inputs = inputs1
Strategy = create_model('Strategy', name=(str, ...))
elif strategy_name == "test_strat2":
inputs = inputs2
Strategy = create_model('Strategy', name=(str, ...), periods=(int, ...))
print(Strategy.schema_json(indent=2))
Output for test_strat1:
{
...
"properties": {
"name": {
"title": "Name",
"type": "string"
}
},
"required": [
"name"
]
}
And for test_strat2:
{
...
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"periods": {
"title": "Periods",
"type": "integer"
}
},
"required": [
"name",
"periods"
]
}
Related Pydantic documentation: https://pydantic-docs.helpmanual.io/usage/models/#dynamic-model-creation
You can see in the docs that:
foo=(str, ...) - str-typed foo attribute with no defaultsbar=123 - int-typed bar attribute with a default value of 123.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With