Python tree data library

Overview
https://img.shields.io/pypi/dm/anytree.svg?label=pypi%20downloads https://travis-ci.org/c0fec0de/anytree.svg?branch=master https://readthedocs.org/projects/anytree/badge/?version=2.8.0 https://codeclimate.com/github/c0fec0de/anytree.png

Links

https://github.com/c0fec0de/anytree/raw/devel/docs/static/buymeacoffee.png

Getting started

Usage is simple.

Construction

>> marc = Node("Marc", parent=udo) >>> lian = Node("Lian", parent=marc) >>> dan = Node("Dan", parent=udo) >>> jet = Node("Jet", parent=dan) >>> jan = Node("Jan", parent=dan) >>> joe = Node("Joe", parent=dan)">
>>> from anytree import Node, RenderTree
>>> udo = Node("Udo")
>>> marc = Node("Marc", parent=udo)
>>> lian = Node("Lian", parent=marc)
>>> dan = Node("Dan", parent=udo)
>>> jet = Node("Jet", parent=dan)
>>> jan = Node("Jan", parent=dan)
>>> joe = Node("Joe", parent=dan)

Node

>>> print(udo)
Node('/Udo')
>>> print(joe)
Node('/Udo/Dan/Joe')

Tree

>>> for pre, fill, node in RenderTree(udo):
...     print("%s%s" % (pre, node.name))
Udo
├── Marc
│   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

For details see Node and RenderTree.

Visualization

>>> from anytree.exporter import DotExporter
>>> # graphviz needs to be installed for the next line!
>>> DotExporter(udo).to_picture("udo.png")

https://anytree.readthedocs.io/en/latest/_images/udo.png

The DotExporter can be started at any node and has various formatting hookups:

>>> DotExporter(dan,
...             nodeattrfunc=lambda node: "fixedsize=true, width=1, height=1, shape=diamond",
...             edgeattrfunc=lambda parent, child: "style=bold"
... ).to_picture("dan.png")

https://anytree.readthedocs.io/en/latest/_images/dan.png

There are various other Importers and Exporters.

Manipulation

A second tree:

>> urs = Node("Urs", parent=mary) >>> chris = Node("Chris", parent=mary) >>> marta = Node("Marta", parent=mary) >>> print(RenderTree(mary)) Node('/Mary') ├── Node('/Mary/Urs') ├── Node('/Mary/Chris') └── Node('/Mary/Marta')">
>>> mary = Node("Mary")
>>> urs = Node("Urs", parent=mary)
>>> chris = Node("Chris", parent=mary)
>>> marta = Node("Marta", parent=mary)
>>> print(RenderTree(mary))
Node('/Mary')
├── Node('/Mary/Urs')
├── Node('/Mary/Chris')
└── Node('/Mary/Marta')

Append:

>>> udo.parent = mary
>>> print(RenderTree(mary))
Node('/Mary')
├── Node('/Mary/Urs')
├── Node('/Mary/Chris')
├── Node('/Mary/Marta')
└── Node('/Mary/Udo')
    ├── Node('/Mary/Udo/Marc')
    │   └── Node('/Mary/Udo/Marc/Lian')
    └── Node('/Mary/Udo/Dan')
        ├── Node('/Mary/Udo/Dan/Jet')
        ├── Node('/Mary/Udo/Dan/Jan')
        └── Node('/Mary/Udo/Dan/Joe')

Subtree rendering:

>>> print(RenderTree(marc))
Node('/Mary/Udo/Marc')
└── Node('/Mary/Udo/Marc/Lian')

Cut:

>>> dan.parent = None
>>> print(RenderTree(dan))
Node('/Dan')
├── Node('/Dan/Jet')
├── Node('/Dan/Jan')
└── Node('/Dan/Joe')

Extending any python class to become a tree node

The enitre tree magic is encapsulated by NodeMixin add it as base class and the class becomes a tree node:

>>> from anytree import NodeMixin, RenderTree
>>> class MyBaseClass(object):  # Just an example of a base class
...     foo = 4
>>> class MyClass(MyBaseClass, NodeMixin):  # Add Node feature
...     def __init__(self, name, length, width, parent=None, children=None):
...         super(MyClass, self).__init__()
...         self.name = name
...         self.length = length
...         self.width = width
...         self.parent = parent
...         if children:
...             self.children = children

Just set the parent attribute to reflect the tree relation:

>>> my0 = MyClass('my0', 0, 0)
>>> my1 = MyClass('my1', 1, 0, parent=my0)
>>> my2 = MyClass('my2', 0, 2, parent=my0)
>>> for pre, fill, node in RenderTree(my0):
...     treestr = u"%s%s" % (pre, node.name)
...     print(treestr.ljust(8), node.length, node.width)
my0      0 0
├── my1  1 0
└── my2  0 2

The children can be used likewise:

>>> my0 = MyClass('my0', 0, 0, children=[
...     MyClass('my1', 1, 0),
...     MyClass('my2', 0, 2),
... ])
>>> for pre, fill, node in RenderTree(my0):
...     treestr = u"%s%s" % (pre, node.name)
...     print(treestr.ljust(8), node.length, node.width)
my0      0 0
├── my1  1 0
└── my2  0 2

Documentation

Please see the Documentation for all details.

Installation

To install the anytree module run:

pip install anytree

If you do not have write-permissions to the python installation, try:

pip install anytree --user
Comments
  • Determination of direct children counts

    Determination of direct children counts

    I would like to determine the number of direct children (for non-leaf nodes). I imagine that unique identifiers will be needed then as references for relevant nodes. But the tree iteration is working with the attribute “name” (which might not be unique) so far. Thus I imagine also that the usage of paths would become helpful (so that an auxiliary node attribute can be avoided as long as pointer alternatives would not be applicable).

    Will a configurable formatting become relevant for the display and further data processing of the calculated counts?

    opened by elfring 9
  • Plans to persist tree to file and create a tree from file?

    Plans to persist tree to file and create a tree from file?

    First of all, amazing work in here. I'm planing to use anytree to a huge kind of backtracking implementation. I will need to persist the tree to a file at some point, and of course, get the tree back from a file.

    Are you planning to do it? Is it possible? Should i give it a try and then send the pull request?

    Thank you

    opened by ArgiesDario 9
  • Remove try-except overload to check if some attribute exists

    Remove try-except overload to check if some attribute exists

    In the current implementation, there are some try-except blocks to check if an object has some attribute. To reduce the generated overhead by the exception handling logic, I propose to start using the getattr builtin function with a default value instead.

    This change doesn't provide a big performance improvement, but it's a constant-factor cost removal with no public API implications.

    To check the difference, I build a 1 million node random tree with a height of 25. The logic to build the anynode.AnyNode instances from the tree encoded as raw dictionaries decreased from ~11 seconds to ~8 seconds on my computer (not a big change, but better than nothing 🙂).

    opened by garciparedes 7
  • NodeMixin - TypeError: multiple bases have instance lay-out conflict

    NodeMixin - TypeError: multiple bases have instance lay-out conflict

    Works: 2.4.3 Breaks: 2.6.0

    >>> from munch import Munch
    >>> from anytree import NodeMixin
    >>> class MyClass(Munch, NodeMixin):
    ...     pass
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: multiple bases have instance lay-out conflict
    

    Where munch is https://github.com/Infinidat/munch

    Googling around a bit this seems to be about conflicts in C implementations of classes on __foo__ attributes. So I did this:

    >>> [k for k in dir(Munch) if k in dir(NodeMixin)]
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
    

    but it didn't make me feel much smarter.

    Does this mean anything to you anytree peeps? I came here because obviously NodeMixin is meant to be mixed in so this feels like a bug rather than just a stupid thing I should not be attempting to do. Especially as it used to work until this version.

    opened by bakert 7
  • RenderTreeGraph(root).to_picture(

    RenderTreeGraph(root).to_picture("tree.png") Not building tree

    getting this error

    FileNotFoundError: [Errno 2] No such file or directory: 'dot'

    While I Run RenderTreeGraph(udo).to_picture("tree.png") Not building tree

    opened by pcakhilnadh 6
  • Resolver.glob returns IndexError where Resolver.get does not

    Resolver.glob returns IndexError where Resolver.get does not

    Example:

    from anytree import Node
    top = Node("top", parent=None)
    sub0 = Node("sub0", parent=top)
    sub0sub0 = Node("sub0sub0", parent=sub0)
    sub0sub1 = Node("sub0sub1", parent=sub0)
    sub1 = Node("sub1", parent=top)
    
    from anytree import Resolver
    r = Resolver('name')
    

    Getting the top node from sub0:

    >>> r.get(sub0, '..')
    Node('/top')
    

    Using glob:

    >>> r.glob(sub0, '..')
    .../anytree/resolver.py in __glob(self, node, parts)
        165     def __glob(self, node, parts):
        166         nodes = []
    --> 167         name = parts[0]
        168         remainder = parts[1:]
        169         # handle relative
    
    IndexError: list index out of range
    
    opened by zegervdv 5
  • remove nodes recursively with a lambda filtering function

    remove nodes recursively with a lambda filtering function

    Hi, I would like to know if it's possible to remove children nodes from a Node with a lambda function criteria, something like:

    outputnode = createnode(inputnode, filter_=lambda n: does_bbox_intersect(n.boundingbox, bounds))

    question 
    opened by DerouineauNicolas 5
  • Use length of children returned from RenderTree.childiter

    Use length of children returned from RenderTree.childiter

    This is just a small fix, but it allows to use the childiter function to not just sort, but also filter nodes when rendering. I need to "hide" some node types when rendering, and thus do this in childiter:

        def childiter(items):
            items = [i for i in items if i.type in lbuild.format.SHOW_NODES]
            return sorted(items, key=lambda item: (item.type, item.name))
    

    However, this renders an additional node line without the node:

        ├── Module(modm:build)   Build System Generators
        │   ├── Module(modm:build:scons)   SCons Build Script Generator
        │   │   ╰── EnumerationOption(info.git) = Disabled in [Disabled, Info, Info+Status]
        ├── Module(modm:cmsis)   ARM CMSIS Support
    

    After this fix:

        ├── Module(modm:build)   Build System Generators
        │   ╰── Module(modm:build:scons)   SCons Build Script Generator
        │       ╰── EnumerationOption(info.git) = Disabled in [Disabled, Info, Info+Status]
        ├── Module(modm:cmsis)   ARM CMSIS Support
    

    cc @c0fec0de

    opened by salkinium 5
  • Works and does not work in an python notebook (anaconda 3)

    Works and does not work in an python notebook (anaconda 3)

    Hallo, Just busy programming an Binary puzzle solver. What works: creating the nodes of the search tree for a solution works fine directly. But if i put the commands in a def ... The nodes are not to be found in command alinea of the notebook. It is probably my missing knowledge of ... How to get the nodes accessibke out of the function .. Help is apreciated

    opened by PKHG 5
  • Enhancement/question: Find lowest common ancestor of two or more nodes?

    Enhancement/question: Find lowest common ancestor of two or more nodes?

    Is there any way to extract lowest common ancestor of nodes without iterating over the ancestor names and finding the common ancestor "manually"? For two nodes it's not too bad, but for more nodes I'm not actually sure how one would accomplish this.

    opened by helske 5
  • Create tree from list of indented strings

    Create tree from list of indented strings

    Hi,

    I am using anytree to generate a tree-view of pytest hooks based on a log file with indented hooks. https://github.com/pytest-dev/pytest/issues/3261

    For that I needed to create a function to convert a list of indented strings to a tree. Apparently another users on stackoverflow have needed it: https://codereview.stackexchange.com/questions/176391/parsing-indented-text-and-inserting-its-data-into-a-tree https://stackoverflow.com/questions/17858404/creating-a-tree-deeply-nested-dict-from-an-indented-text-file-in-python https://stackoverflow.com/questions/32101253/converting-a-string-to-a-tree-structure-in-python?rq=1

    I have created the following script for doing this and it is quite simple: https://github.com/Sup3rGeo/pytest/blob/master/doc/pytesthooks.py

    I believe it makes sense to make this part of anytree as a "indented strings importer".

    So if you agree I would gladly add a pull request for this. Thanks!

    opened by Sup3rGeo 5
  • assert isinstance(data, dict) error

    assert isinstance(data, dict) error

    I am trying to load JSON data formatted as in the documentation and end up with

    Traceback (most recent call last):
      File "d:\dev-pro\searchad\addm123.py", line 10, in <module>
        root = importer.import_(data)
      File "C:\Python310\lib\site-packages\anytree\importer\dictimporter.py", line 38, in import_
        return self.__import(data)
      File "C:\Python310\lib\site-packages\anytree\importer\dictimporter.py", line 47, in __import
        self.__import(child, parent=node)
      File "C:\Python310\lib\site-packages\anytree\importer\dictimporter.py", line 47, in __import
        self.__import(child, parent=node)
      File "C:\Python310\lib\site-packages\anytree\importer\dictimporter.py", line 47, in __import
        self.__import(child, parent=node)
      [Previous line repeated 5 more times]
      File "C:\Python310\lib\site-packages\anytree\importer\dictimporter.py", line 41, in __import
        assert isinstance(data, dict)
    AssertionError
    

    What does it mean, or more precisely - what kind of data can raise it?

    ~~I have empty children entries ("children": []), is this allowed? (just an idea of where the issue could come from)~~ removing "children" entries when empty does not change the issue.

    opened by wsw70 0
  • do you have functionality to count how many time particular branch was added

    do you have functionality to count how many time particular branch was added

    per https://stackoverflow.com/questions/2358045/how-can-i-implement-a-tree-in-python

    do you have functionality to count how many time particular branch was added

    lets say marc = Node("Marc", parent=udo) lian = Node("Lian", parent=marc)

    was added 12 times , then we want to see counts ?

    opened by Sandy4321 0
  • Documentation example for Utilities confusing

    Documentation example for Utilities confusing

    I might misunderstand something, but the example for, e.g., leftsibling in the documentation of anytree/util/__init__.py states two things

    1. It suggest only from anytree import Node
    2. To directly call, e.g., leftsibling(dan)

    For me, both did not work out. I had to

    1. Import the method via from anytree.util import leftsibling
    2. Do a, e.g., print(leftsibling(joe)) in order to get the desired output.
    opened by ArneMeier 0
  • Error in post-attach does not undo the operation

    Error in post-attach does not undo the operation

    Taking the read-only example and implementing checks on post_attach instead of pre_attach, it does not undo the operation that is supposed to be atomic.

    Sample code to replicate the issue below,

    from anytree import NodeMixin
    
    
    class SampleNode(NodeMixin):
        def __init__(self, foo, parent=None):
            super(SampleNode, self).__init__()
            self.foo = foo
            self.readonly = False
            self.parent = parent
        def _post_attach(self, parent):
            if self.root.readonly:
                raise ValueError()
        def _post_detach(self, parent):
            if self.root.readonly:
                raise ValueError()
    
    a = SampleNode("a")
    a0 = SampleNode("a0", parent=a)
    a1 = SampleNode("a1", parent=a)
    a1a = SampleNode("a1a", parent=a1)
    a2 = SampleNode("a2", parent=a)
    
    assert a1.parent == a
    
    a.readonly = True
    with pytest.raises(ValueError):
        a1.parent = a2
    
    a1.parent == a2 # returns True, it should undo the operation
    
    opened by kayjan 0
  • Tree from python nested dictionary

    Tree from python nested dictionary

    Hi there,

    Hi there,

    is there any easy way to create a tree from a python nested dictionary? For instance, I would like to turn: {'tax': {'a':{'c':{}, 'd':{}}, 'b': {'e':{}, 'f':{}}}}

    tax --- a ------- c ------- d --- b ------- e ------- f

    In general, I do not understand what format the json_importer takes as input. Could you please provide some examples? It there any online editor to first manually design the tree with nodes and arrows and then export it in the right format?

    Thank you.

    opened by GiorgioBarnabo 0
  • Performance issues from slow assertion

    Performance issues from slow assertion

    A few days ago I had an issue where anytree operations significantly slowed down over time. cProfile attributed the added time to this assertion. If I'm reading it correctly, it makes adding a child node take O(N) time, where N is the number of its siblings-to-be.

    That N gets rather large in my case. Probably I should refactor my code to avoid that, but I felt I should report it anyway. Setting PYTHONOPTIMIZE=TRUE (to disable assertions) does work as a workaround.

    opened by andrew-vant 0
Releases(2.8.0)
This Repository consists of my solutions in Python 3 to various problems in Data Structures and Algorithms

Problems and it's solutions. Problem solving, a great Speed comes with a good Accuracy. The more Accurate you can write code, the more Speed you will

SAMIR PAUL 1.3k Jan 01, 2023
Solutions for leetcode problems.

Leetcode-solution This is an repository for storring new algorithms that I am learning form the LeetCode for future use. Implemetations Two Sum (pytho

Shrutika Borkute 1 Jan 09, 2022
Data Structure With Python

Data-Structure-With-Python- Python programs also include in this repo Stack A stack is a linear data structure that stores items in a Last-In/First-Ou

Sumit Nautiyal 2 Jan 09, 2022
Programming of a spanning tree algorithm with Python : In depth first with a root node.

ST Algorithm Programming of a spanning tree algorithm with Python : In depth first with a root node. Description This programm reads informations abou

Mathieu Lamon 1 Dec 16, 2021
Datastructures such as linked list, trees, graphs etc

datastructures datastructures such as linked list, trees, graphs etc Made a public repository for coding enthusiasts. Those who want to collaborate on

0 Dec 01, 2021
This repository is for adding codes of data structures and algorithms, leetCode, hackerrank etc solutions in different languages

DSA-Code-Snippet This repository is for adding codes of data structures and algorithms, leetCode, hackerrank etc solutions in different languages Cont

DSCSRMNCR 3 Oct 22, 2021
Leetcode solutions - All algorithms implemented in Python 3 (for education)

Leetcode solutions - All algorithms implemented in Python 3 (for education)

Vineet Dhaimodker 3 Oct 21, 2022
CLASSIX is a fast and explainable clustering algorithm based on sorting

CLASSIX Fast and explainable clustering based on sorting CLASSIX is a fast and explainable clustering algorithm based on sorting. Here are a few highl

69 Jan 06, 2023
Persistent dict, backed by sqlite3 and pickle, multithread-safe.

sqlitedict -- persistent dict, backed-up by SQLite and pickle A lightweight wrapper around Python's sqlite3 database with a simple, Pythonic dict-like

RARE Technologies 954 Dec 23, 2022
Svector (pronounced Swag-tor) provides extension methods to pyrsistent data structures

Svector Svector (pronounced Swag-tor) provides extension methods to pyrsistent data structures. Easily chain your methods confidently with tons of add

James Chua 5 Dec 09, 2022
Map single-cell transcriptomes to copy number evolutionary trees.

Map single-cell transcriptomes to copy number evolutionary trees. Check out the tutorial for more information. Installation $ pip install scatrex SCA

Computational Biology Group (CBG) 12 Jan 01, 2023
🔬 Fixed struct serialization system, using Python 3.9 annotated type hints

py-struct Fixed-size struct serialization, using Python 3.9 annotated type hints This was originally uploaded as a Gist because it's not intended as a

Alba Mendez 4 Jan 14, 2022
IADS 2021-22 Algorithm and Data structure collection

A collection of algorithms and datastructures introduced during UoE's Introduction to Datastructures and Algorithms class.

Artemis Livingstone 20 Nov 07, 2022
Final Project for Practical Python Programming and Algorithms for Data Analysis

Final Project for Practical Python Programming and Algorithms for Data Analysis (PHW2781L, Summer 2020) Redlining, Race-Exclusive Deed Restriction Lan

Aislyn Schalck 1 Jan 27, 2022
dict subclass with keylist/keypath support, normalized I/O operations (base64, csv, ini, json, pickle, plist, query-string, toml, xml, yaml) and many utilities.

python-benedict python-benedict is a dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, ini, json, pickle, plist, query-string, t

Fabio Caccamo 799 Jan 09, 2023
A mutable set that remembers the order of its entries. One of Python's missing data types.

An OrderedSet is a mutable data structure that is a hybrid of a list and a set. It remembers the order of its entries, and every entry has an index nu

Elia Robyn Lake (Robyn Speer) 173 Nov 28, 2022
Python Data Structures and Algorithms

No non-sense and no BS repo for how data structure code should be in Python - simple and elegant.

Prabhu Pant 1.9k Jan 08, 2023
This repo represents all we learned and are learning in Data Structure course.

DataStructure Journey This repo represents all we learned and are learning in Data Structure course which is based on CLRS book and is being taught by

Aprime Afr (Alireza Afroozi) 3 Jan 22, 2022
schemasheets - structuring your data using spreadsheets

schemasheets - structuring your data using spreadsheets Create a data dictionary / schema for your data using simple spreadsheets - no coding required

Linked data Modeling Language 23 Dec 01, 2022
A high-performance immutable mapping type for Python.

immutables An immutable mapping type for Python. The underlying datastructure is a Hash Array Mapped Trie (HAMT) used in Clojure, Scala, Haskell, and

magicstack 996 Jan 02, 2023