def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy): tag_body = [] (mtag,thing,in_body,mextra) = try_mutate(orig_thing,None, getInBody(type(orig_thing)), None) if type(thing) is NoneType: start_tag = start_tag + "%s />\n" % (_family_type('none','None',None,None)) close_tag = '' # bool cannot be used as a base class (see sanity check above) so if thing # is a bool it will always be BooleanType, and either True or False elif Have_BoolClass and type(thing) is BooleanType: if thing is True: typestr = 'True' else: # must be False typestr = 'False' if in_body: start_tag = start_tag + '%s>%s' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = '' # ClassType will get caught by isInstanceLike(), which is not # what we want. There are two cases here - the first catches # old-style classes, the second catches new-style classes. elif isinstance(thing,ClassType) or isNewStyleClass(thing): module = thing.__module__ if module: extra = 'module="%s" class="%s"' % (module, thing.__name__) else: extra = 'class="%s"' % _klass(thing.__name__) start_tag = start_tag + '%s %s/>\n' % \ (_family_type('lang','class',mtag,mextra),extra) close_tag = '' # have to check for instance-like next since ints, etc., can be # instance-like in Python 2.2+. if it's really an object, we don't # want to fall through to the regular int,float,etc. code, since # that would skip the special handling in pickle_instance(). elif isInstanceLike(thing): module = _module(thing) if module: extra = 'module="%s" class="%s"' % (module, _klass(thing)) else: extra = 'class="%s"' % _klass(thing) start_tag, do_copy = \ _tag_compound(start_tag,_family_type('obj','PyObject',mtag,mextra), orig_thing, deepcopy, extra) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: pickle_instance(thing, tag_body, level+1, deepcopy) else: close_tag = '' elif isinstance_any(thing, (IntType, LongType, FloatType, ComplexType)): #thing_str = repr(thing) thing_str = ntoa(thing) if in_body: # we don't call safe_content() here since numerics won't # contain special XML chars. # the unpickler can either call unsafe_content() or not, # it won't matter start_tag = start_tag + '%s>%s' % \ (_family_type('atom','numeric',mtag,mextra), thing_str) close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('atom','numeric',mtag,mextra),thing_str) close_tag = '' elif isinstance_any(thing, (StringType,UnicodeType)): #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # special check for now - this will be fixed in the next major # gnosis release, so I don't care that the code is inline & gross # for now #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if isinstance(thing,UnicodeType): # can't pickle unicode containing the special "escape" sequence # we use for putting strings in the XML body (they'll be unpickled # as strings, not unicode, if we do!) if thing[0:2] == u'\xbb\xbb' and thing[-2:] == u'\xab\xab': raise Exception("Unpickleable Unicode value. To be fixed in next major Gnosis release.") # see if it contains any XML-illegal values if not is_legal_xml(thing): raise Exception("Unpickleable Unicode value. To be fixed in next major Gnosis release.") if isinstance(thing,StringType) and getInBody(StringType): # technically, this will crash safe_content(), but I prefer to # have the test here for clarity try: # safe_content assumes it can always convert the string # to unicode, which isn't true (eg. pickle a UTF-8 value) u = unicode(thing) except: raise Exception("Unpickleable string value (%s). To be fixed in next major Gnosis release." % repr(thing)) #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # End of temporary hack code #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if in_body: start_tag = start_tag + '%s>%s' % \ (_family_type('atom','string',mtag,mextra), safe_content(thing)) close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('atom','string',mtag,mextra), safe_string(thing)) close_tag = '' # General notes: # 1. When we make references, set type to referenced object # type -- we don't need type when unpickling, but it may be useful # to someone reading the XML file # 2. For containers, we have to stick the container into visited{} # before pickling subitems, in case it contains self-references # (we CANNOT just move the visited{} update to the top of this # function, since that would screw up every _family_type() call) elif type(thing) is TupleType: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','tuple',mtag,mextra), orig_thing,deepcopy) if do_copy: for item in thing: tag_body.append(_item_tag(item, level+1, deepcopy)) else: close_tag = '' elif type(thing) is ListType: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','list',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for item in thing: tag_body.append(_item_tag(item, level+1, deepcopy)) else: close_tag = '' elif type(thing) in [DictType]: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('map','dict',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for key, val in thing.items(): tag_body.append(_entry_tag(key, val, level+1, deepcopy)) else: close_tag = '' elif type(thing) in [FunctionType,BuiltinFunctionType]: info = get_function_info(thing) # use module/class tags -- not perfect semantically, but better # that creating new attr names start_tag = start_tag + '%s module="%s" class="%s"/>\n' % \ (_family_type('lang','function',mtag,mextra), info[0],info[1]) close_tag = '' else: # try using pickled value as the XML value tag. # rationale: it won't be (easily) editable, but at least # you'll get valid XML even if your classes happen to # contain a few "foreign" types, and you don't feel like # writing a helper object (see gnosis.xml.pickle.ext for # how to do that) try: # we can't lookup the helper by type, since rawpickle can pickle # any pickleable class, so lookup by tag (unmutator) instead # (mutator & unmutator are always the same object) # always put rawpickles in the element body mutator = get_unmutator('rawpickle',None) thing = safe_content(mutator.mutate(thing).obj) start_tag = start_tag + '%s>%s' % (_family_type('atom',None,'rawpickle',None), thing) close_tag = close_tag.lstrip() except: raise XMLPicklingError, "non-handled type %s" % type(thing) # need to keep a ref to the object for two reasons - # 1. we can ref it later instead of copying it into the XML stream # 2. need to keep temporary objects around so their ids don't get reused # if DEEPCOPY, we can skip this -- reusing ids is not an issue if we # never look at them if not deepcopy: visited[id(orig_thing)] = orig_thing return start_tag + ''.join(tag_body) + close_tag
def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy): tag_body = [] (mtag, thing, in_body, mextra) = try_mutate(orig_thing, None, getInBody(type(orig_thing)), None) if type(thing) is NoneType: start_tag += "%s />\n" % (_family_type('none', 'None', None, None)) close_tag = '' # looks like bool cannot be used as a base class, so if thing # is a bool it will always be BooleanType, and either True or False elif py_version >= '2.3' and type(thing) is BooleanType: if thing is True: typestr = 'True' else: # must be False typestr = 'False' if in_body: start_tag +='%s>%s' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = close_tag.lstrip() else: start_tag +='%s value="%s" />\n' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = '' # ClassType will get caught by isInstanceLike(), which is not # what we want (also check for new-style class objects) elif isinstance(thing, ClassType) or isNewStyleClass(thing): module = thing.__module__ if module: extra = 'module="%s" class="%s"' % (module, thing.__name__) else: extra = 'class="%s"' % _klass(thing.__name__) start_tag +='%s %s/>\n' % \ (_family_type('lang','class',mtag,mextra),extra) close_tag = '' # have to check for instance-like next since ints, etc., can be # instance-like in Python 2.2+. if it's really an object, we don't # want to fall through to the regular int,float,etc. code, since # that would skip the special handling in pickle_instance(). elif isInstanceLike(thing): module = _module(thing) if module: extra = 'module="%s" class="%s"' % (module, _klass(thing)) else: extra = 'class="%s"' % _klass(thing) start_tag, do_copy = \ _tag_compound(start_tag,_family_type('obj','PyObject',mtag,mextra), orig_thing, deepcopy, extra) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: pickle_instance(thing, tag_body, level + 1, deepcopy) else: close_tag = '' elif isinstance_any(thing, (IntType, LongType, FloatType, ComplexType)): #thing_str = repr(thing) thing_str = ntoa(thing) if in_body: # we don't call safe_content() here since numerics won't # contain special XML chars. # the unpickler can either call unsafe_content() or not, # it won't matter start_tag +='%s>%s' % \ (_family_type('atom','numeric',mtag,mextra), thing_str) close_tag = close_tag.lstrip() else: start_tag +='%s value="%s" />\n' % \ (_family_type('atom','numeric',mtag,mextra),thing_str) close_tag = '' elif isinstance_any(thing, (StringType, UnicodeType)): if in_body: start_tag +='%s>%s' % \ (_family_type('atom','string',mtag,mextra), safe_content(thing)) close_tag = close_tag.lstrip() else: start_tag +='%s value="%s" />\n' % \ (_family_type('atom','string',mtag,mextra), safe_string(thing)) close_tag = '' # General notes: # 1. When we make references, set type to referenced object # type -- we don't need type when unpickling, but it may be useful # to someone reading the XML file # 2. For containers, we have to stick the container into visited{} # before pickling subitems, in case it contains self-references # (we CANNOT just move the visited{} update to the top of this # function, since that would screw up every _family_type() call) elif type(thing) is TupleType: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','tuple',mtag,mextra), orig_thing,deepcopy) if do_copy: for item in thing: tag_body.append(_item_tag(item, level + 1, deepcopy)) else: close_tag = '' elif type(thing) is ListType: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','list',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for item in thing: tag_body.append(_item_tag(item, level + 1, deepcopy)) else: close_tag = '' elif type(thing) in [DictType]: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('map','dict',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for key, val in thing.items(): tag_body.append(_entry_tag(key, val, level + 1, deepcopy)) else: close_tag = '' elif type(thing) in [FunctionType, BuiltinFunctionType]: info = get_function_info(thing) # use module/class tags -- not perfect semantically, but better # that creating new attr names start_tag +='%s module="%s" class="%s"/>\n' % \ (_family_type('lang','function',mtag,mextra), info[0],info[1]) close_tag = '' else: # try using pickled value as the XML value tag. # rationale: it won't be (easily) editable, but at least # you'll get valid XML even if your classes happen to # contain a few "foreign" types, and you don't feel like # writing a helper object (see gnosis.xml.pickle.ext for # how to do that) try: # we can't lookup the helper by type, since rawpickle can pickle # any pickleable class, so lookup by tag (unmutator) instead # (mutator & unmutator are always the same object) # always put rawpickles in the element body mutator = get_unmutator('rawpickle', None) thing = safe_content(mutator.mutate(thing).obj) start_tag += '%s>%s' % (_family_type('atom', None, 'rawpickle', None), thing) close_tag = close_tag.lstrip() except: raise XMLPicklingError, "non-handled type %s" % type(thing) # need to keep a ref to the object for two reasons - # 1. we can ref it later instead of copying it into the XML stream # 2. need to keep temporary objects around so their ids don't get reused # if DEEPCOPY, we can skip this -- reusing ids is not an issue if we # never look at them if not deepcopy: visited[id(orig_thing)] = orig_thing return start_tag + ''.join(tag_body) + close_tag
def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy): tag_body = [] (mtag, thing, in_body, mextra) = try_mutate(orig_thing, None, getInBody(type(orig_thing)), None) if type(thing) is type(None): start_tag = start_tag + "%s />\n" % (_family_type( 'none', 'None', None, None)) close_tag = '' # bool cannot be used as a base class (see sanity check above) so if thing # is a bool it will always be BooleanType, and either True or False elif Have_BoolClass and type(thing) is bool: if thing is True: typestr = 'True' else: # must be False typestr = 'False' if in_body: start_tag = start_tag + '%s>%s' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('uniq',typestr,mtag,mextra), '') close_tag = '' # ClassType will get caught by isInstanceLike(), which is not # what we want. There are two cases here - the first catches # old-style classes, the second catches new-style classes. elif isinstance(thing, type) or isNewStyleClass(thing): module = thing.__module__ if module: extra = 'module="%s" class="%s"' % (module, thing.__name__) else: extra = 'class="%s"' % _klass(thing.__name__) start_tag = start_tag + '%s %s/>\n' % \ (_family_type('lang','class',mtag,mextra),extra) close_tag = '' # have to check for instance-like next since ints, etc., can be # instance-like in Python 2.2+. if it's really an object, we don't # want to fall through to the regular int,float,etc. code, since # that would skip the special handling in pickle_instance(). elif isInstanceLike(thing): module = _module(thing) if module: extra = 'module="%s" class="%s"' % (module, _klass(thing)) else: extra = 'class="%s"' % _klass(thing) start_tag, do_copy = \ _tag_compound(start_tag,_family_type('obj','PyObject',mtag,mextra), orig_thing, deepcopy, extra) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: pickle_instance(thing, tag_body, level + 1, deepcopy) else: close_tag = '' elif isinstance_any(thing, (int, int, float, complex)): #thing_str = repr(thing) thing_str = ntoa(thing) if in_body: # we don't call safe_content() here since numerics won't # contain special XML chars. # the unpickler can either call unsafe_content() or not, # it won't matter start_tag = start_tag + '%s>%s' % \ (_family_type('atom','numeric',mtag,mextra), thing_str) close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('atom','numeric',mtag,mextra),thing_str) close_tag = '' elif isinstance_any(thing, (bytes, str)): #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # special check for now - this will be fixed in the next major # gnosis release, so I don't care that the code is inline & gross # for now #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if isinstance(thing, str): # can't pickle unicode containing the special "escape" sequence # we use for putting strings in the XML body (they'll be unpickled # as strings, not unicode, if we do!) if thing[0:2] == '\xbb\xbb' and thing[-2:] == '\xab\xab': raise Exception( "Unpickleable Unicode value. To be fixed in next major Gnosis release." ) # see if it contains any XML-illegal values if not is_legal_xml(thing): raise Exception( "Unpickleable Unicode value. To be fixed in next major Gnosis release." ) if isinstance(thing, bytes) and getInBody(bytes): # technically, this will crash safe_content(), but I prefer to # have the test here for clarity try: # safe_content assumes it can always convert the string # to unicode, which isn't true (eg. pickle a UTF-8 value) u = str(thing) except: raise Exception( "Unpickleable string value (%s). To be fixed in next major Gnosis release." % repr(thing)) #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # End of temporary hack code #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if in_body: start_tag = start_tag + '%s>%s' % \ (_family_type('atom','string',mtag,mextra), safe_content(thing)) close_tag = close_tag.lstrip() else: start_tag = start_tag + '%s value="%s" />\n' % \ (_family_type('atom','string',mtag,mextra), safe_string(thing)) close_tag = '' # General notes: # 1. When we make references, set type to referenced object # type -- we don't need type when unpickling, but it may be useful # to someone reading the XML file # 2. For containers, we have to stick the container into visited{} # before pickling subitems, in case it contains self-references # (we CANNOT just move the visited{} update to the top of this # function, since that would screw up every _family_type() call) elif type(thing) is tuple: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','tuple',mtag,mextra), orig_thing,deepcopy) if do_copy: for item in thing: tag_body.append(_item_tag(item, level + 1, deepcopy)) else: close_tag = '' elif type(thing) is list: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('seq','list',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for item in thing: tag_body.append(_item_tag(item, level + 1, deepcopy)) else: close_tag = '' elif type(thing) in [dict]: start_tag, do_copy = \ _tag_compound(start_tag,_family_type('map','dict',mtag,mextra), orig_thing,deepcopy) # need to remember we've seen container before pickling subitems visited[id(orig_thing)] = orig_thing if do_copy: for key, val in list(thing.items()): tag_body.append(_entry_tag(key, val, level + 1, deepcopy)) else: close_tag = '' elif type(thing) in [FunctionType, BuiltinFunctionType]: info = get_function_info(thing) # use module/class tags -- not perfect semantically, but better # that creating new attr names start_tag = start_tag + '%s module="%s" class="%s"/>\n' % \ (_family_type('lang','function',mtag,mextra), info[0],info[1]) close_tag = '' else: # try using pickled value as the XML value tag. # rationale: it won't be (easily) editable, but at least # you'll get valid XML even if your classes happen to # contain a few "foreign" types, and you don't feel like # writing a helper object (see gnosis.xml.pickle.ext for # how to do that) try: # we can't lookup the helper by type, since rawpickle can pickle # any pickleable class, so lookup by tag (unmutator) instead # (mutator & unmutator are always the same object) # always put rawpickles in the element body mutator = get_unmutator('rawpickle', None) thing = safe_content(mutator.mutate(thing).obj) start_tag = start_tag + '%s>%s' % (_family_type( 'atom', None, 'rawpickle', None), thing) close_tag = close_tag.lstrip() except: raise XMLPicklingError("non-handled type %s" % type(thing)) # need to keep a ref to the object for two reasons - # 1. we can ref it later instead of copying it into the XML stream # 2. need to keep temporary objects around so their ids don't get reused # if DEEPCOPY, we can skip this -- reusing ids is not an issue if we # never look at them if not deepcopy: visited[id(orig_thing)] = orig_thing return start_tag + ''.join(tag_body) + close_tag