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)
🔬 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
This repository contains code for CTF platform.

CTF-platform Repository for backend of CTF hosting website For starting the project first time : Clone the repo in which you have to work in your syst

Yash Jain 3 Feb 18, 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
nocasedict - A case-insensitive ordered dictionary for Python

nocasedict - A case-insensitive ordered dictionary for Python Overview Class NocaseDict is a case-insensitive ordered dictionary that preserves the or

PyWBEM Projects 2 Dec 12, 2021
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
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
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
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
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
A HDF5-based python pickle replacement

Hickle Hickle is an HDF5 based clone of pickle, with a twist: instead of serializing to a pickle file, Hickle dumps to an HDF5 file (Hierarchical Data

Danny Price 450 Dec 21, 2022
Decided to include my solutions for leetcode problems.

LeetCode_Solutions Decided to include my solutions for leetcode problems. LeetCode # 1 TwoSum First leetcode problem and it was kind of a struggle. Th

DandaIT04 0 Jan 01, 2022
Google, Facebook, Amazon, Microsoft, Netflix tech interview questions

Algorithm and Data Structures Interview Questions HackerRank | Practice, Tutorials & Interview Preparation Solutions This repository consists of solut

Quan Le 8 Oct 04, 2022
This repo is all about different data structures and algorithms..

Data Structure and Algorithm : Want to learn data strutrues and algorithms ??? Then Stop thinking more and start to learn today. This repo will help y

Priyanka Kothari 7 Jul 10, 2022
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
My solutions to the competitive programming problems on LeetCode, USACO, LintCode, etc.

This repository holds my solutions to the competitive programming problems on LeetCode, USACO, LintCode, CCC, UVa, SPOJ, and Codeforces. The LeetCode

Yu Shen 32 Sep 17, 2022
A JSON-friendly data structure which allows both object attributes and dictionary keys and values to be used simultaneously and interchangeably.

A JSON-friendly data structure which allows both object attributes and dictionary keys and values to be used simultaneously and interchangeably.

Peter F 93 Dec 01, 2022
Data Structures and algorithms package implementation

Documentation Simple and Easy Package --This is package for enabling basic linear and non-linear data structures and algos-- Data Structures Array Sta

1 Oct 30, 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
A DSA repository but everything is in python.

DSA Status Contents A: Mathematics B: Bit Magic C: Recursion D: Arrays E: Searching F: Sorting G: Matrix H: Hashing I: String J: Linked List K: Stack

Shubhashish Dixit 63 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