Builders Module

The builders package provides typed APIs for constructing TreeStore hierarchies.

Module Structure

        graph TB
    subgraph "genro_treestore.builders"
        BASE[base.py<br/>BuilderBase]
        DEC[decorators.py<br/>@element]
        HTML[html.py<br/>HtmlBuilder]

        subgraph "xsd/"
            XSD[XsdBuilder]
        end

        BASE --> HTML
        BASE --> XSD
        DEC --> BASE
    end
    

BuilderBase

class genro_treestore.BuilderBase[source]

Bases: ABC

Abstract base class for TreeStore builders.

A builder provides domain-specific methods for creating nodes in a TreeStore. There are two ways to define elements:

  1. Using @element decorator on methods:

    @element(children=’item’) def menu(self, target, tag, **attr):

    return self.child(target, tag, **attr)

    @element(tags=’fridge, oven, sink’) def appliance(self, target, tag, **attr):

    return self.child(target, tag, value=’’, **attr)

  2. Using _schema dict for external/dynamic definitions:
    class HtmlBuilder(BuilderBase):
    _schema = {

    ‘div’: {‘children’: ‘=flow’}, ‘br’: {‘leaf’: True}, ‘td’: {

    ‘children’: ‘=flow’, ‘attrs’: {

    ‘colspan’: {‘type’: ‘int’, ‘min’: 1, ‘default’: 1}, ‘rowspan’: {‘type’: ‘int’, ‘min’: 0, ‘default’: 1}, ‘scope’: {‘type’: ‘enum’, ‘values’: [‘row’, ‘col’]},

    }

    },

    }

Schema keys:
  • children: str or set of allowed child tags (supports =ref)

  • leaf: True if element has no children (value=’’)

  • attrs: dict of attribute specs for validation
    • type: ‘int’, ‘string’, ‘uri’, ‘bool’, ‘enum’, ‘idrefs’

    • required: True/False (default: False)

    • min/max: numeric constraints for int type

    • default: default value

    • values: list of valid values for enum type

The lookup order is: decorated methods first, then _schema. Attribute validation is performed with pure Python (no dependencies).

Usage:
>>> store = TreeStore(builder=MyBuilder())
>>> store.fridge()  # calls appliance() with tag='fridge'
classmethod __init_subclass__(**kwargs)[source]

Build the _element_tags dict from @element decorated methods.

Parameters:

kwargs (Any)

Return type:

None

__getattr__(name)[source]

Look up tag in _element_tags or _schema and return handler.

Parameters:

name (str)

Return type:

Any

child(target, tag, label=None, value=None, _position=None, _builder=None, **attr)[source]

Create a child node in the target TreeStore.

Parameters:
  • target (TreeStore) – The TreeStore to add the child to.

  • tag (str) – The node’s type (stored in node.tag).

  • label (str | None (default: None)) – Explicit label. If None, auto-generated as tag_N.

  • value (Any (default: None)) – If provided, creates a leaf node; otherwise creates a branch.

  • _position (str | None (default: None)) – Position specifier (see TreeStore.set_item for syntax).

  • _builder (BuilderBase | None (default: None)) – Override builder for this branch and its descendants. If None, inherits from target.

  • **attr (Any) – Node attributes.

Return type:

TreeStore | TreeStoreNode

Returns:

TreeStore if branch (for adding children), TreeStoreNode if leaf.

Example

>>> builder.child(store, 'div', id='main')
>>> builder.child(store, 'meta', value='', charset='utf-8')  # void
>>> builder.child(store, 'svg', _builder=SvgBuilder())
check(store, parent_tag=None, path='')[source]

Check the TreeStore structure against this builder’s rules.

Checks structure rules defined via @element(children=…) decorator: - valid_children: which tags can be children of this tag - cardinality: per-tag min/max constraints using slice syntax

Parameters:
  • store (TreeStore) – The TreeStore to check.

  • parent_tag (str | None (default: None)) – The tag of the parent node (for context).

  • path (str (default: '')) – Current path in the tree (for error messages).

Return type:

list[str]

Returns:

List of error messages (empty if valid).

Decorators

@element

genro_treestore.element(tags='', children='', validate=True)[source]

Decorator to define element tags and validation rules for a builder method.

The decorator registers the method as handler for the specified tags. If no tags are specified, the method name is used as the tag.

Attribute validation is automatically extracted from function signature type hints when validate=True (default).

Parameters:
  • tags (str | tuple[str, ...] (default: '')) – Tag names this method handles. Can be: - A comma-separated string: ‘fridge, oven, sink’ - A tuple of strings: (‘fridge’, ‘oven’, ‘sink’) If empty, the method name is used as the single tag.

  • children (str | tuple[str, ...] (default: '')) –

    Valid child tag specs for structure validation. Can be: - A comma-separated string: ‘tag1, tag2[:1], tag3[1:]’ - A tuple of strings: (‘tag1’, ‘tag2[:1]’, ‘tag3[1:]’)

    Each spec can be: - ‘tag’ - allowed, no cardinality constraint (0..∞) - ‘tag[n]’ - exactly n required - ‘tag[n:]’ - at least n required - ‘tag[:m]’ - at most m allowed - ‘tag[n:m]’ - between n and m (inclusive) Empty string or empty tuple means no children allowed (leaf node).

  • validate (bool (default: True)) – If True (default), extract attribute validation rules from function signature type hints. Set to False to disable validation.

Return type:

Callable

Example

>>> class MyBuilder(BuilderBase):
...     # Multiple tags pointing to same method
...     @element(tags='fridge, oven, sink')
...     def appliance(self, target, tag, **attr):
...         return self.child(target, tag, value='', **attr)
...
...     # Structure validation with children
...     @element(children='section, item[1:]')
...     def menu(self, target, tag, **attr):
...         return self.child(target, tag, **attr)
...
...     @element()  # No children allowed (leaf)
...     def item(self, target, tag, **attr):
...         return self.child(target, tag, value='', **attr)
...
...     # Attribute validation from signature type hints
...     @element()
...     def td(self, target, tag, colspan: int = 1,
...            scope: Literal['row', 'col'] | None = None, **attr):
...         return self.child(target, tag, colspan=colspan, scope=scope, **attr)

Note

The element decorator handles both tag registration and children validation via the children parameter.

HtmlBuilder

class genro_treestore.HtmlBuilder[source]

Bases: BuilderBase

Builder for HTML5 elements.

Provides dynamic methods for all 112 HTML5 tags via __getattr__. Void elements (meta, br, img, etc.) automatically use empty string value.

The schema is loaded from a pre-compiled MessagePack file generated from W3C Validator RELAX NG schema files.

Usage:
>>> store = TreeStore(builder=HtmlBuilder())
>>> store.div(id='main').p(value='Hello')
>>> store.ul().li(value='Item 1')
VOID_ELEMENTS

Set of void (self-closing) element names.

ALL_TAGS

Set of all valid HTML5 element names.

__init__()[source]

Initialize HtmlBuilder with W3C HTML5 schema.

property VOID_ELEMENTS: frozenset[str]

Void elements (self-closing, no content).

property ALL_TAGS: frozenset[str]

All valid HTML5 element names.

__getattr__(name)[source]

Dynamic method for any HTML tag.

Parameters:

name (str) – Tag name (e.g., ‘div’, ‘span’, ‘meta’)

Return type:

Callable[..., TreeStore | TreeStoreNode]

Returns:

Callable that creates a child with that tag.

Raises:

AttributeError – If name is not a valid HTML tag.

HTML5 Content Model

        graph TB
    subgraph "Content Categories"
        FLOW[Flow Content<br/>div, p, section...]
        PHRASING[Phrasing Content<br/>span, a, em...]
        EMBEDDED[Embedded Content<br/>img, video, iframe...]
        INTERACTIVE[Interactive Content<br/>a, button, input...]
        METADATA[Metadata Content<br/>head, title, meta...]
    end

    FLOW --> PHRASING
    FLOW --> EMBEDDED
    FLOW --> INTERACTIVE
    

XsdBuilder

Dynamic builder from XML Schema (XSD) files.

class genro_treestore.XsdBuilder[source]

Bases: BuilderBase

Builder dynamically generated from XSD schema.

Creates methods for all elements defined in an XSD schema. Pass the schema TreeStore (from TreeStore.from_xml()) to __init__.

Example

>>> xsd = open('fatturapa.xsd').read()
>>> schema = TreeStore.from_xml(xsd)
>>> builder = XsdBuilder(schema)
>>>
>>> fattura = TreeStore(builder=builder)
>>> fattura.FatturaElettronica(versione='FPR12')
Parameters:

schema_store (TreeStore)

__init__(schema_store)[source]

Initialize builder from XSD schema TreeStore.

Parameters:

schema_store (TreeStore) – TreeStore from TreeStore.from_xml(xsd_string).

__getattr__(name)[source]

Dynamic method for any element in the schema.

Parameters:

name (str)

Return type:

Callable[..., TreeStore | TreeStoreNode]

property elements: frozenset[str]

Return all valid element names in the schema.

get_children(element)[source]

Get allowed children for an element.

Parameters:

element (str)

Return type:

frozenset[str] | None

Example

from genro_treestore import TreeStore
from genro_treestore.builders import XsdBuilder

# Load XSD schema
xsd_content = open('invoice.xsd').read()
schema = TreeStore.from_xml(xsd_content)
builder = XsdBuilder(schema)

# Build validated structure
store = TreeStore(builder=builder)
invoice = store.Invoice()
invoice.Header().Date(value='2025-01-01')

Builder Architecture

        classDiagram
    class BuilderBase {
        <<abstract>>
        +_schema: dict
        +child(tag, **attr)
        +__getattr__(name)
    }

    class HtmlBuilder {
        +div(**attr)
        +span(**attr)
        +p(**attr)
        ...
    }

    class XsdBuilder {
        +__init__(schema)
    }

    BuilderBase <|-- HtmlBuilder
    BuilderBase <|-- XsdBuilder
    

Validation Flow

        flowchart TD
    ADD[Add child node]
    CHK{Valid child?}
    CARD{Cardinality OK?}
    OK[Node added]
    ERR[InvalidChildError]
    CERR[TooManyChildrenError]

    ADD --> CHK
    CHK -->|Yes| CARD
    CHK -->|No| ERR
    CARD -->|Yes| OK
    CARD -->|No| CERR
    

Cardinality Syntax

Syntax

Meaning

Example

tag

Zero or more

'div'

tag[:]

Zero or more

'div[:]'

tag[1]

Exactly one

'title[1]'

tag[0:1]

Zero or one

'subtitle[0:1]'

tag[1:]

One or more

'section[1:]'

tag[2:5]

Range

'item[2:5]'

See Also