One property — the object retains its own structure — and a compact set of sub-packages that all speak about the same tree. Hot paths run in a native Rust core; the most common entry points are re-exported at the top level as pg.*.
pg.Object spans a spectrum — from a plain mutable dataclass to a frozen symbolic tree node. You pick where you sit with class-statement kwargs, and override per field where one field needs to differ.
| Kwarg | Default | Semantics it employs |
|---|---|---|
topo | False | The top-level axis. True makes instances symbolic-tree nodes: topo_path / topo_parent, contextual resolution, upward change notification — and flips the write posture to rebind-first. False is a flat, reference-semantics object. |
validate | True | Values flow through each field's ValueSpec at construct, assignment, and rebind — type check, coercion, default-filling. Off, values land verbatim. |
attr_write | follows not topo | Gates direct obj.x = v (validated when on). sym_rebind still works either way — only frozen seals it. |
frozen | False | Seals the object at construction — even sym_rebind raises. Derive changed values with sym_clone(override=...), the dataclasses.replace() analog. |
eq | True | Value-based __eq__ / __hash__ via sym_eq / sym_hash. Off: identity — for unhashable fields or when node identity is the key. |
order | False | Synthesizes < / <= / > / >= over the compare=True fields, à la @dataclass(order=True). |
attr_read | True | Dotted obj.x access. Off, reads go through obj.sym_get(...) only. |
init | True | PEP 681 knob: init=False keeps a parent's explicit __init__ visible to pyright instead of resynthesizing. Runtime no-op. |
| Semantic | Deltas from default | You get |
|---|---|---|
| Plain dataclass | validate=False | Raw verbatim values, free mutation. |
| Validated record | (none — the default) | Validated, value-equal, mutable. Most subclasses. |
| Immutable value | attr_write=False or frozen=True | Construct-once values; safe dict/set keys. |
| Symbolic node | topo=True | Tree positions, path-targeted rebind, patching, search. |
| Frozen node | topo=True, frozen=True | Shared constants; sealed against any change. |
| Flag | Semantics it employs |
|---|---|
default / default_factory | Static default (recognized shapes deep-copy per instance) or a per-instance factory. |
value_spec | Constraints beyond the annotation — bounds, regex, enums, converters. |
transform / validator | Post-validation transform, or a reject-only check on construct, assignment, and rebind. |
repr / compare / hash | Drop the field from format() / sym_eq / sym_hash. |
init=False (+ clone) | Derived field the class manages (typically in on_sym_ready); clone preserves it through sym_clone. |
alias / doc / metadata | Wire-layer key alias, one-line docstring, tool-facing metadata. |
| the annotation itself | Container storage: pg.Dict[...] is symbolic on both axes, builtin dict stays raw, unauthored follows topo. |
The dial is semantic, not a performance lever — every rung runs on the same native core. Full treatment in the pg.Object style guide.
Each does one thing well and composes with the rest through the shared symbolic tree. The tree itself is opt-in per class with topo=True.
Everything here builds on the same pg.Object. Adopt only the pieces your problem needs.