Pydantic usage
JSON Schema files compatible with Bonsai.Sgen
can be generated automatically from Python using the Pydantic data validation library. This has several advantages:
- Python is a more concise and well-known language than JSON Schema.
- We can do object-oriented modelling directly, rather than having to tweak JSON Schema constraints.
- Pydantic models can be used to read and write JSON files directly into Python objects.
Setup instructions
We recommend uv
for Python version, environment, and package dependency management. A self-contained virtual environment can be created using uv venv
.
To install pydantic directly into the virtual environment:
uv pip install pydantic
Model definition
A JSON Schema can be directly defined using Pydantic models which fully specify all the constraints between the types in the schema. For example, the code below can be used to generate the entire schema for the tagged unions example:
person_and_discriminated_pets.py.
import json
from pathlib import Path
from typing import Annotated, Literal, Union
from pydantic import BaseModel, Field, RootModel
class PetBase(BaseModel):
pet_type: str
age: int
class Cat(PetBase):
pet_type: Literal["cat"]
can_meow: bool = Field(default=True)
class Dog(PetBase):
pet_type: Literal["dog"]
can_bark: bool = Field(default=True)
class Pet(RootModel):
root: Annotated[Union[Cat, Dog], Field(discriminator="pet_type")]
class PersonAndPet(BaseModel):
owner: str
pet: Pet
if __name__ == "__main__":
schema = PersonAndPet.model_json_schema()
Path("person-and-discriminated-pets.json").write_text(json.dumps(schema, indent=2))
Note this example is designed as an executable Python module which can be used both as a library to manipulate the model objects, or to generate the schema itself by executing its main function:
uv run "person_and_discriminated_pets.py"
This will generate the file person-and-discriminated-pets.json
which can then be passed to Bonsai.Sgen
to generate JSON serialization classes:
dotnet bonsai.sgen "person-and-discriminated-pets.json" -o Extensions --serializer json
Model serialization
Once the model classes are specified in Pydantic, we can create and manipulate model objects directly in Python, export them to a JSON file, or read a JSON file back into model objects.
Serialize to JSON
from pathlib import Path
from person_and_discriminated_pets import PersonAndPet, Cat
data = PersonAndPet(owner="Avery", pet=Cat(age=2, can_meow=False))
Path("data.json").write_text(data.model_dump_json(indent=2))
Deserialize from JSON
from pathlib import Path
from person_and_discriminated_pets import PersonAndPet
json = Path("data.json").read_text()
data = PersonAndPet.model_validate_json(json)