Anton Ovsyannikov
Anton Ovsyannikov

Reputation: 1190

Pydantic: how to decompose Dict into key and value in the Model?

I have an input structure like this

d = {
    "==": [
        "%var%",
        "10"
    ]
}

I'd like to decompose it to the Model like this:

class Model:
  op_name: str # ==
  lvalue: str # %var%
  rvalue: str # 10

Is it possible with Pydantic?

The best I reach so far is

class Model(BaseModel):
    class Expr(NamedTuple):
        lvalue: str
        rvalue: str

    __root__: Dict[str, Expr]

It can be created from the dict and serialized to json

m = Model.parse_obj(d)

print(m)
print(m.json())
-------
__root__={'==': Expr(lvalue='%var%', rvalue='10')}
{"==": ["%var%", "10"]}

But there is no op_name, so it's hard to deal with this model. Is it possible to decompose it into 3 fields with transparent serialization/deserialization to/from json?

Upvotes: 2

Views: 3396

Answers (1)

Hernán Alarcón
Hernán Alarcón

Reputation: 4089

I think you can use a @root_validator to decompose your input dict into the corresponding fields:

class Model(BaseModel):
  op_name: str
  lvalue: str
  rvalue: str

  @root_validator(pre=True)
  def _decompose(cls, values: Dict[str, Any]) -> Dict[str, Any]:
    new_values = {}
    op_name = next(iter(values.keys()), None)
    if op_name is not None:
      new_values["op_name"] = op_name
      list_values = values.get(op_name)
      if isinstance(list_values, list) and len(list_values) == 2:
        new_values["lvalue"] = list_values[0]
        new_values["rvalue"] = list_values[1]
    return new_values

It is important to use pre=True to decompose the input before any other validation is applied.

See an example in Google Colab.

Upvotes: 2

Related Questions