##// END OF EJS Templates
remove unused namedtuple import
MinRK -
Show More
@@ -1,328 +1,327 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 from collections import namedtuple
22 21 from types import FunctionType
23 22
24 23 try:
25 24 import cPickle as pickle
26 25 except ImportError:
27 26 import pickle
28 27
29 28 try:
30 29 import numpy
31 30 except:
32 31 numpy = None
33 32
34 33 import codeutil
35 34 import py3compat
36 35 from importstring import import_item
37 36
38 37 from IPython.config import Application
39 38
40 39 if py3compat.PY3:
41 40 buffer = memoryview
42 41 class_type = type
43 42 else:
44 43 from types import ClassType
45 44 class_type = (type, ClassType)
46 45
47 46 #-------------------------------------------------------------------------------
48 47 # Classes
49 48 #-------------------------------------------------------------------------------
50 49
51 50
52 51 class CannedObject(object):
53 52 def __init__(self, obj, keys=[]):
54 53 self.keys = keys
55 54 self.obj = copy.copy(obj)
56 55 for key in keys:
57 56 setattr(self.obj, key, can(getattr(obj, key)))
58 57
59 58 self.buffers = []
60 59
61 60 def get_object(self, g=None):
62 61 if g is None:
63 62 g = {}
64 63 for key in self.keys:
65 64 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
66 65 return self.obj
67 66
68 67
69 68 class Reference(CannedObject):
70 69 """object for wrapping a remote reference by name."""
71 70 def __init__(self, name):
72 71 if not isinstance(name, basestring):
73 72 raise TypeError("illegal name: %r"%name)
74 73 self.name = name
75 74 self.buffers = []
76 75
77 76 def __repr__(self):
78 77 return "<Reference: %r>"%self.name
79 78
80 79 def get_object(self, g=None):
81 80 if g is None:
82 81 g = {}
83 82
84 83 return eval(self.name, g)
85 84
86 85
87 86 class CannedFunction(CannedObject):
88 87
89 88 def __init__(self, f):
90 89 self._check_type(f)
91 90 self.code = f.func_code
92 91 if f.func_defaults:
93 92 self.defaults = [ can(fd) for fd in f.func_defaults ]
94 93 else:
95 94 self.defaults = None
96 95 self.module = f.__module__ or '__main__'
97 96 self.__name__ = f.__name__
98 97 self.buffers = []
99 98
100 99 def _check_type(self, obj):
101 100 assert isinstance(obj, FunctionType), "Not a function type"
102 101
103 102 def get_object(self, g=None):
104 103 # try to load function back into its module:
105 104 if not self.module.startswith('__'):
106 105 __import__(self.module)
107 106 g = sys.modules[self.module].__dict__
108 107
109 108 if g is None:
110 109 g = {}
111 110 if self.defaults:
112 111 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
113 112 else:
114 113 defaults = None
115 114 newFunc = FunctionType(self.code, g, self.__name__, defaults)
116 115 return newFunc
117 116
118 117 class CannedClass(CannedObject):
119 118
120 119 def __init__(self, cls):
121 120 self._check_type(cls)
122 121 self.name = cls.__name__
123 122 self.old_style = not isinstance(cls, type)
124 123 self._canned_dict = {}
125 124 for k,v in cls.__dict__.items():
126 125 if k not in ('__weakref__', '__dict__'):
127 126 self._canned_dict[k] = can(v)
128 127 if self.old_style:
129 128 mro = []
130 129 else:
131 130 mro = cls.mro()
132 131
133 132 self.parents = [ can(c) for c in mro[1:] ]
134 133 self.buffers = []
135 134
136 135 def _check_type(self, obj):
137 136 assert isinstance(obj, class_type), "Not a class type"
138 137
139 138 def get_object(self, g=None):
140 139 parents = tuple(uncan(p, g) for p in self.parents)
141 140 return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
142 141
143 142 class CannedArray(CannedObject):
144 143 def __init__(self, obj):
145 144 self.shape = obj.shape
146 145 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
147 146 if sum(obj.shape) == 0:
148 147 # just pickle it
149 148 self.buffers = [pickle.dumps(obj, -1)]
150 149 else:
151 150 # ensure contiguous
152 151 obj = numpy.ascontiguousarray(obj, dtype=None)
153 152 self.buffers = [buffer(obj)]
154 153
155 154 def get_object(self, g=None):
156 155 data = self.buffers[0]
157 156 if sum(self.shape) == 0:
158 157 # no shape, we just pickled it
159 158 return pickle.loads(data)
160 159 else:
161 160 return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)
162 161
163 162
164 163 class CannedBytes(CannedObject):
165 164 wrap = bytes
166 165 def __init__(self, obj):
167 166 self.buffers = [obj]
168 167
169 168 def get_object(self, g=None):
170 169 data = self.buffers[0]
171 170 return self.wrap(data)
172 171
173 172 def CannedBuffer(CannedBytes):
174 173 wrap = buffer
175 174
176 175 #-------------------------------------------------------------------------------
177 176 # Functions
178 177 #-------------------------------------------------------------------------------
179 178
180 179 def _logger():
181 180 """get the logger for the current Application
182 181
183 182 the root logger will be used if no Application is running
184 183 """
185 184 if Application.initialized():
186 185 logger = Application.instance().log
187 186 else:
188 187 logger = logging.getLogger()
189 188 if not logger.handlers:
190 189 logging.basicConfig()
191 190
192 191 return logger
193 192
194 193 def _import_mapping(mapping, original=None):
195 194 """import any string-keys in a type mapping
196 195
197 196 """
198 197 log = _logger()
199 198 log.debug("Importing canning map")
200 199 for key,value in mapping.items():
201 200 if isinstance(key, basestring):
202 201 try:
203 202 cls = import_item(key)
204 203 except Exception:
205 204 if original and key not in original:
206 205 # only message on user-added classes
207 206 log.error("cannning class not importable: %r", key, exc_info=True)
208 207 mapping.pop(key)
209 208 else:
210 209 mapping[cls] = mapping.pop(key)
211 210
212 211 def istype(obj, check):
213 212 """like isinstance(obj, check), but strict
214 213
215 214 This won't catch subclasses.
216 215 """
217 216 if isinstance(check, tuple):
218 217 for cls in check:
219 218 if type(obj) is cls:
220 219 return True
221 220 return False
222 221 else:
223 222 return type(obj) is check
224 223
225 224 def can(obj):
226 225 """prepare an object for pickling"""
227 226
228 227 import_needed = False
229 228
230 229 for cls,canner in can_map.iteritems():
231 230 if isinstance(cls, basestring):
232 231 import_needed = True
233 232 break
234 233 elif istype(obj, cls):
235 234 return canner(obj)
236 235
237 236 if import_needed:
238 237 # perform can_map imports, then try again
239 238 # this will usually only happen once
240 239 _import_mapping(can_map, _original_can_map)
241 240 return can(obj)
242 241
243 242 return obj
244 243
245 244 def can_class(obj):
246 245 if isinstance(obj, class_type) and obj.__module__ == '__main__':
247 246 return CannedClass(obj)
248 247 else:
249 248 return obj
250 249
251 250 def can_dict(obj):
252 251 """can the *values* of a dict"""
253 252 if istype(obj, dict):
254 253 newobj = {}
255 254 for k, v in obj.iteritems():
256 255 newobj[k] = can(v)
257 256 return newobj
258 257 else:
259 258 return obj
260 259
261 260 sequence_types = (list, tuple, set)
262 261
263 262 def can_sequence(obj):
264 263 """can the elements of a sequence"""
265 264 if istype(obj, sequence_types):
266 265 t = type(obj)
267 266 return t([can(i) for i in obj])
268 267 else:
269 268 return obj
270 269
271 270 def uncan(obj, g=None):
272 271 """invert canning"""
273 272
274 273 import_needed = False
275 274 for cls,uncanner in uncan_map.iteritems():
276 275 if isinstance(cls, basestring):
277 276 import_needed = True
278 277 break
279 278 elif isinstance(obj, cls):
280 279 return uncanner(obj, g)
281 280
282 281 if import_needed:
283 282 # perform uncan_map imports, then try again
284 283 # this will usually only happen once
285 284 _import_mapping(uncan_map, _original_uncan_map)
286 285 return uncan(obj, g)
287 286
288 287 return obj
289 288
290 289 def uncan_dict(obj, g=None):
291 290 if istype(obj, dict):
292 291 newobj = {}
293 292 for k, v in obj.iteritems():
294 293 newobj[k] = uncan(v,g)
295 294 return newobj
296 295 else:
297 296 return obj
298 297
299 298 def uncan_sequence(obj, g=None):
300 299 if istype(obj, sequence_types):
301 300 t = type(obj)
302 301 return t([uncan(i,g) for i in obj])
303 302 else:
304 303 return obj
305 304
306 305
307 306 #-------------------------------------------------------------------------------
308 307 # API dictionaries
309 308 #-------------------------------------------------------------------------------
310 309
311 310 # These dicts can be extended for custom serialization of new objects
312 311
313 312 can_map = {
314 313 'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),
315 314 'numpy.ndarray' : CannedArray,
316 315 FunctionType : CannedFunction,
317 316 bytes : CannedBytes,
318 317 buffer : CannedBuffer,
319 318 class_type : can_class,
320 319 }
321 320
322 321 uncan_map = {
323 322 CannedObject : lambda obj, g: obj.get_object(g),
324 323 }
325 324
326 325 # for use in _import_mapping:
327 326 _original_can_map = can_map.copy()
328 327 _original_uncan_map = uncan_map.copy()
General Comments 0
You need to be logged in to leave comments. Login now