def reduce(self, name, bodytext): #dbg("ABOUT TO REDUCE %s %s"%(name,str(self.elem_stk[-1]))) dbg("ABOUT TO REDUCE %s" % (name)) self.prstk() elem = self.elem_stk.pop() refid = elem[4].get('refid') if refid: obj = self.visited[refid] #dbg("GOT REF %s,%s"%(str(refid),obj)) self.val_stk.append((elem[0], elem[3], obj)) dbg("<<<<<<<<<<<< REDUCED") self.prstk() self.nr_objs += 1 return if elem[4].get('value'): valuetext = unsafe_string(elem[4].get('value')) else: valuetext = unsafe_content(bodytext) #valuetext = elem[4].get('value') or bodytext if name in ['attr', 'key', 'val', 'item']: # step 1 -- convert family -> basic_type family = elem[1] if family == 'atom': dbg("** ATOM") obj = valuetext elif family == 'none': dbg("** NONE") obj = None elif family == 'seq': dbg("** SEQ") obj = elem[5] while self.val_stk[-1][0] != 'STOP': obj.insert(0, self.val_stk.pop()[2]) self.val_stk.pop() # pop STOP elif family == 'map': dbg("** MAP") obj = elem[5] while self.val_stk[-1][0] != 'STOP': e = self.val_stk.pop() obj[e[2][0]] = e[2][1] self.val_stk.pop() # pop STOP elif family == 'obj': dbg("** OBJ") obj = self.unpickle_instance(elem) elif family == 'lang': if elem[2] == 'function': obj = unpickle_function(elem[4].get('module'), elem[4].get('class'), self.paranoia) elif elem[2] == 'class': obj = get_class_from_name(elem[4].get('class'), elem[4].get('module'), self.paranoia) else: raise XMLUnpicklingError, \ "Unknown lang type %s" % elem[2] elif family == 'uniq': # uniq is a special type - we don't know how to unpickle # a generic 'uniq' object, so we have to handle the specific # types here instead of in the block below # Gnosis-1.0.6 and earlier encoded functions/classes # as 'uniq' instead of 'lang' -- accept those encodings # for backward compatibility if elem[2] == 'function': obj = unpickle_function(elem[4].get('module'), elem[4].get('class'), self.paranoia) elif elem[2] == 'class': obj = get_class_from_name(elem[4].get('class'), elem[4].get('module'), self.paranoia) elif elem[2] == 'True': obj = TRUE_VALUE elif elem[2] == 'False': obj = FALSE_VALUE else: raise XMLUnpicklingError, \ "Unknown uniq type %s" % elem[2] else: raise XMLUnpicklingError, \ "UNKNOWN family %s,%s,%s" % \ (family,elem[2],elem[3]) # step 2 -- convert basic -> specific type # (many of these are NOPs, but included for clarity) if elem[2] == 'numeric': dbg("** NUMERIC") #if obj.isdigit(): # obj = string.atoi(obj) #else: # obj = eval(obj) obj = to_number(obj) elif elem[2] == 'string': dbg("** STRING") obj = obj elif elem[2] == 'None': obj = obj elif elem[2] in ['tuple', 'list']: dbg("** TUPLE/LIST") if elem[2] != 'list': obj = tuple(obj) else: obj = obj elif elem[2] == 'dict': obj = obj elif elem[2] == 'PyObject': obj = obj elif elem[2] == 'function': obj = obj elif elem[2] == 'class': obj = obj elif elem[2] == 'True': obj = obj elif elem[2] == 'False': obj = obj elif mutate.can_unmutate(elem[2], obj): mextra = elem[4].get('extra') obj = mutate.unmutate(elem[2], obj, self.paranoia, mextra) #elif xmlext.can_handle_xml(elem[1],valuetext): # obj = xmlext.xml_to_obj(elem[1],valuetext,self.paranoia) else: self.prstk(1) raise XMLUnpicklingError, \ "UNHANDLED elem %s"%elem[2] # push on stack and save obj ref self.val_stk.append((elem[0], elem[3], obj)) self.save_obj_id(obj, elem) self.nr_objs += 1 elif name == 'entry': e1 = self.val_stk.pop() e2 = self.val_stk.pop() if e1[0] == 'val': ent = ((elem[0], elem[3], (e2[2], e1[2]))) else: ent = ((elem[0], elem[3], (e1[2], e2[2]))) # <entry> actually has no id self.save_obj_id(ent, elem) self.val_stk.append(ent) elif name == 'PyObject': obj = self.unpickle_instance(elem) # do we need to unmutate it? (check for type= being set - # will only be set for mutated objects) if elem[2] is not None and len(elem[2]): if mutate.can_unmutate(elem[2], obj): # note -- 'extra' isn't handled (yet) at the toplevel obj = mutate.unmutate(elem[2], obj, self.paranoia, None) self.val_stk.append((elem[0], elem[3], obj)) self.save_obj_id(obj, elem) self.nr_objs += 1 else: raise str("UNHANDLED name %s" % name) dbg("<<<<<<<<<<<< REDUCED") self.prstk()
def reduce(self,name,bodytext): #dbg("ABOUT TO REDUCE %s %s"%(name,str(self.elem_stk[-1]))) dbg("ABOUT TO REDUCE %s"%(name)) self.prstk() elem = self.elem_stk.pop() refid = elem[4].get('refid') if refid: obj = self.visited[refid] #dbg("GOT REF %s,%s"%(str(refid),obj)) self.val_stk.append((elem[0],elem[3],obj)) dbg("<<<<<<<<<<<< REDUCED") self.prstk() self.nr_objs += 1 return if elem[4].get('value'): valuetext = unsafe_string(elem[4].get('value')) else: valuetext = unsafe_content(bodytext) #valuetext = elem[4].get('value') or bodytext if name in ['attr','key','val','item']: # step 1 -- convert family -> basic_type family = elem[1] if family == 'atom': dbg("** ATOM") obj = valuetext elif family == 'none': dbg("** NONE") obj = None elif family == 'seq': dbg("** SEQ") obj = elem[5] while self.val_stk[-1][0] != 'STOP': obj.insert(0,self.val_stk.pop()[2]) self.val_stk.pop() # pop STOP elif family == 'map': dbg("** MAP") obj = elem[5] while self.val_stk[-1][0] != 'STOP': e = self.val_stk.pop() obj[e[2][0]] = e[2][1] self.val_stk.pop() # pop STOP elif family == 'obj': dbg("** OBJ") obj = self.unpickle_instance(elem) elif family == 'lang': if elem[2] == 'function': obj = unpickle_function(elem[4].get('module'), elem[4].get('class'), self.paranoia) elif elem[2] == 'class': obj = get_class_from_name(elem[4].get('class'), elem[4].get('module'), self.paranoia) else: raise XMLUnpicklingError, \ "Unknown lang type %s" % elem[2] elif family == 'uniq': # uniq is a special type - we don't know how to unpickle # a generic 'uniq' object, so we have to handle the specific # types here instead of in the block below # Gnosis-1.0.6 and earlier encoded functions/classes # as 'uniq' instead of 'lang' -- accept those encodings # for backward compatibility if elem[2] == 'function': obj = unpickle_function(elem[4].get('module'), elem[4].get('class'), self.paranoia) elif elem[2] == 'class': obj = get_class_from_name(elem[4].get('class'), elem[4].get('module'), self.paranoia) elif elem[2] == 'True': obj = TRUE_VALUE elif elem[2] == 'False': obj = FALSE_VALUE else: raise XMLUnpicklingError, \ "Unknown uniq type %s" % elem[2] else: raise XMLUnpicklingError, \ "UNKNOWN family %s,%s,%s" % \ (family,elem[2],elem[3]) # step 2 -- convert basic -> specific type # (many of these are NOPs, but included for clarity) if elem[2] == 'numeric': dbg("** NUMERIC") #if obj.isdigit(): # obj = string.atoi(obj) #else: # obj = eval(obj) obj = to_number(obj) elif elem[2] == 'string': dbg("** STRING") obj = obj elif elem[2] == 'None': obj = obj elif elem[2] in ['tuple','list']: dbg("** TUPLE/LIST") if elem[2] != 'list': obj = tuple(obj) else: obj = obj elif elem[2] == 'dict': obj = obj elif elem[2] == 'PyObject': obj = obj elif elem[2] == 'function': obj = obj elif elem[2] == 'class': obj = obj elif elem[2] == 'True': obj = obj elif elem[2] == 'False': obj = obj elif mutate.can_unmutate(elem[2],obj): mextra = elem[4].get('extra') obj = mutate.unmutate(elem[2],obj,self.paranoia,mextra) #elif xmlext.can_handle_xml(elem[1],valuetext): # obj = xmlext.xml_to_obj(elem[1],valuetext,self.paranoia) else: self.prstk(1) raise XMLUnpicklingError, \ "UNHANDLED elem %s"%elem[2] # push on stack and save obj ref self.val_stk.append((elem[0],elem[3],obj)) self.save_obj_id(obj,elem) self.nr_objs += 1 elif name == 'entry': e1 = self.val_stk.pop() e2 = self.val_stk.pop() if e1[0] == 'val': ent = ((elem[0],elem[3],(e2[2],e1[2]))) else: ent = ((elem[0],elem[3],(e1[2],e2[2]))) # <entry> actually has no id self.save_obj_id(ent,elem) self.val_stk.append(ent) elif name == 'PyObject': obj = self.unpickle_instance(elem) # do we need to unmutate it? (check for type= being set - # will only be set for mutated objects) if elem[2] is not None and len(elem[2]): if mutate.can_unmutate(elem[2],obj): # note -- 'extra' isn't handled (yet) at the toplevel obj = mutate.unmutate(elem[2],obj,self.paranoia,None) self.val_stk.append((elem[0],elem[3],obj)) self.save_obj_id(obj,elem) self.nr_objs += 1 else: raise str("UNHANDLED name %s"%name) dbg("<<<<<<<<<<<< REDUCED") self.prstk()
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