Builder system for genro-bag - grammar, validation, compilation
Project description
genro-builders
Builder system for genro-bag — domain-specific grammars, rendering, and runtime data binding via pointers, built on top of bag data structures.
Installation
pip install genro-builders
Quick start
A page is a builder: subclass the dialect and implement main.
from genro_builders.contrib.html import HtmlBuilder
class HelloPage(HtmlBuilder):
def main(self, root):
body = root.body()
body.h1("Hello World")
body.p("My first page with genro-builders.")
page = HelloPage()
page.create()
print(page.render(pretty=True))
The lifecycle is two-phase, both on the builder:
create()runssetup(self.data)(seed the data), then the user-definedmain(self.source)that populates the source Bag through the dialect's grammar API, then the first calculation of the data-elements.render(mode=None, target=None, validate=True, **opts)drives the universal walk on the source and produces the dialect's output. Defaultmodecomes from the dialect; defaulttargetreturns the string. The walk also checks minimum child cardinality (validate=Falsedeliberately emits a partial document).
Dialects (contrib)
The package ships with reference dialects, each as a <Dialect>Builder
grammar:
- HTML5 —
genro_builders.contrib.html.HtmlBuilder(HTML5 grammar with CSS kwargs) - SVG —
genro_builders.contrib.svg.SvgBuilder - CSS —
genro_builders.contrib.css.CssBuilder - XSD —
genro_builders.xml(codegen: an XSD schema becomes a<Dialect>Builderyou commit and import)
Mixed-dialect documents are supported via sub-builders: a grammar
element marked _meta['subbuilder'] switches the active dialect from
that node down, and the render walk picks the right renderer per node.
HTML hosts SVG with body.svg(...); SVG hosts HTML with
svg.html(...), wrapped in <foreignObject> automatically.
from genro_builders.contrib.html import HtmlBuilder
class Badge(HtmlBuilder):
def main(self, root):
body = root.body()
svg = body.svg(viewBox="0 0 200 80", width=200, height=80)
svg.rect(x=0, y=0, width=200, height=80, fill="#2c3e50")
page = Badge()
page.create()
print(page.render())
Architecture (one-paragraph map)
A builder declares the grammar of a dialect (decorators
@element, @abstract; the three data-elements data_setter /
data_formula / data_controller are plain @element marked as
data) and is also the document: it owns name, source,
create()/render(), and exposes its renderers as renderer_<mode>
properties. A handler (BuilderHandler) is 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 who
reads what (pointer_map) and owns the live() mutation section. A
renderer is responsible for one mode: the universal walk produces
fragments via dialect-specific rendered_item, then finalize ships
the result to the target.
Runtime data binding (pull-based)
Attribute values and node text can carry pointers and templates, resolved at render time:
^path— reactive pointer (read and subscribed)=path— passive pointer (read only)${name}— template token; an attribute referenced by a template of the same node is a consumed input, never emitted
from genro_builders.builder import BuilderHandler
from genro_builders.contrib.html import HtmlBuilder
class Page(HtmlBuilder):
def setup(self, data):
data.set_item("greeting", "Hello")
def main(self, root):
root.body().h1("^greeting")
page = Page()
handler = BuilderHandler()
handler.add_builder(page) # mounts under page.name and creates
print(page.render())
# ...<h1>Hello</h1>...
# Mutate the data and re-render: pull-based, no auto-render.
page.data.set_item("greeting", "Ciao")
print(page.render())
# ...<h1>Ciao</h1>...
Push reactivity has a first level: with an application,
handler.activate() arms the subscriptions, and inside a
with handler.live(): section every mutation queues a render flushed
at the section exit (contract RX.1). Without an application,
live() raises. Finer granularity is on the roadmap (RX).
The companion API on each source node:
node.abs_datapath(path)— turn a relative path into an absolute one in the datastorenode.get_relative_data(path)/node.set_relative_data(path, value)— read/write the datastore relative to the nodenode.SET / GET / PUT / FIRE— the reactive macros over the same two entry points
Render target
page = HelloPage()
page.create()
# Return a string (default)
text = page.render()
# Write to a path
page.render(target="out.html")
# Push to a file-like or invoke a callable
import io
page.render(target=io.StringIO())
page.render(target=print)
# Register a default target (per mode), then render to it
page.set_render_target("out.html")
page.render()
Examples
Runnable tutorials under
src/genro_builders/contrib/<dialect>/examples/,
grouped by scenario:
- HTML —
no_data/(grammar, styling, sub-builders, validation, render modes),with_data/(pointers, datapath, presentation),with_logic/(data-elements),reactive/(live sections) - SVG —
01_introduction,badge_sheet,bar_chart, and more - CSS —
01_introduction
Each example ships a runnable .py, a readme.md, and the rendered
output. The test suite runs them all (tests/test_examples.py).
Documentation
- Getting Started — first page in 5 minutes
- Builders overview — builder/handler/renderer split
- Decorators —
@element,@abstract, sub-builders, data-elements - Common patterns —
._chaining,node_by_id, render targets - Per-grammar references: HTML, SVG, CSS, XSD
- Architectural contract and roadmap:
roadmap/
Downstream
genro-builders is a generic engine: the grammars, the renderers, and the reactive data binding know nothing about who consumes them. The source carries no reference to any downstream layer — this is the one place that names them. Known consumers in the Genro ecosystem:
- genro-ws-web — WebSocket-driven reactive SPA framework (the production widget kit and the push transport live here)
- genro-office — Office document generation (Word and Excel builders)
- genro-print — print and PDF generation system
- genro-textual — Textual UI framework for Bag-driven applications
- genro-scriba — infrastructure configuration file generator (Traefik, Docker Compose, and more)
License
Apache License 2.0 — Copyright 2025 Softwell S.r.l.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file genro_builders-0.18.0.tar.gz.
File metadata
- Download URL: genro_builders-0.18.0.tar.gz
- Upload date:
- Size: 430.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d800ca01630dcc4c0e7006c467e97f2668ce3a6271484148a45d0a0190b9170d
|
|
| MD5 |
9162988c263d076ee79b4972d21e9041
|
|
| BLAKE2b-256 |
53a593b3428edf44b25ec75922103ab43c3fec25414a63c1d680137cc0855e1b
|
Provenance
The following attestation bundles were made for genro_builders-0.18.0.tar.gz:
Publisher:
publish.yml on genropy/genro-builders
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
genro_builders-0.18.0.tar.gz -
Subject digest:
d800ca01630dcc4c0e7006c467e97f2668ce3a6271484148a45d0a0190b9170d - Sigstore transparency entry: 2071250716
- Sigstore integration time:
-
Permalink:
genropy/genro-builders@566175fcc3ca28d2f6e4cc7389c144bb74f85c86 -
Branch / Tag:
refs/tags/v0.18.0 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@566175fcc3ca28d2f6e4cc7389c144bb74f85c86 -
Trigger Event:
push
-
Statement type:
File details
Details for the file genro_builders-0.18.0-py3-none-any.whl.
File metadata
- Download URL: genro_builders-0.18.0-py3-none-any.whl
- Upload date:
- Size: 366.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81976b418cda7e3fd5c72e848dea0a46ff4d7851befd350a4f4bbf9aa6583519
|
|
| MD5 |
2b091b32d3cb9aa35093f5956638d66f
|
|
| BLAKE2b-256 |
029bc188a1238de3451a3cd04140eb5e5c1f9f22f18b07085b6fab8744ddb0b3
|
Provenance
The following attestation bundles were made for genro_builders-0.18.0-py3-none-any.whl:
Publisher:
publish.yml on genropy/genro-builders
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
genro_builders-0.18.0-py3-none-any.whl -
Subject digest:
81976b418cda7e3fd5c72e848dea0a46ff4d7851befd350a4f4bbf9aa6583519 - Sigstore transparency entry: 2071250725
- Sigstore integration time:
-
Permalink:
genropy/genro-builders@566175fcc3ca28d2f6e4cc7389c144bb74f85c86 -
Branch / Tag:
refs/tags/v0.18.0 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@566175fcc3ca28d2f6e4cc7389c144bb74f85c86 -
Trigger Event:
push
-
Statement type: