Statistics
| Revision:

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()