Skip to content

build

build #

Build — the page under construction: the stack components attach to, and the title.

  1. PageBuilder opens a build around the page function, then builds the root stack and opens it; the active build lives in one ContextVar, so a page function called from another builds its own page.
  2. Every component attaches itself to the innermost open stack from Component.__post_init__ (attach); a stack given children= takes those back from the stack they attached to (claim); entering a Stack opens it (push) and leaving closes it (pop); Title sets title.

Build #

The page being built: its open stacks, innermost last, and its title so far.

Source code in capturegraph-lib/capturegraph/ui/build.py
class Build:
    """The page being built: its open stacks, innermost last, and its title so far."""

    _active: ClassVar[ContextVar[Build | None]] = ContextVar("page_build", default=None)

    def __init__(self) -> None:
        """A build with no stack open yet; nothing attaches until one is pushed."""
        self.stacks: list[Stack] = []
        self.title: str | None = None
        self._token: Token[Build | None] | None = None

    @classmethod
    def current(cls) -> Build:
        """The active build.

        Raises:
            RuntimeError: If no ``PageBuilder`` function is running.
        """
        build = cls._active.get()
        if build is None:
            raise RuntimeError(
                "no page is being built — open a stack or set a title inside a function "
                "decorated with @cg.ui.PageBuilder()"
            )
        return build

    @classmethod
    def attach(cls, component: Component) -> None:
        """Add a freshly built ``component`` to the innermost open stack, if one is being built."""
        build = cls._active.get()
        if build is not None and build.stacks:
            build.stacks[-1].children.append(component)

    @classmethod
    def claim(cls, stack: Stack) -> None:
        """Take ``stack``'s given children back from the open stack they attached to."""
        build = cls._active.get()
        if build is None or not build.stacks:
            return
        given = {id(child) for child in stack.children}
        siblings = build.stacks[-1].children
        siblings[:] = [child for child in siblings if id(child) not in given]

    def push(self, stack: Stack) -> None:
        """Open ``stack``: components built from now on attach to it."""
        self.stacks.append(stack)

    def pop(self, stack: Stack) -> None:
        """Close ``stack``, which must be the innermost open one.

        Raises:
            RuntimeError: If another stack is still open inside it.
        """
        if self.stacks[-1] is not stack:
            raise RuntimeError(f"{type(stack).__name__} closed while a nested stack is still open")
        self.stacks.pop()

    def __enter__(self) -> Self:
        """Make this the active build."""
        self._token = self._active.set(self)
        return self

    def __exit__(self, *exc: object) -> None:
        """Restore whatever build was active before."""
        if self._token is not None:
            self._active.reset(self._token)
            self._token = None

__enter__() #

Make this the active build.

Source code in capturegraph-lib/capturegraph/ui/build.py
def __enter__(self) -> Self:
    """Make this the active build."""
    self._token = self._active.set(self)
    return self

__exit__(*exc) #

Restore whatever build was active before.

Source code in capturegraph-lib/capturegraph/ui/build.py
def __exit__(self, *exc: object) -> None:
    """Restore whatever build was active before."""
    if self._token is not None:
        self._active.reset(self._token)
        self._token = None

__init__() #

A build with no stack open yet; nothing attaches until one is pushed.

Source code in capturegraph-lib/capturegraph/ui/build.py
def __init__(self) -> None:
    """A build with no stack open yet; nothing attaches until one is pushed."""
    self.stacks: list[Stack] = []
    self.title: str | None = None
    self._token: Token[Build | None] | None = None

attach(component) classmethod #

Add a freshly built component to the innermost open stack, if one is being built.

Source code in capturegraph-lib/capturegraph/ui/build.py
@classmethod
def attach(cls, component: Component) -> None:
    """Add a freshly built ``component`` to the innermost open stack, if one is being built."""
    build = cls._active.get()
    if build is not None and build.stacks:
        build.stacks[-1].children.append(component)

claim(stack) classmethod #

Take stack's given children back from the open stack they attached to.

Source code in capturegraph-lib/capturegraph/ui/build.py
@classmethod
def claim(cls, stack: Stack) -> None:
    """Take ``stack``'s given children back from the open stack they attached to."""
    build = cls._active.get()
    if build is None or not build.stacks:
        return
    given = {id(child) for child in stack.children}
    siblings = build.stacks[-1].children
    siblings[:] = [child for child in siblings if id(child) not in given]

current() classmethod #

The active build.

Raises:

Type Description
RuntimeError

If no PageBuilder function is running.

Source code in capturegraph-lib/capturegraph/ui/build.py
@classmethod
def current(cls) -> Build:
    """The active build.

    Raises:
        RuntimeError: If no ``PageBuilder`` function is running.
    """
    build = cls._active.get()
    if build is None:
        raise RuntimeError(
            "no page is being built — open a stack or set a title inside a function "
            "decorated with @cg.ui.PageBuilder()"
        )
    return build

pop(stack) #

Close stack, which must be the innermost open one.

Raises:

Type Description
RuntimeError

If another stack is still open inside it.

Source code in capturegraph-lib/capturegraph/ui/build.py
def pop(self, stack: Stack) -> None:
    """Close ``stack``, which must be the innermost open one.

    Raises:
        RuntimeError: If another stack is still open inside it.
    """
    if self.stacks[-1] is not stack:
        raise RuntimeError(f"{type(stack).__name__} closed while a nested stack is still open")
    self.stacks.pop()

push(stack) #

Open stack: components built from now on attach to it.

Source code in capturegraph-lib/capturegraph/ui/build.py
def push(self, stack: Stack) -> None:
    """Open ``stack``: components built from now on attach to it."""
    self.stacks.append(stack)