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)
Simple spill-to-disk dictionary

Chest A dictionary that spills to disk. Chest acts likes a dictionary but it can write its contents to disk. This is useful in the following two occas

Blaze 59 Dec 19, 2022
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
Python library for doing things with Grid-like structures

gridthings Python library for doing things with Grid-like structures Development This project uses poetry for dependency management, pre-commit for li

Matt Kafonek 2 Dec 21, 2021
An command-line utility that schedules your exams preparation routines

studyplan A tiny utility that schedules your exams preparation routines. You only need to specify the tasks and the deadline. App will output a iCal f

Ilya Breitburg 3 May 18, 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
A Python dictionary implementation designed to act as an in-memory cache for FaaS environments

faas-cache-dict A Python dictionary implementation designed to act as an in-memory cache for FaaS environments. Formally you would describe this a mem

Juan 3 Dec 13, 2022
This repository is a compilation of important Data Structures and Algorithms based on Python.

Python DSA 🐍 This repository is a compilation of important Data Structures and Algorithms based on Python. Please make seperate folders for different

Bhavya Verma 27 Oct 29, 2022
Chemical Structure Generator

CSG: Chemical Structure Generator A simple Chemical Structure Generator. Requirements Python 3 (= v3.8) PyQt5 (optional; = v5.15.0 required for grap

JP&K 5 Oct 22, 2022
RLStructures is a library to facilitate the implementation of new reinforcement learning algorithms.

RLStructures is a lightweight Python library that provides simple APIs as well as data structures that make as few assumptions as possibl

Facebook Research 262 Nov 18, 2022
Python tree data library

Links Documentation PyPI GitHub Changelog Issues Contributors If you enjoy anytree Getting started Usage is simple. Construction from anytree impo

776 Dec 28, 2022
Supporting information (calculation outputs, structures)

Supporting information (calculation outputs, structures)

Eric Berquist 2 Feb 02, 2022
Basic sort and search algorithms written in python.

Basic sort and search algorithms written in python. These were all developed as part of my Computer Science course to demonstrate understanding so they aren't 100% efficent

Ben Jones 0 Dec 14, 2022
pyprobables is a pure-python library for probabilistic data structures

pyprobables is a pure-python library for probabilistic data structures. The goal is to provide the developer with a pure-python implementation of common probabilistic data-structures to use in their

Tyler Barrus 86 Dec 25, 2022
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 number that can be looked up.

Elia Robyn Lake (Robyn Speer) 173 Nov 28, 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
My notes on Data structure and Algos in golang implementation and python

My notes on DS and Algo Table of Contents Arrays LinkedList Trees Types of trees: Tree/Graph Traversal Algorithms Heap Priorty Queue Trie Graphs Graph

Chia Yong Kang 0 Feb 13, 2022
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
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
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
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