API Reference#
nutree.tree module#
Declare the Tree
class.
- MIN_PYTHON_VERSION_INFO = (3, 8)#
Minimal Python version that is supported by WsgiDAV
- class Tree(name: str | None = None, *, factory: Type[Node] | None = None, calc_data_id: Callable[[Tree, Any], str | int] | None = None, shadow_attrs: bool = False)[source]#
Bases:
object
A Tree object is a shallow wrapper around a single, invisible system root node. All visible toplevel nodes are direct children of this root node. Trees expose methods to iterate, search, copy, filter, serialize, etc.
A name string can be passed for enhanced printing.
If a factory is passed, it must be a class that is derived from
Node
and will be used to instantiate node instances.calc_data_id can be a callback function that calculates data IDs from data objects (by default
hash(data)
is used).Set shadow_attrs to true, to enable aliasing of node attributes, i.e. make node.data.NAME accessible as node.NAME.
See Shadow Attributes (Attribute Aliasing).- DEFAULT_CONNECTOR_STYLE = 'round43'#
Default connector prefixes
format(style=...)
argument.
- DEFAULT_KEY_MAP = {'data_id': 'i', 'str': 's'}#
Default value for
save(..., key_map=...)
argument.
- DEFAULT_VALUE_MAP = {}#
Default value for
save(..., value_map=...)
argument.
- __getitem__(data: object) Node [source]#
Implement
tree[data]
syntax to lookup a node.data may be a plain string, data object, data_id, or node_id.
Note: This is a flexible and concise way to access tree nodes. However,
find_all()
orfind_first()
may be faster.AmbiguousMatchError
is raised if multiple matches are found. Usefind_all()
orfind_first()
instead to resolve this.
- __iter__(method: IterMethod = IterMethod.PRE_ORDER) Iterator[Node] #
Implement
for node in tree: ...
syntax to iterate nodes depth-first.
- add(child: Node | Tree | Any, *, before: Node | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) Node #
Alias for
add_child()
- add_child(child: Node | Tree | Any, *, before: Node | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) Node [source]#
Add a toplevel node.
See Node’s
add_child()
method for details.
- calc_data_id(data) str | int [source]#
Called internally to calculate data_id for a data object.
This value is used to lookup nodes by data, identify clones, and for (de)serialization. It defaults to
hash(data)
but may be overloaded when the data objects have meaningful keys that should be used instead.Note: By default, the __hash__() values of str and bytes objects are ‘salted’ with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python.
- property children: list[Node]#
Return list of direct child nodes, i.e. toplevel nodes (list may be empty).
- copy(*, name: str = None, predicate: Callable[[Node], None | bool | IterationControl] = None) Tree [source]#
Return a copy of this tree.
New
Tree
andNode
instances are created. The new nodes reference the original data objects.predicate may be passed to filter the result, which is equivalent to calling
filtered()
See Node’s
copy_to()
and Iteration Callbacks method for details.
- copy_to(target: Node | Tree, *, deep=True) None [source]#
Copy this tree’s nodes to another target.
See Node’s
copy_to()
method for details.
- property count: int#
Return the total number of nodes.
- property count_unique: int#
Return the total number of unique nodes.
Multiple references to the same data object (‘clones’) are only counted once. This is different from
count()
, which returns the number of all nodes.
- static deserialize_mapper(parent: Node, data: dict) str | object | None [source]#
Used as default mapper argument for
load()
.
- diff(other: Tree, *, ordered=False, reduce=False) Tree [source]#
Compare this tree against other and return a merged, annotated copy.
The resulting tree contains a union of all nodes from this and the other tree. Additional metadata is added to the resulting nodes to classify changes from the perspective of this tree. For example a node that only exists in other, will have
node.get_meta("dc") == DiffClassification.ADDED
defined.If ordered is true, changes in the child order are also considered a change.
If reduce is true, unchanged nodes are removed, leaving a compact tree with only the modifications.See Diff and Merge for details.
- filter(predicate: Callable[[Node], None | bool | IterationControl]) None [source]#
In-place removal of unmatching nodes.
See also Iteration Callbacks.
- filtered(predicate: Callable[[Node], None | bool | IterationControl]) Tree [source]#
Return a filtered copy of this tree.
See also Iteration Callbacks.
- find(data=None, *, match=None, data_id=None, node_id=None) Node | None #
Alias for
find_first()
- find_all(data=None, *, match=None, data_id=None, max_results: int = None) list[Node] [source]#
Return a list of matching nodes (list may be empty).
See also Node’s
find_all()
method and Iteration Callbacks.
- find_first(data=None, *, match=None, data_id=None, node_id=None) Node | None [source]#
Return the one matching node or None.
Note that ‘first’ sometimes means ‘one arbitrary’ matching node, which is not neccessarily the first of a specific iteration method. See also Node’s
find_first()
method and Iteration Callbacks.
- format(*, repr=None, style=None, title=None, join='\n') str [source]#
Return a pretty string representation of the tree hierarchy.
See Node’s
format()
method for details.
- format_iter(*, repr=None, style=None, title=None) Iterator[str] [source]#
This variant of
format()
returns a line generator.
- classmethod from_dict(obj: list[dict], *, mapper=None) Tree [source]#
Return a new
Tree
instance from a list of dicts.See also
to_dict_list()
and Node’sfind_first()
methods, and Iteration Callbacks.
- get_random_node() Node [source]#
Return a random node.
Note that there is also IterMethod.RANDOM_ORDER.
- get_toplevel_nodes() list[Node] [source]#
Return list of direct child nodes, i.e. toplevel nodes (may be empty, alias for
children()
).
- iterator(method: IterMethod = IterMethod.PRE_ORDER) Iterator[Node] [source]#
Traverse tree structure and yield nodes.
See Node’s
iterator()
method for details.
- classmethod load(target: IO[str] | str | Path, *, mapper: Callable[[Node, dict], str | object] | None = None, file_meta: dict = None, auto_uncompress: bool = True) Tree [source]#
Create a new
Tree
instance from a file path or JSON file stream.If
file_meta
is a dict, it receives the content if the file’smeta
header.See also
save()
.
- name#
Tree name used for logging
- print(*, repr=None, style=None, title=None, join: str = '\n', file: IO[str] | None = None) None [source]#
Convenience method that simply runs print(self.
format()
).
- save(target: IO[str] | str | Path, *, compression: bool | int = False, mapper: Callable[[Node, dict], None | dict] | None = None, meta: dict | None = None, key_map: Dict[str, str] | bool = True, value_map: Dict[str, List[str]] | bool = True) None [source]#
Store tree in a compact JSON file stream.
If target is a string, it is interpreted as a file path. Otherwise it must be a file object.
If compression is true, the file is compressed using gzip (zipfile.ZIP_DEFLATED). Other values are: zipfile.ZIP_STORED, zipfile.ZIP_BZIP2, zipfile.ZIP_LZMA. Pass False to disable compression and store as plain json.
See also (De)Serialize and
to_list_iter()
andload()
methods.
- serialize_mapper(node: Node, data: dict) dict | None [source]#
Used as default mapper argument for
save()
.
- sort(*, key=None, reverse=False, deep=True) None [source]#
Sort toplevel nodes (optionally recursively).
key defaults to
attrgetter("name")
, so children are sorted by their string representation.
- property system_root: _SystemRootNode#
- to_dict_list(*, mapper: Callable[[Node, dict], None | dict] | None = None) list[dict] [source]#
Call Node’s
to_dict()
method for all child nodes and return list of results.
- to_dot(*, add_root=True, unique_nodes=True, graph_attrs=None, node_attrs=None, edge_attrs=None, node_mapper=None, edge_mapper=None) Iterator[str] [source]#
Generate a DOT formatted graph representation.
See Node’s
to_dot()
method for details.
- to_dotfile(target: IO[str] | str | Path, *, format=None, add_root=True, unique_nodes=True, graph_attrs=None, node_attrs=None, edge_attrs=None, node_mapper=None, edge_mapper=None)[source]#
Serialize a DOT formatted graph representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- to_list_iter(*, mapper: Callable[[Node, dict], None | dict] | None = None, key_map: Dict[str, str] | None = None, value_map: Dict[str, List[str]] | None = None) Iterator[dict] [source]#
Yield a parent-referencing list of child nodes.
- to_mermaid_flowchart(target: IO[str] | str | Path, *, as_markdown: bool = True, direction: Literal['LR', 'RL', 'TB', 'TD', 'BT'] = 'TD', title: str | bool | None = True, format: Literal['svg', 'pdf', 'png'] | None = None, mmdc_options: dict | None = None, add_root: bool = True, unique_nodes: bool = True, headers: Iterable[str] | None = None, node_mapper: Callable[[Node], str] | None = None, edge_mapper: Callable[[int, Node, int, Node], str] | None = None) Iterator[str] [source]#
Serialize a Mermaid flowchart representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- visit(callback: TraversalCallbackType, *, method=IterMethod.PRE_ORDER, memo=None) Any | None [source]#
Call callback(node, memo) for all nodes.
See Node’s
visit()
method and Iteration Callbacks for details.
nutree.node module#
Declare the Node
class.
- class Node(data, *, parent: Node, data_id: str | int | None = None, node_id: int | None = None, meta: dict = None)[source]#
Bases:
object
A Node represents a single element in the tree. It is a shallow wrapper around a user data instance, that adds navigation, modification, and other functionality.
Node objects are rarely created using this contructor, but indirectly by invoking helper methods like
add_child()
, etc.- data
is the arbitrary object that this node will hold.
- parent
is the parent
Node()
instance. This node will also inherit the tree reference from it.- data_id
is an optional integer or string that will be used as ID (instead of calculating
hash(data)
). A tree may contain more than one node with the same data and data_id. In this case we call the nodes ‘clones’.- node_id
is an optional integer, that is used as unique ID for this node. Even ‘clones’ must have unique node IDs. The default is calculated as id(self).
- meta
is an optional dictionary. See also
get_meta()
,set_meta()
,update_meta()
, andclear_meta()
.
- DEFAULT_RENDER_REPR = '{node.data!r}'#
Default value for
repr
argument when formatting data for print/display.
- __eq__(other) bool [source]#
Implement
node == other
syntax to compare embedded data.If other is a
Node
instance,self.data == other.data
is evaluated. Otherwiseself.data == other
is compared.Use
node is other
syntax instead to check if two nodes are truly identical.
- __iter__(method=IterMethod.PRE_ORDER, *, add_self=False) Iterator[Node] #
Implement
for subnode in node: ...
syntax to iterate descendant nodes.
- add(child: Node | Tree | Any, *, before: Node | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) Node #
Alias for
add_child()
- add_child(child: Node | Tree | Any, *, before: Node | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) Node [source]#
Append or insert a new subnode or branch as child.
If child is an existing
Node
instance, a copy of this node will be created, that references the same child.data object.
If deep is true, the children are copied recursively.If child is a
Tree
, all of its topnodes are added recursively (unless deep is false).If child is neither a
Node
nor aTree
, child itself will become the data object of a new node that is added.The source node may come from the same or from a foreign tree.
Note that adding the same data below one parent is not allowed.If this node has no children yet, the new node is created as first child. Otherwise, it will be appended to the existing children by default.
The before option may be used to specifiy the position:False, None: append the new node as last child
True, 0: prepend the new node as first child
<int>: prepend the new node before the existing child with this index
<Node>: prepend the new node before this child node
- Parameters:
child (Node|Tree|Any) – Either an existing Node or a data object.
before (bool|int|Node|None) – Optional position.
deep (bool) – Copy descendants if any. This argument defaults to false when child is a
Node
. It defaults to true when child is aTree
.data_id (str|int|None) – Allow to override the new node’s data_id. This argument is only allowed for single nodes, but not for deep copies. Default None will to calculate from
hash(node.data)
.node_id (str|int|None) – Optional custom unique node key (defaults to
id(node)
) This argument is only allowed for single nodes, but not for deep copies.
- Returns:
the new
Node
instance
- append_child(child: Node | Tree | Any, *, deep=None, data_id=None, node_id=None)[source]#
Append a new subnode.
This is a shortcut for
add_child()
withbefore=None
.
- append_sibling(child: Node | Tree | Any, *, deep=None, data_id=None, node_id=None) Node [source]#
Add a new node after self.
This method calls
add_child()
onself.parent
.
- copy(*, add_self=True, predicate: PredicateCallbackType = None) Tree [source]#
Return a new
Tree
instance from this branch.See also Iteration Callbacks.
- copy_to(target: Node | Tree, *, add_self=True, before: Node | bool | int | None = None, deep: bool = False) Node [source]#
Copy this node to another parent and return the new node.
If add_self is set, a copy of this node becomes a child of target. Otherwise copies of all children of this node are created below target.
By default new nodes are appended to existing children. The before argument defines an alternative positioning. It is only available when add_self is true. See
add_child()
for a description of before.If deep is set, all descendants are copied recursively.
- count_descendants(*, leaves_only=False) int [source]#
Return number of descendant nodes, not counting self.
- property data: Any#
Return the wrapped data instance (use
set_data()
to modify).
- property data_id: str | int#
Return the wrapped data instance’s id (use
set_data()
to modify).
- filter(predicate: Callable[[Node], None | bool | IterationControl]) None [source]#
In-place removal of mismatching nodes.
See also Iteration Callbacks.
- filtered(predicate: PredicateCallbackType) Tree [source]#
Return a filtered copy of this node and descendants as tree.
See also Iteration Callbacks.
- find(data=None, *, match=None, data_id=None) Node | None #
Alias for
find_first()
- find_all(data=None, *, match=None, data_id=None, add_self=False, max_results=None) list[Node] [source]#
Return a list of matching nodes (list may be empty).
See also Iteration Callbacks.
- find_first(data=None, *, match=None, data_id=None) Node | None [source]#
Return the first matching node or None.
See also Iteration Callbacks.
- format(*, repr=None, style=None, add_self=True, join='\n') str [source]#
Return a pretty string representation of the node hierarchy.
more
- Parameters:
repr (str) – A string or callback that defines how the node is rendered after the connector prefixes are generated.
style (str) – A string that defines the connector type, e.g. “round42” will produce “│ “, “╰─”, “├─”.
add_self (bool) – If false, only the descendants of this node are formatted.
join (str) – A string that is used to terminate the single lines. Defaults to “n”, but may be set to “, “ together with style=”list” to create a single line output.
Example
print(node.format(repr=”{node.name}”, style=”round42”))
- format_iter(*, repr=None, style=None, add_self=True) Iterator[str] [source]#
This variant of
format()
returns a line generator.
- from_dict(obj: list[dict], *, mapper: Callable[[Node, dict], str | object] | None = None) None [source]#
Append copies of all source children to self.
- get_clones(*, add_self=False) list[Node] [source]#
Return a list of all nodes that reference the same data if any.
- get_common_ancestor(other: Node) Node | None [source]#
Return the nearest node that contains self and other (may be None).
- get_parent_list(*, add_self=False, bottom_up=False) list[Node] [source]#
Return ordered list of all parent nodes.
- get_path(*, add_self=True, separator='/', repr='{node.name}') str [source]#
Return a breadcrumb string, e.g. ‘/A/a1/a12’.
- get_siblings(*, add_self=False) list[Node] [source]#
Return a list of all sibling entries of self (excluding self) if any.
- is_ancestor_of(other: Node) bool [source]#
Return true if this node is a parent, grandparent, … of other.
- is_descendant_of(other: Node) bool [source]#
Return true if this node is direct or indirect child of other.
- is_first_sibling() bool [source]#
Return true if this node is the first sibling, i.e. the first child of its parent.
- is_last_sibling() bool [source]#
Return true if this node is the last sibling, i.e. the last child of its parent.
- is_system_root() bool [source]#
Return true if this node is the invisible system root
_SystemRootNode
.
- iterator(method=IterMethod.PRE_ORDER, *, add_self=False) Iterator[Node] [source]#
Generator that walks the hierarchy.
- property meta: dict | None#
Return the node’s metadata dictionary or None if empty.
See also
get_meta()
,set_meta()
,update_meta()
,clear_meta()
.
- move_to(new_parent: Node | Tree, *, before: Node | bool | int | None = None)[source]#
Move this node to another parent.
By default, the node is appended to existing children. See
add_child()
for a description of before.
- property name: str#
String representation of the embedded data object.
- property node_id: int#
Return the node’s unique key.
- property path: str#
All ancestor names including self, starting with and separated by ‘/’.
- prepend_child(child: Node | Tree | Any, *, deep=None, data_id=None, node_id=None)[source]#
Prepend a new subnode.
This is a shortcut for
add_child()
withbefore=True
.
- prepend_sibling(child: Node | Tree | Any, *, deep=None, data_id=None, node_id=None) Node [source]#
Add a new node before self.
This method calls
add_child()
onself.parent
.
- remove(*, keep_children=False, with_clones=False) None [source]#
Remove this node.
If keep_children is true, all children will be moved one level up, so they become siblings, before this node is removed.
If with_clones is true, all nodes that reference the same data instance are removed as well.
- set_data(data, *, data_id=None, with_clones: bool = None) None [source]#
Change node’s data and/or data_id and update bookkeeping.
- sort_children(*, key=None, reverse=False, deep=False) None [source]#
Sort child nodes.
key defaults to
attrgetter("name")
, so children are sorted by their string representation.
- to_dict(*, mapper: Callable[[Node, dict], None | dict] | None = None) dict [source]#
Return a nested dict of this node and its children.
- to_dot(*, add_self=False, unique_nodes=True, graph_attrs: dict = None, node_attrs: dict = None, edge_attrs: dict = None, node_mapper: Callable[[Node, dict], None | Any] = None, edge_mapper: Callable[[Node, dict], None | Any] = None) Iterator[str] [source]#
Generate a DOT formatted graph representation.
See Graphs for details.
- to_list_iter(*, mapper: Callable[[Node, dict], None | dict] | None = None, key_map: Dict[str, str] | None = None, value_map: Dict[str, List[str]] | None = None) Iterator[dict] [source]#
Yield children as parent-referencing list.
`py [(parent_key, data)] `
- to_mermaid_flowchart(target: IO[str] | str | Path, *, as_markdown: bool = True, direction: Literal['LR', 'RL', 'TB', 'TD', 'BT'] = 'TD', title: str | bool | None = True, format: Literal['svg', 'pdf', 'png'] | None = None, mmdc_options: dict | None = None, add_self: bool = True, unique_nodes: bool = True, headers: Iterable[str] | None = None, node_mapper: Callable[[Node], str] | None = None, edge_mapper: Callable[[int, Node, int, Node], str] | None = None) None [source]#
Serialize a Mermaid flowchart representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- to_rdf_graph(*, add_self: bool = True, node_mapper: Callable[[None, None, Node], None | bool] = None)[source]#
Return an instance of
rdflib.Graph
.See Graphs for details.
- update_meta(values: dict, *, replace: bool = False) None [source]#
Add values dict to current metadata.
If replace is true, previous metatdata will be cleared.
- visit(callback: Callable[[Node, Any], None | bool | StopTraversal | SkipBranch], *, add_self=False, method=IterMethod.PRE_ORDER, memo=None) None | Any [source]#
Call callback(node, memo) for all subnodes.
The callback may return
SkipBranch
(or an instance thereof) to omit child nodes but continue traversal otherwise. Raising SkipBranch has the same effect.The callback may return
False
orStopIteration
to immediately interrupt traversal. Raising StopTraversal(value) has the same effect but also allows to specify a return value for the visit method.
See also Iteration Callbacks.- Parameters:
callback (function(node, memo)) – Callback
function(node, memo)
add_self (bool) – If true, this node will also be visited (typically as first call).
method (IterMethod) – Traversal method, defaults to pre-order, depth-first search.
memo (Any) – This value will be passed to all calls and may be useful to implement caching or collect and return traversal results. If no memo argument is passed, an empty dict is created at start, which has a life-span of the traversal only.
nutree.typed_tree module#
Declare the TypedTree
class.
- class ANY_KIND[source]#
Bases:
object
Special argument value for some methods that access child nodes.
- class TypedNode(kind: str, data, *, parent: TypedNode, data_id=None, node_id=None, meta: dict = None)[source]#
Bases:
Node
A special node variant, derived from
Node
and used byTypedTree
.In addition to
Node
, we have a kind member to define the node’s type.- DEFAULT_RENDER_REPR = '{node.kind} → {node.data}'#
Default value for
repr
argument when formatting data for print/display.
- __eq__(other) bool #
Implement
node == other
syntax to compare embedded data.If other is a
Node
instance,self.data == other.data
is evaluated. Otherwiseself.data == other
is compared.Use
node is other
syntax instead to check if two nodes are truly identical.
- __getattr__(name: str) Any #
Implement
node.NAME
aliasing tonode.data.NAME
.
- __iter__(method=IterMethod.PRE_ORDER, *, add_self=False) Iterator[Node] #
Implement
for subnode in node: ...
syntax to iterate descendant nodes.
- add(child: TypedNode | TypedTree | Any, *, kind: str = None, before: TypedNode | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) TypedNode #
Alias for
add_child()
- add_child(child: TypedNode | TypedTree | Any, *, kind: str = None, before: TypedNode | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) TypedNode [source]#
See …
- append_child(child: TypedNode | TypedTree | Any, *, kind: str = None, deep=None, data_id=None, node_id=None)[source]#
Append a new subnode.
This is a shortcut for
add_child()
withbefore=None
.
- append_sibling(child: TypedNode | TypedTree | Any, *, deep=None, data_id=None, node_id=None) TypedNode [source]#
Add a new node of same kind after self.
This method calls
add_child()
onself.parent
.
- calc_depth() int #
Return the distance to the root node (1 for toplevel nodes).
- calc_height() int #
Return the maximum depth of all descendants (0 for leaves).
- property children: list[TypedNode]#
Return list of direct child nodes (list may be empty).
Note that this property returns all children, independent of the kind. See also
get_children()
.
- clear_meta(key: str = None) None #
Reset all metadata or a distinct entry.
- copy(*, add_self=True, predicate=None) TypedTree [source]#
Return a new
TypedTree
instance from this branch.See also
_add_from()
and Iteration Callbacks.
- copy_to(target: Node | Tree, *, add_self=True, before: Node | bool | int | None = None, deep: bool = False) Node #
Copy this node to another parent and return the new node.
If add_self is set, a copy of this node becomes a child of target. Otherwise copies of all children of this node are created below target.
By default new nodes are appended to existing children. The before argument defines an alternative positioning. It is only available when add_self is true. See
add_child()
for a description of before.If deep is set, all descendants are copied recursively.
- count_descendants(*, leaves_only=False) int #
Return number of descendant nodes, not counting self.
- property data: Any#
Return the wrapped data instance (use
set_data()
to modify).
- property data_id: str | int#
Return the wrapped data instance’s id (use
set_data()
to modify).
- depth() int #
Return the distance to the root node (1 for toplevel nodes).
- filter(predicate: Callable[[Node], None | bool | IterationControl]) None #
In-place removal of mismatching nodes.
See also Iteration Callbacks.
- filtered(predicate: Callable[[Node], None | bool | IterationControl]) TypedTree [source]#
Return a filtered copy of this node and descendants as tree.
See also Iteration Callbacks.
- find(data=None, *, match=None, data_id=None) Node | None #
Return the first matching node or None.
See also Iteration Callbacks.
- find_all(data=None, *, match=None, data_id=None, add_self=False, max_results=None) list[Node] #
Return a list of matching nodes (list may be empty).
See also Iteration Callbacks.
- find_first(data=None, *, match=None, data_id=None) Node | None #
Return the first matching node or None.
See also Iteration Callbacks.
- first_child(kind: str | ANY_KIND) TypedNode | None [source]#
First direct child node or None if no children exist.
- first_sibling(*, any_kind=False) TypedNode [source]#
Return first sibling of the same kind (may be self).
- format(*, repr=None, style=None, add_self=True, join='\n') str #
Return a pretty string representation of the node hierarchy.
more
- Parameters:
repr (str) – A string or callback that defines how the node is rendered after the connector prefixes are generated.
style (str) – A string that defines the connector type, e.g. “round42” will produce “│ “, “╰─”, “├─”.
add_self (bool) – If false, only the descendants of this node are formatted.
join (str) – A string that is used to terminate the single lines. Defaults to “n”, but may be set to “, “ together with style=”list” to create a single line output.
Example
print(node.format(repr=”{node.name}”, style=”round42”))
- format_iter(*, repr=None, style=None, add_self=True) Iterator[str] #
This variant of
format()
returns a line generator.
- from_dict(obj: list[dict], *, mapper: Callable[[Node, dict], str | object] | None = None) None #
Append copies of all source children to self.
- get_children(kind: str | ANY_KIND) list[TypedNode] [source]#
Return list of direct child nodes of a given type (list may be empty).
- get_clones(*, add_self=False) list[Node] #
Return a list of all nodes that reference the same data if any.
- get_common_ancestor(other: Node) Node | None #
Return the nearest node that contains self and other (may be None).
- get_meta(key: str, default=None) Any #
Return metadata value.
- get_parent_list(*, add_self=False, bottom_up=False) list[Node] #
Return ordered list of all parent nodes.
- get_path(*, add_self=True, separator='/', repr='{node.name}') str #
Return a breadcrumb string, e.g. ‘/A/a1/a12’.
- get_siblings(*, add_self=False, any_kind=False) list[TypedNode] [source]#
Return a list of all sibling entries of self (excluding self) if any.
- has_children(kind: str | ANY_KIND) bool [source]#
Return true if this node has one or more children.
- is_clone() bool #
Return true if this node’s data is referenced at least one more time.
- is_first_sibling(*, any_kind=False) bool [source]#
Return true if this node is the first sibling, i.e. the first child of its parent.
- is_last_sibling(*, any_kind=False) bool [source]#
Return true if this node is the last sibling, i.e. the last child of this kind of its parent.
- is_leaf() bool #
Return true if this node is an end node, i.e. has no children.
- is_system_root() bool #
Return true if this node is the invisible system root
_SystemRootNode
.
- is_top() bool #
Return true if this node has no parent.
- iterator(method=IterMethod.PRE_ORDER, *, add_self=False) Iterator[Node] [source]#
Generator that walks the hierarchy.
- property kind: str#
- last_child(kind: str | ANY_KIND) TypedNode | None [source]#
Last direct child node or None if no children exist.
- last_sibling(*, any_kind=False) TypedNode [source]#
Return last sibling of the same kind (may be self).
- property meta: dict | None#
Return the node’s metadata dictionary or None if empty.
See also
get_meta()
,set_meta()
,update_meta()
,clear_meta()
.
- move_to(new_parent: TypedNode | TypedTree, *, before: TypedNode | bool | int | None = None)[source]#
Move this node before or after new_parent.
- property name: str#
String representation of the embedded data object.
- next_sibling(*, any_kind=False) TypedNode | None [source]#
Return successor of the same kind or None if node is last sibling.
- property node_id: int#
Return the node’s unique key.
- property path: str#
All ancestor names including self, starting with and separated by ‘/’.
- prepend_child(child: TypedNode | TypedTree | Any, *, kind: str = None, deep=None, data_id=None, node_id=None)[source]#
Prepend a new subnode.
This is a shortcut for
add_child()
withbefore=True
.
- prepend_sibling(child: TypedNode | TypedTree | Any, *, deep=None, data_id=None, node_id=None) TypedNode [source]#
Add a new node of same kind before self.
This method calls
add_child()
onself.parent
.
- prev_sibling(*, any_kind=False) TypedNode | None [source]#
Return predecessor of the same kind or None if node is first sibling.
- remove(*, keep_children=False, with_clones=False) None #
Remove this node.
If keep_children is true, all children will be moved one level up, so they become siblings, before this node is removed.
If with_clones is true, all nodes that reference the same data instance are removed as well.
- remove_children() None #
Remove all children of this node, making it a leaf node.
- rename(new_name: str) None #
Set self.data to a new string (assuming plain string node).
- set_data(data, *, data_id=None, with_clones: bool = None) None #
Change node’s data and/or data_id and update bookkeeping.
- set_meta(key: str, value) None #
Set metadata value (pass value None to remove).
- sort_children(*, key=None, reverse=False, deep=False) None #
Sort child nodes.
key defaults to
attrgetter("name")
, so children are sorted by their string representation.
- to_dict(*, mapper: Callable[[Node, dict], None | dict] | None = None) dict #
Return a nested dict of this node and its children.
- to_dot(*, add_self=False, unique_nodes=True, graph_attrs: dict = None, node_attrs: dict = None, edge_attrs: dict = None, node_mapper: Callable[[Node, dict], None | Any] = None, edge_mapper: Callable[[Node, dict], None | Any] = None) Iterator[str] [source]#
Generate a DOT formatted graph representation.
See Graphs for details.
- to_list_iter(*, mapper: Callable[[Node, dict], None | dict] | None = None, key_map: Dict[str, str] | None = None, value_map: Dict[str, List[str]] | None = None) Iterator[dict] #
Yield children as parent-referencing list.
`py [(parent_key, data)] `
- to_mermaid_flowchart(target: IO[str] | str | Path, *, as_markdown: bool = True, direction: Literal['LR', 'RL', 'TB', 'TD', 'BT'] = 'TD', title: str | bool | None = True, format: Literal['svg', 'pdf', 'png'] | None = None, mmdc_options: dict | None = None, add_self: bool = True, unique_nodes: bool = True, headers: Iterable[str] | None = None, node_mapper: Callable[[Node], str] | None = None, edge_mapper: Callable[[int, Node, int, Node], str] | None = None) None #
Serialize a Mermaid flowchart representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- to_rdf_graph(*, add_self: bool = True, node_mapper: Callable[[None, None, Node], None | bool] = None)#
Return an instance of
rdflib.Graph
.See Graphs for details.
- update_meta(values: dict, *, replace: bool = False) None #
Add values dict to current metadata.
If replace is true, previous metatdata will be cleared.
- visit(callback: Callable[[Node, Any], None | bool | StopTraversal | SkipBranch], *, add_self=False, method=IterMethod.PRE_ORDER, memo=None) None | Any #
Call callback(node, memo) for all subnodes.
The callback may return
SkipBranch
(or an instance thereof) to omit child nodes but continue traversal otherwise. Raising SkipBranch has the same effect.The callback may return
False
orStopIteration
to immediately interrupt traversal. Raising StopTraversal(value) has the same effect but also allows to specify a return value for the visit method.
See also Iteration Callbacks.- Parameters:
callback (function(node, memo)) – Callback
function(node, memo)
add_self (bool) – If true, this node will also be visited (typically as first call).
method (IterMethod) – Traversal method, defaults to pre-order, depth-first search.
memo (Any) – This value will be passed to all calls and may be useful to implement caching or collect and return traversal results. If no memo argument is passed, an empty dict is created at start, which has a life-span of the traversal only.
- class TypedTree(name: str | None = None, *, factory: Type[Node] | None = None, calc_data_id: Callable[[Tree, Any], str | int] | None = None, shadow_attrs: bool = False)[source]#
Bases:
Tree
A special tree variant, derived from
Tree
, that usesTypedNode
objects, which maintain an addition kind attribute.See Typed Tree for details.
- DEFAULT_CHILD_TYPE = 'child'#
Default value for
add_child
when loading.
- DEFAULT_CONNECTOR_STYLE = 'round43'#
Default connector prefixes
format(style=...)
argument.
- DEFAULT_KEY_MAP = {'data_id': 'i', 'kind': 'k', 'str': 's'}#
Default value for
key_map
argument when saving
- DEFAULT_VALUE_MAP = {}#
Default value for
value_map
argument when saving
- __contains__(data)#
Implement
data in tree
syntax to check for node existence.
- __delitem__(data)#
Implement
del tree[data]
syntax to remove nodes.
- __enter__()#
Implement
with tree: ...
syntax to acquire an RLock.
- __iter__(method: IterMethod = IterMethod.PRE_ORDER) Iterator[Node] #
Traverse tree structure and yield nodes.
See Node’s
iterator()
method for details.
- __len__()#
Make
len(tree)
return the number of nodes (also makes empty trees falsy).
- add(child: TypedNode | TypedTree | Any, *, kind: str = None, before: TypedNode | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) TypedNode #
Alias for
add_child()
- add_child(child: TypedNode | TypedTree | Any, *, kind: str = None, before: TypedNode | bool | int | None = None, deep: bool = None, data_id=None, node_id=None) TypedNode [source]#
Add a toplevel node.
See Node’s
add_child()
method for details.
- calc_data_id(data) str | int #
Called internally to calculate data_id for a data object.
This value is used to lookup nodes by data, identify clones, and for (de)serialization. It defaults to
hash(data)
but may be overloaded when the data objects have meaningful keys that should be used instead.Note: By default, the __hash__() values of str and bytes objects are ‘salted’ with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python.
- calc_height() int #
Return the maximum depth of all nodes.
- property children: list[Node]#
Return list of direct child nodes, i.e. toplevel nodes (list may be empty).
- clear() None #
Remove all nodes from this tree.
- copy(*, name: str = None, predicate: Callable[[Node], None | bool | IterationControl] = None) Tree #
Return a copy of this tree.
New
Tree
andNode
instances are created. The new nodes reference the original data objects.predicate may be passed to filter the result, which is equivalent to calling
filtered()
See Node’s
copy_to()
and Iteration Callbacks method for details.
- copy_to(target: Node | Tree, *, deep=True) None #
Copy this tree’s nodes to another target.
See Node’s
copy_to()
method for details.
- property count: int#
Return the total number of nodes.
- property count_unique: int#
Return the total number of unique nodes.
Multiple references to the same data object (‘clones’) are only counted once. This is different from
count()
, which returns the number of all nodes.
- static deserialize_mapper(parent: Node, data: dict) str | object | None [source]#
Used as default mapper argument for
load()
.
- diff(other: Tree, *, ordered=False, reduce=False) Tree #
Compare this tree against other and return a merged, annotated copy.
The resulting tree contains a union of all nodes from this and the other tree. Additional metadata is added to the resulting nodes to classify changes from the perspective of this tree. For example a node that only exists in other, will have
node.get_meta("dc") == DiffClassification.ADDED
defined.If ordered is true, changes in the child order are also considered a change.
If reduce is true, unchanged nodes are removed, leaving a compact tree with only the modifications.See Diff and Merge for details.
- filter(predicate: Callable[[Node], None | bool | IterationControl]) None #
In-place removal of unmatching nodes.
See also Iteration Callbacks.
- filtered(predicate: Callable[[Node], None | bool | IterationControl]) Tree #
Return a filtered copy of this tree.
See also Iteration Callbacks.
- find(data=None, *, match=None, data_id=None, node_id=None) Node | None #
Return the one matching node or None.
Note that ‘first’ sometimes means ‘one arbitrary’ matching node, which is not neccessarily the first of a specific iteration method. See also Node’s
find_first()
method and Iteration Callbacks.
- find_all(data=None, *, match=None, data_id=None, max_results: int = None) list[Node] #
Return a list of matching nodes (list may be empty).
See also Node’s
find_all()
method and Iteration Callbacks.
- find_first(data=None, *, match=None, data_id=None, node_id=None) Node | None #
Return the one matching node or None.
Note that ‘first’ sometimes means ‘one arbitrary’ matching node, which is not neccessarily the first of a specific iteration method. See also Node’s
find_first()
method and Iteration Callbacks.
- format(*, repr=None, style=None, title=None, join='\n') str #
Return a pretty string representation of the tree hierarchy.
See Node’s
format()
method for details.
- format_iter(*, repr=None, style=None, title=None) Iterator[str] #
This variant of
format()
returns a line generator.
- classmethod from_dict(obj: list[dict], *, mapper=None) Tree #
Return a new
Tree
instance from a list of dicts.See also
to_dict_list()
and Node’sfind_first()
methods, and Iteration Callbacks.
- get_toplevel_nodes() list[Node] #
Return list of direct child nodes, i.e. toplevel nodes (may be empty, alias for
children()
).
- iterator(method: IterMethod = IterMethod.PRE_ORDER) Iterator[Node] #
Traverse tree structure and yield nodes.
See Node’s
iterator()
method for details.
- classmethod load(target: IO[str] | str | Path, *, mapper: Callable[[Node, dict], str | object] | None = None, file_meta: dict = None) TypedTree [source]#
Create a new
TypedTree
instance from a JSON file stream.
- name#
Tree name used for logging
- print(*, repr=None, style=None, title=None, join: str = '\n', file: IO[str] | None = None) None #
Convenience method that simply runs print(self.
format()
).
- save(target: IO[str] | str | Path, *, mapper: Callable[[Node, dict], None | dict] | None = None, meta: dict | None = None, key_map: Dict[str, str] | bool = True, value_map: Dict[str, List[str]] | bool = True) None [source]#
Store tree in a compact JSON file stream.
See also (De)Serialize and
to_list_iter()
andload()
methods.
- sort(*, key=None, reverse=False, deep=True) None #
Sort toplevel nodes (optionally recursively).
key defaults to
attrgetter("name")
, so children are sorted by their string representation.
- property system_root: _SystemRootNode#
- to_dict_list(*, mapper: Callable[[Node, dict], None | dict] | None = None) list[dict] #
Call Node’s
to_dict()
method for all child nodes and return list of results.
- to_dot(*, add_root=True, unique_nodes=True, graph_attrs=None, node_attrs=None, edge_attrs=None, node_mapper=None, edge_mapper=None) Iterator[str] #
Generate a DOT formatted graph representation.
See Node’s
to_dot()
method for details.
- to_dotfile(target: IO[str] | str | Path, *, format=None, add_root=True, unique_nodes=True, graph_attrs=None, node_attrs=None, edge_attrs=None, node_mapper=None, edge_mapper=None)#
Serialize a DOT formatted graph representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- to_list_iter(*, mapper: Callable[[Node, dict], None | dict] | None = None, key_map: Dict[str, str] | None = None, value_map: Dict[str, List[str]] | None = None) Iterator[dict] #
Yield a parent-referencing list of child nodes.
- to_mermaid_flowchart(target: IO[str] | str | Path, *, as_markdown: bool = True, direction: Literal['LR', 'RL', 'TB', 'TD', 'BT'] = 'TD', title: str | bool | None = True, format: Literal['svg', 'pdf', 'png'] | None = None, mmdc_options: dict | None = None, add_root: bool = True, unique_nodes: bool = True, headers: Iterable[str] | None = None, node_mapper: Callable[[Node], str] | None = None, edge_mapper: Callable[[int, Node, int, Node], str] | None = None) Iterator[str] #
Serialize a Mermaid flowchart representation.
Optionally convert to a Graphviz display formats. See Graphs for details.
- visit(callback: TraversalCallbackType, *, method=IterMethod.PRE_ORDER, memo=None) Any | None #
Call callback(node, memo) for all nodes.
See Node’s
visit()
method and Iteration Callbacks for details.
nutree.common module#
Functions and declarations used by the nutree.tree
and nutree.node
modules.
- exception AmbiguousMatchError[source]#
Bases:
TreeError
Thrown when a single-value lookup found multiple matches.
- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- CONNECTORS = {'ascii11': (' ', '|', '`', '-'), 'ascii21': (' ', '| ', '` ', '- '), 'ascii22': (' ', '| ', '`-', '+-'), 'ascii32': (' ', '| ', '`- ', '+- '), 'ascii42': (' ', ' | ', ' `- ', ' +- '), 'ascii43': (' ', '| ', '`-- ', '+-- '), 'lines11': (' ', '│', '└', '├'), 'lines21': (' ', '│ ', '└ ', '├ '), 'lines22': (' ', '│ ', '└─', '├─'), 'lines32': (' ', '│ ', '└─ ', '├─ '), 'lines32c': (' ', '│', '└─ ', '├─ ', '└┬ ', '├┬ '), 'lines42': (' ', ' │ ', ' └─ ', ' ├─ '), 'lines43': (' ', '│ ', '└── ', '├── '), 'lines43c': (' ', '│ ', '└── ', '├── ', '└─┬ ', '├─┬ '), 'lines43r': (' ', ' │ ', ' └──', ' ├──'), 'round11': (' ', '│', '╰', '├'), 'round21': (' ', '│ ', '╰ ', '├ '), 'round22': (' ', '│ ', '╰─', '├─'), 'round32': (' ', '│ ', '╰─ ', '├─ '), 'round32c': (' ', '│', '╰─ ', '├─ ', '╰┬ ', '├┬ '), 'round42': (' ', ' │ ', ' ╰─ ', ' ├─ '), 'round43': (' ', '│ ', '╰── ', '├── '), 'round43c': (' ', '│ ', '╰── ', '├── ', '╰─┬ ', '├─┬ '), 'round43r': (' ', ' │ ', ' ╰──', ' ├──'), 'space1': (' ', ' ', ' ', ' '), 'space2': (' ', ' ', ' ', ' '), 'space3': (' ', ' ', ' ', ' '), 'space4': (' ', ' | ', ' ', ' ')}#
Node connector prefixes, for use with
format(style=...)
argument.
- CalcIdCallbackType#
Type of
Tree(..., calc_data_id)`
alias of
Callable
[[Tree
,Any
],Union
[str
,int
]]
- DataIdType#
Type of
Node.data_id
alias of
Union
[str
,int
]
- DeserializeMapperType#
Callback for tree.load()
alias of
Callable
[[Node
,dict
],Union
[str
,object
]]
- FILE_FORMAT_VERSION: str = '1.0'#
File format version used by tree.save() as meta.$format_version
- class IterMethod(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]#
Bases:
Enum
Traversal order.
- LEVEL_ORDER = 'level'#
Breadth-first (aka level-order)
- LEVEL_ORDER_RTL = 'level_rtl'#
Breadth-first (aka level-order) right-to-left
- POST_ORDER = 'post'#
Depth-first, post-order
- PRE_ORDER = 'pre'#
Depth-first, pre-order
- RANDOM_ORDER = 'random'#
Random order traversal
- UNORDERED = 'unordered'#
Fastest traversal in unpredictable order. It may appear to be the order of node insertion, but do not rely on this!
- ZIGZAG = 'zigzag'#
ZigZag order
- ZIGZAG_RTL = 'zigzag_rtl'#
ZigZag order
- classmethod __contains__(member)#
Return True if member is a member of this enum raises TypeError if member is not an enum member
note: in 3.12 TypeError will no longer be raised, and True will also be returned if member is the value of a member in this enum
- classmethod __getitem__(name)#
Return the member matching name.
- classmethod __iter__()#
Return members in definition order.
- classmethod __len__()#
Return the number of members (no aliases)
- exception IterationControl[source]#
Bases:
Exception
Common base class for tree iteration controls.
- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- KeyMapType#
Type of
tree.save(..., key_map)
alias of
Dict
[str
,str
]
- MapperCallbackType#
alias of
Callable
[[Node
,dict
],Union
[None
,Any
]]
- NodeFactoryType#
Type of
Tree(..., factory)`
alias of
Type
[Node
]
- PYTHON_VERSION = '3.11.6'#
Currently used Python version as string
- PredicateCallbackType#
alias of
Callable
[[Node
],Union
[None
,bool
,IterationControl
]]
- ROOT_ID: str = '__root__'#
Used as ID for the system root node
- exception SelectBranch[source]#
Bases:
IterationControl
Raised or returned by traversal callbacks to unconditionally accept all descendants.
- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- SerializeMapperType#
Callback for tree.save()
alias of
Callable
[[Node
,dict
],Union
[None
,dict
]]
- exception SkipBranch(*, and_self=None)[source]#
Bases:
IterationControl
Raised or returned by traversal callbacks to skip the current node’s descendants.
If and_self is true, some iterators will consider the node itself, but still skip the descendants. For example
copy()
andfind_all()
. If and_self is false, some iterators will consider the node’s children only.- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- exception StopTraversal(value=None)[source]#
Bases:
IterationControl
Raised or returned by traversal callbacks to stop iteration.
Optionally, a return value may be passed. Note that if a callback returns
False
, this will be converted to anStopTraversal(None)
exception.- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- exception TreeError[source]#
Bases:
RuntimeError
Base class for all nutree errors.
- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- exception UniqueConstraintError[source]#
Bases:
TreeError
Thrown when trying to add the same node_id to the same parent
- add_note()#
Exception.add_note(note) – add a note to the exception
- args#
- ValueMapType#
Type of
tree.save(..., value_map)
alias of
Dict
[str
,List
[str
]]
- call_mapper(fn: MapperCallbackType | None, node: Node, data: dict) Any [source]#
Call the function and normalize result and exceptions.
Handles MapperCallbackType: Call fn(node, data) if defined and return the result. If fn is undefined or returns None, return data.
- call_predicate(fn: Callable, node: Node) IterationControl | None | Any [source]#
Call the function and normalize result and exceptions.
Handles PredicateCallbackType: Call fn(node) and converts all raised IterationControl responses to a canonical result.
- call_traversal_cb(fn: Callable, node: Node, memo: Any) False | None [source]#
Call the function and handle result and exceptions.
This method calls fn(node, memo) and converts all returned or raised IterationControl responses to a canonical result:
Handles TraversalCallbackType
Return False if the method returns SkipBranch or an instance of SkipBranch.
Raise StopTraversal(value) if the method returns False, StopTraversal, or an instance of StopTraversal.
If a form of StopIteration is returned, we treat as StopTraversal, but emit a warning.
Other return values are ignored and converted to None.
- open_as_compressed_output_stream(path: str | Path, *, compression: bool | int = True, encoding: str = 'utf8') IO[str] [source]#
Open a file for writing, ZIP-compressing if requested.
Example:
with open_as_compressed_stream("/path/to/foo.nutree") as fp: fp: print(line)
- open_as_uncompressed_input_stream(path: str | Path, *, encoding: str = 'utf8', auto_uncompress: bool = True) IO[str] [source]#
Open a file for reading, decompressing if necessary.
Decompression is done by checking for the magic header (independent of the file extension).
Example:
with open_as_uncompressed_stream("/path/to/foo.nutree") as fp: for line in fp: print(line)