c0fec0de / anytree Goto Github PK
View Code? Open in Web Editor NEWPython tree data library
License: Apache License 2.0
Python tree data library
License: Apache License 2.0
Currently, the documentation only shows initializing Node
using a string
. However, it isn't clear whether strings are required. For example, I'm interested in creating a tree out of enumerated type values. But I get a variety of strange behavior when trying to do that.
I guess there are some scalability issue with anytree due to the linear search in most(all?) of the find operations.
A tree with 3 million nodes takes about 30-45 minutes to create compared to couple of seconds with just dict(of dicts)
i guess 'insert a child a node if no child node exists' gets slowed down due to the linear search of child nodes.
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
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
Probably not an anytree issue, but perhaps someone already had the same experience.
I use wxPython's TextCtrl to render my Anytree object. Everything renders nice except for the percent signs. In the example below each "115428736n" (a hash maybe?) stands / should stand for the percent sign.
Any idea what this might be and how to fix it?
08:23:22: └── results
08:23:22: ├── 41 115428736n BF1 für Head crown, serf = 3.94 ≤ SheetThickness, 10 NW (9.5 MW).
08:23:22: ├── 60 115428736n BF1 für Head knuckle, serf = 5.75 ≤ SheetThickness, 10 NW (9.5 MW).
I want to use anytree in anaconda in Win10 OS, but when i just run
root = Node("root")
s0 = Node("sub0", parent=root)
s0b = Node("sub0B", parent=s0)
s0a = Node("sub0A", parent=s0)
s1 = Node("sub1", parent=root)
s1a = Node("sub1A", parent=s1)
s1b = Node("sub1B", parent=s1)
s1c = Node("sub1C", parent=s1)
s1ca = Node("sub1Ca", parent=s1c)
RenderTreeGraph(root).to_picture("tree.png")
I get error like this
runfile('C:/Users/NWPU/.spyder-py3/temp.py', wdir='C:/Users/NWPU/.spyder-py3')
Traceback (most recent call last):
File "<ipython-input-12-2380dbac90f7>", line 1, in <module>
runfile('C:/Users/NWPU/.spyder-py3/temp.py', wdir='C:/Users/NWPU/.spyder-py3')
File "C:\ProgramData\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 710, in runfile
execfile(filename, namespace)
File "C:\ProgramData\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 101, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/NWPU/.spyder-py3/temp.py", line 42, in <module>
RenderTreeGraph(root).to_picture("tree.png")
File "C:\ProgramData\Anaconda3\lib\site-packages\anytree\exporter\dotexporter.py", line 229, in to_picture
check_call(cmd)
File "C:\ProgramData\Anaconda3\lib\subprocess.py", line 286, in check_call
retcode = call(*popenargs, **kwargs)
File "C:\ProgramData\Anaconda3\lib\subprocess.py", line 267, in call
with Popen(*popenargs, **kwargs) as p:
File "C:\ProgramData\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 209, in __init__
super(SubprocessPopen, self).__init__(*args, **kwargs)
File "C:\ProgramData\Anaconda3\lib\subprocess.py", line 709, in __init__
restore_signals, start_new_session)
File "C:\ProgramData\Anaconda3\lib\subprocess.py", line 997, in _execute_child
startupinfo)
FileNotFoundError: [WinError 2] 系统找不到指定的文件。
could somebody help me out?
It would be great to be able to import dot files (or other formats) in addition to export
Please like this ticket, if you are using anytree.
Feel free to share infos about your project.
If a node's parent is changed, the node will be detached (i.e. its parent's children list is updated), but the parent of the corresponding node remains unchanged; if the __check_loop method now raises a LoopError which is captured, the tree becomes inconsistent and the node cannot be re-attached to its previous parent because of lines 102 to 104 in node.py:
elif parent is not value:
# detach, check_loop, attach ...
else:
# keep parent
pass
Therefore, I suggest to add the following line to node.py:
elif parent is not value:
# change parent node
self.__detach(parent)
# reset parent
self._parent = None
self.__check_loop(value)
self.__attach(value)
Like this, a node has a defined parent after it has been detached, even if an error occurred.
Even more elegant would be
elif parent is not value:
# reset parent
self.parent = None
self.__check_loop(value)
self.__attach(value)
However, the former solution can be implemented in a non-intrusive way by modifying _post_detach
.
Hi everyone, I'm using AnyTree in an independent environment where there is no pip.
I started by moving the anytree folders to the required folders, and started getting import error for six. I downloaded six and placed it in as well, and now I get:
'module' object has no attribute 'iterator'
In case anyone is interested - this is the code for doing this without pip:
from os import sys
sys.path.insert(0, "C:\Program Files (x86)\SmartBear\TestComplete 12\Bin\Extensions\Python\Python34\Lib\site-packages")
import six
import anytree
udo = Node("Udo")
print(udo)
Any ideas on how to fix this? If this isn't related to AnyTree sorry for wasting your time - google only returned this result: https://stackoverflow.com/questions/25612946
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.
When using the iterators for the tree objects, I realized that Python (2.7.13) does not recognize them as iterators, presumably because there is no __next__()
method:
>>> my_node1, my_node2, my_node3 = Node("a"), Node("b"), Node("c")
>>> my_node2.parent = my_node1
>>> my_iter = tree_iter.PreOrderIter(my_node1)
>>> next(my_iter)
Traceback (most recent call last):
...
TypeError: PreOrderIter object is not an iterator
Instead, I have to wrap it in iter()
to work:
>>> my_iter = iter(tree_iter.PreOrderIter(my_node1))
>>> next(my_iter)
Node('/a')
Is this intended behavior?
Would it be better if children was a list as opposed to a tuple? (and thus supports appends)
Looks like a typo
is it possible to have some kind of of support for symbolic links where a node can point/link to another part of the tree?
Hi,
I am using anytree
to generate a tree-view of pytest hooks based on a log file with indented hooks. pytest-dev/pytest#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!
The NodeMixin class does not define any slots and therefore prevent any child class from using them.
I'm using in one of my current projects the NodeMixin class and I quite enjoy the simple way it works. I very much appreciate the work put in the module.
I wonder if it would be possible to extend the package to enable defining two - or possibly more - "parallel" trees from the same set of nodes to account for different logics in the nodes.
Think: all people in the world can be ordered in a family tree on a pure "biological" basis but also like "real" parents - who grew who up. Not necessarily the best example but I hope you get the point.
Current implementation uses the parent attribute as a keyword to define the parent-child relations. Would it be possible to change this to a configurable keyword and - naive thinking, without really knowing and/or having studied the inner workings of the module - use mostly getattr-setattr to do the job?
Hi,
I wanted to start talking about the current naming convention of the detach and attach slots:
_pre_detach
_post_detach
_pre_attach
_post_attach
In theory and accordingly to PEP 8, the fact they start with an underscore implies for seasoned Python developers that they are part of the recognised private part of the API:
Use one leading underscore only for non-public methods and instance variables.
This is not a major problem but it makes me a bit uncomfortable.
As a side note last week when we were discussing about some of work I have done leveraging anytree, a co-worker asked me why the _pre_detach
definitions in my code were named like so, told him I could not do much about it and it was the way anytree was exposing the hooks.
I reckon that it would be great to name them in a way that it is clear that they are part of the public API of anytree.
I got an error findall not defined. i already import Ascii
and im using Python 2.7
here is my code
from anytree import Node, RenderTree, AsciiStyle, LevelOrderIter
def buildTree(dataset):
root = Node("root")
for data in dataset:
parent = 0;
for item in data:
if parent==0:
parent = root
findall(parent, filter_=lambda node: node.name in ("a", "b"))
parent = Node(item, parent=parent, support = 1)
for pre, fill, node in RenderTree(root):
print("%s%s" % (pre, node.name))
here is the error
Traceback (most recent call last):
File "C:\Users\Kevin\PycharmProjects\AqeelaTugasAkhir\index.py", line 83, in <module>
tree = buildTree(itemOrdered)
File "C:\Users\Kevin\PycharmProjects\AqeelaTugasAkhir\index.py", line 60, in buildTree
findall(parent, filter_=lambda node: node.name in ("a", "b"))
NameError: global name 'findall' is not defined
What's wrong with findall?
thanks for help
Awesome project !!
I was wondering if there are any way to sort the children when rendering a tree ? For example let's say I'd like the children to be sorted by name (or by attribute, ...), I could pass a sorting callback function to RenderTree
that would sort them similarly to what sorted
does with key
.
Thanks
Could be an anaconda bug or something, this is the output I get:
Collecting anytree
Downloading anytree-2.4.3.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-build-pwc646vg/anytree/setup.py", line 6, in
from setuptools import setup
ImportError: cannot import name 'setup'
For Python
Hey,
My image output generated by RenderTreeGraph is looking a bit squished.
Any way to change the image size?
It would be great if it were possible to pass options to PreOrderIter in the exporter. Concretely, I'd like to limit the depth of the exported subtree, and it should be easy if it were posisble to hand-down a "maxlevel" option to PreOrderIter (I think). But since that is hard-coded, that is not trivial to do.
Would that make sense?
Hi,
An AttributeError
exception is being raised when I try to access an instantiation time kwarg
in the attach callbacks.
Here is a reproducible example:
from anytree import Node
class MyNode(Node):
def __init__(self, name, parent=None, **kwargs):
super(MyNode, self).__init__(name, parent, **kwargs)
def _post_attach(self, parent):
print(self.my_attribute)
node_a = MyNode('A')
node_b = MyNode('B', node_a, my_attribute=True)
print(node_b)
and the traceback:
AttributeErrorTraceback (most recent call last)
<ipython-input-22-94f8f5bf82a3> in <module>()
12
13 node_a = MyNode('A')
---> 14 node_b = MyNode('B', node_a, my_attribute=True)
15 print(node_b)
<ipython-input-22-94f8f5bf82a3> in __init__(self, name, parent, **kwargs)
5 class MyNode(AbstractNode):
6 def __init__(self, name, parent=None, **kwargs):
----> 7 super(MyNode, self).__init__(name, parent, **kwargs)
8
9 def _post_attach(self, parent):
<ipython-input-18-7c2ada3c82ac> in __init__(self, name, parent, **kwargs)
8 kwargs['attribute'] = True
9
---> 10 super(AbstractNode, self).__init__(name, parent, **kwargs)
11
12 class ConcreteNode(AbstractNode):
C:\Users\thomas\Packages\anytree\2.2.1\anytree\Lib\site-packages\anytree\node.pyc in __init__(self, name, parent, **kwargs)
429 """
430 self.name = name
--> 431 self.parent = parent
432 self.__dict__.update(kwargs)
433
C:\Users\thomas\Packages\anytree\2.2.1\anytree\Lib\site-packages\anytree\node.pyc in parent(self, value)
100 self.__check_loop(value)
101 self.__detach(parent)
--> 102 self.__attach(value)
103 else:
104 # keep parent
C:\Users\thomas\Packages\anytree\2.2.1\anytree\Lib\site-packages\anytree\node.pyc in __attach(self, parent)
128 assert self not in parentchildren, "Tree internal data is corrupt."
129 parentchildren.append(self)
--> 130 self._post_attach(parent)
131
132 @property
<ipython-input-22-94f8f5bf82a3> in _post_attach(self, parent)
8
9 def _post_attach(self, parent):
---> 10 print(self.my_attribute)
11
12
AttributeError: 'MyNode' object has no attribute 'my_attribute'
The reason is because Node.__dict__
gets updated only after accessing the Node.parent
property here:
https://github.com/c0fec0de/anytree/blob/master/anytree/node.py#L432
Moving the statement before fixes the issue.
Version 2.1.1 - glob returns only the closest children:
d = Node("parent")
child_1 = Node("child_1", parent=d, value="5")
child_2 = Node("child_2", parent=d, value="5")
grandson_1 = Node("child_1", parent=child_1, value="5")
grandson_2 = Node("child_1", parent=child_1, value="5")
r = Resolver("value")
nodes = r.glob(d, "5")
Will return only child_1 and child_2
I'm sorry if I'm overlooking a more obvious and better way to do this, but when I want to find all of the leaves of a node I have been using a list comprehension like this:
leaves = [node for node in root.descendants if node.is_leaf]
and it seems like it would be a nice feature to be able to do this:
leaves = root.leaves
Thanks for all your work on this very useful package!
Hi!
I have an issue installing anytree on py34 (also 3.3, but I don't think it is supported) in a virtualenv using tox.
Collecting anytree (from pymenu==0.1.0)
Downloading anytree-2.2.0.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/tmp/pip-build-q22xz5l_/anytree/setup.py", line 24, in <module>
config = _read_metainfo("anytree/__init__.py")
File "/tmp/pip-build-q22xz5l_/anytree/setup.py", line 18, in _read_metainfo
match = pat.match(line)
TypeError: can't use a string pattern on a bytes-like object
You can see it on my travis build:
Hi,
The self.path
attribute is incomplete when accessed from the Node._post_attach
definition slot:
from anytree import Node
class MyNode(Node):
def __init__(self, name, parent=None, **kwargs):
super(MyNode, self).__init__(name, parent, **kwargs)
def _post_attach(self, parent):
print(self.parent)
print(self.path)
node_a = MyNode('A')
node_b = MyNode('B', node_a)
node_c = MyNode('C', node_b)
node_d = MyNode('D', node_c)
print(node_d.path)
None
(MyNode('/B'),)
None
(MyNode('/C'),)
None
(MyNode('/D'),)
(MyNode('/A'), MyNode('/A/B'), MyNode('/A/B/C'), MyNode('/A/B/C/D'))
This is surprising from an API usage perspective as you would expect self.parent
and self.path
to be representing the state of the given node after being parented. It would probably worth defining what attaching exactly means.
Cheers,
Thomas
I might not have done this correctly (submitting an issue and pull request) as it is my first time using github. Let me know if I need to fix anything!
On Windows, the current "to_picture" function does not work as the temporary file name is not visible to the system. Therefore, calling "dot" on the command line will result in a FileNotFoundError.
The fix changes the function so that on windows/cygwin, the file is not deleted until after the picture is made. Once the picture is made, the file in unlinked.
When trying to use DotExporter to generate PNG's on Mac OS 10.12.6:
>>> from anytree.exporter import DotExporter
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named exporter
Name: anytree
Version: 2.2.2
Name: graphviz
Version: 0.8.1
A tree successfully gets exported to a dictionary/JSON form. But when I import it back to a tree it loses all information about children or parent of any node except the root.
Please see this issue.
I find that I can only export Node object with Exporter in Python2. In Python3, however, I can only export AnyNode Object with Exporter and when I export Node Object, it shows 'Node' object does not support indexing.
I hope you can fix it. Thanks!
Windows 8.1 (64 bit)
graphviz 2.38.0
Python 2.7.15 (32 bit)
anytree 2.4.3
>dot -v dot - graphviz version 2.38.0 (20140413.2041) libdir = "C:\Program Files (x86)\Graphviz2.38\bin" Activated plugin library: gvplugin_dot_layout.dll Using layout: dot:dot_layout Activated plugin library: gvplugin_core.dll Using render: dot:core Using device: dot:dot:core The plugin configuration file: C:\Program Files (x86)\Graphviz2.38\bin\config6 was successfully loaded. render : cairo dot fig gd gdiplus map pic pov ps svg tk vml vrml xdot layout : circo dot fdp neato nop nop1 nop2 osage patchwork sfdp twopi textlayout : textlayout device : bmp canon cmap cmapx cmapx_np dot emf emfplus eps fig gd gd2 gif gv imap imap_np ismap jpe jpeg jpg metafile pdf pic plain plain-ext png pov ps ps2 svg svgz tif tiff tk vml vmlz vrml wbmp xdot xdot1.2 xdot1.4 loadimage : (lib) bmp eps gd gd2 gif jpe jpeg jpg png ps svg
python anytree_picture_export.py
`from anytree import Node, RenderTree
from anytree.exporter import DotExporter
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)
DotExporter(udo).to_picture("udo.png")`
I am trying to produce a graph plot with anytree (see code above) and getting the following error:
>python anytree_picture_export.py Error: dot: can't open c:\users\user\appdata\local\temp\tmpvdgutg Traceback (most recent call last): File "anytree_picture_export.py", line 12, in <module> DotExporter(udo).to_picture("udo.png") File "C:\Python27\lib\site-packages\anytree\exporter\dotexporter.py", line 229, in to_picture check_call(cmd) File "C:\Python27\lib\subprocess.py", line 190, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['dot', 'c:\\users\\user\\appdata\\local\\temp\\tmpvdgutg', '-T', 'png', '-o', 'udo.png']' returned non-zero exit status 2
I tried to change the file format to "pdf" and "jpg" with the same error message. Stepping through the DotExporter, the temporary file dotfile is created and the dot lines are written correctly, yet there seems to be a problem with file permission or handling.
Title says it all.
It would be really cool to have diff api which
Consider this as feature request.
Currently, the __repr__
function for printing node expects all the arguments to of type str
.
However, I think a general construct which can print a node independent of it's type
is more suitable.
Here is how I encountered this bug:
In []: a = [1, 2, 3]
In []: me = Person('Kshitij', 20) # some user defined class
In []: myroot = Node(a)
In []: leaf = Node(b, parent=myroot)
In []: print(myroot)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-23-fd64928be722> in <module>()
----> 1 print(myroot)
/usr/local/lib/python3.5/dist-packages/anytree/__init__.py in __repr__(self)
376 def __repr__(self):
377 classname = self.__class__.__name__
--> 378 args = ["%r" % "/".join([node.name for node in self.path])]
379 for key, value in filter(lambda item: not item[0].startswith("_"),
380 sorted(self.__dict__.items(),
TypeError: sequence item 0: expected str instance, list found
In[]: for pre, fill, node in RenderTree(myroot):
print('{}{}'.format(pre, node.name))
[1, 2, 3]
└── Person(name='Kshitij', age=20)
getting this error
FileNotFoundError: [Errno 2] No such file or directory: 'dot'
While I Run
RenderTreeGraph(udo).to_picture("tree.png") Not building tree
How can we display Node descriptions that has been set beforehand in DotExporter.to_picture() ?
In my case my nodes was initialised with Node("A", task="task A"), I want the task to be displayed under the node name. Something like this:
+--------+
| A |
| task A|
+--------+
With regards to the example on http://anytree.readthedocs.io/en/latest/importer/jsonimporter.html
If you change the word "children" on line 7 into "Children" (uppercase, that is), the example will still finish with exit code 0, but no tree will be printed. Doing the same on line 10 has no effect.
Since __get_nodemap returns OrderedDict, it requires that the search by part will be unique, and hence doesn't allow searching for more than one node with the same value.
E.g.
d = Node("parent")
child_1 = Node("child_1", parent=d, value="5")
child_2 = Node("child_2", parent=d, value="5")
r = Resolver("value")
nodes = r.glob(d, "5")
will return only the last found node.
I find it sometimes useful to set the children of a node simultaneously all in one step. This is motivated by trees--or, more precisely, their interpretation--that can be invalidated by adding children sequentially; however, in order to check whether a particular set of children would result in a valid tree, I need to be able to add all children at once. Therefore, I extended this class by a setter method for the children
attribute, as well as hooks _pre_detach_children
, _post_detach_children
, _pre_attach_children
, and _post_attach_children
. Any interest in incorporating this?
I think that a search function should be added to this module. It will search in all the nodes and then return the path of all the nodes (as a list) which match the given text. I have already made this function, I would like to contribute to this module.
Hi,
In my application I have a Mapping type that is also a NodeMixin. Since the Mapping redefines eq to be key-wise comparison the following assertion gets triggered when two sibling nodes have the same keys and values:
assert self in parentchildren, "Tree internal data is corrupt."
I attached a diff to change this to use object identity comparison:
assert any(x is self for x in parentchildren), "Tree internal data is corrupt."
Best,
Bob
assert.diff.txt
It would be nice to be able to use RenderTreeGraph(root, graph='graph')
so that it replaces the ->
for a --
in anytree.dotexport at function __iter_edges
.
Currently it causes DOT to give back a syntax error and I would like to render undirected graphs as well.
Hi !
The iterator module is missing in the archive on pipy.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.