コード例 #1
0
"""The jsonstruct.tags module provides the custom tags
used for pickling and unpickling Python objects.

These tags are keys into the flattened dictionaries
created by the Pickler class.  The Unpickler uses
these custom key names to identify dictionaries
that need to be specially handled.
"""
from jsonstruct.compat import set

ID = 'py/id'
OBJECT = 'py/object'
TYPE = 'py/type'
REPR = 'py/repr'
REF = 'py/ref'
TUPLE = 'py/tuple'
SET = 'py/set'
SEQ = 'py/seq'
STATE = 'py/state'

# All reserved tag names
RESERVED = set([OBJECT, TYPE, REPR, REF, TUPLE, SET, SEQ, STATE])
コード例 #2
0
ファイル: util.py プロジェクト: blekinge/jsonstruct
# you should have received as part of this distribution.

"""Helper functions for pickling and unpickling.  Most functions assist in
determining the type of an object.
"""
import time
import types
import inspect

from jsonstruct import tags
from jsonstruct.compat import set
from jsonstruct.compat import unicode, long


COLLECTIONS = (list, set, tuple)
COLLECTIONS_SET = set(COLLECTIONS)
PRIMITIVES = set((str, unicode, bool, float, int, long))


def is_type(obj):
    """Returns True is obj is a reference to a type.

    >>> is_type(1)
    False

    >>> is_type(object)
    True

    >>> class Klass: pass
    >>> is_type(Klass)
    True
コード例 #3
0
    def restore(self, obj, cls_def = None):
        """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'}

        cls_def could be either a type or an instance. In case of instance, it
        will be used to define types inside a list or dict. eg. [Test()] means
        a list of Test.
        """
        self._push()

        if has_tag(obj, tags.ID):
            return self._pop(self._objs[obj[tags.ID]])

        # Backwards compatibility
        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)

        # Backwards compatibility
        if has_tag(obj, tags.REPR):
            obj = loadrepr(obj[tags.REPR])
            return self._pop(self._mkref(obj))

        if util.is_type(cls_def):
            if not util.is_dictionary(obj):
                # Type mismatch. cls_def is a type but we didn't get a dict
                # from JSON. Return None.
                return self._pop(None)

            # check custom handlers
            HandlerClass = handlers.BaseHandler._registry.get(cls_def)
            if HandlerClass:
                handler = HandlerClass(self)
                instance = handler.restore(obj)
                return self._pop(self._mkref(instance))

            factory = loadfactory(obj)
            args = getargs(obj, cls_def)
            if args:
                args = self.restore(args)
            try:
                if hasattr(cls_def, '__new__'):
                    # new style classes
                    if factory:
                        instance = cls_def.__new__(cls_def, factory, *args)
                        instance.default_factory = factory
                    else:
                        instance = cls_def.__new__(cls_def, *args)
                else:
                    instance = object.__new__(cls_def)
            except TypeError:
                # old-style classes
                try:
                    instance = cls_def()
                except TypeError:
                    # fail gracefully if the constructor requires arguments
                    return self._pop(self._mkref(obj))

            # Add to the instance table to allow being referenced by a
            # downstream object
            self._mkref(instance)

            if isinstance(instance, tuple):
                return self._pop(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 in util.get_public_variables(cls_def):
                if k in obj:
                    v = obj[k]

                    # ignore the reserved attribute
                    if k in tags.RESERVED:
                        continue

                    self._namestack.append(k)
                    # step into the namespace
                    value = self.restore(v, get_attr_cls_def(cls_def, k))
                    if (util.is_noncomplex(instance) or
                            util.is_dictionary(instance)):
                        instance[k] = value
                    else:
                        setattr(instance, k, value)
                    # step out
                    self._namestack.pop()
                else:
                    # Attribute in cls_def but not given in JSON. Assign it to
                    # None so that user could tell that it wasn't given know.
                    setattr(instance, k, None)

            # 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):
            if util.is_collection(cls_def):
                parent = type(cls_def)()
            else:
                parent = []
            self._mkref(parent)
            item_type = get_collection_item_type(cls_def)
            is_set = type(parent) is set
            for v in obj:
                restored_v = self.restore(v, item_type)
                if is_set:
                    parent.add(restored_v)
                else:
                    parent.append(restored_v)

            return self._pop(parent)

        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):
            if util.is_dictionary(cls_def):
                data = type(cls_def)()
            else:
                data = {}
            k_type, v_type = get_dictionary_item_type(cls_def)

            for k, v in sorted(obj.items(), key=operator.itemgetter(0)):
                self._namestack.append(k)
                data[self.restore(k, k_type)] = self.restore(v, v_type)
                self._namestack.pop()

            return self._pop(data)

        return self._pop(obj)