def _restore_from_dict(self, obj, instance, ignorereserved=True): restore_key = self._restore_key_fn() method = _obj_setattr for k, v in sorted(obj.items(), key=util.itemgetter): # ignore the reserved attribute if ignorereserved and k in tags.RESERVED: continue self._namestack.append(k) k = restore_key(k) # step into the namespace value = self._restore(v) if (util.is_noncomplex(instance) or util.is_dictionary_subclass(instance)): instance[k] = value else: setattr(instance, k, value) # This instance has an instance variable named `k` that is # currently a proxy and must be replaced if isinstance(value, _Proxy): self._proxies.append((instance, k, value, method)) # step out self._namestack.pop()
def restore(self, obj): """ Restores a flattened object to its original python state. Simply returns any of the basic builtin types >>> u = Unpickler() >>> u.restore('hello world') 'hello world' >>> u.restore({'key': 'value'}) {'key': 'value'} """ self._push() if has_tag(obj, tags.ID): objNumber = obj[tags.ID] try: objRef = self._objs[objNumber] except IndexError: raise IndexError( 'Cannot find objRef %d in self._objs of len(%d), looking for obj %r' % (objNumber, len(self._objs), obj)) poppedValue = self._pop(objRef) return poppedValue if has_tag(obj, tags.REF): return self._pop(self._namedict.get(obj[tags.REF])) if has_tag(obj, tags.TYPE): typeref = loadclass(obj[tags.TYPE]) if not typeref: return self._pop(obj) return self._pop(typeref) if has_tag(obj, tags.REPR): return self._pop(loadrepr(obj[tags.REPR])) if has_tag(obj, tags.OBJECT): cls = loadclass(obj[tags.OBJECT]) if not cls: return self._pop(obj) # check custom handlers HandlerClass = handlers.registry.get(cls) if HandlerClass: handler = HandlerClass(self) return self._pop(handler.restore(obj)) try: if hasattr(cls, '__new__'): instance = cls.__new__(cls) else: instance = object.__new__(cls) except TypeError: # old-style classes try: instance = cls() except TypeError: # fail gracefully if the constructor requires arguments self._mkref(obj) return self._pop(obj) # keep a obj->name mapping for use in the _isobjref() case self._mkref(instance) if hasattr(instance, '__setstate__') and has_tag(obj, tags.STATE): state = self.restore(obj[tags.STATE]) instance.__setstate__(state) return self._pop(instance) for k, v in sorted(obj.iteritems(), key=operator.itemgetter(0)): # ignore the reserved attribute if k in tags.RESERVED: continue self._namestack.append(k) # step into the namespace value = self.restore(v) if (util.is_noncomplex(instance) or util.is_dictionary_subclass(instance)): instance[k] = value else: setattr(instance, k, value) # step out self._namestack.pop() # Handle list and set subclasses if has_tag(obj, tags.SEQ): if hasattr(instance, 'append'): for v in obj[tags.SEQ]: instance.append(self.restore(v)) if hasattr(instance, 'add'): for v in obj[tags.SEQ]: instance.add(self.restore(v)) return self._pop(instance) if util.is_list(obj): return self._pop([self.restore(v) for v in obj]) if has_tag(obj, tags.TUPLE): return self._pop(tuple([self.restore(v) for v in obj[tags.TUPLE]])) if has_tag(obj, tags.SET): return self._pop(set([self.restore(v) for v in obj[tags.SET]])) if util.is_dictionary(obj): data = {} for k, v in sorted(obj.iteritems(), key=operator.itemgetter(0)): self._namestack.append(k) data[k] = self.restore(v) self._namestack.pop() return self._pop(data) return self._pop(obj)
def restore(self, obj): """ Restores a flattened object to its original python state. Simply returns any of the basic builtin types >>> u = Unpickler() >>> u.restore('hello world') 'hello world' >>> u.restore({'key': 'value'}) {'key': 'value'} """ self._push() if has_tag(obj, tags.ID): objNumber = obj[tags.ID] try: objRef = self._objs[objNumber] except IndexError: raise IndexError('Cannot find objRef %d in self._objs of len(%d), looking for obj %r' % (objNumber, len(self._objs), obj)) poppedValue = self._pop(objRef) return poppedValue if has_tag(obj, tags.REF): return self._pop(self._namedict.get(obj[tags.REF])) if has_tag(obj, tags.TYPE): typeref = loadclass(obj[tags.TYPE]) if not typeref: return self._pop(obj) return self._pop(typeref) if has_tag(obj, tags.REPR): return self._pop(loadrepr(obj[tags.REPR])) if has_tag(obj, tags.OBJECT): cls = loadclass(obj[tags.OBJECT]) if not cls: return self._pop(obj) # check custom handlers HandlerClass = handlers.registry.get(cls) if HandlerClass: handler = HandlerClass(self) return self._pop(handler.restore(obj)) try: if hasattr(cls, '__new__'): instance = cls.__new__(cls) else: instance = object.__new__(cls) except TypeError: # old-style classes try: instance = cls() except TypeError: # fail gracefully if the constructor requires arguments self._mkref(obj) return self._pop(obj) # keep a obj->name mapping for use in the _isobjref() case self._mkref(instance) if hasattr(instance, '__setstate__') and has_tag(obj, tags.STATE): state = self.restore(obj[tags.STATE]) instance.__setstate__(state) return self._pop(instance) for k, v in sorted(obj.iteritems(), key=operator.itemgetter(0)): # ignore the reserved attribute if k in tags.RESERVED: continue self._namestack.append(k) # step into the namespace value = self.restore(v) if (util.is_noncomplex(instance) or util.is_dictionary_subclass(instance)): instance[k] = value else: setattr(instance, k, value) # step out self._namestack.pop() # Handle list and set subclasses if has_tag(obj, tags.SEQ): if hasattr(instance, 'append'): for v in obj[tags.SEQ]: instance.append(self.restore(v)) if hasattr(instance, 'add'): for v in obj[tags.SEQ]: instance.add(self.restore(v)) return self._pop(instance) if util.is_list(obj): return self._pop([self.restore(v) for v in obj]) if has_tag(obj, tags.TUPLE): return self._pop(tuple([self.restore(v) for v in obj[tags.TUPLE]])) if has_tag(obj, tags.SET): return self._pop(set([self.restore(v) for v in obj[tags.SET]])) if util.is_dictionary(obj): data = {} for k, v in sorted(obj.iteritems(), key=operator.itemgetter(0)): self._namestack.append(k) data[k] = self.restore(v) self._namestack.pop() return self._pop(data) return self._pop(obj)
def _flatten_obj_instance(self, obj): """Recursively flatten an instance and return a json-friendly dict """ data = {} has_class = hasattr(obj, '__class__') has_dict = hasattr(obj, '__dict__') has_slots = not has_dict and hasattr(obj, '__slots__') has_getnewargs = util.has_method(obj, '__getnewargs__') has_getnewargs_ex = util.has_method(obj, '__getnewargs_ex__') has_getinitargs = util.has_method(obj, '__getinitargs__') has_reduce, has_reduce_ex = util.has_reduce(obj) # Support objects with __getstate__(); this ensures that # both __setstate__() and __getstate__() are implemented has_getstate = hasattr(obj, '__getstate__') # not using has_method since __getstate__() is handled separately below if has_class: cls = obj.__class__ else: cls = type(obj) # Check for a custom handler class_name = util.importable_name(cls) handler = handlers.get(cls, handlers.get(class_name)) if handler is not None: if self.unpicklable: data[tags.OBJECT] = class_name return handler(self).flatten(obj, data) reduce_val = None if has_class and not util.is_module(obj): if self.unpicklable: class_name = util.importable_name(cls) data[tags.OBJECT] = class_name # test for a reduce implementation, and redirect before doing anything else # if that is what reduce requests if has_reduce_ex: try: # we're implementing protocol 2 reduce_val = obj.__reduce_ex__(2) except TypeError: # A lot of builtin types have a reduce which just raises a TypeError # we ignore those pass if has_reduce and not reduce_val: try: reduce_val = obj.__reduce__() except TypeError: # A lot of builtin types have a reduce which just raises a TypeError # we ignore those pass if reduce_val: try: # At this stage, we only handle the case where __reduce__ returns a string # other reduce functionality is implemented further down if isinstance(reduce_val, (str, unicode)): varpath = iter(reduce_val.split('.')) # curmod will be transformed by the loop into the value to pickle curmod = sys.modules[next(varpath)] for modname in varpath: curmod = getattr(curmod, modname) # replace obj with value retrieved return self._flatten(curmod) except KeyError: # well, we can't do anything with that, so we ignore it pass if has_getnewargs_ex: data[tags.NEWARGSEX] = list(map(self._flatten, obj.__getnewargs_ex__())) if has_getnewargs and not has_getnewargs_ex: data[tags.NEWARGS] = self._flatten(obj.__getnewargs__()) if has_getinitargs: data[tags.INITARGS] = self._flatten(obj.__getinitargs__()) if has_getstate: try: state = obj.__getstate__() except TypeError: # Has getstate but it cannot be called, e.g. file descriptors # in Python3 self._pickle_warning(obj) return None else: return self._getstate(state, data) if util.is_module(obj): if self.unpicklable: data[tags.REPR] = '%s/%s' % (obj.__name__, obj.__name__) else: data = unicode(obj) return data if util.is_dictionary_subclass(obj): self._flatten_dict_obj(obj, data) return data if util.is_sequence_subclass(obj): return self._flatten_sequence_obj(obj, data) if util.is_noncomplex(obj): return [self._flatten(v) for v in obj] if util.is_iterator(obj): # force list in python 3 data[tags.ITERATOR] = list(map(self._flatten, islice(obj, self._max_iter))) return data if reduce_val and not isinstance(reduce_val, (str, unicode)): # at this point, reduce_val should be some kind of iterable # pad out to len 5 rv_as_list = list(reduce_val) insufficiency = 5 - len(rv_as_list) if insufficiency: rv_as_list += [None] * insufficiency if rv_as_list[0].__name__ == '__newobj__': rv_as_list[0] = tags.NEWOBJ data[tags.REDUCE] = list(map(self._flatten, rv_as_list)) # lift out iterators, so we don't have to iterator and uniterator their content # on unpickle if data[tags.REDUCE][3]: data[tags.REDUCE][3] = data[tags.REDUCE][3][tags.ITERATOR] if data[tags.REDUCE][4]: data[tags.REDUCE][4] = data[tags.REDUCE][4][tags.ITERATOR] return data if has_dict: # Support objects that subclasses list and set if util.is_sequence_subclass(obj): return self._flatten_sequence_obj(obj, data) # hack for zope persistent objects; this unghostifies the object getattr(obj, '_', None) return self._flatten_dict_obj(obj.__dict__, data) if has_slots: return self._flatten_newstyle_with_slots(obj, data) # catchall return for data created above without a return # (e.g. __getnewargs__ is not supposed to be the end of the story) if data: return data self._pickle_warning(obj) return None
def _flatten_obj_instance(self, obj): """Recursively flatten an instance and return a json-friendly dict """ data = {} has_class = hasattr(obj, '__class__') has_dict = hasattr(obj, '__dict__') has_slots = not has_dict and hasattr(obj, '__slots__') has_getstate = has_dict and hasattr(obj, '__getstate__') has_getstate_support = has_getstate and hasattr(obj, '__setstate__') HandlerClass = handlers.registry.get(type(obj)) if (has_class and not util.is_repr(obj) and not util.is_module(obj)): module, name = _getclassdetail(obj) if self.unpicklable is True: data[tags.OBJECT] = '%s.%s' % (module, name) # Check for a custom handler if HandlerClass: handler = HandlerClass(self) return handler.flatten(obj, data) if util.is_module(obj): if self.unpicklable is True: data[tags.REPR] = '%s/%s' % (obj.__name__, obj.__name__) else: data = unicode(obj) return data if util.is_repr(obj): if self.unpicklable is True: data[tags.REPR] = '%s/%s' % (obj.__class__.__module__, repr(obj)) else: data = unicode(obj) return data if util.is_dictionary_subclass(obj): return self._flatten_dict_obj(obj, data) if util.is_noncomplex(obj): return [self.flatten(v) for v in obj] if has_dict: # Support objects that subclasses list and set if util.is_collection_subclass(obj): return self._flatten_collection_obj(obj, data) # Support objects with __getstate__(); this ensures that # both __setstate__() and __getstate__() are implemented if has_getstate_support: state = self.flatten(obj.__getstate__()) if self.unpicklable: data[tags.STATE] = state else: data = state return data # hack for zope persistent objects; this unghostifies the object getattr(obj, '_', None) return self._flatten_dict_obj(obj.__dict__, data) if has_slots: return self._flatten_newstyle_with_slots(obj, data)