0

I create a tree with anytree library. I want to be able to modify it, then export - save it to disk, and import it back with the modifications. For instance, the example tree:

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)

Udo
├── Marc
│   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

I can modify it, for instance cutting Dan off and adding a children to Marc

dan.parent = None 
bonny = Node ("Bonny", parent = marc)

Udo
└── Marc
    ├── Lian
    └── Bonny

But when I export the tree to json and then import it back, the only node I seem to be able to reference is the root. So I can't do this kind of modification anymore because the variable names like dan or marc are not there, ie, I don't find a way to reference a node. Am I missing anything?

with open ('cajon/anytreeexample.json', 'r+', encoding = 'utf-8') as f:
    datos = importer.read(f)

print (datos)

This means that after importing the tree what you have is just a root node

AnyNode(name='Udo')  # Udo is the root

From here you can get Udo's children, and the children's children like

marc, dan = udo.children
lian = marc.children
jet, jan, joe = dan.children

But they are not working as a node

print (lian.parent)
AttributeError: 'tuple' object has no attribute 'parent'

And seems you cannot attach a children to them, which is my main purpose with this structure:

sonny = AnyNode("Sonny", parent = lian)
TypeError: __init__() got multiple values for argument 'parent'

So my question is, is there a way to load the json saved tree into a proper anytree structure, where you can append new nodes?

gaurwraith
  • 143
  • 8
  • You can reference the root, its children, its children's children, etc. – Stop harming Monica Aug 17 '18 at 23:28
  • @Goyo I added some questions that arised after this idea. (I contemplated it, but didn't know how I would go to, say, a 5th level node, looks very complicated,I really don't know if it is – gaurwraith Aug 18 '18 at 00:20
  • "But how would I do this without hard coding it ??" What do you mean? In order to bind a variable you need to assign the value `variable = value`, there is no other way. "Also it seems like some are not working as a node" `.children` returns a tuple, not a node. "And seems I also don't know how to add children" How about `sonny = Node("Sonny", parent = dan)`? – Stop harming Monica Aug 18 '18 at 11:32
  • @Goyo that last line of code, I tried it before, doesn't work, precisely because after exporting you only get tuples not nodes. Also this tree has 6 nodes but I think I will have 600, first two levels fixed then adding as I find new nodes. There's got to be a different way than for each node instantiating it with node = Node ("Name", parent = parent) That's what I mean with hard coding. My idea was that when I find something that belongs in a branch, I can just use a function that says "append this newnode under nodeX" . Then save it and next time I load the tree the newnode is there – gaurwraith Aug 18 '18 at 11:51
  • 1
    `.children` always return a tuple of nodes, exporting has nothing to do with it. In order to append `newnode` under `nodeX`, assuming both `newnode` and `nodeX` are nodes, you just do `newnode.parent = nodeX`. – Stop harming Monica Aug 18 '18 at 12:20
  • @gaurwraith take a look below, anytree actually behaves like you expected you just forgot a `,` – Fabian N. Aug 18 '18 at 12:41

1 Answers1

1

You actually did it the right way: you just forgot a ,

from anytree import Node

udo = Node("Udo")
marc = Node("Marc", parent=udo)
Node("Lian", parent=marc)

lian, = marc.children # this is a tupel, even if its only one entry -> add ,
sonny = Node("Sonny", parent = lian)

print (lian.parent)
> Node('/Udo/Marc')

print (sonny)
> Node('/Udo/Marc/Lian/Sonny')

@How to find your nodes: You are looking for anytrees find_by_attr:

Search for a single node with attribute name having value [...]

So after loading your tree with

with open ('cajon/anytreeexample.json', 'r+', encoding = 'utf-8') as f:
    datos = importer.read(f)

You can search for nodes by name:

udo = datos.find_by_attr("Udo") # should be the same as datos if udo was the root

And then add more like so:

Node("Sonny", parent = datos.find_by_attr("lian"))
Fabian N.
  • 3,807
  • 2
  • 23
  • 46