a have a problem with the following with the following code:
from lxml import etree as ET
class test(object):
def __init__(self, **args):
self.tag = []
self.meshfiles = []
self.root = None
def addMesh(self, **args):
if not "filename" in args:
raise KeyError("No filename given")
else:
self.meshfiles.append(args["filename"])
def populateTree(self, tag, text='', attr={}, children={}):
return {'tag': tag, 'text': text, 'attr': attr, 'children': children}
@property
def tree(self):
baum = {'meshes': {}}
if len(self.meshfiles) == 1:
baum['meshes'] = self.populateTree('mesh', text=self.meshfiles[0])
else:
baum['meshes'] = self.populateTree('meshes')
for i, meshfile in enumerate(self.meshfiles):
# works:
baum['meshes']['children'][i] = self.populateTree('mesh', text=meshfile)
# not working:
# baum['meshes']['children'][i] = self.populateTree('mesh', text=meshfile, children={})
return baum
def createXML(self):
self.root = ET.Element("rootelement")
self.dict2xml(self.root, self.tree)
return ET.tostring(self.root, pretty_print=True)
def dict2xml(self, parent, dictionary):
for entry in dictionary:
self.tag.append(ET.SubElement(parent, dictionary[entry]['tag']))
self.tag[-1].text = str(dictionary[entry]['text'])
for attr in dictionary[entry]['attr']:
self.tag[-1].set(attr, dictionary[entry]['attr'][attr])
if len(dictionary[entry]['children']) > 0:
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
if __name__ == "__main__":
t = test()
t.addMesh(filename="a")
t.addMesh(filename="c")
t.addMesh(filename="b")
print(t.tree)
print(t.createXML())
While this example gives a recursion error:
{'meshes': {'tag': 'meshes', 'text': '', 'attr': {}, 'children': {0: {'tag': 'mesh', 'text': 'a', 'attr': {}, 'children': {...}}, 1: {'tag': 'mesh', 'text': 'c', 'attr': {}, 'children': {...}}, 2: {'tag': 'mesh', 'text': 'b', 'attr': {}, 'children': {...}}}}}
Traceback (most recent call last):
File "/home/buchwalj/temp/bug-python/test.py", line 48, in <module>
print(t.createXML())
File "/home/buchwalj/temp/bug-python/test.py", line 32, in createXML
self.dict2xml(self.root, self.tree)
File "/home/buchwalj/temp/bug-python/test.py", line 41, in dict2xml
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
File "/home/buchwalj/temp/bug-python/test.py", line 41, in dict2xml
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
File "/home/buchwalj/temp/bug-python/test.py", line 41, in dict2xml
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
[Previous line repeated 994 more times]
File "/home/buchwalj/temp/bug-python/test.py", line 36, in dict2xml
self.tag.append(ET.SubElement(parent, dictionary[entry]['tag']))
RecursionError: maximum recursion depth exceeded while calling a Python object
Commenting out line 27 instead of 25 prints out the correct dictionary with the corresponding xml. The only difference there is, that the working example uses the same argument as the default argument in the function call instead of the default argument itself. Is this a bug or am I doing something wrong here?
Using empty dictionary as defaults are actually bad ideas, mainly because dictionaries are mutable objects, meaning if you accidentally changing the content of the dictionary, it is there to stay (cause reference to object stays the same). See: Why is the empty dictionary a dangerous default value in Python?
I would suggest changing your populateTree
function to something like:
def populateTree(self, tag, text='', attr=None, children=None):
if attr is None:
attr = {}
if children is None:
children = {}
return {'tag': tag, 'text': text, 'attr': attr, 'children': children}
so it creates a new empty dictionary everything populateTree
is called without those arguments.