Skip to content

Supported types

Every annotation below maps to a widget. Anything not listed raises UnsupportedTypeError — which you can fix without touching this package, by registering a handler.

Primitives

Annotation Widget Returns
int spin box int
float double spin box float
decimal.Decimal double spin box Decimal at the displayed precision
str line edit str
bool checkbox bool
bytes line edit bytes, UTF-8 encoded
None / NoneType disabled label None
typing.Any line edit str

Dates and times

Annotation Widget Returns
datetime.datetime date-time picker with calendar datetime
datetime.date date picker with calendar date
datetime.time time picker time
datetime.timedelta spin box in seconds timedelta

Identifiers and paths

Annotation Widget Returns
uuid.UUID line edit, seeded with a fresh uuid4 UUID
pathlib.Path line edit with a Browse… button Path
ipaddress.IPv4Address line edit, seeded 127.0.0.1 IPv4Address
ipaddress.IPv6Address line edit, seeded ::1 IPv6Address

Choices

Annotation Widget Returns
Enum subclass drop-down the member, not its label
IntEnum, StrEnum, auto() drop-down the member
Literal[...] drop-down the literal value, correctly typed

A string-valued enum member is labelled by its value; anything else by its name. Literal[1, "1"] produces two distinct entries, qualified by type, and returns whichever was chosen.

Containers

Annotation Widget Returns
list[T] add/remove list of T widgets list
set[T], frozenset[T] same, deduplicated set / frozenset
tuple[A, B] one widget per position tuple
tuple[T, ...] add/remove list tuple
dict[K, V] key/value table dict
bare list / dict as above, elements treated as Any list / dict

Values are stored as real Python objects, so a list[date] returns date objects and a dict[str, Decimal] returns Decimal values.

Composition

Annotation Widget Returns
BaseModel subclass button opening a sub-form dict of that model's values
X \| Y, Union[X, Y] type selector plus stacked widgets the selected branch's value
Optional[X] selector offering X and None X or None
Annotated[X, ...] whatever X maps to X, with the metadata applied

Nesting composes: list[SomeModel], dict[str, list[int]] and Optional[list[Annotated[int, Gt(0)]]] all work, because each container dispatches on its element type recursively.

Constraints

These are read from Field(...) and applied to the widget.

Constraint Effect
ge, le spin box minimum / maximum
gt, lt same, stepped one unit inward to an inclusive bound
max_length line edit maximum length
decimal_places displayed precision and step of a numeric widget
multiple_of the widget's single-step
title the row's label
description placeholder text and tooltip
default, default_factory pre-fills the widget

A constraint the widget cannot express is still enforced: Pydantic validates on OK, and the dialog stays open with the error shown.

Not supported

complex, arbitrary classes, and anything with arbitrary_types_allowed raise UnsupportedTypeError. The message names the offending type. Adding support is a handful of lines — see How it works.