def _thing_from_dom(dom_node, container=None, paranoia=1): "Converts an [xml_pickle] DOM tree to a 'native' Python object" for node in subnodes(dom_node): if node.nodeName == "PyObject": container = unpickle_instance(node, paranoia) # do we need to unmutate it? (check for type= being set -- # will only be set for mutated objects) if node.getAttribute('type'): # get unmutator by type= klass = node.getAttribute('type') if mutate.can_unmutate(klass, container): # note -- 'extra' isn't handled (yet) at the toplevel container = mutate.unmutate(klass, container, paranoia, None) try: id = node.getAttribute('id') visited[id] = container except KeyError: pass elif node.nodeName in ['attr', 'item', 'key', 'val']: node_family = node.getAttribute('family') node_type = node.getAttribute('type') node_name = node.getAttribute('name') # check refid first (if present, type is type of referenced object) ref_id = node.getAttribute('refid') if len(ref_id): # might be empty or None if node.nodeName == 'attr': setattr(container, node_name, visited[ref_id]) else: container.append(visited[ref_id]) # done, skip rest of block continue # if we didn't find a family tag, guess (do after refid check -- # old pickles will set type="ref" which _fix_family can't handle) node_family = _fix_family(node_family, node_type) node_valuetext = get_node_valuetext(node) # step 1 - set node_val to basic thing #if node_name == '__parent__' and getExcludeParentAttr(): # continue # Do not pickle xml_objectify bookkeeping attribute if node_family == 'none': node_val = None elif node_family == 'atom': node_val = node_valuetext elif node_family == 'seq': # seq must exist in visited{} before we unpickle subitems, # in order to handle self-references seq = [] _save_obj_with_id(node, seq) node_val = _thing_from_dom(node, seq, paranoia) elif node_family == 'map': # map must exist in visited{} before we unpickle subitems, # in order to handle self-references map = {} _save_obj_with_id(node, map) node_val = _thing_from_dom(node, map, paranoia) elif node_family == 'obj': node_val = unpickle_instance(node, paranoia) elif node_family == 'lang': # lang is a special type - we don't know how to unpickle # a generic 'lang' object, so we have to handle the specific # types here instead of in the block below # # In the future, this might be expanded to include # other languages, but for now, only Python is supported. if node_type == 'function': node_val = unpickle_function(node.getAttribute('module'), node.getAttribute('class'), paranoia) elif node_type == 'class': node_val = get_class_from_name(node.getAttribute('class'), node.getAttribute('module'), paranoia) else: raise XMLUnpicklingError, "Unknown lang type %s" % node_type elif node_family == 'uniq': # uniq is another special type that is handled here instead # of below. # Gnosis-1.0.6 encoded functions/classes as 'uniq' instead # of 'lang' -- accept these for backward compatibility. if node_type == 'function': node_val = unpickle_function(node.getAttribute('module'), node.getAttribute('class'), paranoia) elif node_type == 'class': node_val = get_class_from_name(node.getAttribute('class'), node.getAttribute('module'), paranoia) elif node_type == 'True': node_val = TRUE_VALUE elif node_type == 'False': node_val = FALSE_VALUE else: raise XMLUnpicklingError, "Unknown uniq type %s" % node_type else: raise XMLUnpicklingError, "UNKNOWN family %s,%s,%s" % ( node_family, node_type, node_name) # step 2 - take basic thing and make exact thing # Note there are several NOPs here since node_val has been decided # above for certain types. However, I left them in since I think it's # clearer to show all cases being handled (easier to see the pattern # when doing later maintenance). if node_type == 'None': node_val = None elif node_type == 'numeric': #node_val = safe_eval(node_val) node_val = to_number(node_val) elif node_type == 'string': node_val = node_val elif node_type == 'list': node_val = node_val elif node_type == 'tuple': # subtlety - if tuples could self-reference, this would be wrong # since the self ref points to a list, yet we're making it into # a tuple. it appears however that self-referencing tuples aren't # really all that legal (regular pickle can't handle them), so # this shouldn't be a practical problem. node_val = tuple(node_val) elif node_type == 'dict': node_val = node_val elif node_type == 'function': node_val = node_val elif node_type == 'class': node_val = node_val elif node_type == 'True': node_val = node_val elif node_type == 'False': node_val = node_val elif mutate.can_unmutate(node_type, node_val): mextra = node.getAttribute('extra') node_val = mutate.unmutate(node_type, node_val, paranoia, mextra) elif node_type == 'PyObject': node_val = node_val #elif ext.can_handle_xml(node_type,node_valuetext): # node_val = ext.xml_to_obj(node_type, node_valuetext, paranoia) else: raise XMLUnpicklingError, "Unknown type %s,%s" % (node, node_type) if node.nodeName == 'attr': setattr(container, node_name, node_val) else: container.append(node_val) _save_obj_with_id(node, node_val) elif node.nodeName == 'entry': keyval = _thing_from_dom(node, [], paranoia) key, val = keyval[0], keyval[1] container[key] = val # <entry> has no id for refchecking else: raise XMLUnpicklingError, \ "element %s is not in PyObjects.dtd" % node.nodeName return container
def _thing_from_dom(dom_node, container=None, paranoia=1): "Converts an [xml_pickle] DOM tree to a 'native' Python object" for node in subnodes(dom_node): if node.nodeName == "PyObject": container = unpickle_instance(node, paranoia) # do we need to unmutate it? (check for type= being set -- # will only be set for mutated objects) if node.getAttribute('type'): # get unmutator by type= klass = node.getAttribute('type') if mutate.can_unmutate(klass,container): # note -- 'extra' isn't handled (yet) at the toplevel container = mutate.unmutate(klass,container,paranoia,None) try: id = node.getAttribute('id') visited[id] = container except KeyError: pass elif node.nodeName in ['attr','item','key','val']: node_family = node.getAttribute('family') node_type = node.getAttribute('type') node_name = node.getAttribute('name') # check refid first (if present, type is type of referenced object) ref_id = node.getAttribute('refid') if len(ref_id): # might be empty or None if node.nodeName == 'attr': setattr(container, node_name, visited[ref_id]) else: container.append(visited[ref_id]) # done, skip rest of block continue # if we didn't find a family tag, guess (do after refid check -- # old pickles will set type="ref" which _fix_family can't handle) node_family = _fix_family(node_family,node_type) node_valuetext = get_node_valuetext(node) # step 1 - set node_val to basic thing #if node_name == '__parent__' and getExcludeParentAttr(): # continue # Do not pickle xml_objectify bookkeeping attribute if node_family == 'none': node_val = None elif node_family == 'atom': node_val = node_valuetext elif node_family == 'seq': # seq must exist in visited{} before we unpickle subitems, # in order to handle self-references seq = [] _save_obj_with_id(node,seq) node_val = _thing_from_dom(node,seq,paranoia) elif node_family == 'map': # map must exist in visited{} before we unpickle subitems, # in order to handle self-references map = {} _save_obj_with_id(node,map) node_val = _thing_from_dom(node,map,paranoia) elif node_family == 'obj': node_val = unpickle_instance(node, paranoia) elif node_family == 'lang': # lang is a special type - we don't know how to unpickle # a generic 'lang' object, so we have to handle the specific # types here instead of in the block below # # In the future, this might be expanded to include # other languages, but for now, only Python is supported. if node_type == 'function': node_val = unpickle_function(node.getAttribute('module'), node.getAttribute('class'), paranoia) elif node_type == 'class': node_val = get_class_from_name(node.getAttribute('class'), node.getAttribute('module'), paranoia) else: raise XMLUnpicklingError, "Unknown lang type %s" % node_type elif node_family == 'uniq': # uniq is another special type that is handled here instead # of below. # Gnosis-1.0.6 encoded functions/classes as 'uniq' instead # of 'lang' -- accept these for backward compatibility. if node_type == 'function': node_val = unpickle_function(node.getAttribute('module'), node.getAttribute('class'), paranoia) elif node_type == 'class': node_val = get_class_from_name(node.getAttribute('class'), node.getAttribute('module'), paranoia) elif node_type == 'True': node_val = TRUE_VALUE elif node_type == 'False': node_val = FALSE_VALUE else: raise XMLUnpicklingError, "Unknown uniq type %s" % node_type else: raise XMLUnpicklingError, "UNKNOWN family %s,%s,%s" % (node_family,node_type,node_name) # step 2 - take basic thing and make exact thing # Note there are several NOPs here since node_val has been decided # above for certain types. However, I left them in since I think it's # clearer to show all cases being handled (easier to see the pattern # when doing later maintenance). if node_type == 'None': node_val = None elif node_type == 'numeric': #node_val = safe_eval(node_val) node_val = to_number(node_val) elif node_type == 'string': node_val = node_val elif node_type == 'list': node_val = node_val elif node_type == 'tuple': # subtlety - if tuples could self-reference, this would be wrong # since the self ref points to a list, yet we're making it into # a tuple. it appears however that self-referencing tuples aren't # really all that legal (regular pickle can't handle them), so # this shouldn't be a practical problem. node_val = tuple(node_val) elif node_type == 'dict': node_val = node_val elif node_type == 'function': node_val = node_val elif node_type == 'class': node_val = node_val elif node_type == 'True': node_val = node_val elif node_type == 'False': node_val = node_val elif mutate.can_unmutate(node_type,node_val): mextra = node.getAttribute('extra') node_val = mutate.unmutate(node_type,node_val,paranoia, mextra) elif node_type == 'PyObject': node_val = node_val #elif ext.can_handle_xml(node_type,node_valuetext): # node_val = ext.xml_to_obj(node_type, node_valuetext, paranoia) else: raise XMLUnpicklingError, "Unknown type %s,%s" % (node,node_type) if node.nodeName == 'attr': setattr(container,node_name,node_val) else: container.append(node_val) _save_obj_with_id(node,node_val) elif node.nodeName == 'entry': keyval = _thing_from_dom(node, [], paranoia) key, val = keyval[0], keyval[1] container[key] = val # <entry> has no id for refchecking else: raise XMLUnpicklingError, \ "element %s is not in PyObjects.dtd" % node.nodeName return container