##// END OF EJS Templates
can func_defaults...
MinRK -
Show More
@@ -1,237 +1,244 b''
1 1 # encoding: utf-8
2 2
3 3 """Pickle related utilities. Perhaps this should be called 'can'."""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #-------------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-------------------------------------------------------------------------------
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Imports
16 16 #-------------------------------------------------------------------------------
17 17
18 18 import copy
19 19 import logging
20 20 import sys
21 21 from types import FunctionType
22 22
23 23 try:
24 24 import cPickle as pickle
25 25 except ImportError:
26 26 import pickle
27 27
28 28 try:
29 29 import numpy
30 30 except:
31 31 numpy = None
32 32
33 33 import codeutil
34 34 import py3compat
35 35 from importstring import import_item
36 36
37 37 from IPython.config import Application
38 38
39 39 if py3compat.PY3:
40 40 buffer = memoryview
41 41
42 42 #-------------------------------------------------------------------------------
43 43 # Classes
44 44 #-------------------------------------------------------------------------------
45 45
46 46
47 47 class CannedObject(object):
48 48 def __init__(self, obj, keys=[]):
49 49 self.keys = keys
50 50 self.obj = copy.copy(obj)
51 51 for key in keys:
52 52 setattr(self.obj, key, can(getattr(obj, key)))
53 53
54 54 self.buffers = []
55 55
56 56 def get_object(self, g=None):
57 57 if g is None:
58 58 g = {}
59 59 for key in self.keys:
60 60 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
61 61 return self.obj
62 62
63 63
64 64 class Reference(CannedObject):
65 65 """object for wrapping a remote reference by name."""
66 66 def __init__(self, name):
67 67 if not isinstance(name, basestring):
68 68 raise TypeError("illegal name: %r"%name)
69 69 self.name = name
70 70 self.buffers = []
71 71
72 72 def __repr__(self):
73 73 return "<Reference: %r>"%self.name
74 74
75 75 def get_object(self, g=None):
76 76 if g is None:
77 77 g = {}
78 78
79 79 return eval(self.name, g)
80 80
81 81
82 82 class CannedFunction(CannedObject):
83 83
84 84 def __init__(self, f):
85 85 self._check_type(f)
86 86 self.code = f.func_code
87 self.defaults = f.func_defaults
87 if f.func_defaults:
88 self.defaults = [ can(fd) for fd in f.func_defaults ]
89 else:
90 self.defaults = None
88 91 self.module = f.__module__ or '__main__'
89 92 self.__name__ = f.__name__
90 93 self.buffers = []
91 94
92 95 def _check_type(self, obj):
93 96 assert isinstance(obj, FunctionType), "Not a function type"
94 97
95 98 def get_object(self, g=None):
96 99 # try to load function back into its module:
97 100 if not self.module.startswith('__'):
98 101 try:
99 102 __import__(self.module)
100 103 except ImportError:
101 104 pass
102 105 else:
103 106 g = sys.modules[self.module].__dict__
104 107
105 108 if g is None:
106 109 g = {}
107 newFunc = FunctionType(self.code, g, self.__name__, self.defaults)
110 if self.defaults:
111 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
112 else:
113 defaults = None
114 newFunc = FunctionType(self.code, g, self.__name__, defaults)
108 115 return newFunc
109 116
110 117
111 118 class CannedArray(CannedObject):
112 119 def __init__(self, obj):
113 120 self.shape = obj.shape
114 121 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
115 122 if sum(obj.shape) == 0:
116 123 # just pickle it
117 124 self.buffers = [pickle.dumps(obj, -1)]
118 125 else:
119 126 # ensure contiguous
120 127 obj = numpy.ascontiguousarray(obj, dtype=None)
121 128 self.buffers = [buffer(obj)]
122 129
123 130 def get_object(self, g=None):
124 131 data = self.buffers[0]
125 132 if sum(self.shape) == 0:
126 133 # no shape, we just pickled it
127 134 return pickle.loads(data)
128 135 else:
129 136 return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)
130 137
131 138
132 139 class CannedBytes(CannedObject):
133 140 wrap = bytes
134 141 def __init__(self, obj):
135 142 self.buffers = [obj]
136 143
137 144 def get_object(self, g=None):
138 145 data = self.buffers[0]
139 146 return self.wrap(data)
140 147
141 148 def CannedBuffer(CannedBytes):
142 149 wrap = buffer
143 150
144 151 #-------------------------------------------------------------------------------
145 152 # Functions
146 153 #-------------------------------------------------------------------------------
147 154
148 155 def _error(*args, **kwargs):
149 156 if Application.initialized():
150 157 logger = Application.instance().log
151 158 else:
152 159 logger = logging.getLogger()
153 160 if not logger.handlers:
154 161 logging.basicConfig()
155 162 logger.error(*args, **kwargs)
156 163
157 164 def can(obj):
158 165 """prepare an object for pickling"""
159 166 for cls,canner in can_map.iteritems():
160 167 if isinstance(cls, basestring):
161 168 try:
162 169 cls = import_item(cls)
163 170 except Exception:
164 171 _error("cannning class not importable: %r", cls, exc_info=True)
165 172 cls = None
166 173 continue
167 174 if isinstance(obj, cls):
168 175 return canner(obj)
169 176 return obj
170 177
171 178 def can_dict(obj):
172 179 """can the *values* of a dict"""
173 180 if isinstance(obj, dict):
174 181 newobj = {}
175 182 for k, v in obj.iteritems():
176 183 newobj[k] = can(v)
177 184 return newobj
178 185 else:
179 186 return obj
180 187
181 188 def can_sequence(obj):
182 189 """can the elements of a sequence"""
183 190 if isinstance(obj, (list, tuple)):
184 191 t = type(obj)
185 192 return t([can(i) for i in obj])
186 193 else:
187 194 return obj
188 195
189 196 def uncan(obj, g=None):
190 197 """invert canning"""
191 198 for cls,uncanner in uncan_map.iteritems():
192 199 if isinstance(cls, basestring):
193 200 try:
194 201 cls = import_item(cls)
195 202 except Exception:
196 203 _error("uncanning class not importable: %r", cls, exc_info=True)
197 204 cls = None
198 205 continue
199 206 if isinstance(obj, cls):
200 207 return uncanner(obj, g)
201 208 return obj
202 209
203 210 def uncan_dict(obj, g=None):
204 211 if isinstance(obj, dict):
205 212 newobj = {}
206 213 for k, v in obj.iteritems():
207 214 newobj[k] = uncan(v,g)
208 215 return newobj
209 216 else:
210 217 return obj
211 218
212 219 def uncan_sequence(obj, g=None):
213 220 if isinstance(obj, (list, tuple)):
214 221 t = type(obj)
215 222 return t([uncan(i,g) for i in obj])
216 223 else:
217 224 return obj
218 225
219 226
220 227 #-------------------------------------------------------------------------------
221 228 # API dictionary
222 229 #-------------------------------------------------------------------------------
223 230
224 231 # These dicts can be extended for custom serialization of new objects
225 232
226 233 can_map = {
227 234 'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),
228 235 'numpy.ndarray' : CannedArray,
229 236 FunctionType : CannedFunction,
230 237 bytes : CannedBytes,
231 238 buffer : CannedBuffer,
232 239 }
233 240
234 241 uncan_map = {
235 242 CannedObject : lambda obj, g: obj.get_object(g),
236 243 }
237 244
General Comments 0
You need to be logged in to leave comments. Login now