Computed fields in pydantic

I noticed that I haven’t written anything in about a year, so I figured it would be nice to document some smaller things that I’ve learned recently.

In order to parse a configuration file, I recently needed to compute fields in a pydantic.BaseModel so that the information was accessible not only via the property, but also in the object’s built-in dict() method. Unfortunately, this is not straightforward:

from pydantic import BaseModel

class Rectangle(BaseModel):
  width: int
  length: int

  @property
  def area(self) -> int:
    return self.width * self.length

r = Rectangle(width=3, length=2)

# Accessing the computed property works:
print(r.area)
> 6

# But it's not part of the instances dict()
print(r.dict())
> {'width': 3, 'length': 2}

In the example below, I’m using the pydantic.root_validator to overcome this issue:

import warnings
import typing

from pydantic import root_validator

class Rectangle(BaseModel):
  width: int
  length: int
  area: typing.Optional[int]

  @root_validator
  def compute_area(cls, values) -> typing.Dict:

    new_area = values["width"] * values["length"]

    if values["area"] is not None:
      warnings.warn(
        f"Overriding area with new values {new_area}"
      )
    
    values["area"] = new_area
    
    return values

# Test the new Rectangle
r = Rectangle(width=3, length=2)

# The dict methods works:
print(r.dict())
> {'width': 3, 'length': 2, 'area': 6}

Please keep in mind that this is not the intended way to use a root_validator, which is of course supposed to validate entries, not create them.

The entire issue is currently being discussed in the pydantic github repo, which also shows some other approaches to deal with this issue.

2 thoughts on “Computed fields in pydantic

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s