Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

# cython: old_style_globals=True 

""" 

Function pickling 

  

REFERENCE: The python cookbook. 

""" 

from __future__ import absolute_import 

  

import types 

import six 

from six.moves import copyreg 

from six.moves import cPickle 

  

  

def code_ctor(*args): 

""" 

EXAMPLES: 

  

This indirectly tests this function. :: 

  

sage: def foo(a,b,c=10): return a+b+c 

sage: sage.misc.fpickle.reduce_code(foo.__code__) 

(<built-in function code_ctor>, ...) 

sage: unpickle_function(pickle_function(foo)) 

<function foo at ...> 

""" 

return types.CodeType(*args) 

  

  

def reduce_code(co): 

""" 

EXAMPLES:: 

  

sage: def foo(N): return N+1 

sage: sage.misc.fpickle.reduce_code(foo.__code__) 

(<built-in function code_ctor>, ...) 

""" 

if co.co_freevars or co.co_cellvars: 

raise ValueError("Cannot pickle code objects from closures") 

  

if six.PY2: 

co_args = (co.co_argcount,) 

else: 

co_args = (co.co_argcount, co.co_kwonlyargcount) 

  

co_args += (co.co_nlocals, co.co_stacksize, co.co_flags, co.co_code, 

co.co_consts, co.co_names, co.co_varnames, co.co_filename, 

co.co_name, co.co_firstlineno, co.co_lnotab) 

  

return (code_ctor, co_args) 

  

  

copyreg.pickle(types.CodeType, reduce_code) 

  

def pickle_function(func): 

""" 

Pickle the Python function func. This is not a normal pickle; you 

must use the unpickle_function method to unpickle the pickled 

function. 

  

NOTE: This does not work on all functions, but does work on 

'surprisingly' many functions. In particular, it does not 

work on functions that includes nested functions. 

  

INPUT: 

  

func -- a Python function 

  

OUTPUT: 

  

a string 

  

EXAMPLES:: 

  

sage: def f(N): return N+1 

... 

sage: g = pickle_function(f) 

sage: h = unpickle_function(g) 

sage: h(10) 

11 

""" 

return cPickle.dumps(func.__code__) 

  

def unpickle_function(pickled): 

""" 

Unpickle a pickled function. 

  

EXAMPLES: 

  

sage: def f(N,M): return N*M 

... 

sage: unpickle_function(pickle_function(f))(3,5) 

15 

""" 

recovered = cPickle.loads(pickled) 

return types.FunctionType(recovered, globals()) 

  

  

  

def call_pickled_function(fpargs): 

import sage.all 

from sage.misc.fpickle import unpickle_function 

(fp, (args, kwds)) = fpargs 

f = eval("unpickle_function(fp)", sage.all.__dict__, {'fp':fp}) 

res = eval("f(*args, **kwds)",sage.all.__dict__, {'args':args, 'kwds':kwds, 'f':f}) 

return ((args, kwds), res) 

  

# The following four methods are taken from twisted.persisted.styles - the 

# import of twisted.persisted.styles takes a long time and we do not use 

# most functionality it provides 

def pickleMethod(method): 

'support function for copyreg to pickle method refs' 

  

# Note: On Python 3 there is no .im_class but we can get the instance's 

# class through .__self__.__class__ 

cls = getattr(method, 'im_class', method.__self__.__class__) 

return (unpickleMethod, (method.__func__.__name__, method.__self__, cls)) 

  

  

def unpickleMethod(im_name, 

__self__, 

im_class): 

'support function for copyreg to unpickle method refs' 

try: 

unbound = getattr(im_class,im_name) 

if __self__ is None: 

return unbound 

  

# Note: On Python 2 "unbound methods" are just functions, so they don't 

# have a __func__ 

bound = types.MethodType(getattr(unbound, '__func__', unbound), 

__self__) 

return bound 

except AttributeError: 

assert __self__ is not None, "No recourse: no instance to guess from." 

# Attempt a common fix before bailing -- if classes have 

# changed around since we pickled this method, we may still be 

# able to get it by looking on the instance's current class. 

unbound = getattr(__self__.__class__, im_name) 

if __self__ is None: 

return unbound 

  

bound = types.MethodType(getattr(unbound, '__func__', unbound), 

__self__) 

return bound 

  

copyreg.pickle(types.MethodType, 

pickleMethod, 

unpickleMethod) 

  

oldModules = {} 

  

def pickleModule(module): 

'support function for copyreg to pickle module refs' 

return unpickleModule, (module.__name__,) 

  

def unpickleModule(name): 

'support function for copyreg to unpickle module refs' 

if name in oldModules: 

name = oldModules[name] 

return __import__(name,{},{},'x') 

  

copyreg.pickle(types.ModuleType, 

pickleModule, 

unpickleModule)