Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/misc/fpickle.pyx
4057 views
1
"""
2
Function pickling
3
4
REFERENCE: The python cookbook.
5
"""
6
7
import types, copy_reg, cPickle
8
9
def code_ctor(*args):
10
"""
11
EXAMPLES:
12
This indirectly tests this function.
13
sage: def foo(a,b,c=10): return a+b+c
14
sage: sage.misc.fpickle.reduce_code(foo.func_code)
15
(<built-in function code_ctor>, ...)
16
sage: unpickle_function(pickle_function(foo))
17
<function foo at ...>
18
"""
19
return types.CodeType(*args)
20
21
def reduce_code(co):
22
"""
23
EXAMPLES:
24
sage: def foo(N): return N+1
25
sage: sage.misc.fpickle.reduce_code(foo.func_code)
26
(<built-in function code_ctor>, ...)
27
"""
28
if co.co_freevars or co.co_cellvars:
29
raise ValueError, "Cannot pickle code objects from closures"
30
return code_ctor, (co.co_argcount, co.co_nlocals, co.co_stacksize,
31
co.co_flags, co.co_code, co.co_consts, co.co_names,
32
co.co_varnames, co.co_filename, co.co_name,
33
co.co_firstlineno, co.co_lnotab)
34
35
copy_reg.pickle(types.CodeType, reduce_code)
36
37
def pickle_function(func):
38
"""
39
Pickle the Python function func. This is not a normal pickle; you
40
must use the unpickle_function method to unpickle the pickled
41
function.
42
43
NOTE: This does not work on all functions, but does work on
44
'surprisingly' many functions. In particular, it does not
45
work on functions that includes nested functions.
46
47
INPUT:
48
func -- a Python function
49
OUTPUT:
50
a string
51
52
EXAMPLES:
53
sage: def f(N): return N+1
54
...
55
sage: g = pickle_function(f)
56
sage: h = unpickle_function(g)
57
sage: h(10)
58
11
59
"""
60
return cPickle.dumps(func.func_code)
61
62
def unpickle_function(pickled):
63
"""
64
Unpickle a pickled function.
65
EXAMPLES:
66
sage: def f(N,M): return N*M
67
...
68
sage: unpickle_function(pickle_function(f))(3,5)
69
15
70
"""
71
recovered = cPickle.loads(pickled)
72
return types.FunctionType(recovered, globals())
73
74
75
76
def call_pickled_function(fpargs):
77
import sage.all
78
from sage.misc.fpickle import unpickle_function
79
(fp, (args, kwds)) = fpargs
80
f = eval("unpickle_function(fp)", sage.all.__dict__, {'fp':fp})
81
res = eval("f(*args, **kwds)",sage.all.__dict__, {'args':args, 'kwds':kwds, 'f':f})
82
return ((args, kwds), res)
83
84
# The following four methods are taken from twisted.persisted.styles - the
85
# import of twisted.persisted.styles takes a long time and we do not use
86
# most functionality it provides
87
def pickleMethod(method):
88
'support function for copy_reg to pickle method refs'
89
return unpickleMethod, (method.im_func.__name__,
90
method.im_self,
91
method.im_class)
92
93
def unpickleMethod(im_name,
94
im_self,
95
im_class):
96
'support function for copy_reg to unpickle method refs'
97
try:
98
unbound = getattr(im_class,im_name)
99
if im_self is None:
100
return unbound
101
bound=types.MethodType(unbound.im_func,
102
im_self)
103
return bound
104
except AttributeError:
105
assert im_self is not None,"No recourse: no instance to guess from."
106
# Attempt a common fix before bailing -- if classes have
107
# changed around since we pickled this method, we may still be
108
# able to get it by looking on the instance's current class.
109
unbound = getattr(im_self.__class__,im_name)
110
if im_self is None:
111
return unbound
112
bound=types.MethodType(unbound.im_func,
113
im_self)
114
return bound
115
116
copy_reg.pickle(types.MethodType,
117
pickleMethod,
118
unpickleMethod)
119
120
oldModules = {}
121
122
def pickleModule(module):
123
'support function for copy_reg to pickle module refs'
124
return unpickleModule, (module.__name__,)
125
126
def unpickleModule(name):
127
'support function for copy_reg to unpickle module refs'
128
if oldModules.has_key(name):
129
name = oldModules[name]
130
return __import__(name,{},{},'x')
131
132
copy_reg.pickle(types.ModuleType,
133
pickleModule,
134
unpickleModule)
135
136