Exemple #1
0
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
Exemple #2
0
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