---
title: "PyTreeSpec"
sidebar_label: "PyTreeSpec"
description: "The clika_runtime.pytree PyTreeSpec class."
---

<!-- Generated by tools/api_reference/generate_api_docs.py. Do not edit. -->

The structure of a pytree without its leaves.

    A spec comes from :func:`~clika_runtime.pytree.tree_flatten` or
    :func:`~clika_runtime.pytree.tree_structure`, from the ``treespec_*``
    constructors, or from this constructor in the ``(type, context,
    children_specs)`` form::

        >>> from clika_runtime import pytree
        >>> leaves, spec = pytree.tree_flatten({"a": [1, (2, None)], "b": 3})
        >>> leaves
        [1, 2, None, 3]
        >>> spec
        TreeSpec({'a': [*, (*, *)], 'b': *})
        >>> spec.num_leaves, spec.num_nodes, spec.num_children
        (4, 7, 2)
        >>> spec.unflatten([10, 20, 30, 40])
        {'a': [10, (20, 30)], 'b': 40}
        >>> pytree.TreeSpec(dict, ["a", "b"], [pytree.LeafSpec(), pytree.LeafSpec()])
        TreeSpec({'a': *, 'b': *})

    ``none_is_leaf`` (default ``True``) records whether ``None`` was a leaf when
    the tree was flattened; with ``False`` a ``None`` is a node with no children
    and contributes no leaf. Two specs compare equal only with the same
    ``none_is_leaf``. ``namespace`` is the registry namespace the tree was
    flattened under; the global namespace (``""``) is compatible with every
    other one.
    

## `children_specs` (property)

The specs of the root's children, in order (a list copy).

## `context` (property)

The root container's context: the keys of a dictionary, the class of
a namedtuple, the ``maxlen`` of a deque, a custom node's own context;
``None`` for a leaf, a tuple or a list.

## `kind` (property)

The root node's :class:`~clika_runtime.pytree.TreeKind`.

## `namespace` (property)

The registry namespace the tree was flattened under.

## `none_is_leaf` (property)

Whether ``None`` was treated as a leaf when this spec was built.

## `num_children` (property)

How many children the root container has.

## `num_leaves` (property)

How many leaves a tree of this structure has.

## `num_nodes` (property)

How many nodes the structure has, leaves and containers together.

## `type` (property)

The root container's type; ``None`` for a leaf spec.

## `__init__`

```python
__init__(self, type: 'type | None' = None, context: 'Any' = None, children_specs: 'Iterable[TreeSpec]' = (), *, none_is_leaf: 'bool' = True, namespace: 'str' = '') -> 'None'
```

Initialize self.  See help(type(self)) for accurate signature.

## `accessors`

```python
accessors(self) -> 'list[Any]'
```

One :class:`~clika_runtime.pytree.PyTreeAccessor` per leaf, in leaf
order: a callable path that fetches the leaf from a tree of this
structure.

## `broadcast_to_common_suffix`

```python
broadcast_to_common_suffix(self, other: 'TreeSpec') -> 'TreeSpec'
```

The smallest spec both this one and ``other`` are prefixes of: at
every position, the deeper of the two structures.

>>> a = pytree.tree_structure([1, (2, 3), 4])
>>> b = pytree.tree_structure([5, 6, (7, 8)])
>>> a.broadcast_to_common_suffix(b)
TreeSpec([*, (*, *), (*, *)])

Raises:
    ValueError: Where the two structures disagree (different node types,
        arities, keys, or contexts at the same position).

## `child`

```python
child(self, index: 'int') -> 'TreeSpec'
```

The spec of the root's ``index``-th child (negative indices count
from the end).

## `children`

```python
children(self) -> 'list[TreeSpec]'
```

The specs of the root's children, in order.

## `compose`

```python
compose(self, inner: 'TreeSpec') -> 'TreeSpec'
```

The spec of a tree with this structure whose every leaf is a tree of
``inner``'s structure.

>>> pytree.tree_structure([1, 2]).compose(pytree.tree_structure((1, 2)))
TreeSpec([(*, *), (*, *)])

## `entries`

```python
entries(self) -> 'list[Any]'
```

The root's child entries: indices for sequences, keys for
dictionaries, the names a custom node's flatten function supplied.

## `entry`

```python
entry(self, index: 'int') -> 'Any'
```

The entry of the root's ``index``-th child.

## `flatten_up_to`

```python
flatten_up_to(self, tree: 'Any') -> 'list[Any]'
```

Flatten ``tree`` only as deep as this spec goes, and return the
subtrees standing where this spec has leaves.

``tree`` must have this spec as a prefix: the same containers, arities
and keys down to this spec's leaves; anything below a leaf is returned
whole. This is how :func:`~clika_runtime.pytree.tree_map` pairs the
leaves of its first tree with the matching subtrees of the rest.

>>> spec = pytree.tree_structure({"a": 1, "b": 2})
>>> spec.flatten_up_to({"a": [1, 2], "b": {"c": 3}})
[[1, 2], {'c': 3}]

Raises:
    ValueError: At the first node whose type, arity, keys, or context
        differs from this spec; the message names that node.

## `is_leaf`

```python
is_leaf(self, *, strict: 'bool' = True) -> 'bool'
```

Whether this spec is a single leaf. With ``strict=False`` a
childless ``None`` node counts too.

## `is_one_level`

```python
is_one_level(self) -> 'bool'
```

Whether the root's children are all leaves (a leaf spec itself is
not one-level).

## `is_prefix`

```python
is_prefix(self, other: 'TreeSpec', *, strict: 'bool' = False) -> 'bool'
```

Whether ``other`` can be built by replacing some of this spec's
leaves with subtrees.

This is the relation multi-tree :func:`~clika_runtime.pytree.tree_map`
needs between its first tree and the rest. Dictionary key order and a
deque ``maxlen`` do not matter here (they do matter to ``==``). With
``strict=True`` the two specs must also differ.

>>> pytree.tree_structure([1, 2]).is_prefix(pytree.tree_structure([1, (2, 3)]))
True

## `is_suffix`

```python
is_suffix(self, other: 'TreeSpec', *, strict: 'bool' = False) -> 'bool'
```

Whether this spec can be built by replacing some of ``other``'s
leaves with subtrees; the reverse of :meth:`is_prefix`.

## `keypaths`

```python
keypaths(self) -> 'list[tuple[Any, ...]]'
```

One key path per leaf, in leaf order (see
:func:`~clika_runtime.pytree.keystr`).

## `one_level`

```python
one_level(self) -> 'TreeSpec | None'
```

This spec's root with every child replaced by a leaf; ``None`` for a
leaf spec.

## `paths`

```python
paths(self) -> 'list[tuple[Any, ...]]'
```

One tuple of entries per leaf, root to leaf, in leaf order.

## `transform`

```python
transform(self, f_node: 'Callable[[TreeSpec], TreeSpec] | None' = None, f_leaf: 'Callable[[TreeSpec], TreeSpec] | None' = None) -> 'TreeSpec'
```

Rebuild the spec node by node.

``f_node`` receives each container as a one-level spec (its children
replaced by leaves) and returns a one-level spec with the same number
of children, which takes its place; ``f_leaf`` receives each leaf spec
and returns any spec, which is spliced in. ``None`` leaves that side
unchanged.

>>> spec = pytree.tree_structure({"a": (1, 2), "b": 3})
>>> spec.transform(lambda s: pytree.treespec_list(s.children()))
TreeSpec([[*, *], *])
>>> spec.transform(f_leaf=lambda s: pytree.tree_structure([1, 2]))
TreeSpec({'a': ([*, *], [*, *]), 'b': [*, *]})

Raises:
    TypeError: If a function returns something other than a TreeSpec.
    ValueError: If a returned spec has a different ``none_is_leaf``, an
        incompatible namespace, or (for ``f_node``) is not one-level
        with the same number of children.

## `traverse`

```python
traverse(self, leaves: 'Iterable[Any]', f_node: 'Callable[[Any], Any] | None' = None, f_leaf: 'Callable[[Any], Any] | None' = None) -> 'Any'
```

Like :meth:`walk`, but ``f_node`` receives each REBUILT container
(children already placed) and returns its replacement.

## `unflatten`

```python
unflatten(self, leaves: 'Iterable[Any]') -> 'Any'
```

Put ``leaves`` back into this structure.

Raises:
    ValueError: If ``leaves`` does not hold exactly :attr:`num_leaves`
        values; the message states both counts.

## `walk`

```python
walk(self, leaves: 'Iterable[Any]', f_node: 'Callable[[builtins.type | None, Any, tuple[Any, ...]], Any] | None' = None, f_leaf: 'Callable[[Any], Any] | None' = None) -> 'Any'
```

Fold the structure bottom-up over ``leaves`` without rebuilding the
containers.

``f_leaf(leaf)`` transforms each leaf (identity when ``None``);
``f_node(node_type, context, children)`` combines a container's
transformed children (``children`` is a tuple) into one value. When
``f_node`` is ``None`` the containers are rebuilt as in
:meth:`unflatten`.

>>> spec = pytree.tree_structure({"a": (1, 2), "b": 3})
>>> spec.walk([1, 2, 3], lambda t, ctx, children: sum(children), lambda x: x * 10)
60

Raises:
    ValueError: If ``leaves`` does not hold exactly :attr:`num_leaves` values.
