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.
Has something changed here? getting self is not defined when I run this snippet
Hi Joe, thanks for pointing that out! I edited to post to correct this: I needed to use `values[‘width’]` instead of `self.width` in this context.