Builders overview
Last Updated: 2026-06-10 Status: 🟢 APPROVATO — allineato al contratto v0.8.0.
A builder is a Python class that defines a grammar for a structured document — HTML, SVG, CSS, or any user-defined dialect — and IS the document: it owns the source bag and the create/render lifecycle.
The three objects
The framework is built around three concrete classes:
Builder (
HtmlBuilder,SvgBuilder,CssBuilder, …) — declares the grammar via decorators AND carries the document: a mountname, thesourcebag,create()/render(), the render targets. A page is a builder subclass withmain(self, root).Renderer (
HtmlRenderer,SvgRenderer,CssRenderer, …) — walks the source bag and emits a string. Exposed asrenderer_<mode>properties on the builder class; instances are fresh and ephemeral (onerender()call each).BuilderHandler — the data source. One segmented datastore that mounts N builders by name (
add_builder), hands each its own data segment (_is the shared one), tracks readers (pointer_map) and owns thelive()mutation section. Only needed when the page reads data; it is not subclassed.
The two phases
The builder’s lifecycle has two phases, called explicitly:
page = MyPage()
page.create() # setup(data) + main(source) + first calculation
page.render() # serializes source
Phase |
Method |
What it does |
|---|---|---|
Create |
|
Calls |
Render |
|
Walks the source via |
The source bag is inspectable as page.source after create().
With data, the handler mounts and creates the page:
page = CustomerPage(name="customer")
handler = BuilderHandler()
handler.add_builder(page) # mounts under page.name, calls create()
page.render()
Grammar declaration
A builder declares its grammar via decorators on methods:
from genro_builders.builder import BuilderBase, element
class MyBuilder(BuilderBase):
@element(sub_tags='body')
def html(self): ...
@element(sub_tags='h1,p[]')
def body(self): ...
@element(sub_tags='') # leaf (void element)
def br(self): ...
An unknown item in sub_tags raises at class definition time. See
Decorators for the full list.
Page subclassing
The user defines the page by subclassing the dialect builder and
overriding main (and setup when the page reads data):
from genro_builders.contrib.html import HtmlBuilder
class CustomerPage(HtmlBuilder):
def main(self, root):
root.body().h1("Customer page")
What lives where
Concern |
Owned by |
|---|---|
Grammar (tags, validation, schema) |
Builder class |
Source bag (the recipe) |
Builder instance ( |
Rendering (string output) |
Renderer ( |
Render targets (file, stream, callable; per mode) |
Builder instance |
Node lookup by id |
Builder ( |
Data (segmented datastore, |
BuilderHandler |
Pointer tracking, |
BuilderHandler |
This separation is fixed by the architecture contract (areas
BLD / PAG / HND). See roadmap/architecture-contract.md.
What is here, and what is next
Already implemented:
Pull-based binding —
^pointer/=pointer/${name}resolved at render time, with read-time pointer registration (DAT.2); data presentation viamask/_wdg(DAT.5); consumed template inputs (DAT.6).Data-elements —
data_setter,data_formula,data_controller(plain@elementmarked as data), first calculation duringcreate(), single-wave recompute on mutation (DAT.4). See Decorators.Multibuilder — N pages on one handler, segmented data (
HND).Push reactivity, Level 0 — with an application, inside
with handler.live():every mutation queues a render flushed at the section exit (RX.1).
Designed but not yet implemented:
Components (
CMP) and@slot(PAG.6) — named reusable structures with render-time expansion; fill-by-id at node birth. Seeroadmap/component-design.md.Data-element cascade (slice 2) — multi-wave re-firing (
DAT.4).Finer-grained push reactivity — partial render in the
live()flush, SRC/DATA granularity (RX).