##// END OF EJS Templates
handle simple closures in pickleutil...
MinRK -
Show More
@@ -0,0 +1,62 b''
1
2 import pickle
3
4 import nose.tools as nt
5 from IPython.utils import codeutil
6 from IPython.utils.pickleutil import can, uncan
7
8 def interactive(f):
9 f.__module__ = '__main__'
10 return f
11
12 def dumps(obj):
13 return pickle.dumps(can(obj))
14
15 def loads(obj):
16 return uncan(pickle.loads(obj))
17
18 def test_no_closure():
19 @interactive
20 def foo():
21 a = 5
22 return a
23
24 pfoo = dumps(foo)
25 bar = loads(pfoo)
26 nt.assert_equal(foo(), bar())
27
28 def test_generator_closure():
29 # this only creates a closure on Python 3
30 @interactive
31 def foo():
32 i = 'i'
33 r = [ i for j in (1,2) ]
34 return r
35
36 pfoo = dumps(foo)
37 bar = loads(pfoo)
38 nt.assert_equal(foo(), bar())
39
40 def test_nested_closure():
41 @interactive
42 def foo():
43 i = 'i'
44 def g():
45 return i
46 return g()
47
48 pfoo = dumps(foo)
49 bar = loads(pfoo)
50 nt.assert_equal(foo(), bar())
51
52 def test_closure():
53 i = 'i'
54 @interactive
55 def foo():
56 return i
57
58 pfoo = dumps(foo)
59 bar = loads(pfoo)
60 nt.assert_equal(foo(), bar())
61
62 No newline at end of file
@@ -1,47 +1,35 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """Utilities to enable code objects to be pickled.
3 """Utilities to enable code objects to be pickled.
4
4
5 Any process that import this module will be able to pickle code objects. This
5 Any process that import this module will be able to pickle code objects. This
6 includes the func_code attribute of any function. Once unpickled, new
6 includes the func_code attribute of any function. Once unpickled, new
7 functions can be built using new.function(code, globals()). Eventually
7 functions can be built using new.function(code, globals()). Eventually
8 we need to automate all of this so that functions themselves can be pickled.
8 we need to automate all of this so that functions themselves can be pickled.
9
9
10 Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
10 Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
11 """
11 """
12
12
13 __docformat__ = "restructuredtext en"
13 # Copyright (c) IPython Development Team.
14
14 # Distributed under the terms of the Modified BSD License.
15 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
20 #-------------------------------------------------------------------------------
21
22 #-------------------------------------------------------------------------------
23 # Imports
24 #-------------------------------------------------------------------------------
25
15
26 import sys
16 import sys
27 import types
17 import types
28 try:
18 try:
29 import copyreg # Py 3
19 import copyreg # Py 3
30 except ImportError:
20 except ImportError:
31 import copy_reg as copyreg # Py 2
21 import copy_reg as copyreg # Py 2
32
22
33 def code_ctor(*args):
23 def code_ctor(*args):
34 return types.CodeType(*args)
24 return types.CodeType(*args)
35
25
36 def reduce_code(co):
26 def reduce_code(co):
37 if co.co_freevars or co.co_cellvars:
38 raise ValueError("Sorry, cannot pickle code objects with closures")
39 args = [co.co_argcount, co.co_nlocals, co.co_stacksize,
27 args = [co.co_argcount, co.co_nlocals, co.co_stacksize,
40 co.co_flags, co.co_code, co.co_consts, co.co_names,
28 co.co_flags, co.co_code, co.co_consts, co.co_names,
41 co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
29 co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
42 co.co_lnotab]
30 co.co_lnotab, co.co_freevars, co.co_cellvars]
43 if sys.version_info[0] >= 3:
31 if sys.version_info[0] >= 3:
44 args.insert(1, co.co_kwonlyargcount)
32 args.insert(1, co.co_kwonlyargcount)
45 return code_ctor, tuple(args)
33 return code_ctor, tuple(args)
46
34
47 copyreg.pickle(types.CodeType, reduce_code) No newline at end of file
35 copyreg.pickle(types.CodeType, reduce_code)
@@ -1,390 +1,413 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
3 """Pickle related utilities. Perhaps this should be called 'can'."""
2 """Pickle related utilities. Perhaps this should be called 'can'."""
4
3
5 __docformat__ = "restructuredtext en"
4 # Copyright (c) IPython Development Team.
6
5 # Distributed under the terms of the Modified BSD License.
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008-2011 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
13
14 #-------------------------------------------------------------------------------
15 # Imports
16 #-------------------------------------------------------------------------------
17
6
18 import copy
7 import copy
19 import logging
8 import logging
20 import sys
9 import sys
21 from types import FunctionType
10 from types import FunctionType
22
11
23 try:
12 try:
24 import cPickle as pickle
13 import cPickle as pickle
25 except ImportError:
14 except ImportError:
26 import pickle
15 import pickle
27
16
28 from . import codeutil # This registers a hook when it's imported
17 from . import codeutil # This registers a hook when it's imported
29 from . import py3compat
18 from . import py3compat
30 from .importstring import import_item
19 from .importstring import import_item
31 from .py3compat import string_types, iteritems
20 from .py3compat import string_types, iteritems
32
21
33 from IPython.config import Application
22 from IPython.config import Application
34
23
35 if py3compat.PY3:
24 if py3compat.PY3:
36 buffer = memoryview
25 buffer = memoryview
37 class_type = type
26 class_type = type
38 else:
27 else:
39 from types import ClassType
28 from types import ClassType
40 class_type = (type, ClassType)
29 class_type = (type, ClassType)
41
30
31 def _get_cell_type(a=None):
32 """the type of a closure cell doesn't seem to be importable,
33 so just create one
34 """
35 def inner():
36 return a
37 return type(py3compat.get_closure(inner)[0])
38
39 cell_type = _get_cell_type()
40
42 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
43 # Functions
42 # Functions
44 #-------------------------------------------------------------------------------
43 #-------------------------------------------------------------------------------
45
44
46
45
47 def use_dill():
46 def use_dill():
48 """use dill to expand serialization support
47 """use dill to expand serialization support
49
48
50 adds support for object methods and closures to serialization.
49 adds support for object methods and closures to serialization.
51 """
50 """
52 # import dill causes most of the magic
51 # import dill causes most of the magic
53 import dill
52 import dill
54
53
55 # dill doesn't work with cPickle,
54 # dill doesn't work with cPickle,
56 # tell the two relevant modules to use plain pickle
55 # tell the two relevant modules to use plain pickle
57
56
58 global pickle
57 global pickle
59 pickle = dill
58 pickle = dill
60
59
61 try:
60 try:
62 from IPython.kernel.zmq import serialize
61 from IPython.kernel.zmq import serialize
63 except ImportError:
62 except ImportError:
64 pass
63 pass
65 else:
64 else:
66 serialize.pickle = dill
65 serialize.pickle = dill
67
66
68 # disable special function handling, let dill take care of it
67 # disable special function handling, let dill take care of it
69 can_map.pop(FunctionType, None)
68 can_map.pop(FunctionType, None)
70
69
71
70
72 #-------------------------------------------------------------------------------
71 #-------------------------------------------------------------------------------
73 # Classes
72 # Classes
74 #-------------------------------------------------------------------------------
73 #-------------------------------------------------------------------------------
75
74
76
75
77 class CannedObject(object):
76 class CannedObject(object):
78 def __init__(self, obj, keys=[], hook=None):
77 def __init__(self, obj, keys=[], hook=None):
79 """can an object for safe pickling
78 """can an object for safe pickling
80
79
81 Parameters
80 Parameters
82 ==========
81 ==========
83
82
84 obj:
83 obj:
85 The object to be canned
84 The object to be canned
86 keys: list (optional)
85 keys: list (optional)
87 list of attribute names that will be explicitly canned / uncanned
86 list of attribute names that will be explicitly canned / uncanned
88 hook: callable (optional)
87 hook: callable (optional)
89 An optional extra callable,
88 An optional extra callable,
90 which can do additional processing of the uncanned object.
89 which can do additional processing of the uncanned object.
91
90
92 large data may be offloaded into the buffers list,
91 large data may be offloaded into the buffers list,
93 used for zero-copy transfers.
92 used for zero-copy transfers.
94 """
93 """
95 self.keys = keys
94 self.keys = keys
96 self.obj = copy.copy(obj)
95 self.obj = copy.copy(obj)
97 self.hook = can(hook)
96 self.hook = can(hook)
98 for key in keys:
97 for key in keys:
99 setattr(self.obj, key, can(getattr(obj, key)))
98 setattr(self.obj, key, can(getattr(obj, key)))
100
99
101 self.buffers = []
100 self.buffers = []
102
101
103 def get_object(self, g=None):
102 def get_object(self, g=None):
104 if g is None:
103 if g is None:
105 g = {}
104 g = {}
106 obj = self.obj
105 obj = self.obj
107 for key in self.keys:
106 for key in self.keys:
108 setattr(obj, key, uncan(getattr(obj, key), g))
107 setattr(obj, key, uncan(getattr(obj, key), g))
109
108
110 if self.hook:
109 if self.hook:
111 self.hook = uncan(self.hook, g)
110 self.hook = uncan(self.hook, g)
112 self.hook(obj, g)
111 self.hook(obj, g)
113 return self.obj
112 return self.obj
114
113
115
114
116 class Reference(CannedObject):
115 class Reference(CannedObject):
117 """object for wrapping a remote reference by name."""
116 """object for wrapping a remote reference by name."""
118 def __init__(self, name):
117 def __init__(self, name):
119 if not isinstance(name, string_types):
118 if not isinstance(name, string_types):
120 raise TypeError("illegal name: %r"%name)
119 raise TypeError("illegal name: %r"%name)
121 self.name = name
120 self.name = name
122 self.buffers = []
121 self.buffers = []
123
122
124 def __repr__(self):
123 def __repr__(self):
125 return "<Reference: %r>"%self.name
124 return "<Reference: %r>"%self.name
126
125
127 def get_object(self, g=None):
126 def get_object(self, g=None):
128 if g is None:
127 if g is None:
129 g = {}
128 g = {}
130
129
131 return eval(self.name, g)
130 return eval(self.name, g)
132
131
133
132
133 class CannedCell(CannedObject):
134 """Can a closure cell"""
135 def __init__(self, cell):
136 self.cell_contents = can(cell.cell_contents)
137
138 def get_object(self, g=None):
139 cell_contents = uncan(self.cell_contents, g)
140 def inner():
141 return cell_contents
142 return py3compat.get_closure(inner)[0]
143
144
134 class CannedFunction(CannedObject):
145 class CannedFunction(CannedObject):
135
146
136 def __init__(self, f):
147 def __init__(self, f):
137 self._check_type(f)
148 self._check_type(f)
138 self.code = f.__code__
149 self.code = f.__code__
139 if f.__defaults__:
150 if f.__defaults__:
140 self.defaults = [ can(fd) for fd in f.__defaults__ ]
151 self.defaults = [ can(fd) for fd in f.__defaults__ ]
141 else:
152 else:
142 self.defaults = None
153 self.defaults = None
154
155 closure = py3compat.get_closure(f)
156 if closure:
157 self.closure = tuple( can(cell) for cell in closure )
158 else:
159 self.closure = None
160
143 self.module = f.__module__ or '__main__'
161 self.module = f.__module__ or '__main__'
144 self.__name__ = f.__name__
162 self.__name__ = f.__name__
145 self.buffers = []
163 self.buffers = []
146
164
147 def _check_type(self, obj):
165 def _check_type(self, obj):
148 assert isinstance(obj, FunctionType), "Not a function type"
166 assert isinstance(obj, FunctionType), "Not a function type"
149
167
150 def get_object(self, g=None):
168 def get_object(self, g=None):
151 # try to load function back into its module:
169 # try to load function back into its module:
152 if not self.module.startswith('__'):
170 if not self.module.startswith('__'):
153 __import__(self.module)
171 __import__(self.module)
154 g = sys.modules[self.module].__dict__
172 g = sys.modules[self.module].__dict__
155
173
156 if g is None:
174 if g is None:
157 g = {}
175 g = {}
158 if self.defaults:
176 if self.defaults:
159 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
177 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
160 else:
178 else:
161 defaults = None
179 defaults = None
162 newFunc = FunctionType(self.code, g, self.__name__, defaults)
180 if self.closure:
181 closure = tuple(uncan(cell, g) for cell in self.closure)
182 else:
183 closure = None
184 newFunc = FunctionType(self.code, g, self.__name__, defaults, closure)
163 return newFunc
185 return newFunc
164
186
165 class CannedClass(CannedObject):
187 class CannedClass(CannedObject):
166
188
167 def __init__(self, cls):
189 def __init__(self, cls):
168 self._check_type(cls)
190 self._check_type(cls)
169 self.name = cls.__name__
191 self.name = cls.__name__
170 self.old_style = not isinstance(cls, type)
192 self.old_style = not isinstance(cls, type)
171 self._canned_dict = {}
193 self._canned_dict = {}
172 for k,v in cls.__dict__.items():
194 for k,v in cls.__dict__.items():
173 if k not in ('__weakref__', '__dict__'):
195 if k not in ('__weakref__', '__dict__'):
174 self._canned_dict[k] = can(v)
196 self._canned_dict[k] = can(v)
175 if self.old_style:
197 if self.old_style:
176 mro = []
198 mro = []
177 else:
199 else:
178 mro = cls.mro()
200 mro = cls.mro()
179
201
180 self.parents = [ can(c) for c in mro[1:] ]
202 self.parents = [ can(c) for c in mro[1:] ]
181 self.buffers = []
203 self.buffers = []
182
204
183 def _check_type(self, obj):
205 def _check_type(self, obj):
184 assert isinstance(obj, class_type), "Not a class type"
206 assert isinstance(obj, class_type), "Not a class type"
185
207
186 def get_object(self, g=None):
208 def get_object(self, g=None):
187 parents = tuple(uncan(p, g) for p in self.parents)
209 parents = tuple(uncan(p, g) for p in self.parents)
188 return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
210 return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
189
211
190 class CannedArray(CannedObject):
212 class CannedArray(CannedObject):
191 def __init__(self, obj):
213 def __init__(self, obj):
192 from numpy import ascontiguousarray
214 from numpy import ascontiguousarray
193 self.shape = obj.shape
215 self.shape = obj.shape
194 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
216 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
195 self.pickled = False
217 self.pickled = False
196 if sum(obj.shape) == 0:
218 if sum(obj.shape) == 0:
197 self.pickled = True
219 self.pickled = True
198 elif obj.dtype == 'O':
220 elif obj.dtype == 'O':
199 # can't handle object dtype with buffer approach
221 # can't handle object dtype with buffer approach
200 self.pickled = True
222 self.pickled = True
201 elif obj.dtype.fields and any(dt == 'O' for dt,sz in obj.dtype.fields.values()):
223 elif obj.dtype.fields and any(dt == 'O' for dt,sz in obj.dtype.fields.values()):
202 self.pickled = True
224 self.pickled = True
203 if self.pickled:
225 if self.pickled:
204 # just pickle it
226 # just pickle it
205 self.buffers = [pickle.dumps(obj, -1)]
227 self.buffers = [pickle.dumps(obj, -1)]
206 else:
228 else:
207 # ensure contiguous
229 # ensure contiguous
208 obj = ascontiguousarray(obj, dtype=None)
230 obj = ascontiguousarray(obj, dtype=None)
209 self.buffers = [buffer(obj)]
231 self.buffers = [buffer(obj)]
210
232
211 def get_object(self, g=None):
233 def get_object(self, g=None):
212 from numpy import frombuffer
234 from numpy import frombuffer
213 data = self.buffers[0]
235 data = self.buffers[0]
214 if self.pickled:
236 if self.pickled:
215 # no shape, we just pickled it
237 # no shape, we just pickled it
216 return pickle.loads(data)
238 return pickle.loads(data)
217 else:
239 else:
218 return frombuffer(data, dtype=self.dtype).reshape(self.shape)
240 return frombuffer(data, dtype=self.dtype).reshape(self.shape)
219
241
220
242
221 class CannedBytes(CannedObject):
243 class CannedBytes(CannedObject):
222 wrap = bytes
244 wrap = bytes
223 def __init__(self, obj):
245 def __init__(self, obj):
224 self.buffers = [obj]
246 self.buffers = [obj]
225
247
226 def get_object(self, g=None):
248 def get_object(self, g=None):
227 data = self.buffers[0]
249 data = self.buffers[0]
228 return self.wrap(data)
250 return self.wrap(data)
229
251
230 def CannedBuffer(CannedBytes):
252 def CannedBuffer(CannedBytes):
231 wrap = buffer
253 wrap = buffer
232
254
233 #-------------------------------------------------------------------------------
255 #-------------------------------------------------------------------------------
234 # Functions
256 # Functions
235 #-------------------------------------------------------------------------------
257 #-------------------------------------------------------------------------------
236
258
237 def _logger():
259 def _logger():
238 """get the logger for the current Application
260 """get the logger for the current Application
239
261
240 the root logger will be used if no Application is running
262 the root logger will be used if no Application is running
241 """
263 """
242 if Application.initialized():
264 if Application.initialized():
243 logger = Application.instance().log
265 logger = Application.instance().log
244 else:
266 else:
245 logger = logging.getLogger()
267 logger = logging.getLogger()
246 if not logger.handlers:
268 if not logger.handlers:
247 logging.basicConfig()
269 logging.basicConfig()
248
270
249 return logger
271 return logger
250
272
251 def _import_mapping(mapping, original=None):
273 def _import_mapping(mapping, original=None):
252 """import any string-keys in a type mapping
274 """import any string-keys in a type mapping
253
275
254 """
276 """
255 log = _logger()
277 log = _logger()
256 log.debug("Importing canning map")
278 log.debug("Importing canning map")
257 for key,value in list(mapping.items()):
279 for key,value in list(mapping.items()):
258 if isinstance(key, string_types):
280 if isinstance(key, string_types):
259 try:
281 try:
260 cls = import_item(key)
282 cls = import_item(key)
261 except Exception:
283 except Exception:
262 if original and key not in original:
284 if original and key not in original:
263 # only message on user-added classes
285 # only message on user-added classes
264 log.error("canning class not importable: %r", key, exc_info=True)
286 log.error("canning class not importable: %r", key, exc_info=True)
265 mapping.pop(key)
287 mapping.pop(key)
266 else:
288 else:
267 mapping[cls] = mapping.pop(key)
289 mapping[cls] = mapping.pop(key)
268
290
269 def istype(obj, check):
291 def istype(obj, check):
270 """like isinstance(obj, check), but strict
292 """like isinstance(obj, check), but strict
271
293
272 This won't catch subclasses.
294 This won't catch subclasses.
273 """
295 """
274 if isinstance(check, tuple):
296 if isinstance(check, tuple):
275 for cls in check:
297 for cls in check:
276 if type(obj) is cls:
298 if type(obj) is cls:
277 return True
299 return True
278 return False
300 return False
279 else:
301 else:
280 return type(obj) is check
302 return type(obj) is check
281
303
282 def can(obj):
304 def can(obj):
283 """prepare an object for pickling"""
305 """prepare an object for pickling"""
284
306
285 import_needed = False
307 import_needed = False
286
308
287 for cls,canner in iteritems(can_map):
309 for cls,canner in iteritems(can_map):
288 if isinstance(cls, string_types):
310 if isinstance(cls, string_types):
289 import_needed = True
311 import_needed = True
290 break
312 break
291 elif istype(obj, cls):
313 elif istype(obj, cls):
292 return canner(obj)
314 return canner(obj)
293
315
294 if import_needed:
316 if import_needed:
295 # perform can_map imports, then try again
317 # perform can_map imports, then try again
296 # this will usually only happen once
318 # this will usually only happen once
297 _import_mapping(can_map, _original_can_map)
319 _import_mapping(can_map, _original_can_map)
298 return can(obj)
320 return can(obj)
299
321
300 return obj
322 return obj
301
323
302 def can_class(obj):
324 def can_class(obj):
303 if isinstance(obj, class_type) and obj.__module__ == '__main__':
325 if isinstance(obj, class_type) and obj.__module__ == '__main__':
304 return CannedClass(obj)
326 return CannedClass(obj)
305 else:
327 else:
306 return obj
328 return obj
307
329
308 def can_dict(obj):
330 def can_dict(obj):
309 """can the *values* of a dict"""
331 """can the *values* of a dict"""
310 if istype(obj, dict):
332 if istype(obj, dict):
311 newobj = {}
333 newobj = {}
312 for k, v in iteritems(obj):
334 for k, v in iteritems(obj):
313 newobj[k] = can(v)
335 newobj[k] = can(v)
314 return newobj
336 return newobj
315 else:
337 else:
316 return obj
338 return obj
317
339
318 sequence_types = (list, tuple, set)
340 sequence_types = (list, tuple, set)
319
341
320 def can_sequence(obj):
342 def can_sequence(obj):
321 """can the elements of a sequence"""
343 """can the elements of a sequence"""
322 if istype(obj, sequence_types):
344 if istype(obj, sequence_types):
323 t = type(obj)
345 t = type(obj)
324 return t([can(i) for i in obj])
346 return t([can(i) for i in obj])
325 else:
347 else:
326 return obj
348 return obj
327
349
328 def uncan(obj, g=None):
350 def uncan(obj, g=None):
329 """invert canning"""
351 """invert canning"""
330
352
331 import_needed = False
353 import_needed = False
332 for cls,uncanner in iteritems(uncan_map):
354 for cls,uncanner in iteritems(uncan_map):
333 if isinstance(cls, string_types):
355 if isinstance(cls, string_types):
334 import_needed = True
356 import_needed = True
335 break
357 break
336 elif isinstance(obj, cls):
358 elif isinstance(obj, cls):
337 return uncanner(obj, g)
359 return uncanner(obj, g)
338
360
339 if import_needed:
361 if import_needed:
340 # perform uncan_map imports, then try again
362 # perform uncan_map imports, then try again
341 # this will usually only happen once
363 # this will usually only happen once
342 _import_mapping(uncan_map, _original_uncan_map)
364 _import_mapping(uncan_map, _original_uncan_map)
343 return uncan(obj, g)
365 return uncan(obj, g)
344
366
345 return obj
367 return obj
346
368
347 def uncan_dict(obj, g=None):
369 def uncan_dict(obj, g=None):
348 if istype(obj, dict):
370 if istype(obj, dict):
349 newobj = {}
371 newobj = {}
350 for k, v in iteritems(obj):
372 for k, v in iteritems(obj):
351 newobj[k] = uncan(v,g)
373 newobj[k] = uncan(v,g)
352 return newobj
374 return newobj
353 else:
375 else:
354 return obj
376 return obj
355
377
356 def uncan_sequence(obj, g=None):
378 def uncan_sequence(obj, g=None):
357 if istype(obj, sequence_types):
379 if istype(obj, sequence_types):
358 t = type(obj)
380 t = type(obj)
359 return t([uncan(i,g) for i in obj])
381 return t([uncan(i,g) for i in obj])
360 else:
382 else:
361 return obj
383 return obj
362
384
363 def _uncan_dependent_hook(dep, g=None):
385 def _uncan_dependent_hook(dep, g=None):
364 dep.check_dependency()
386 dep.check_dependency()
365
387
366 def can_dependent(obj):
388 def can_dependent(obj):
367 return CannedObject(obj, keys=('f', 'df'), hook=_uncan_dependent_hook)
389 return CannedObject(obj, keys=('f', 'df'), hook=_uncan_dependent_hook)
368
390
369 #-------------------------------------------------------------------------------
391 #-------------------------------------------------------------------------------
370 # API dictionaries
392 # API dictionaries
371 #-------------------------------------------------------------------------------
393 #-------------------------------------------------------------------------------
372
394
373 # These dicts can be extended for custom serialization of new objects
395 # These dicts can be extended for custom serialization of new objects
374
396
375 can_map = {
397 can_map = {
376 'IPython.parallel.dependent' : can_dependent,
398 'IPython.parallel.dependent' : can_dependent,
377 'numpy.ndarray' : CannedArray,
399 'numpy.ndarray' : CannedArray,
378 FunctionType : CannedFunction,
400 FunctionType : CannedFunction,
379 bytes : CannedBytes,
401 bytes : CannedBytes,
380 buffer : CannedBuffer,
402 buffer : CannedBuffer,
403 cell_type : CannedCell,
381 class_type : can_class,
404 class_type : can_class,
382 }
405 }
383
406
384 uncan_map = {
407 uncan_map = {
385 CannedObject : lambda obj, g: obj.get_object(g),
408 CannedObject : lambda obj, g: obj.get_object(g),
386 }
409 }
387
410
388 # for use in _import_mapping:
411 # for use in _import_mapping:
389 _original_can_map = can_map.copy()
412 _original_can_map = can_map.copy()
390 _original_uncan_map = uncan_map.copy()
413 _original_uncan_map = uncan_map.copy()
General Comments 0
You need to be logged in to leave comments. Login now