aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py')
-rwxr-xr-xlib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py1151
1 files changed, 0 insertions, 1151 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py
deleted file mode 100755
index 18795304..00000000
--- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/spread/jelly.py
+++ /dev/null
@@ -1,1151 +0,0 @@
-# -*- test-case-name: twisted.test.test_jelly -*-
-# Copyright (c) Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-"""
-S-expression-based persistence of python objects.
-
-It does something very much like L{Pickle<pickle>}; however, pickle's main goal
-seems to be efficiency (both in space and time); jelly's main goals are
-security, human readability, and portability to other environments.
-
-This is how Jelly converts various objects to s-expressions.
-
-Boolean::
- True --> ['boolean', 'true']
-
-Integer::
- 1 --> 1
-
-List::
- [1, 2] --> ['list', 1, 2]
-
-String::
- \"hello\" --> \"hello\"
-
-Float::
- 2.3 --> 2.3
-
-Dictionary::
- {'a': 1, 'b': 'c'} --> ['dictionary', ['b', 'c'], ['a', 1]]
-
-Module::
- UserString --> ['module', 'UserString']
-
-Class::
- UserString.UserString --> ['class', ['module', 'UserString'], 'UserString']
-
-Function::
- string.join --> ['function', 'join', ['module', 'string']]
-
-Instance: s is an instance of UserString.UserString, with a __dict__
-{'data': 'hello'}::
- [\"UserString.UserString\", ['dictionary', ['data', 'hello']]]
-
-Class Method: UserString.UserString.center::
- ['method', 'center', ['None'], ['class', ['module', 'UserString'],
- 'UserString']]
-
-Instance Method: s.center, where s is an instance of UserString.UserString::
- ['method', 'center', ['instance', ['reference', 1, ['class',
- ['module', 'UserString'], 'UserString']], ['dictionary', ['data', 'd']]],
- ['dereference', 1]]
-
-The C{set} builtin and the C{sets.Set} class are serialized to the same
-thing, and unserialized to C{set} if available, else to C{sets.Set}. It means
-that there's a possibility of type switching in the serialization process. The
-solution is to always use C{set} if possible, and only use C{sets.Set} under
-Python 2.3; this can be accomplished by using L{twisted.python.compat.set}.
-
-The same rule applies for C{frozenset} and C{sets.ImmutableSet}.
-
-@author: Glyph Lefkowitz
-"""
-
-# System Imports
-import pickle
-import types
-import warnings
-from types import StringType
-from types import UnicodeType
-from types import IntType
-from types import TupleType
-from types import ListType
-from types import LongType
-from types import FloatType
-from types import FunctionType
-from types import MethodType
-from types import ModuleType
-from types import DictionaryType
-from types import InstanceType
-from types import NoneType
-from types import ClassType
-import copy
-
-import datetime
-from types import BooleanType
-
-try:
- import decimal
-except ImportError:
- decimal = None
-
-try:
- _set = set
-except NameError:
- _set = None
-
-try:
- # Filter out deprecation warning for Python >= 2.6
- warnings.filterwarnings("ignore", category=DeprecationWarning,
- message="the sets module is deprecated", append=True)
- import sets as _sets
-finally:
- warnings.filters.pop()
-
-
-from zope.interface import implements
-
-# Twisted Imports
-from twisted.python.reflect import namedObject, qual
-from twisted.persisted.crefutil import NotKnown, _Tuple, _InstanceMethod
-from twisted.persisted.crefutil import _DictKeyAndValue, _Dereference
-from twisted.persisted.crefutil import _Container
-from twisted.python.compat import reduce
-
-from twisted.spread.interfaces import IJellyable, IUnjellyable
-
-DictTypes = (DictionaryType,)
-
-None_atom = "None" # N
-# code
-class_atom = "class" # c
-module_atom = "module" # m
-function_atom = "function" # f
-
-# references
-dereference_atom = 'dereference' # D
-persistent_atom = 'persistent' # p
-reference_atom = 'reference' # r
-
-# mutable collections
-dictionary_atom = "dictionary" # d
-list_atom = 'list' # l
-set_atom = 'set'
-
-# immutable collections
-# (assignment to __dict__ and __class__ still might go away!)
-tuple_atom = "tuple" # t
-instance_atom = 'instance' # i
-frozenset_atom = 'frozenset'
-
-
-# errors
-unpersistable_atom = "unpersistable"# u
-unjellyableRegistry = {}
-unjellyableFactoryRegistry = {}
-
-_NO_STATE = object()
-
-def _newInstance(cls, state=_NO_STATE):
- """
- Make a new instance of a class without calling its __init__ method.
- Supports both new- and old-style classes.
-
- @param state: A C{dict} used to update C{inst.__dict__} or C{_NO_STATE}
- to skip this part of initialization.
-
- @return: A new instance of C{cls}.
- """
- if not isinstance(cls, types.ClassType):
- # new-style
- inst = cls.__new__(cls)
-
- if state is not _NO_STATE:
- inst.__dict__.update(state) # Copy 'instance' behaviour
- else:
- if state is not _NO_STATE:
- inst = InstanceType(cls, state)
- else:
- inst = InstanceType(cls)
- return inst
-
-
-
-def _maybeClass(classnamep):
- try:
- object
- except NameError:
- isObject = 0
- else:
- isObject = isinstance(classnamep, type)
- if isinstance(classnamep, ClassType) or isObject:
- return qual(classnamep)
- return classnamep
-
-
-
-def setUnjellyableForClass(classname, unjellyable):
- """
- Set which local class will represent a remote type.
-
- If you have written a Copyable class that you expect your client to be
- receiving, write a local "copy" class to represent it, then call::
-
- jellier.setUnjellyableForClass('module.package.Class', MyCopier).
-
- Call this at the module level immediately after its class
- definition. MyCopier should be a subclass of RemoteCopy.
-
- The classname may be a special tag returned by
- 'Copyable.getTypeToCopyFor' rather than an actual classname.
-
- This call is also for cached classes, since there will be no
- overlap. The rules are the same.
- """
-
- global unjellyableRegistry
- classname = _maybeClass(classname)
- unjellyableRegistry[classname] = unjellyable
- globalSecurity.allowTypes(classname)
-
-
-
-def setUnjellyableFactoryForClass(classname, copyFactory):
- """
- Set the factory to construct a remote instance of a type::
-
- jellier.setUnjellyableFactoryForClass('module.package.Class', MyFactory)
-
- Call this at the module level immediately after its class definition.
- C{copyFactory} should return an instance or subclass of
- L{RemoteCopy<pb.RemoteCopy>}.
-
- Similar to L{setUnjellyableForClass} except it uses a factory instead
- of creating an instance.
- """
-
- global unjellyableFactoryRegistry
- classname = _maybeClass(classname)
- unjellyableFactoryRegistry[classname] = copyFactory
- globalSecurity.allowTypes(classname)
-
-
-
-def setUnjellyableForClassTree(module, baseClass, prefix=None):
- """
- Set all classes in a module derived from C{baseClass} as copiers for
- a corresponding remote class.
-
- When you have a heirarchy of Copyable (or Cacheable) classes on one
- side, and a mirror structure of Copied (or RemoteCache) classes on the
- other, use this to setUnjellyableForClass all your Copieds for the
- Copyables.
-
- Each copyTag (the \"classname\" argument to getTypeToCopyFor, and
- what the Copyable's getTypeToCopyFor returns) is formed from
- adding a prefix to the Copied's class name. The prefix defaults
- to module.__name__. If you wish the copy tag to consist of solely
- the classname, pass the empty string \'\'.
-
- @param module: a module object from which to pull the Copied classes.
- (passing sys.modules[__name__] might be useful)
-
- @param baseClass: the base class from which all your Copied classes derive.
-
- @param prefix: the string prefixed to classnames to form the
- unjellyableRegistry.
- """
- if prefix is None:
- prefix = module.__name__
-
- if prefix:
- prefix = "%s." % prefix
-
- for i in dir(module):
- i_ = getattr(module, i)
- if type(i_) == types.ClassType:
- if issubclass(i_, baseClass):
- setUnjellyableForClass('%s%s' % (prefix, i), i_)
-
-
-
-def getInstanceState(inst, jellier):
- """
- Utility method to default to 'normal' state rules in serialization.
- """
- if hasattr(inst, "__getstate__"):
- state = inst.__getstate__()
- else:
- state = inst.__dict__
- sxp = jellier.prepare(inst)
- sxp.extend([qual(inst.__class__), jellier.jelly(state)])
- return jellier.preserve(inst, sxp)
-
-
-
-def setInstanceState(inst, unjellier, jellyList):
- """
- Utility method to default to 'normal' state rules in unserialization.
- """
- state = unjellier.unjelly(jellyList[1])
- if hasattr(inst, "__setstate__"):
- inst.__setstate__(state)
- else:
- inst.__dict__ = state
- return inst
-
-
-
-class Unpersistable:
- """
- This is an instance of a class that comes back when something couldn't be
- unpersisted.
- """
-
- def __init__(self, reason):
- """
- Initialize an unpersistable object with a descriptive C{reason} string.
- """
- self.reason = reason
-
-
- def __repr__(self):
- return "Unpersistable(%s)" % repr(self.reason)
-
-
-
-class Jellyable:
- """
- Inherit from me to Jelly yourself directly with the `getStateFor'
- convenience method.
- """
- implements(IJellyable)
-
- def getStateFor(self, jellier):
- return self.__dict__
-
-
- def jellyFor(self, jellier):
- """
- @see: L{twisted.spread.interfaces.IJellyable.jellyFor}
- """
- sxp = jellier.prepare(self)
- sxp.extend([
- qual(self.__class__),
- jellier.jelly(self.getStateFor(jellier))])
- return jellier.preserve(self, sxp)
-
-
-
-class Unjellyable:
- """
- Inherit from me to Unjelly yourself directly with the
- C{setStateFor} convenience method.
- """
- implements(IUnjellyable)
-
- def setStateFor(self, unjellier, state):
- self.__dict__ = state
-
-
- def unjellyFor(self, unjellier, jellyList):
- """
- Perform the inverse operation of L{Jellyable.jellyFor}.
-
- @see: L{twisted.spread.interfaces.IUnjellyable.unjellyFor}
- """
- state = unjellier.unjelly(jellyList[1])
- self.setStateFor(unjellier, state)
- return self
-
-
-
-class _Jellier:
- """
- (Internal) This class manages state for a call to jelly()
- """
-
- def __init__(self, taster, persistentStore, invoker):
- """
- Initialize.
- """
- self.taster = taster
- # `preserved' is a dict of previously seen instances.
- self.preserved = {}
- # `cooked' is a dict of previously backreferenced instances to their
- # `ref' lists.
- self.cooked = {}
- self.cooker = {}
- self._ref_id = 1
- self.persistentStore = persistentStore
- self.invoker = invoker
-
-
- def _cook(self, object):
- """
- (internal) Backreference an object.
-
- Notes on this method for the hapless future maintainer: If I've already
- gone through the prepare/preserve cycle on the specified object (it is
- being referenced after the serializer is \"done with\" it, e.g. this
- reference is NOT circular), the copy-in-place of aList is relevant,
- since the list being modified is the actual, pre-existing jelly
- expression that was returned for that object. If not, it's technically
- superfluous, since the value in self.preserved didn't need to be set,
- but the invariant that self.preserved[id(object)] is a list is
- convenient because that means we don't have to test and create it or
- not create it here, creating fewer code-paths. that's why
- self.preserved is always set to a list.
-
- Sorry that this code is so hard to follow, but Python objects are
- tricky to persist correctly. -glyph
- """
- aList = self.preserved[id(object)]
- newList = copy.copy(aList)
- # make a new reference ID
- refid = self._ref_id
- self._ref_id = self._ref_id + 1
- # replace the old list in-place, so that we don't have to track the
- # previous reference to it.
- aList[:] = [reference_atom, refid, newList]
- self.cooked[id(object)] = [dereference_atom, refid]
- return aList
-
-
- def prepare(self, object):
- """
- (internal) Create a list for persisting an object to. This will allow
- backreferences to be made internal to the object. (circular
- references).
-
- The reason this needs to happen is that we don't generate an ID for
- every object, so we won't necessarily know which ID the object will
- have in the future. When it is 'cooked' ( see _cook ), it will be
- assigned an ID, and the temporary placeholder list created here will be
- modified in-place to create an expression that gives this object an ID:
- [reference id# [object-jelly]].
- """
-
- # create a placeholder list to be preserved
- self.preserved[id(object)] = []
- # keep a reference to this object around, so it doesn't disappear!
- # (This isn't always necessary, but for cases where the objects are
- # dynamically generated by __getstate__ or getStateToCopyFor calls, it
- # is; id() will return the same value for a different object if it gets
- # garbage collected. This may be optimized later.)
- self.cooker[id(object)] = object
- return []
-
-
- def preserve(self, object, sexp):
- """
- (internal) Mark an object's persistent list for later referral.
- """
- # if I've been cooked in the meanwhile,
- if id(object) in self.cooked:
- # replace the placeholder empty list with the real one
- self.preserved[id(object)][2] = sexp
- # but give this one back.
- sexp = self.preserved[id(object)]
- else:
- self.preserved[id(object)] = sexp
- return sexp
-
- constantTypes = {types.StringType : 1, types.IntType : 1,
- types.FloatType : 1, types.LongType : 1}
-
-
- def _checkMutable(self,obj):
- objId = id(obj)
- if objId in self.cooked:
- return self.cooked[objId]
- if objId in self.preserved:
- self._cook(obj)
- return self.cooked[objId]
-
-
- def jelly(self, obj):
- if isinstance(obj, Jellyable):
- preRef = self._checkMutable(obj)
- if preRef:
- return preRef
- return obj.jellyFor(self)
- objType = type(obj)
- if self.taster.isTypeAllowed(qual(objType)):
- # "Immutable" Types
- if ((objType is StringType) or
- (objType is IntType) or
- (objType is LongType) or
- (objType is FloatType)):
- return obj
- elif objType is MethodType:
- return ["method",
- obj.im_func.__name__,
- self.jelly(obj.im_self),
- self.jelly(obj.im_class)]
-
- elif UnicodeType and objType is UnicodeType:
- return ['unicode', obj.encode('UTF-8')]
- elif objType is NoneType:
- return ['None']
- elif objType is FunctionType:
- name = obj.__name__
- return ['function', str(pickle.whichmodule(obj, obj.__name__))
- + '.' +
- name]
- elif objType is ModuleType:
- return ['module', obj.__name__]
- elif objType is BooleanType:
- return ['boolean', obj and 'true' or 'false']
- elif objType is datetime.datetime:
- if obj.tzinfo:
- raise NotImplementedError(
- "Currently can't jelly datetime objects with tzinfo")
- return ['datetime', '%s %s %s %s %s %s %s' % (
- obj.year, obj.month, obj.day, obj.hour,
- obj.minute, obj.second, obj.microsecond)]
- elif objType is datetime.time:
- if obj.tzinfo:
- raise NotImplementedError(
- "Currently can't jelly datetime objects with tzinfo")
- return ['time', '%s %s %s %s' % (obj.hour, obj.minute,
- obj.second, obj.microsecond)]
- elif objType is datetime.date:
- return ['date', '%s %s %s' % (obj.year, obj.month, obj.day)]
- elif objType is datetime.timedelta:
- return ['timedelta', '%s %s %s' % (obj.days, obj.seconds,
- obj.microseconds)]
- elif objType is ClassType or issubclass(objType, type):
- return ['class', qual(obj)]
- elif decimal is not None and objType is decimal.Decimal:
- return self.jelly_decimal(obj)
- else:
- preRef = self._checkMutable(obj)
- if preRef:
- return preRef
- # "Mutable" Types
- sxp = self.prepare(obj)
- if objType is ListType:
- sxp.extend(self._jellyIterable(list_atom, obj))
- elif objType is TupleType:
- sxp.extend(self._jellyIterable(tuple_atom, obj))
- elif objType in DictTypes:
- sxp.append(dictionary_atom)
- for key, val in obj.items():
- sxp.append([self.jelly(key), self.jelly(val)])
- elif (_set is not None and objType is set or
- objType is _sets.Set):
- sxp.extend(self._jellyIterable(set_atom, obj))
- elif (_set is not None and objType is frozenset or
- objType is _sets.ImmutableSet):
- sxp.extend(self._jellyIterable(frozenset_atom, obj))
- else:
- className = qual(obj.__class__)
- persistent = None
- if self.persistentStore:
- persistent = self.persistentStore(obj, self)
- if persistent is not None:
- sxp.append(persistent_atom)
- sxp.append(persistent)
- elif self.taster.isClassAllowed(obj.__class__):
- sxp.append(className)
- if hasattr(obj, "__getstate__"):
- state = obj.__getstate__()
- else:
- state = obj.__dict__
- sxp.append(self.jelly(state))
- else:
- self.unpersistable(
- "instance of class %s deemed insecure" %
- qual(obj.__class__), sxp)
- return self.preserve(obj, sxp)
- else:
- if objType is InstanceType:
- raise InsecureJelly("Class not allowed for instance: %s %s" %
- (obj.__class__, obj))
- raise InsecureJelly("Type not allowed for object: %s %s" %
- (objType, obj))
-
-
- def _jellyIterable(self, atom, obj):
- """
- Jelly an iterable object.
-
- @param atom: the identifier atom of the object.
- @type atom: C{str}
-
- @param obj: any iterable object.
- @type obj: C{iterable}
-
- @return: a generator of jellied data.
- @rtype: C{generator}
- """
- yield atom
- for item in obj:
- yield self.jelly(item)
-
-
- def jelly_decimal(self, d):
- """
- Jelly a decimal object.
-
- @param d: a decimal object to serialize.
- @type d: C{decimal.Decimal}
-
- @return: jelly for the decimal object.
- @rtype: C{list}
- """
- sign, guts, exponent = d.as_tuple()
- value = reduce(lambda left, right: left * 10 + right, guts)
- if sign:
- value = -value
- return ['decimal', value, exponent]
-
-
- def unpersistable(self, reason, sxp=None):
- """
- (internal) Returns an sexp: (unpersistable "reason"). Utility method
- for making note that a particular object could not be serialized.
- """
- if sxp is None:
- sxp = []
- sxp.append(unpersistable_atom)
- sxp.append(reason)
- return sxp
-
-
-
-class _Unjellier:
-
- def __init__(self, taster, persistentLoad, invoker):
- self.taster = taster
- self.persistentLoad = persistentLoad
- self.references = {}
- self.postCallbacks = []
- self.invoker = invoker
-
-
- def unjellyFull(self, obj):
- o = self.unjelly(obj)
- for m in self.postCallbacks:
- m()
- return o
-
-
- def unjelly(self, obj):
- if type(obj) is not types.ListType:
- return obj
- jelType = obj[0]
- if not self.taster.isTypeAllowed(jelType):
- raise InsecureJelly(jelType)
- regClass = unjellyableRegistry.get(jelType)
- if regClass is not None:
- if isinstance(regClass, ClassType):
- inst = _Dummy() # XXX chomp, chomp
- inst.__class__ = regClass
- method = inst.unjellyFor
- elif isinstance(regClass, type):
- # regClass.__new__ does not call regClass.__init__
- inst = regClass.__new__(regClass)
- method = inst.unjellyFor
- else:
- method = regClass # this is how it ought to be done
- val = method(self, obj)
- if hasattr(val, 'postUnjelly'):
- self.postCallbacks.append(inst.postUnjelly)
- return val
- regFactory = unjellyableFactoryRegistry.get(jelType)
- if regFactory is not None:
- state = self.unjelly(obj[1])
- inst = regFactory(state)
- if hasattr(inst, 'postUnjelly'):
- self.postCallbacks.append(inst.postUnjelly)
- return inst
- thunk = getattr(self, '_unjelly_%s'%jelType, None)
- if thunk is not None:
- ret = thunk(obj[1:])
- else:
- nameSplit = jelType.split('.')
- modName = '.'.join(nameSplit[:-1])
- if not self.taster.isModuleAllowed(modName):
- raise InsecureJelly(
- "Module %s not allowed (in type %s)." % (modName, jelType))
- clz = namedObject(jelType)
- if not self.taster.isClassAllowed(clz):
- raise InsecureJelly("Class %s not allowed." % jelType)
- if hasattr(clz, "__setstate__"):
- ret = _newInstance(clz)
- state = self.unjelly(obj[1])
- ret.__setstate__(state)
- else:
- state = self.unjelly(obj[1])
- ret = _newInstance(clz, state)
- if hasattr(clz, 'postUnjelly'):
- self.postCallbacks.append(ret.postUnjelly)
- return ret
-
-
- def _unjelly_None(self, exp):
- return None
-
-
- def _unjelly_unicode(self, exp):
- if UnicodeType:
- return unicode(exp[0], "UTF-8")
- else:
- return Unpersistable("Could not unpersist unicode: %s" % (exp[0],))
-
-
- def _unjelly_decimal(self, exp):
- """
- Unjelly decimal objects, if decimal is available. If not, return a
- L{Unpersistable} object instead.
- """
- if decimal is None:
- return Unpersistable(
- "Could not unpersist decimal: %s" % (exp[0] * (10**exp[1]),))
- value = exp[0]
- exponent = exp[1]
- if value < 0:
- sign = 1
- else:
- sign = 0
- guts = decimal.Decimal(value).as_tuple()[1]
- return decimal.Decimal((sign, guts, exponent))
-
-
- def _unjelly_boolean(self, exp):
- if BooleanType:
- assert exp[0] in ('true', 'false')
- return exp[0] == 'true'
- else:
- return Unpersistable("Could not unpersist boolean: %s" % (exp[0],))
-
-
- def _unjelly_datetime(self, exp):
- return datetime.datetime(*map(int, exp[0].split()))
-
-
- def _unjelly_date(self, exp):
- return datetime.date(*map(int, exp[0].split()))
-
-
- def _unjelly_time(self, exp):
- return datetime.time(*map(int, exp[0].split()))
-
-
- def _unjelly_timedelta(self, exp):
- days, seconds, microseconds = map(int, exp[0].split())
- return datetime.timedelta(
- days=days, seconds=seconds, microseconds=microseconds)
-
-
- def unjellyInto(self, obj, loc, jel):
- o = self.unjelly(jel)
- if isinstance(o, NotKnown):
- o.addDependant(obj, loc)
- obj[loc] = o
- return o
-
-
- def _unjelly_dereference(self, lst):
- refid = lst[0]
- x = self.references.get(refid)
- if x is not None:
- return x
- der = _Dereference(refid)
- self.references[refid] = der
- return der
-
-
- def _unjelly_reference(self, lst):
- refid = lst[0]
- exp = lst[1]
- o = self.unjelly(exp)
- ref = self.references.get(refid)
- if (ref is None):
- self.references[refid] = o
- elif isinstance(ref, NotKnown):
- ref.resolveDependants(o)
- self.references[refid] = o
- else:
- assert 0, "Multiple references with same ID!"
- return o
-
-
- def _unjelly_tuple(self, lst):
- l = range(len(lst))
- finished = 1
- for elem in l:
- if isinstance(self.unjellyInto(l, elem, lst[elem]), NotKnown):
- finished = 0
- if finished:
- return tuple(l)
- else:
- return _Tuple(l)
-
-
- def _unjelly_list(self, lst):
- l = range(len(lst))
- for elem in l:
- self.unjellyInto(l, elem, lst[elem])
- return l
-
-
- def _unjellySetOrFrozenset(self, lst, containerType):
- """
- Helper method to unjelly set or frozenset.
-
- @param lst: the content of the set.
- @type lst: C{list}
-
- @param containerType: the type of C{set} to use.
- """
- l = range(len(lst))
- finished = True
- for elem in l:
- data = self.unjellyInto(l, elem, lst[elem])
- if isinstance(data, NotKnown):
- finished = False
- if not finished:
- return _Container(l, containerType)
- else:
- return containerType(l)
-
-
- def _unjelly_set(self, lst):
- """
- Unjelly set using either the C{set} builtin if available, or
- C{sets.Set} as fallback.
- """
- if _set is not None:
- containerType = set
- else:
- containerType = _sets.Set
- return self._unjellySetOrFrozenset(lst, containerType)
-
-
- def _unjelly_frozenset(self, lst):
- """
- Unjelly frozenset using either the C{frozenset} builtin if available,
- or C{sets.ImmutableSet} as fallback.
- """
- if _set is not None:
- containerType = frozenset
- else:
- containerType = _sets.ImmutableSet
- return self._unjellySetOrFrozenset(lst, containerType)
-
-
- def _unjelly_dictionary(self, lst):
- d = {}
- for k, v in lst:
- kvd = _DictKeyAndValue(d)
- self.unjellyInto(kvd, 0, k)
- self.unjellyInto(kvd, 1, v)
- return d
-
-
- def _unjelly_module(self, rest):
- moduleName = rest[0]
- if type(moduleName) != types.StringType:
- raise InsecureJelly(
- "Attempted to unjelly a module with a non-string name.")
- if not self.taster.isModuleAllowed(moduleName):
- raise InsecureJelly(
- "Attempted to unjelly module named %r" % (moduleName,))
- mod = __import__(moduleName, {}, {},"x")
- return mod
-
-
- def _unjelly_class(self, rest):
- clist = rest[0].split('.')
- modName = '.'.join(clist[:-1])
- if not self.taster.isModuleAllowed(modName):
- raise InsecureJelly("module %s not allowed" % modName)
- klaus = namedObject(rest[0])
- objType = type(klaus)
- if objType not in (types.ClassType, types.TypeType):
- raise InsecureJelly(
- "class %r unjellied to something that isn't a class: %r" % (
- rest[0], klaus))
- if not self.taster.isClassAllowed(klaus):
- raise InsecureJelly("class not allowed: %s" % qual(klaus))
- return klaus
-
-
- def _unjelly_function(self, rest):
- modSplit = rest[0].split('.')
- modName = '.'.join(modSplit[:-1])
- if not self.taster.isModuleAllowed(modName):
- raise InsecureJelly("Module not allowed: %s"% modName)
- # XXX do I need an isFunctionAllowed?
- function = namedObject(rest[0])
- return function
-
-
- def _unjelly_persistent(self, rest):
- if self.persistentLoad:
- pload = self.persistentLoad(rest[0], self)
- return pload
- else:
- return Unpersistable("Persistent callback not found")
-
-
- def _unjelly_instance(self, rest):
- clz = self.unjelly(rest[0])
- if type(clz) is not types.ClassType:
- raise InsecureJelly("Instance found with non-class class.")
- if hasattr(clz, "__setstate__"):
- inst = _newInstance(clz, {})
- state = self.unjelly(rest[1])
- inst.__setstate__(state)
- else:
- state = self.unjelly(rest[1])
- inst = _newInstance(clz, state)
- if hasattr(clz, 'postUnjelly'):
- self.postCallbacks.append(inst.postUnjelly)
- return inst
-
-
- def _unjelly_unpersistable(self, rest):
- return Unpersistable("Unpersistable data: %s" % (rest[0],))
-
-
- def _unjelly_method(self, rest):
- """
- (internal) Unjelly a method.
- """
- im_name = rest[0]
- im_self = self.unjelly(rest[1])
- im_class = self.unjelly(rest[2])
- if type(im_class) is not types.ClassType:
- raise InsecureJelly("Method found with non-class class.")
- if im_name in im_class.__dict__:
- if im_self is None:
- im = getattr(im_class, im_name)
- elif isinstance(im_self, NotKnown):
- im = _InstanceMethod(im_name, im_self, im_class)
- else:
- im = MethodType(im_class.__dict__[im_name], im_self, im_class)
- else:
- raise TypeError('instance method changed')
- return im
-
-
-
-class _Dummy:
- """
- (Internal) Dummy class, used for unserializing instances.
- """
-
-
-
-class _DummyNewStyle(object):
- """
- (Internal) Dummy class, used for unserializing instances of new-style
- classes.
- """
-
-
-def _newDummyLike(instance):
- """
- Create a new instance like C{instance}.
-
- The new instance has the same class and instance dictionary as the given
- instance.
-
- @return: The new instance.
- """
- if isinstance(instance.__class__, type):
- # New-style class
- dummy = _DummyNewStyle()
- else:
- # Classic class
- dummy = _Dummy()
- dummy.__class__ = instance.__class__
- dummy.__dict__ = instance.__dict__
- return dummy
-
-
-#### Published Interface.
-
-
-class InsecureJelly(Exception):
- """
- This exception will be raised when a jelly is deemed `insecure'; e.g. it
- contains a type, class, or module disallowed by the specified `taster'
- """
-
-
-
-class DummySecurityOptions:
- """
- DummySecurityOptions() -> insecure security options
- Dummy security options -- this class will allow anything.
- """
-
- def isModuleAllowed(self, moduleName):
- """
- DummySecurityOptions.isModuleAllowed(moduleName) -> boolean
- returns 1 if a module by that name is allowed, 0 otherwise
- """
- return 1
-
-
- def isClassAllowed(self, klass):
- """
- DummySecurityOptions.isClassAllowed(class) -> boolean
- Assumes the module has already been allowed. Returns 1 if the given
- class is allowed, 0 otherwise.
- """
- return 1
-
-
- def isTypeAllowed(self, typeName):
- """
- DummySecurityOptions.isTypeAllowed(typeName) -> boolean
- Returns 1 if the given type is allowed, 0 otherwise.
- """
- return 1
-
-
-
-class SecurityOptions:
- """
- This will by default disallow everything, except for 'none'.
- """
-
- basicTypes = ["dictionary", "list", "tuple",
- "reference", "dereference", "unpersistable",
- "persistent", "long_int", "long", "dict"]
-
- def __init__(self):
- """
- SecurityOptions() initialize.
- """
- # I don't believe any of these types can ever pose a security hazard,
- # except perhaps "reference"...
- self.allowedTypes = {"None": 1,
- "bool": 1,
- "boolean": 1,
- "string": 1,
- "str": 1,
- "int": 1,
- "float": 1,
- "datetime": 1,
- "time": 1,
- "date": 1,
- "timedelta": 1,
- "NoneType": 1}
- if hasattr(types, 'UnicodeType'):
- self.allowedTypes['unicode'] = 1
- if decimal is not None:
- self.allowedTypes['decimal'] = 1
- self.allowedTypes['set'] = 1
- self.allowedTypes['frozenset'] = 1
- self.allowedModules = {}
- self.allowedClasses = {}
-
-
- def allowBasicTypes(self):
- """
- Allow all `basic' types. (Dictionary and list. Int, string, and float
- are implicitly allowed.)
- """
- self.allowTypes(*self.basicTypes)
-
-
- def allowTypes(self, *types):
- """
- SecurityOptions.allowTypes(typeString): Allow a particular type, by its
- name.
- """
- for typ in types:
- if not isinstance(typ, str):
- typ = qual(typ)
- self.allowedTypes[typ] = 1
-
-
- def allowInstancesOf(self, *classes):
- """
- SecurityOptions.allowInstances(klass, klass, ...): allow instances
- of the specified classes
-
- This will also allow the 'instance', 'class' (renamed 'classobj' in
- Python 2.3), and 'module' types, as well as basic types.
- """
- self.allowBasicTypes()
- self.allowTypes("instance", "class", "classobj", "module")
- for klass in classes:
- self.allowTypes(qual(klass))
- self.allowModules(klass.__module__)
- self.allowedClasses[klass] = 1
-
-
- def allowModules(self, *modules):
- """
- SecurityOptions.allowModules(module, module, ...): allow modules by
- name. This will also allow the 'module' type.
- """
- for module in modules:
- if type(module) == types.ModuleType:
- module = module.__name__
- self.allowedModules[module] = 1
-
-
- def isModuleAllowed(self, moduleName):
- """
- SecurityOptions.isModuleAllowed(moduleName) -> boolean
- returns 1 if a module by that name is allowed, 0 otherwise
- """
- return moduleName in self.allowedModules
-
-
- def isClassAllowed(self, klass):
- """
- SecurityOptions.isClassAllowed(class) -> boolean
- Assumes the module has already been allowed. Returns 1 if the given
- class is allowed, 0 otherwise.
- """
- return klass in self.allowedClasses
-
-
- def isTypeAllowed(self, typeName):
- """
- SecurityOptions.isTypeAllowed(typeName) -> boolean
- Returns 1 if the given type is allowed, 0 otherwise.
- """
- return (typeName in self.allowedTypes or '.' in typeName)
-
-
-globalSecurity = SecurityOptions()
-globalSecurity.allowBasicTypes()
-
-
-
-def jelly(object, taster=DummySecurityOptions(), persistentStore=None,
- invoker=None):
- """
- Serialize to s-expression.
-
- Returns a list which is the serialized representation of an object. An
- optional 'taster' argument takes a SecurityOptions and will mark any
- insecure objects as unpersistable rather than serializing them.
- """
- return _Jellier(taster, persistentStore, invoker).jelly(object)
-
-
-
-def unjelly(sexp, taster=DummySecurityOptions(), persistentLoad=None,
- invoker=None):
- """
- Unserialize from s-expression.
-
- Takes an list that was the result from a call to jelly() and unserializes
- an arbitrary object from it. The optional 'taster' argument, an instance
- of SecurityOptions, will cause an InsecureJelly exception to be raised if a
- disallowed type, module, or class attempted to unserialize.
- """
- return _Unjellier(taster, persistentLoad, invoker).unjellyFull(sexp)