|
|
# encoding: utf-8
|
|
|
|
|
|
"""Pickle related utilities. Perhaps this should be called 'can'."""
|
|
|
|
|
|
__docformat__ = "restructuredtext en"
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Copyright (C) 2008 The IPython Development Team
|
|
|
#
|
|
|
# Distributed under the terms of the BSD License. The full license is in
|
|
|
# the file COPYING, distributed as part of this software.
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Imports
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
import copy
|
|
|
import sys
|
|
|
from types import FunctionType
|
|
|
|
|
|
import codeutil
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Classes
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
class CannedObject(object):
|
|
|
def __init__(self, obj, keys=[]):
|
|
|
self.keys = keys
|
|
|
self.obj = copy.copy(obj)
|
|
|
for key in keys:
|
|
|
setattr(self.obj, key, can(getattr(obj, key)))
|
|
|
|
|
|
|
|
|
def getObject(self, g=None):
|
|
|
if g is None:
|
|
|
g = globals()
|
|
|
for key in self.keys:
|
|
|
setattr(self.obj, key, uncan(getattr(self.obj, key), g))
|
|
|
return self.obj
|
|
|
|
|
|
class Reference(CannedObject):
|
|
|
"""object for wrapping a remote reference by name."""
|
|
|
def __init__(self, name):
|
|
|
if not isinstance(name, basestring):
|
|
|
raise TypeError("illegal name: %r"%name)
|
|
|
self.name = name
|
|
|
|
|
|
def __repr__(self):
|
|
|
return "<Reference: %r>"%self.name
|
|
|
|
|
|
def getObject(self, g=None):
|
|
|
if g is None:
|
|
|
g = globals()
|
|
|
try:
|
|
|
return g[self.name]
|
|
|
except KeyError:
|
|
|
raise NameError("name %r is not defined"%self.name)
|
|
|
|
|
|
|
|
|
class CannedFunction(CannedObject):
|
|
|
|
|
|
def __init__(self, f):
|
|
|
self._checkType(f)
|
|
|
self.code = f.func_code
|
|
|
self.defaults = f.func_defaults
|
|
|
self.module = f.__module__ or '__main__'
|
|
|
self.__name__ = f.__name__
|
|
|
|
|
|
def _checkType(self, obj):
|
|
|
assert isinstance(obj, FunctionType), "Not a function type"
|
|
|
|
|
|
def getObject(self, g=None):
|
|
|
# try to load function back into its module:
|
|
|
if not self.module.startswith('__'):
|
|
|
try:
|
|
|
__import__(self.module)
|
|
|
except ImportError:
|
|
|
pass
|
|
|
else:
|
|
|
g = sys.modules[self.module].__dict__
|
|
|
|
|
|
if g is None:
|
|
|
g = globals()
|
|
|
newFunc = FunctionType(self.code, g, self.__name__, self.defaults)
|
|
|
return newFunc
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
# Functions
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
def can(obj):
|
|
|
# import here to prevent module-level circular imports
|
|
|
from IPython.parallel import dependent
|
|
|
if isinstance(obj, dependent):
|
|
|
keys = ('f','df')
|
|
|
return CannedObject(obj, keys=keys)
|
|
|
elif isinstance(obj, FunctionType):
|
|
|
return CannedFunction(obj)
|
|
|
elif isinstance(obj,dict):
|
|
|
return canDict(obj)
|
|
|
elif isinstance(obj, (list,tuple)):
|
|
|
return canSequence(obj)
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
def canDict(obj):
|
|
|
if isinstance(obj, dict):
|
|
|
newobj = {}
|
|
|
for k, v in obj.iteritems():
|
|
|
newobj[k] = can(v)
|
|
|
return newobj
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
def canSequence(obj):
|
|
|
if isinstance(obj, (list, tuple)):
|
|
|
t = type(obj)
|
|
|
return t([can(i) for i in obj])
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
def uncan(obj, g=None):
|
|
|
if isinstance(obj, CannedObject):
|
|
|
return obj.getObject(g)
|
|
|
elif isinstance(obj,dict):
|
|
|
return uncanDict(obj, g)
|
|
|
elif isinstance(obj, (list,tuple)):
|
|
|
return uncanSequence(obj, g)
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
def uncanDict(obj, g=None):
|
|
|
if isinstance(obj, dict):
|
|
|
newobj = {}
|
|
|
for k, v in obj.iteritems():
|
|
|
newobj[k] = uncan(v,g)
|
|
|
return newobj
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
def uncanSequence(obj, g=None):
|
|
|
if isinstance(obj, (list, tuple)):
|
|
|
t = type(obj)
|
|
|
return t([uncan(i,g) for i in obj])
|
|
|
else:
|
|
|
return obj
|
|
|
|
|
|
|
|
|
def rebindFunctionGlobals(f, glbls):
|
|
|
return FunctionType(f.func_code, glbls)
|
|
|
|