My requirement is to convert python dictionary which can take multiple forms into appropriate pydantic BaseModel class instance. Following are details:
class ConditionType(str, Enum):
EXPRESSION = 'EXPRESSION'
CYCLE_DUR_TREND = 'CYCLE_DUR_TREND'
class ConditionalExpressionProps(BaseConditionalProps):
conditional_expression: str
class CycleDurationTrendProps(BaseConditionalProps):
direction_up : bool = True
n : int = Field(1, ge=1, le=1000)
class ConditionalConfig(BaseModel):
cond_type: ConditionType = ConditionType.EXPRESSION
condition_prop: BaseConditionalProps
class SendNotificationChannel(BaseModel):
id: str
customer_id: str
conditional_config: Optional[ConditionalConfig]
I want to create a SendNotificationChannel instance with correct conditional_config
set such that condition_prop becomes ConditionalExpressionProps
or CycleDurationTrendProps
based on the structure of dict.
For example, if dict is:
{
"id" : "1",
"customer_id" : "abc",
"conditional_config" : {
"cond_type": "EXPRESSION",
"conditional_expression" : ".s_num>10"
}
}
then on doing something like SendNotificationChannel(**dict)
should make the conditional_config.condition_prop
of type ConditionalExpressionProps
, and similarly for CycleDurationTrendProps
.
However when I'm doing this, its taking BaseConditionalProps
.
>>> channel = {"conditional_config" : {"cond_type": "EXPRESSION", "condition_prop":{"conditional_expression":"ALPHA"}}}
>>> channel_obj = SendNotificationChannel(**channel)
>>> channel_obj
SendNotificationChannel(conditional_config=ConditionalConfig(cond_type=<ConditionType.EXPRESSION: 'EXPRESSION'>, condition_prop=BaseConditionalProps()))
>>> channel_obj.conditional_config.condition_prop
BaseConditionalProps()
>>>
I'd want to know how would someone solve this problem, or if I'm tackling this the incorrect way.
CodePudding user response:
If I understand your question correctly you can to use .parse_obj
method for your problem. Also you need to update the condition_prop
field type. The following code it is example:
from enum import Enum
from typing import Optional, Union
from pydantic import BaseModel, Field
class ConditionType(str, Enum):
EXPRESSION = 'EXPRESSION'
CYCLE_DUR_TREND = 'CYCLE_DUR_TREND'
class BaseConditionalProps(BaseModel):
pass
class ConditionalExpressionProps(BaseConditionalProps):
conditional_expression: str
class CycleDurationTrendProps(BaseConditionalProps):
direction_up : bool = True
n : int = Field(1, ge=1, le=1000)
class ConditionalConfig(BaseModel):
cond_type: ConditionType = ConditionType.EXPRESSION
condition_prop: Union[ConditionalExpressionProps, CycleDurationTrendProps]
class SendNotificationChannel(BaseModel):
id: str
customer_id: str
conditional_config: Optional[ConditionalConfig]
channel_1 = {
"id" : "1",
"customer_id" : "abc",
"conditional_config" : {
"cond_type": "EXPRESSION",
"condition_prop": {
"conditional_expression" : ".s_num>10"
}
}
}
channel_1_obj = SendNotificationChannel.parse_obj(channel_1)
print(channel_1_obj)
# id='1' customer_id='abc' conditional_config=ConditionalConfig(cond_type=<ConditionType.EXPRESSION: 'EXPRESSION'>, condition_prop=ConditionalExpressionProps(conditional_expression='.s_num>10'))
channel_2 = {
"id" : "2",
"customer_id" : "def",
"conditional_config" : {
"cond_type": "CYCLE_DUR_TREND",
"condition_prop": {
"n" : 10
}
}
}
channel_2_obj = SendNotificationChannel.parse_obj(channel_2)
print(channel_2_obj)
# id='2' customer_id='def' conditional_config=ConditionalConfig(cond_type=<ConditionType.CYCLE_DUR_TREND: 'CYCLE_DUR_TREND'>, condition_prop=CycleDurationTrendProps(direction_up=True, n=10))