Exceptions Module

The exceptions module defines all custom exceptions raised by TreeStore.

Exception Hierarchy

        graph TB
    subgraph "Exception Hierarchy"
        BASE[TreeStoreError<br/>Base exception]
        IC[InvalidChildError<br/>Invalid child tag]
        IP[InvalidParentError<br/>Invalid parent context]
        MC[MissingChildError<br/>Missing mandatory child]
        TMC[TooManyChildrenError<br/>Cardinality exceeded]

        BASE --> IC
        BASE --> IP
        BASE --> MC
        BASE --> TMC
    end
    

TreeStoreError

exception genro_treestore.TreeStoreError[source]

Bases: Exception

Base exception for all TreeStore errors.

This is the root exception class for the TreeStore library. All specific exceptions inherit from this class, allowing callers to catch any TreeStore error with:

try:
    # TreeStore operations
except TreeStoreError as e:
    # Handle any TreeStore error
args

Standard exception arguments containing the error message.

Base exception for all TreeStore errors. Catch this to handle any TreeStore-specific exception.

from genro_treestore import TreeStore, TreeStoreError

try:
    store = TreeStore(builder=my_builder)
    store.invalid_tag()
except TreeStoreError as e:
    print(f"TreeStore error: {e}")

InvalidChildError

exception genro_treestore.InvalidChildError[source]

Bases: TreeStoreError

Raised when a child tag is not allowed under the current parent.

This exception is raised when attempting to add a child node with a tag that violates the builder’s structural rules. Common causes:

  • Adding a child to a void/leaf element (e.g., children under <br>)

  • Tag not in the parent’s allowed children list

  • Tag explicitly excluded from the parent

Example

>>> store = TreeStore(builder=HtmlBuilder(), raise_on_error=True)
>>> ul = store.body().ul()
>>> ul.div()  # div is not a valid child of ul
InvalidChildError: 'div' is not a valid child of 'ul'

See also

Raised when attempting to add a child that is not allowed by the builder’s validation rules.

from genro_treestore import TreeStore, InvalidChildError
from genro_treestore.builders import HtmlBuilder

store = TreeStore(builder=HtmlBuilder())
ul = store.ul()

try:
    ul.div()  # div is not a valid child of ul
except InvalidChildError as e:
    print(f"Invalid child: {e}")
    # InvalidChildError: 'div' is not a valid child of 'ul'

InvalidParentError

exception genro_treestore.InvalidParentError[source]

Bases: TreeStoreError

Raised when a node is placed under an invalid parent type.

This exception is raised when a tag requires a specific parent type but is being added to a different parent. This is the inverse of InvalidChildError - it validates from the child’s perspective rather than the parent’s.

Common use cases:

  • <li> elements must be children of <ul>, <ol>, or <menu>

  • <td>/<th> elements must be children of <tr>

  • <option> elements must be children of <select> or <datalist>

Example

>>> store = TreeStore(builder=HtmlBuilder(), raise_on_error=True)
>>> div = store.body().div()
>>> div.td()  # td must be child of tr
InvalidParentError: 'td' cannot be child of 'div', requires 'tr'

See also

Raised when a tag is added in an invalid parent context.

from genro_treestore import TreeStore, InvalidParentError

store = TreeStore(builder=my_builder)

try:
    store.body()  # body may only be child of html
except InvalidParentError as e:
    print(f"Invalid parent: {e}")

MissingChildError

exception genro_treestore.MissingChildError[source]

Bases: TreeStoreError

Raised when a required child tag is missing from a parent.

This exception is raised during validation when a parent node is missing one or more mandatory children as defined by the builder’s cardinality rules (minimum count > 0).

The error is typically raised when:

  • Calling store.builder.check() explicitly

  • Using ValidationSubscriber with hard error mode

  • Finalizing a structure that requires certain children

Example

>>> # Assuming a builder requires 'head' and 'body' in 'html'
>>> store = TreeStore(builder=HtmlBuilder())
>>> html = store.html()
>>> # Missing head and body children
>>> store.builder.check(html)
MissingChildError: 'html' requires child 'head' (min: 1, found: 0)

See also

  • check()

  • ValidationSubscriber

Raised when a mandatory child element is missing during validation.

from genro_treestore import TreeStore, MissingChildError
from genro_treestore.builders import BuilderBase, element

class DocBuilder(BuilderBase):
    @element(children='title[1]')  # title is required
    def section(self, target, tag, **attr):
        return self.child(target, tag, **attr)

    @element()
    def title(self, target, tag, value=None, **attr):
        return self.child(target, tag, value=value, **attr)

store = TreeStore(builder=DocBuilder())
sec = store.section()

# During validation, if title is missing:
# MissingChildError: 'section' requires at least 1 'title' child

TooManyChildrenError

exception genro_treestore.TooManyChildrenError[source]

Bases: TreeStoreError

Raised when a child tag exceeds its maximum allowed count.

This exception is raised when adding a child would exceed the maximum cardinality defined by the builder’s rules. For example, an HTML document can only have one <head> element.

Cardinality is specified using slice notation in builder definitions:

  • tag or tag[:] - unlimited (0 to infinity)

  • tag[1] - exactly one required

  • tag[0:1] - zero or one (optional, max 1)

  • tag[1:3] - between 1 and 3 inclusive

Example

>>> # Assuming 'head' has max cardinality of 1
>>> store = TreeStore(builder=HtmlBuilder(), raise_on_error=True)
>>> html = store.html()
>>> html.head()  # First head - OK
>>> html.head()  # Second head - Error
TooManyChildrenError: 'html' already has maximum 'head' children (1)

See also

  • element()

  • _parse_children_spec()

Raised when adding a child would exceed the maximum cardinality.

from genro_treestore import TreeStore, TooManyChildrenError
from genro_treestore.builders import BuilderBase, element

class DocBuilder(BuilderBase):
    @element(children='title[1]')  # exactly one title
    def section(self, target, tag, **attr):
        return self.child(target, tag, **attr)

    @element()
    def title(self, target, tag, value=None, **attr):
        return self.child(target, tag, value=value, **attr)

store = TreeStore(builder=DocBuilder())
sec = store.section()
sec.title(value='First Title')

try:
    sec.title(value='Second Title')  # exceeds limit
except TooManyChildrenError as e:
    print(f"Too many: {e}")
    # TooManyChildrenError: 'section' allows at most 1 'title' child

Exception Handling Patterns

Catching All TreeStore Errors

from genro_treestore import TreeStoreError

try:
    # Any TreeStore operation
    store.some_operation()
except TreeStoreError as e:
    logger.error(f"TreeStore operation failed: {e}")

Specific Exception Handling

from genro_treestore import (
    InvalidChildError,
    MissingChildError,
    TooManyChildrenError,
)

try:
    store.build_structure()
except InvalidChildError as e:
    print(f"Invalid structure: {e}")
except MissingChildError as e:
    print(f"Missing required element: {e}")
except TooManyChildrenError as e:
    print(f"Too many elements: {e}")

Exception Flow

        flowchart TD
    OP[Operation]
    CHK{Validation<br/>Check}
    OK[Success]
    IC[InvalidChildError]
    MC[MissingChildError]
    TMC[TooManyChildrenError]

    OP --> CHK
    CHK -->|Valid child| OK
    CHK -->|Unknown tag| IC
    CHK -->|Missing required| MC
    CHK -->|Exceeds max| TMC
    

See Also