Dataclasses & Pydantic Models#

Dataclasses and Pydantic models can easily be registered with their GUI.

Dataclasses#

Example: automatically create a GUI for a “Person” dataclass#

To create a GUI for a dataclass, you first need to register the dataclass with its GUI.

For this, you can use fl.register_dataclass(dataclass_type, **fiat_attributes) or the @fl.dataclass_with_gui_registration(**fiat_attributes) decorator.

In either case, you can specify GUI options for the fields using the fiat_attributes mechanism.

Option 1: using register_dataclass:

import fiatlight as fl
from dataclasses import dataclass

class Person:
    name: str
    age: int

fl.register_dataclass(Person, age__range=(0, 120))

Option 2: using the decorator dataclass_with_gui_registration:

import fiatlight as fl
from dataclasses import dataclass

@fl.dataclass_with_gui_registration(age__range=(0, 120))
class Person:
    name: str
    age: int

(This option is shorter, but more intrusive, as it modifies the original class definition.)

Use the generated GUI in Fiatlight#

You can use the dataclass as a function parameter, and fiatlight will generate a GUI for it.

def greet(person: Person) -> str:
    return f"Hello {person.name}, you are {person.age} years old."

# Note: this app *will not* remember the values of the dataclass fields between runs
fl.run(greet, app_name="Dataclass Person")
_images/7a1ce23263f7d34ea7fc550e9ea7cbd71b546302c4a670a793d0bb2d2de635bf.png

Or use the generate GUI in standalone application#

Alternatively, you can use the generated GUI in a standalone application. Below we run an application using hello_imgui. For more info, see Dear ImGui Bundle doc.

from imgui_bundle import hello_imgui

PERSON = Person(name="John", age=30)

def gui():
    global PERSON
    _changed, PERSON = fl.immediate_edit("Who are you?", PERSON)

hello_imgui.run(gui)
_images/d82a6458cd60c68bd18a712c6f7a6645f996b316762e051bc668bbcdf6270f41.jpg

Pydantic models#

Below is a more complete example of how to use Pydantic models with fiatlight.

Example: automatically create a GUI for nested Pydantic models#

Notes:

  • fiatlight will automatically generate a serialization/deserialization mechanism for Pydantic models, so that user entries can be saved and reloaded (when used as function parameters). This is not available for dataclasses.

  • Pydantic models can be nested: in the example below, you will see 3 levels of nesting, and fiatlight will generate a nice GUI for those.

  • You can use fl.register_base_model to register a Pydantic model with its GUI and add fiat attributes Alternatively, you can use the @fl.base_model_with_gui_registration decorator (but this is more intrusive, as it modifies the original class definition).

  • You can specify GUI options for the fields using the fiat_attributes mechanism.

  • Pydantic field validators (such as Field(ge=0, le=90, ...)) are supported and will be reflected in the GUI.

  • Custom validators can be used, as shown in the example below.

  • Validation errors will be displayed in the GUI (in yellow)

import fiatlight as fl
from enum import Enum
from pydantic import BaseModel, Field


# An Enum which will be associated to a Gui automatically
class TrainingDataType(Enum):
    Test = "test"
    Train = "train"
    Validation = "validation"


# GeographicInfo: a pydantic model, with validation on latitude and longitude
# which will be reflected in the GUI
class GeographicInfo(BaseModel):
    latitude: float = Field(ge=0, le=90, default=0)
    longitude: float = Field(ge=-180, lt=180, default=0)

# We register the GeographicInfo model with its GUI
# (the sliders for lon/lat will be limited to the ranges specified in the Fields)
fl.register_base_model(GeographicInfo)


# A custom validator, which will be used to validate the short description
def validate_short_description(value: str) -> str:
    if len(value) > 30:
        raise ValueError("Description is too long")
    return value


# A second model, which nests the first one (GeographicInfo)
class ImageInfo(BaseModel):
    geo_info: GeographicInfo = GeographicInfo()
    description: str = "Short Description..."
    width: int = 0
    height: int = 0

# We register the ImageInfo model with its GUI, and add some fiat attributes
# Also, we add a custom Fiatlight validator for the description field
fl.register_base_model(
    ImageInfo,
    width__range=(0, 2000),
    height__range=(0, 2000),
    description__label="Description",
    description__validator=validate_short_description,
    geo_info__label="Geographic Info",
)



# A third model, which nests the second one (ImageInfo)
# In total, it has 3 levels: TrainingImage -> ImageInfo -> GeographicInfo
# In this case, we use the decorator to register the model with its GUI
@fl.base_model_with_gui_registration(
    image_path__label="Select Image",
    training_type__label="Training Set",
    info__label="Image Info",
)
class TrainingImage(BaseModel):
    image_path: fl.fiat_types.ImagePath = ""  # type: ignore
    training_type: TrainingDataType = TrainingDataType.Test
    info: ImageInfo = ImageInfo(width=0, height=0)

Use the generated GUI in a standalone application#

from imgui_bundle import hello_imgui

# We create an instance of the Pydantic model
IMAGE = TrainingImage()

def gui():
    global IMAGE
    _changed, IMAGE = fl.immediate_edit("Image Info", IMAGE)

hello_imgui.run(gui)
_images/6b644dd343c0acb25fa9286449e90d421b51ae5e08a29b3589a1ffda732dd06b.jpg

Or use the generated GUI in Fiatlight#

def process_image(image: TrainingImage) -> str:
    import os
    basename = os.path.basename(image.image_path)
    return basename

# Note: this app *will* remember the values of the Pydantic model fields between runs
fl.run(process_image, app_name="Pydantic Image Model")
_images/0b41005936254fca867241d4bc635bb0d12b8d61682e56198402bb80e68917ef.png

In the previous screenshot, the GUI generated by fl.base_model_with_gui_registration will automatically validate the data according to the model’s constraints, and thus display an error message (because in this case, the description is too long).

Video Tutorial#

A short video tutorial is available for this topic.

🔗 Watch Video