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