Trees are a common data structure and there are many different ways to implement them.
This package provides a common interface to access and operate on these objects.
Installing
Use pip to install abstracttree:
$ pip install --upgrade abstracttree
Usage
You can start by implementing the mixins below. Otherwise, a lot of trees are supported out of the box.
Mixins
graph TD;
Tree[Tree];
MutableTree[MutableTree];
DownTree[DownTree];
Tree[Tree];
MutableTree[MutableTree];
MutableDownTree[MutableDownTree];
MutableTree[MutableTree];
BinaryDownTree[BinaryDownTree];
BinaryTree[BinaryTree];
Tree-->MutableTree;
DownTree-->Tree;
DownTree-->MutableDownTree;
MutableDownTree-->MutableTree;
DownTree-->BinaryDownTree;
BinaryDownTree-->BinaryTree;
Tree-->BinaryTree;
DownTree | | children | nodes , nodes.preorder() , nodes.postorder() , nodes.levelorder() , descendants , leaves , levels , levels.zigzag() , is_leaf , transform() , nid |
Tree | DownTree | parent | root , is_root , ancestors , path , siblings |
MutableDownTree | DownTree | add_child() , remove_child() | add_children() |
MutableTree | MutableDownTree , Tree | | detach() |
BinaryDownTree | DownTree | left_child , right_child | children , nodes.inorder() , descendants.inorder() |
BinaryTree | BinaryDownTree , Tree | | |
For example, to create a simple tree with children (but no parent):
from abstracttree import DownTree, print_tree
class MyTree(DownTree):
def __init__(self, value, children=()):
self.value = value
self._children = children
def __str__(self):
return "MyTree " + str(self.value)
@property
def children(self):
return self._children
tree = MyTree(1, children=[MyTree(2), MyTree(3)])
print_tree(tree)
Generics
Unfortunately, not all trees inherit from the mixins above. Yet, some objects still have treelike behaviour.
Therefore, AbstractTree provides support for a slightly weaker protocol.
The following objects are TreeLike
:
- All objects that support
obj.children
and obj.parent
.
- Builtins classes
pathlib.Path
and zipfile.Path
.
- Third party tree classes from anytree, bigtree, itertree and littletree.
The following objects are DownTreeLike
:
- All objects that support
obj.children
.
- Anything implementing
DownTree
.
- Recursive collections like lists, tuples, sets, dicts. This can be useful when dealing with json-data.
This can be tested using isinstance
:
isinstance(Path(r"C:\\Windows\System"), TreeLike)
isinstance(range(100), DownTreeLike)
isinstance(range(100), TreeLike)
isinstance(5, DownTreeLike)
isinstance("some text", DownTreeLike)
Basic functions
On downtreelikes:
children(node)
label(node)
nid(node)
eqv(node1, node2)
Additionally, on treelikes:
parent(node)
root(node)
Examples:
>>> from abstracttree import *
>>> children([1, 2, 3])
[1, 2, 3]
>>> children({"name": "Philip", "children": ["Pete", "Mariam"]})
[MappingItem(key="name", value="Philip"), MappingItem(key="children", value=["Pete", "Miriam"])]
>>> parent(Path(r"C:\\Windows\System"))
Path(r"C:\\Windows")
>>> label(Path(r"C:\\Windows\System"))
"System"
>>> eqv(Path(r"C:\\Windows\System"), Path(r"C:\\Windows\System"))
True
>>> eqv([1, 2, 3], [1, 2, 3])
False
Iterators
On downtreelikes:
nodes(tree)
descendants(node)
leaves(root)
If you want to iterate though the nodes in a specific order, use:
preorder(node)
postorder(node)
levelorder(node)
These will return tuples with (node, item). The item-object contains information about the depth of the node.
Additionally, on treelikes:
ancestors(node)
path(node)
siblings(node)
Adapters
To upgrade a TreeLike
to a full Tree
use as_tree
.
path_tree = as_tree(pathlib.Path("my_documents"))
for node in path_tree.descendants:
path_obj = node.value
There is also TreeAdapter
to help with classes that are very different.
Exporting
Export to various formats
print_tree(tree)
plot_tree(tree)
to_dot(tree)
to_mermaid(tree)
to_latex(tree)
to_reportlab(tree)
to_image(Path('.'), "filetree.png", how="dot")
to_image(DownTree, "tree_hierarchy.svg", how="mermaid")
to_pillow(tree).show()