Skip to content

Commit

Permalink
Made UniqueDotExporter output deterministic
Browse files Browse the repository at this point in the history
Changed from python object ids to a simple counter as DOT node name.
This way identical trees will produce identical DOT output, regardless of their location in memory.
Doctests now work too, because the output does not vary anymore.
  • Loading branch information
eckp committed Mar 11, 2022
1 parent d63289b commit aab1dc0
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 39 deletions.
65 changes: 35 additions & 30 deletions anytree/exporter/dotexporter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import codecs
import itertools
import logging
import re
from os import path
Expand Down Expand Up @@ -334,26 +335,26 @@ def __init__(self, node, graph="digraph", name="tree", options=None,
>>> s1ca = Node("sub1Ca", parent=s1c)
>>> from anytree.exporter import UniqueDotExporter
>>> for line in UniqueDotExporter(root): # doctest: +SKIP
>>> for line in UniqueDotExporter(root):
... print(line)
digraph tree {
"0x7f1bf2c9c510" [label="root"];
"0x7f1bf2c9c5a0" [label="sub0"];
"0x7f1bf2c9c630" [label="s0"];
"0x7f1bf2c9c6c0" [label="s0"];
"0x7f1bf2c9c750" [label="sub1"];
"0x7f1bf2c9c7e0" [label="s1"];
"0x7f1bf2c9c870" [label="s1"];
"0x7f1bf2c9c900" [label="s1"];
"0x7f1bf2c9c990" [label="sub1Ca"];
"0x7f1bf2c9c510" -> "0x7f1bf2c9c5a0";
"0x7f1bf2c9c510" -> "0x7f1bf2c9c750";
"0x7f1bf2c9c5a0" -> "0x7f1bf2c9c630";
"0x7f1bf2c9c5a0" -> "0x7f1bf2c9c6c0";
"0x7f1bf2c9c750" -> "0x7f1bf2c9c7e0";
"0x7f1bf2c9c750" -> "0x7f1bf2c9c870";
"0x7f1bf2c9c750" -> "0x7f1bf2c9c900";
"0x7f1bf2c9c900" -> "0x7f1bf2c9c990";
"0" [label="root"];
"1" [label="sub0"];
"2" [label="s0"];
"3" [label="s0"];
"4" [label="sub1"];
"5" [label="s1"];
"6" [label="s1"];
"7" [label="s1"];
"8" [label="sub1Ca"];
"0" -> "1";
"0" -> "4";
"1" -> "2";
"1" -> "3";
"4" -> "5";
"4" -> "6";
"4" -> "7";
"7" -> "8";
}
The resulting graph:
Expand All @@ -369,25 +370,29 @@ def __init__(self, node, graph="digraph", name="tree", options=None,
>>> s0a = AnyNode(id="s0", parent=s0)
>>> from anytree.exporter import UniqueDotExporter
>>> for line in UniqueDotExporter(root, nodeattrfunc=lambda n: 'label="%s"' % (n.id)): # doctest: +SKIP
>>> for line in UniqueDotExporter(root, nodeattrfunc=lambda n: 'label="%s"' % (n.id)):
... print(line)
digraph tree {
"0x7f5c70449af8" [label="root"];
"0x7f5c70449bd0" [label="sub0"];
"0x7f5c70449c60" [label="s0"];
"0x7f5c70449cf0" [label="s0"];
"0x7f5c70449af8" -> "0x7f5c70449bd0";
"0x7f5c70449bd0" -> "0x7f5c70449c60";
"0x7f5c70449bd0" -> "0x7f5c70449cf0";
"0" [label="root"];
"1" [label="sub0"];
"2" [label="s0"];
"3" [label="s0"];
"0" -> "1";
"1" -> "2";
"1" -> "3";
}
"""
super(UniqueDotExporter, self).__init__(node, graph=graph, name=name, options=options, indent=indent,
nodenamefunc=nodenamefunc, nodeattrfunc=nodeattrfunc,
edgeattrfunc=edgeattrfunc, edgetypefunc=edgetypefunc)

@staticmethod
def _default_nodenamefunc(node):
return hex(id(node))
self.node_ids = {}
self.node_counter = itertools.count()

def _default_nodenamefunc(self, node):
node_id = id(node)
if node_id not in self.node_ids:
self.node_ids[node_id] = next(self.node_counter)
return self.node_ids[id(node)]

@staticmethod
def _default_nodeattrfunc(node):
Expand Down
14 changes: 5 additions & 9 deletions tests/test_uniquedotexporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,11 @@ def test_tree1():
s0 = Node("sub0", parent=root)
s0b = Node("sub0B", parent=s0)

id_root = hex(id(root))
id_s0 = hex(id(s0))
id_s0b = hex(id(s0b))

lines = tuple(UniqueDotExporter(root))
eq_(lines, ('digraph tree {',
' "{id_root}" [label="root"];'.format(id_root=id_root),
' "{id_s0}" [label="sub0"];'.format(id_s0=id_s0),
' "{id_s0b}" [label="sub0B"];'.format(id_s0b=id_s0b),
' "{id_root}" -> "{id_s0}";'.format(id_root=id_root, id_s0=id_s0),
' "{id_s0}" -> "{id_s0b}";'.format(id_s0=id_s0, id_s0b=id_s0b),
' "0" [label="root"];',
' "1" [label="sub0"];',
' "2" [label="sub0B"];',
' "0" -> "1";',
' "1" -> "2";',
'}'))

0 comments on commit aab1dc0

Please sign in to comment.