svn-gvsig-desktop / tags / v1_0_2_Build_907 / extensions / extScripting / scripts / jython / Lib / pickle.py @ 11015
History | View | Annotate | Download (25.9 KB)
1 | 5782 | jmvivo | """Create portable serialized representations of Python objects.
|
---|---|---|---|
2 |
|
||
3 | See module cPickle for a (much) faster implementation.
|
||
4 | See module copy_reg for a mechanism for registering custom picklers.
|
||
5 |
|
||
6 | Classes:
|
||
7 |
|
||
8 | Pickler
|
||
9 | Unpickler
|
||
10 |
|
||
11 | Functions:
|
||
12 |
|
||
13 | dump(object, file)
|
||
14 | dumps(object) -> string
|
||
15 | load(file) -> object
|
||
16 | loads(string) -> object
|
||
17 |
|
||
18 | Misc variables:
|
||
19 |
|
||
20 | __version__
|
||
21 | format_version
|
||
22 | compatible_formats
|
||
23 |
|
||
24 | """
|
||
25 | |||
26 | __version__ = "$Revision$" # Code version |
||
27 | |||
28 | from types import * |
||
29 | from copy_reg import dispatch_table, safe_constructors |
||
30 | import marshal |
||
31 | import sys |
||
32 | import struct |
||
33 | import re |
||
34 | |||
35 | __all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler", |
||
36 | "Unpickler", "dump", "dumps", "load", "loads"] |
||
37 | |||
38 | format_version = "1.3" # File format version we write |
||
39 | compatible_formats = ["1.0", "1.1", "1.2"] # Old format versions we can read |
||
40 | |||
41 | mdumps = marshal.dumps |
||
42 | mloads = marshal.loads |
||
43 | |||
44 | class PickleError(Exception): pass |
||
45 | class PicklingError(PickleError): pass |
||
46 | class UnpicklingError(PickleError): pass |
||
47 | |||
48 | class _Stop(Exception): |
||
49 | def __init__(self, value): |
||
50 | self.value = value
|
||
51 | |||
52 | try:
|
||
53 | from org.python.core import PyStringMap |
||
54 | except ImportError: |
||
55 | PyStringMap = None
|
||
56 | |||
57 | MARK = '('
|
||
58 | STOP = '.'
|
||
59 | POP = '0'
|
||
60 | POP_MARK = '1'
|
||
61 | DUP = '2'
|
||
62 | FLOAT = 'F'
|
||
63 | INT = 'I'
|
||
64 | BININT = 'J'
|
||
65 | BININT1 = 'K'
|
||
66 | LONG = 'L'
|
||
67 | BININT2 = 'M'
|
||
68 | NONE = 'N'
|
||
69 | PERSID = 'P'
|
||
70 | BINPERSID = 'Q'
|
||
71 | REDUCE = 'R'
|
||
72 | STRING = 'S'
|
||
73 | BINSTRING = 'T'
|
||
74 | SHORT_BINSTRING = 'U'
|
||
75 | UNICODE = 'V'
|
||
76 | BINUNICODE = 'X'
|
||
77 | APPEND = 'a'
|
||
78 | BUILD = 'b'
|
||
79 | GLOBAL = 'c'
|
||
80 | DICT = 'd'
|
||
81 | EMPTY_DICT = '}'
|
||
82 | APPENDS = 'e'
|
||
83 | GET = 'g'
|
||
84 | BINGET = 'h'
|
||
85 | INST = 'i'
|
||
86 | LONG_BINGET = 'j'
|
||
87 | LIST = 'l'
|
||
88 | EMPTY_LIST = ']'
|
||
89 | OBJ = 'o'
|
||
90 | PUT = 'p'
|
||
91 | BINPUT = 'q'
|
||
92 | LONG_BINPUT = 'r'
|
||
93 | SETITEM = 's'
|
||
94 | TUPLE = 't'
|
||
95 | EMPTY_TUPLE = ')'
|
||
96 | SETITEMS = 'u'
|
||
97 | BINFLOAT = 'G'
|
||
98 | |||
99 | __all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)]) |
||
100 | |||
101 | class Pickler: |
||
102 | |||
103 | def __init__(self, file, bin = 0): |
||
104 | self.write = file.write |
||
105 | self.memo = {}
|
||
106 | self.bin = bin |
||
107 | |||
108 | def dump(self, object): |
||
109 | self.save(object) |
||
110 | self.write(STOP)
|
||
111 | |||
112 | def put(self, i): |
||
113 | if self.bin: |
||
114 | s = mdumps(i)[1:]
|
||
115 | if i < 256: |
||
116 | return BINPUT + s[0] |
||
117 | |||
118 | return LONG_BINPUT + s
|
||
119 | |||
120 | return PUT + `i` + '\n' |
||
121 | |||
122 | def get(self, i): |
||
123 | if self.bin: |
||
124 | s = mdumps(i)[1:]
|
||
125 | |||
126 | if i < 256: |
||
127 | return BINGET + s[0] |
||
128 | |||
129 | return LONG_BINGET + s
|
||
130 | |||
131 | return GET + `i` + '\n' |
||
132 | |||
133 | def save(self, object, pers_save = 0): |
||
134 | memo = self.memo
|
||
135 | |||
136 | if not pers_save: |
||
137 | pid = self.persistent_id(object) |
||
138 | if pid is not None: |
||
139 | self.save_pers(pid)
|
||
140 | return
|
||
141 | |||
142 | d = id(object) |
||
143 | |||
144 | t = type(object) |
||
145 | |||
146 | if (t is TupleType) and (len(object) == 0): |
||
147 | if self.bin: |
||
148 | self.save_empty_tuple(object) |
||
149 | else:
|
||
150 | self.save_tuple(object) |
||
151 | return
|
||
152 | |||
153 | if memo.has_key(d):
|
||
154 | self.write(self.get(memo[d][0])) |
||
155 | return
|
||
156 | |||
157 | try:
|
||
158 | f = self.dispatch[t]
|
||
159 | except KeyError: |
||
160 | pid = self.inst_persistent_id(object) |
||
161 | if pid is not None: |
||
162 | self.save_pers(pid)
|
||
163 | return
|
||
164 | |||
165 | try:
|
||
166 | reduce = dispatch_table[t] |
||
167 | except KeyError: |
||
168 | try:
|
||
169 | reduce = object.__reduce__
|
||
170 | except AttributeError: |
||
171 | raise PicklingError, \
|
||
172 | "can't pickle %s object: %s" % (`t.__name__`,
|
||
173 | `object`)
|
||
174 | else:
|
||
175 | tup = reduce()
|
||
176 | else:
|
||
177 | tup = reduce(object) |
||
178 | |||
179 | if type(tup) is StringType: |
||
180 | self.save_global(object, tup) |
||
181 | return
|
||
182 | |||
183 | if type(tup) is not TupleType: |
||
184 | raise PicklingError, "Value returned by %s must be a " \ |
||
185 | "tuple" % reduce |
||
186 | |||
187 | l = len(tup)
|
||
188 | |||
189 | if (l != 2) and (l != 3): |
||
190 | raise PicklingError, "tuple returned by %s must contain " \ |
||
191 | "only two or three elements" % reduce |
||
192 | |||
193 | callable = tup[0]
|
||
194 | arg_tup = tup[1]
|
||
195 | |||
196 | if l > 2: |
||
197 | state = tup[2]
|
||
198 | else:
|
||
199 | state = None
|
||
200 | |||
201 | if type(arg_tup) is not TupleType and arg_tup is not None: |
||
202 | raise PicklingError, "Second element of tuple returned " \ |
||
203 | "by %s must be a tuple" % reduce |
||
204 | |||
205 | self.save_reduce(callable, arg_tup, state) |
||
206 | memo_len = len(memo)
|
||
207 | self.write(self.put(memo_len)) |
||
208 | memo[d] = (memo_len, object)
|
||
209 | return
|
||
210 | |||
211 | f(self, object) |
||
212 | |||
213 | def persistent_id(self, object): |
||
214 | return None |
||
215 | |||
216 | def inst_persistent_id(self, object): |
||
217 | return None |
||
218 | |||
219 | def save_pers(self, pid): |
||
220 | if not self.bin: |
||
221 | self.write(PERSID + str(pid) + '\n') |
||
222 | else:
|
||
223 | self.save(pid, 1) |
||
224 | self.write(BINPERSID)
|
||
225 | |||
226 | def save_reduce(self, callable, arg_tup, state = None): |
||
227 | write = self.write
|
||
228 | save = self.save
|
||
229 | |||
230 | save(callable)
|
||
231 | save(arg_tup) |
||
232 | write(REDUCE) |
||
233 | |||
234 | if state is not None: |
||
235 | save(state) |
||
236 | write(BUILD) |
||
237 | |||
238 | dispatch = {} |
||
239 | |||
240 | def save_none(self, object): |
||
241 | self.write(NONE)
|
||
242 | dispatch[NoneType] = save_none |
||
243 | |||
244 | def save_int(self, object): |
||
245 | if self.bin: |
||
246 | # If the int is small enough to fit in a signed 4-byte 2's-comp
|
||
247 | # format, we can store it more efficiently than the general
|
||
248 | # case.
|
||
249 | high_bits = object >> 31 # note that Python shift sign-extends |
||
250 | if high_bits == 0 or high_bits == -1: |
||
251 | # All high bits are copies of bit 2**31, so the value
|
||
252 | # fits in a 4-byte signed int.
|
||
253 | i = mdumps(object)[1:] |
||
254 | assert len(i) == 4 |
||
255 | if i[-2:] == '\000\000': # fits in 2-byte unsigned int |
||
256 | if i[-3] == '\000': # fits in 1-byte unsigned int |
||
257 | self.write(BININT1 + i[0]) |
||
258 | else:
|
||
259 | self.write(BININT2 + i[:2]) |
||
260 | else:
|
||
261 | self.write(BININT + i)
|
||
262 | return
|
||
263 | # Text pickle, or int too big to fit in signed 4-byte format.
|
||
264 | self.write(INT + `object` + '\n') |
||
265 | dispatch[IntType] = save_int |
||
266 | |||
267 | def save_long(self, object): |
||
268 | self.write(LONG + `object` + '\n') |
||
269 | dispatch[LongType] = save_long |
||
270 | |||
271 | def save_float(self, object, pack=struct.pack): |
||
272 | if self.bin: |
||
273 | self.write(BINFLOAT + pack('>d', object)) |
||
274 | else:
|
||
275 | self.write(FLOAT + `object` + '\n') |
||
276 | dispatch[FloatType] = save_float |
||
277 | |||
278 | def save_string(self, object): |
||
279 | d = id(object) |
||
280 | memo = self.memo
|
||
281 | |||
282 | if self.bin: |
||
283 | l = len(object) |
||
284 | s = mdumps(l)[1:]
|
||
285 | if l < 256: |
||
286 | self.write(SHORT_BINSTRING + s[0] + object) |
||
287 | else:
|
||
288 | self.write(BINSTRING + s + object) |
||
289 | else:
|
||
290 | self.write(STRING + `object` + '\n') |
||
291 | |||
292 | memo_len = len(memo)
|
||
293 | self.write(self.put(memo_len)) |
||
294 | memo[d] = (memo_len, object)
|
||
295 | dispatch[StringType] = save_string |
||
296 | |||
297 | def save_unicode(self, object): |
||
298 | d = id(object) |
||
299 | memo = self.memo
|
||
300 | |||
301 | if self.bin: |
||
302 | encoding = object.encode('utf-8') |
||
303 | l = len(encoding)
|
||
304 | s = mdumps(l)[1:]
|
||
305 | self.write(BINUNICODE + s + encoding)
|
||
306 | else:
|
||
307 | object = object.replace(u"\\", u"\\u005c") |
||
308 | object = object.replace(u"\n", u"\\u000a") |
||
309 | self.write(UNICODE + object.encode('raw-unicode-escape') + '\n') |
||
310 | |||
311 | memo_len = len(memo)
|
||
312 | self.write(self.put(memo_len)) |
||
313 | memo[d] = (memo_len, object)
|
||
314 | dispatch[UnicodeType] = save_unicode |
||
315 | |||
316 | if StringType == UnicodeType:
|
||
317 | # This is true for Jython
|
||
318 | def save_string(self, object): |
||
319 | d = id(object) |
||
320 | memo = self.memo
|
||
321 | unicode = object.isunicode()
|
||
322 | |||
323 | if self.bin: |
||
324 | if unicode: |
||
325 | object = object.encode("utf-8") |
||
326 | l = len(object) |
||
327 | s = mdumps(l)[1:]
|
||
328 | if l < 256 and not unicode: |
||
329 | self.write(SHORT_BINSTRING + s[0] + object) |
||
330 | else:
|
||
331 | if unicode: |
||
332 | self.write(BINUNICODE + s + object) |
||
333 | else:
|
||
334 | self.write(BINSTRING + s + object) |
||
335 | else:
|
||
336 | if unicode: |
||
337 | object = object.replace(u"\\", u"\\u005c") |
||
338 | object = object.replace(u"\n", u"\\u000a") |
||
339 | object = object.encode('raw-unicode-escape') |
||
340 | self.write(UNICODE + object + '\n') |
||
341 | else:
|
||
342 | self.write(STRING + `object` + '\n') |
||
343 | |||
344 | memo_len = len(memo)
|
||
345 | self.write(self.put(memo_len)) |
||
346 | memo[d] = (memo_len, object)
|
||
347 | dispatch[StringType] = save_string |
||
348 | |||
349 | def save_tuple(self, object): |
||
350 | |||
351 | write = self.write
|
||
352 | save = self.save
|
||
353 | memo = self.memo
|
||
354 | |||
355 | d = id(object) |
||
356 | |||
357 | write(MARK) |
||
358 | |||
359 | for element in object: |
||
360 | save(element) |
||
361 | |||
362 | if len(object) and memo.has_key(d): |
||
363 | if self.bin: |
||
364 | write(POP_MARK + self.get(memo[d][0])) |
||
365 | return
|
||
366 | |||
367 | write(POP * (len(object) + 1) + self.get(memo[d][0])) |
||
368 | return
|
||
369 | |||
370 | memo_len = len(memo)
|
||
371 | self.write(TUPLE + self.put(memo_len)) |
||
372 | memo[d] = (memo_len, object)
|
||
373 | dispatch[TupleType] = save_tuple |
||
374 | |||
375 | def save_empty_tuple(self, object): |
||
376 | self.write(EMPTY_TUPLE)
|
||
377 | |||
378 | def save_list(self, object): |
||
379 | d = id(object) |
||
380 | |||
381 | write = self.write
|
||
382 | save = self.save
|
||
383 | memo = self.memo
|
||
384 | |||
385 | if self.bin: |
||
386 | write(EMPTY_LIST) |
||
387 | else:
|
||
388 | write(MARK + LIST) |
||
389 | |||
390 | memo_len = len(memo)
|
||
391 | write(self.put(memo_len))
|
||
392 | memo[d] = (memo_len, object)
|
||
393 | |||
394 | using_appends = (self.bin and (len(object) > 1)) |
||
395 | |||
396 | if using_appends:
|
||
397 | write(MARK) |
||
398 | |||
399 | for element in object: |
||
400 | save(element) |
||
401 | |||
402 | if not using_appends: |
||
403 | write(APPEND) |
||
404 | |||
405 | if using_appends:
|
||
406 | write(APPENDS) |
||
407 | dispatch[ListType] = save_list |
||
408 | |||
409 | def save_dict(self, object): |
||
410 | d = id(object) |
||
411 | |||
412 | write = self.write
|
||
413 | save = self.save
|
||
414 | memo = self.memo
|
||
415 | |||
416 | if self.bin: |
||
417 | write(EMPTY_DICT) |
||
418 | else:
|
||
419 | write(MARK + DICT) |
||
420 | |||
421 | memo_len = len(memo)
|
||
422 | self.write(self.put(memo_len)) |
||
423 | memo[d] = (memo_len, object)
|
||
424 | |||
425 | using_setitems = (self.bin and (len(object) > 1)) |
||
426 | |||
427 | if using_setitems:
|
||
428 | write(MARK) |
||
429 | |||
430 | items = object.items()
|
||
431 | for key, value in items: |
||
432 | save(key) |
||
433 | save(value) |
||
434 | |||
435 | if not using_setitems: |
||
436 | write(SETITEM) |
||
437 | |||
438 | if using_setitems:
|
||
439 | write(SETITEMS) |
||
440 | |||
441 | dispatch[DictionaryType] = save_dict |
||
442 | if not PyStringMap is None: |
||
443 | dispatch[PyStringMap] = save_dict |
||
444 | |||
445 | def save_inst(self, object): |
||
446 | d = id(object) |
||
447 | cls = object.__class__
|
||
448 | |||
449 | memo = self.memo
|
||
450 | write = self.write
|
||
451 | save = self.save
|
||
452 | |||
453 | if hasattr(object, '__getinitargs__'): |
||
454 | args = object.__getinitargs__()
|
||
455 | len(args) # XXX Assert it's a sequence |
||
456 | _keep_alive(args, memo) |
||
457 | else:
|
||
458 | args = () |
||
459 | |||
460 | write(MARK) |
||
461 | |||
462 | if self.bin: |
||
463 | save(cls) |
||
464 | |||
465 | for arg in args: |
||
466 | save(arg) |
||
467 | |||
468 | memo_len = len(memo)
|
||
469 | if self.bin: |
||
470 | write(OBJ + self.put(memo_len))
|
||
471 | else:
|
||
472 | write(INST + cls.__module__ + '\n' + cls.__name__ + '\n' + |
||
473 | self.put(memo_len))
|
||
474 | |||
475 | memo[d] = (memo_len, object)
|
||
476 | |||
477 | try:
|
||
478 | getstate = object.__getstate__
|
||
479 | except AttributeError: |
||
480 | stuff = object.__dict__
|
||
481 | else:
|
||
482 | stuff = getstate() |
||
483 | _keep_alive(stuff, memo) |
||
484 | save(stuff) |
||
485 | write(BUILD) |
||
486 | dispatch[InstanceType] = save_inst |
||
487 | |||
488 | def save_global(self, object, name = None): |
||
489 | write = self.write
|
||
490 | memo = self.memo
|
||
491 | |||
492 | if name is None: |
||
493 | name = object.__name__
|
||
494 | |||
495 | try:
|
||
496 | module = object.__module__
|
||
497 | except AttributeError: |
||
498 | module = whichmodule(object, name)
|
||
499 | |||
500 | memo_len = len(memo)
|
||
501 | write(GLOBAL + module + '\n' + name + '\n' + |
||
502 | self.put(memo_len))
|
||
503 | memo[id(object)] = (memo_len, object) |
||
504 | dispatch[ClassType] = save_global |
||
505 | dispatch[FunctionType] = save_global |
||
506 | dispatch[BuiltinFunctionType] = save_global |
||
507 | |||
508 | |||
509 | def _keep_alive(x, memo): |
||
510 | """Keeps a reference to the object x in the memo.
|
||
511 |
|
||
512 | Because we remember objects by their id, we have
|
||
513 | to assure that possibly temporary objects are kept
|
||
514 | alive by referencing them.
|
||
515 | We store a reference at the id of the memo, which should
|
||
516 | normally not be used unless someone tries to deepcopy
|
||
517 | the memo itself...
|
||
518 | """
|
||
519 | try:
|
||
520 | memo[id(memo)].append(x)
|
||
521 | except KeyError: |
||
522 | # aha, this is the first one :-)
|
||
523 | memo[id(memo)]=[x]
|
||
524 | |||
525 | |||
526 | classmap = {} |
||
527 | |||
528 | # This is no longer used to find classes, but still for functions
|
||
529 | def whichmodule(cls, clsname): |
||
530 | """Figure out the module in which a class occurs.
|
||
531 |
|
||
532 | Search sys.modules for the module.
|
||
533 | Cache in classmap.
|
||
534 | Return a module name.
|
||
535 | If the class cannot be found, return __main__.
|
||
536 | """
|
||
537 | if classmap.has_key(cls):
|
||
538 | return classmap[cls]
|
||
539 | |||
540 | for name, module in sys.modules.items(): |
||
541 | if name != '__main__' and \ |
||
542 | hasattr(module, clsname) and \ |
||
543 | getattr(module, clsname) is cls: |
||
544 | break
|
||
545 | else:
|
||
546 | name = '__main__'
|
||
547 | classmap[cls] = name |
||
548 | return name
|
||
549 | |||
550 | |||
551 | class Unpickler: |
||
552 | |||
553 | def __init__(self, file): |
||
554 | self.readline = file.readline |
||
555 | self.read = file.read |
||
556 | self.memo = {}
|
||
557 | |||
558 | def load(self): |
||
559 | self.mark = ['spam'] # Any new unique object |
||
560 | self.stack = []
|
||
561 | self.append = self.stack.append |
||
562 | read = self.read
|
||
563 | dispatch = self.dispatch
|
||
564 | try:
|
||
565 | while 1: |
||
566 | key = read(1)
|
||
567 | dispatch[key](self)
|
||
568 | except _Stop, stopinst:
|
||
569 | return stopinst.value
|
||
570 | |||
571 | def marker(self): |
||
572 | stack = self.stack
|
||
573 | mark = self.mark
|
||
574 | k = len(stack)-1 |
||
575 | while stack[k] is not mark: k = k-1 |
||
576 | return k
|
||
577 | |||
578 | dispatch = {} |
||
579 | |||
580 | def load_eof(self): |
||
581 | raise EOFError |
||
582 | dispatch[''] = load_eof
|
||
583 | |||
584 | def load_persid(self): |
||
585 | pid = self.readline()[:-1] |
||
586 | self.append(self.persistent_load(pid)) |
||
587 | dispatch[PERSID] = load_persid |
||
588 | |||
589 | def load_binpersid(self): |
||
590 | stack = self.stack
|
||
591 | |||
592 | pid = stack[-1]
|
||
593 | del stack[-1] |
||
594 | |||
595 | self.append(self.persistent_load(pid)) |
||
596 | dispatch[BINPERSID] = load_binpersid |
||
597 | |||
598 | def load_none(self): |
||
599 | self.append(None) |
||
600 | dispatch[NONE] = load_none |
||
601 | |||
602 | def load_int(self): |
||
603 | self.append(int(self.readline()[:-1])) |
||
604 | dispatch[INT] = load_int |
||
605 | |||
606 | def load_binint(self): |
||
607 | self.append(mloads('i' + self.read(4))) |
||
608 | dispatch[BININT] = load_binint |
||
609 | |||
610 | def load_binint1(self): |
||
611 | self.append(mloads('i' + self.read(1) + '\000\000\000')) |
||
612 | dispatch[BININT1] = load_binint1 |
||
613 | |||
614 | def load_binint2(self): |
||
615 | self.append(mloads('i' + self.read(2) + '\000\000')) |
||
616 | dispatch[BININT2] = load_binint2 |
||
617 | |||
618 | def load_long(self): |
||
619 | self.append(long(self.readline()[:-1], 0)) |
||
620 | dispatch[LONG] = load_long |
||
621 | |||
622 | def load_float(self): |
||
623 | self.append(float(self.readline()[:-1])) |
||
624 | dispatch[FLOAT] = load_float |
||
625 | |||
626 | def load_binfloat(self, unpack=struct.unpack): |
||
627 | self.append(unpack('>d', self.read(8))[0]) |
||
628 | dispatch[BINFLOAT] = load_binfloat |
||
629 | |||
630 | def load_string(self): |
||
631 | rep = self.readline()[:-1] |
||
632 | if not self._is_string_secure(rep): |
||
633 | raise ValueError, "insecure string pickle" |
||
634 | self.append(eval(rep, |
||
635 | {'__builtins__': {}})) # Let's be careful |
||
636 | dispatch[STRING] = load_string |
||
637 | |||
638 | def _is_string_secure(self, s): |
||
639 | """Return true if s contains a string that is safe to eval
|
||
640 |
|
||
641 | The definition of secure string is based on the implementation
|
||
642 | in cPickle. s is secure as long as it only contains a quoted
|
||
643 | string and optional trailing whitespace.
|
||
644 | """
|
||
645 | q = s[0]
|
||
646 | if q not in ("'", '"'): |
||
647 | return 0 |
||
648 | # find the closing quote
|
||
649 | offset = 1
|
||
650 | i = None
|
||
651 | while 1: |
||
652 | try:
|
||
653 | i = s.index(q, offset) |
||
654 | except ValueError: |
||
655 | # if there is an error the first time, there is no
|
||
656 | # close quote
|
||
657 | if offset == 1: |
||
658 | return 0 |
||
659 | if s[i-1] != '\\': |
||
660 | break
|
||
661 | # check to see if this one is escaped
|
||
662 | nslash = 0
|
||
663 | j = i - 1
|
||
664 | while j >= offset and s[j] == '\\': |
||
665 | j = j - 1
|
||
666 | nslash = nslash + 1
|
||
667 | if nslash % 2 == 0: |
||
668 | break
|
||
669 | offset = i + 1
|
||
670 | for c in s[i+1:]: |
||
671 | if ord(c) > 32: |
||
672 | return 0 |
||
673 | return 1 |
||
674 | |||
675 | def load_binstring(self): |
||
676 | len = mloads('i' + self.read(4)) |
||
677 | self.append(self.read(len)) |
||
678 | dispatch[BINSTRING] = load_binstring |
||
679 | |||
680 | def load_unicode(self): |
||
681 | self.append(unicode(self.readline()[:-1],'raw-unicode-escape')) |
||
682 | dispatch[UNICODE] = load_unicode |
||
683 | |||
684 | def load_binunicode(self): |
||
685 | len = mloads('i' + self.read(4)) |
||
686 | self.append(unicode(self.read(len),'utf-8')) |
||
687 | dispatch[BINUNICODE] = load_binunicode |
||
688 | |||
689 | def load_short_binstring(self): |
||
690 | len = mloads('i' + self.read(1) + '\000\000\000') |
||
691 | self.append(self.read(len)) |
||
692 | dispatch[SHORT_BINSTRING] = load_short_binstring |
||
693 | |||
694 | def load_tuple(self): |
||
695 | k = self.marker()
|
||
696 | self.stack[k:] = [tuple(self.stack[k+1:])] |
||
697 | dispatch[TUPLE] = load_tuple |
||
698 | |||
699 | def load_empty_tuple(self): |
||
700 | self.stack.append(())
|
||
701 | dispatch[EMPTY_TUPLE] = load_empty_tuple |
||
702 | |||
703 | def load_empty_list(self): |
||
704 | self.stack.append([])
|
||
705 | dispatch[EMPTY_LIST] = load_empty_list |
||
706 | |||
707 | def load_empty_dictionary(self): |
||
708 | self.stack.append({})
|
||
709 | dispatch[EMPTY_DICT] = load_empty_dictionary |
||
710 | |||
711 | def load_list(self): |
||
712 | k = self.marker()
|
||
713 | self.stack[k:] = [self.stack[k+1:]] |
||
714 | dispatch[LIST] = load_list |
||
715 | |||
716 | def load_dict(self): |
||
717 | k = self.marker()
|
||
718 | d = {} |
||
719 | items = self.stack[k+1:] |
||
720 | for i in range(0, len(items), 2): |
||
721 | key = items[i] |
||
722 | value = items[i+1]
|
||
723 | d[key] = value |
||
724 | self.stack[k:] = [d]
|
||
725 | dispatch[DICT] = load_dict |
||
726 | |||
727 | def load_inst(self): |
||
728 | k = self.marker()
|
||
729 | args = tuple(self.stack[k+1:]) |
||
730 | del self.stack[k:] |
||
731 | module = self.readline()[:-1] |
||
732 | name = self.readline()[:-1] |
||
733 | klass = self.find_class(module, name)
|
||
734 | instantiated = 0
|
||
735 | if (not args and type(klass) is ClassType and |
||
736 | not hasattr(klass, "__getinitargs__")): |
||
737 | try:
|
||
738 | value = _EmptyClass() |
||
739 | value.__class__ = klass |
||
740 | instantiated = 1
|
||
741 | except RuntimeError: |
||
742 | # In restricted execution, assignment to inst.__class__ is
|
||
743 | # prohibited
|
||
744 | pass
|
||
745 | if not instantiated: |
||
746 | try:
|
||
747 | value = apply(klass, args)
|
||
748 | except TypeError, err: |
||
749 | raise TypeError, "in constructor for %s: %s" % ( |
||
750 | klass.__name__, str(err)), sys.exc_info()[2] |
||
751 | self.append(value)
|
||
752 | dispatch[INST] = load_inst |
||
753 | |||
754 | def load_obj(self): |
||
755 | stack = self.stack
|
||
756 | k = self.marker()
|
||
757 | klass = stack[k + 1]
|
||
758 | del stack[k + 1] |
||
759 | args = tuple(stack[k + 1:]) |
||
760 | del stack[k:]
|
||
761 | instantiated = 0
|
||
762 | if (not args and type(klass) is ClassType and |
||
763 | not hasattr(klass, "__getinitargs__")): |
||
764 | try:
|
||
765 | value = _EmptyClass() |
||
766 | value.__class__ = klass |
||
767 | instantiated = 1
|
||
768 | except RuntimeError: |
||
769 | # In restricted execution, assignment to inst.__class__ is
|
||
770 | # prohibited
|
||
771 | pass
|
||
772 | if not instantiated: |
||
773 | value = apply(klass, args)
|
||
774 | self.append(value)
|
||
775 | dispatch[OBJ] = load_obj |
||
776 | |||
777 | def load_global(self): |
||
778 | module = self.readline()[:-1] |
||
779 | name = self.readline()[:-1] |
||
780 | klass = self.find_class(module, name)
|
||
781 | self.append(klass)
|
||
782 | dispatch[GLOBAL] = load_global |
||
783 | |||
784 | def find_class(self, module, name): |
||
785 | try:
|
||
786 | __import__(module)
|
||
787 | mod = sys.modules[module] |
||
788 | klass = getattr(mod, name)
|
||
789 | except (ImportError, KeyError, AttributeError): |
||
790 | raise SystemError, \ |
||
791 | "Failed to import class %s from module %s" % \
|
||
792 | (name, module) |
||
793 | return klass
|
||
794 | |||
795 | def load_reduce(self): |
||
796 | stack = self.stack
|
||
797 | |||
798 | callable = stack[-2]
|
||
799 | arg_tup = stack[-1]
|
||
800 | del stack[-2:] |
||
801 | |||
802 | if type(callable) is not ClassType: |
||
803 | if not safe_constructors.has_key(callable): |
||
804 | try:
|
||
805 | safe = callable.__safe_for_unpickling__
|
||
806 | except AttributeError: |
||
807 | safe = None
|
||
808 | |||
809 | if not safe: |
||
810 | raise UnpicklingError, "%s is not safe for " \ |
||
811 | "unpickling" % callable |
||
812 | |||
813 | if arg_tup is None: |
||
814 | value = callable.__basicnew__()
|
||
815 | else:
|
||
816 | value = apply(callable, arg_tup) |
||
817 | self.append(value)
|
||
818 | dispatch[REDUCE] = load_reduce |
||
819 | |||
820 | def load_pop(self): |
||
821 | del self.stack[-1] |
||
822 | dispatch[POP] = load_pop |
||
823 | |||
824 | def load_pop_mark(self): |
||
825 | k = self.marker()
|
||
826 | del self.stack[k:] |
||
827 | dispatch[POP_MARK] = load_pop_mark |
||
828 | |||
829 | def load_dup(self): |
||
830 | self.append(self.stack[-1]) |
||
831 | dispatch[DUP] = load_dup |
||
832 | |||
833 | def load_get(self): |
||
834 | self.append(self.memo[self.readline()[:-1]]) |
||
835 | dispatch[GET] = load_get |
||
836 | |||
837 | def load_binget(self): |
||
838 | i = mloads('i' + self.read(1) + '\000\000\000') |
||
839 | self.append(self.memo[`i`]) |
||
840 | dispatch[BINGET] = load_binget |
||
841 | |||
842 | def load_long_binget(self): |
||
843 | i = mloads('i' + self.read(4)) |
||
844 | self.append(self.memo[`i`]) |
||
845 | dispatch[LONG_BINGET] = load_long_binget |
||
846 | |||
847 | def load_put(self): |
||
848 | self.memo[self.readline()[:-1]] = self.stack[-1] |
||
849 | dispatch[PUT] = load_put |
||
850 | |||
851 | def load_binput(self): |
||
852 | i = mloads('i' + self.read(1) + '\000\000\000') |
||
853 | self.memo[`i`] = self.stack[-1] |
||
854 | dispatch[BINPUT] = load_binput |
||
855 | |||
856 | def load_long_binput(self): |
||
857 | i = mloads('i' + self.read(4)) |
||
858 | self.memo[`i`] = self.stack[-1] |
||
859 | dispatch[LONG_BINPUT] = load_long_binput |
||
860 | |||
861 | def load_append(self): |
||
862 | stack = self.stack
|
||
863 | value = stack[-1]
|
||
864 | del stack[-1] |
||
865 | list = stack[-1]
|
||
866 | list.append(value)
|
||
867 | dispatch[APPEND] = load_append |
||
868 | |||
869 | def load_appends(self): |
||
870 | stack = self.stack
|
||
871 | mark = self.marker()
|
||
872 | list = stack[mark - 1]
|
||
873 | for i in range(mark + 1, len(stack)): |
||
874 | list.append(stack[i])
|
||
875 | |||
876 | del stack[mark:]
|
||
877 | dispatch[APPENDS] = load_appends |
||
878 | |||
879 | def load_setitem(self): |
||
880 | stack = self.stack
|
||
881 | value = stack[-1]
|
||
882 | key = stack[-2]
|
||
883 | del stack[-2:] |
||
884 | dict = stack[-1]
|
||
885 | dict[key] = value
|
||
886 | dispatch[SETITEM] = load_setitem |
||
887 | |||
888 | def load_setitems(self): |
||
889 | stack = self.stack
|
||
890 | mark = self.marker()
|
||
891 | dict = stack[mark - 1]
|
||
892 | for i in range(mark + 1, len(stack), 2): |
||
893 | dict[stack[i]] = stack[i + 1] |
||
894 | |||
895 | del stack[mark:]
|
||
896 | dispatch[SETITEMS] = load_setitems |
||
897 | |||
898 | def load_build(self): |
||
899 | stack = self.stack
|
||
900 | value = stack[-1]
|
||
901 | del stack[-1] |
||
902 | inst = stack[-1]
|
||
903 | try:
|
||
904 | setstate = inst.__setstate__ |
||
905 | except AttributeError: |
||
906 | try:
|
||
907 | inst.__dict__.update(value) |
||
908 | except RuntimeError: |
||
909 | # XXX In restricted execution, the instance's __dict__ is not
|
||
910 | # accessible. Use the old way of unpickling the instance
|
||
911 | # variables. This is a semantic different when unpickling in
|
||
912 | # restricted vs. unrestricted modes.
|
||
913 | for k, v in value.items(): |
||
914 | setattr(inst, k, v)
|
||
915 | else:
|
||
916 | setstate(value) |
||
917 | dispatch[BUILD] = load_build |
||
918 | |||
919 | def load_mark(self): |
||
920 | self.append(self.mark) |
||
921 | dispatch[MARK] = load_mark |
||
922 | |||
923 | def load_stop(self): |
||
924 | value = self.stack[-1] |
||
925 | del self.stack[-1] |
||
926 | raise _Stop(value)
|
||
927 | dispatch[STOP] = load_stop |
||
928 | |||
929 | # Helper class for load_inst/load_obj
|
||
930 | |||
931 | class _EmptyClass: |
||
932 | pass
|
||
933 | |||
934 | # Shorthands
|
||
935 | |||
936 | from StringIO import StringIO |
||
937 | |||
938 | def dump(object, file, bin = 0): |
||
939 | Pickler(file, bin).dump(object) |
||
940 | |||
941 | def dumps(object, bin = 0): |
||
942 | file = StringIO() |
||
943 | Pickler(file, bin).dump(object) |
||
944 | return file.getvalue() |
||
945 | |||
946 | def load(file): |
||
947 | return Unpickler(file).load() |
||
948 | |||
949 | def loads(str): |
||
950 | file = StringIO(str)
|
||
951 | return Unpickler(file).load() |
||
952 | |||
953 | |||
954 | # The rest is used for testing only
|
||
955 | |||
956 | class C: |
||
957 | def __cmp__(self, other): |
||
958 | return cmp(self.__dict__, other.__dict__) |
||
959 | |||
960 | def test(): |
||
961 | fn = 'out'
|
||
962 | c = C() |
||
963 | c.foo = 1
|
||
964 | c.bar = 2
|
||
965 | x = [0, 1, 2, 3] |
||
966 | y = ('abc', 'abc', c, c) |
||
967 | x.append(y) |
||
968 | x.append(y) |
||
969 | x.append(5)
|
||
970 | f = open(fn, 'w') |
||
971 | F = Pickler(f) |
||
972 | F.dump(x) |
||
973 | f.close() |
||
974 | f = open(fn, 'r') |
||
975 | U = Unpickler(f) |
||
976 | x2 = U.load() |
||
977 | print x
|
||
978 | print x2
|
||
979 | print x == x2
|
||
980 | print map(id, x) |
||
981 | print map(id, x2) |
||
982 | print F.memo
|
||
983 | print U.memo
|
||
984 | |||
985 | if __name__ == '__main__': |
||
986 | test() |