• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zodbpickle / 3792090977

pending completion
3792090977

push

github

GitHub
Drop support for Python 2.7, 3.5, 3.6. (#74)

543 of 706 branches covered (76.91%)

Branch coverage included in aggregate %.

26 of 42 new or added lines in 8 files covered. (61.9%)

2 existing lines in 2 files now uncovered.

2443 of 2744 relevant lines covered (89.03%)

5.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.24
/src/zodbpickle/tests/pickletester_3.py
1
import io
6✔
2
import os
6✔
3
import unittest
6✔
4
import sys
6✔
5
import copyreg
6✔
6
import weakref
6✔
7
import tempfile
6✔
8
from http.cookies import SimpleCookie
6✔
9
from zodbpickle import pickle_3 as pickle
6✔
10
from zodbpickle import pickletools_3 as pickletools
6✔
11

12
from test.support import (
6✔
13
    TestFailed, run_with_locale,
14
    _2G, _4G, bigmemtest,
15
    )
16

17
try:
6✔
18
    from test.support import no_tracing
6✔
19
except ImportError:
20
    from functools import wraps
21
    def no_tracing(func):
22
        if not hasattr(sys, 'gettrace'):
23
            return func
24
        @wraps(func)
25
        def wrapper(*args, **kwargs):
26
            original_trace = sys.gettrace()
27
            try:
28
                sys.settrace(None)
29
                return func(*args, **kwargs)
30
            finally:
31
                sys.settrace(original_trace)
32
        return wrapper
33

34
_PY311b1 = sys.hexversion >= 0x30b00b1  # 3.11.0b1
6✔
35

36
from zodbpickle.pickle_3 import bytes_types
6✔
37
from . import _is_pypy
6✔
38

39
# Tests that try a number of pickle protocols should have a
40
#     for proto in protocols:
41
# kind of outer loop.
42
protocols = range(pickle.HIGHEST_PROTOCOL + 1)
6✔
43

44
ascii_char_size = 1
6✔
45

46
fd, TESTFN = tempfile.mkstemp('.pickletester_3')
6✔
47
os.close(fd)
6✔
48

49
# Return True if opcode code appears in the pickle, else False.
50
def opcode_in_pickle(code, pickle):
6✔
51
    for op, dummy, dummy in pickletools.genops(pickle):
6✔
52
        if op.code == code.decode("latin-1"):
6✔
53
            return True
6✔
54
    return False
6✔
55

56
# Return the number of times opcode code appears in pickle.
57
def count_opcode(code, pickle):
6✔
58
    n = 0
6✔
59
    for op, dummy, dummy in pickletools.genops(pickle):
6✔
60
        if op.code == code.decode("latin-1"):
6✔
61
            n += 1
6✔
62
    return n
6✔
63

64

65
class UnseekableIO(io.BytesIO):
6✔
66
    def peek(self, *args):
6✔
67
        raise NotImplementedError
68

69
    def seekable(self):
6✔
70
        return False
5✔
71

72
    def seek(self, *args):
6✔
73
        raise io.UnsupportedOperation
×
74

75
    def tell(self):
6✔
76
        raise io.UnsupportedOperation
×
77

78

79
# We can't very well test the extension registry without putting known stuff
80
# in it, but we have to be careful to restore its original state.  Code
81
# should do this:
82
#
83
#     e = ExtensionSaver(extension_code)
84
#     try:
85
#         fiddle w/ the extension registry's stuff for extension_code
86
#     finally:
87
#         e.restore()
88

89
class ExtensionSaver:
6✔
90
    # Remember current registration for code (if any), and remove it (if
91
    # there is one).
92
    def __init__(self, code):
6✔
93
        self.code = code
6✔
94
        if code in copyreg._inverted_registry:
6!
95
            self.pair = copyreg._inverted_registry[code]
×
96
            copyreg.remove_extension(self.pair[0], self.pair[1], code)
×
97
        else:
98
            self.pair = None
6✔
99

100
    # Restore previous registration for code.
101
    def restore(self):
6✔
102
        code = self.code
6✔
103
        curpair = copyreg._inverted_registry.get(code)
6✔
104
        if curpair is not None:
6!
105
            copyreg.remove_extension(curpair[0], curpair[1], code)
6✔
106
        pair = self.pair
6✔
107
        if pair is not None:
6!
108
            copyreg.add_extension(pair[0], pair[1], code)
×
109

110
class C:
6✔
111
    def __eq__(self, other):
6✔
112
        return self.__dict__ == other.__dict__
6✔
113

114
class D(C):
6✔
115
    def __init__(self, arg):
6✔
116
        pass
6✔
117

118
class E(C):
6✔
119
    def __getinitargs__(self):
6✔
120
        return ()
×
121

122
import __main__
6✔
123
__main__.C = C
6✔
124
C.__module__ = "__main__"
6✔
125
__main__.D = D
6✔
126
D.__module__ = "__main__"
6✔
127
__main__.E = E
6✔
128
E.__module__ = "__main__"
6✔
129

130
class myint(int):
6✔
131
    def __init__(self, x):
6✔
132
        self.str = str(x)
6✔
133

134
class initarg(C):
6✔
135

136
    def __init__(self, a, b):
6✔
137
        self.a = a
6✔
138
        self.b = b
6✔
139

140
    def __getinitargs__(self):
6✔
141
        return self.a, self.b
×
142

143
class metaclass(type):
6✔
144
    pass
6✔
145

146
class use_metaclass(metaclass=metaclass):
6✔
147
    pass
6✔
148

149
class pickling_metaclass(type):
6✔
150
    def __eq__(self, other):
6✔
151
        return (type(self) == type(other) and
6✔
152
                self.reduce_args == other.reduce_args)
153

154
    def __reduce__(self):
6✔
155
        return (create_dynamic_class, self.reduce_args)
6✔
156

157
def create_dynamic_class(name, bases):
6✔
158
    result = pickling_metaclass(name, bases, dict())
6✔
159
    result.reduce_args = (name, bases)
6✔
160
    return result
6✔
161

162
# DATA0 .. DATA2 are the pickles we expect under the various protocols, for
163
# the object returned by create_data().
164

165
DATA0 = (
6✔
166
    b'(lp0\nL0L\naL1L\naF2.0\nac'
167
    b'builtins\ncomplex\n'
168
    b'p1\n(F3.0\nF0.0\ntp2\nRp'
169
    b'3\naL1L\naL-1L\naL255L\naL-'
170
    b'255L\naL-256L\naL65535L\na'
171
    b'L-65535L\naL-65536L\naL2'
172
    b'147483647L\naL-2147483'
173
    b'647L\naL-2147483648L\na('
174
    b'Vabc\np4\ng4\nccopyreg'
175
    b'\n_reconstructor\np5\n('
176
    b'c__main__\nC\np6\ncbu'
177
    b'iltins\nobject\np7\nNt'
178
    b'p8\nRp9\n(dp10\nVfoo\np1'
179
    b'1\nL1L\nsVbar\np12\nL2L\nsb'
180
    b'g9\ntp13\nag13\naL5L\na.'
181
)
182

183
# Disassembly of DATA0
184
DATA0_DIS = """\
6✔
185
    0: (    MARK
186
    1: l        LIST       (MARK at 0)
187
    2: p    PUT        0
188
    5: L    LONG       0
189
    9: a    APPEND
190
   10: L    LONG       1
191
   14: a    APPEND
192
   15: F    FLOAT      2.0
193
   20: a    APPEND
194
   21: c    GLOBAL     'builtins complex'
195
   39: p    PUT        1
196
   42: (    MARK
197
   43: F        FLOAT      3.0
198
   48: F        FLOAT      0.0
199
   53: t        TUPLE      (MARK at 42)
200
   54: p    PUT        2
201
   57: R    REDUCE
202
   58: p    PUT        3
203
   61: a    APPEND
204
   62: L    LONG       1
205
   66: a    APPEND
206
   67: L    LONG       -1
207
   72: a    APPEND
208
   73: L    LONG       255
209
   79: a    APPEND
210
   80: L    LONG       -255
211
   87: a    APPEND
212
   88: L    LONG       -256
213
   95: a    APPEND
214
   96: L    LONG       65535
215
  104: a    APPEND
216
  105: L    LONG       -65535
217
  114: a    APPEND
218
  115: L    LONG       -65536
219
  124: a    APPEND
220
  125: L    LONG       2147483647
221
  138: a    APPEND
222
  139: L    LONG       -2147483647
223
  153: a    APPEND
224
  154: L    LONG       -2147483648
225
  168: a    APPEND
226
  169: (    MARK
227
  170: V        UNICODE    'abc'
228
  175: p        PUT        4
229
  178: g        GET        4
230
  181: c        GLOBAL     'copyreg _reconstructor'
231
  205: p        PUT        5
232
  208: (        MARK
233
  209: c            GLOBAL     '__main__ C'
234
  221: p            PUT        6
235
  224: c            GLOBAL     'builtins object'
236
  241: p            PUT        7
237
  244: N            NONE
238
  245: t            TUPLE      (MARK at 208)
239
  246: p        PUT        8
240
  249: R        REDUCE
241
  250: p        PUT        9
242
  253: (        MARK
243
  254: d            DICT       (MARK at 253)
244
  255: p        PUT        10
245
  259: V        UNICODE    'foo'
246
  264: p        PUT        11
247
  268: L        LONG       1
248
  272: s        SETITEM
249
  273: V        UNICODE    'bar'
250
  278: p        PUT        12
251
  282: L        LONG       2
252
  286: s        SETITEM
253
  287: b        BUILD
254
  288: g        GET        9
255
  291: t        TUPLE      (MARK at 169)
256
  292: p    PUT        13
257
  296: a    APPEND
258
  297: g    GET        13
259
  301: a    APPEND
260
  302: L    LONG       5
261
  306: a    APPEND
262
  307: .    STOP
263
highest protocol among opcodes = 0
264
"""
265

266
DATA1 = (
6✔
267
    b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c'
268
    b'builtins\ncomplex\nq\x01'
269
    b'(G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00t'
270
    b'q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xffJ'
271
    b'\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff'
272
    b'\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00\x80(X\x03\x00\x00\x00ab'
273
    b'cq\x04h\x04ccopyreg\n_reco'
274
    b'nstructor\nq\x05(c__main'
275
    b'__\nC\nq\x06cbuiltins\n'
276
    b'object\nq\x07Ntq\x08Rq\t}q\n('
277
    b'X\x03\x00\x00\x00fooq\x0bK\x01X\x03\x00\x00\x00bar'
278
    b'q\x0cK\x02ubh\ttq\rh\rK\x05e.'
279
)
280

281
# Disassembly of DATA1
282
DATA1_DIS = """\
6✔
283
    0: ]    EMPTY_LIST
284
    1: q    BINPUT     0
285
    3: (    MARK
286
    4: K        BININT1    0
287
    6: K        BININT1    1
288
    8: G        BINFLOAT   2.0
289
   17: c        GLOBAL     'builtins complex'
290
   35: q        BINPUT     1
291
   37: (        MARK
292
   38: G            BINFLOAT   3.0
293
   47: G            BINFLOAT   0.0
294
   56: t            TUPLE      (MARK at 37)
295
   57: q        BINPUT     2
296
   59: R        REDUCE
297
   60: q        BINPUT     3
298
   62: K        BININT1    1
299
   64: J        BININT     -1
300
   69: K        BININT1    255
301
   71: J        BININT     -255
302
   76: J        BININT     -256
303
   81: M        BININT2    65535
304
   84: J        BININT     -65535
305
   89: J        BININT     -65536
306
   94: J        BININT     2147483647
307
   99: J        BININT     -2147483647
308
  104: J        BININT     -2147483648
309
  109: (        MARK
310
  110: X            BINUNICODE 'abc'
311
  118: q            BINPUT     4
312
  120: h            BINGET     4
313
  122: c            GLOBAL     'copyreg _reconstructor'
314
  146: q            BINPUT     5
315
  148: (            MARK
316
  149: c                GLOBAL     '__main__ C'
317
  161: q                BINPUT     6
318
  163: c                GLOBAL     'builtins object'
319
  180: q                BINPUT     7
320
  182: N                NONE
321
  183: t                TUPLE      (MARK at 148)
322
  184: q            BINPUT     8
323
  186: R            REDUCE
324
  187: q            BINPUT     9
325
  189: }            EMPTY_DICT
326
  190: q            BINPUT     10
327
  192: (            MARK
328
  193: X                BINUNICODE 'foo'
329
  201: q                BINPUT     11
330
  203: K                BININT1    1
331
  205: X                BINUNICODE 'bar'
332
  213: q                BINPUT     12
333
  215: K                BININT1    2
334
  217: u                SETITEMS   (MARK at 192)
335
  218: b            BUILD
336
  219: h            BINGET     9
337
  221: t            TUPLE      (MARK at 109)
338
  222: q        BINPUT     13
339
  224: h        BINGET     13
340
  226: K        BININT1    5
341
  228: e        APPENDS    (MARK at 3)
342
  229: .    STOP
343
highest protocol among opcodes = 1
344
"""
345

346
DATA2 = (
6✔
347
    b'\x80\x02]q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c'
348
    b'builtins\ncomplex\n'
349
    b'q\x01G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00'
350
    b'\x86q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xff'
351
    b'J\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff'
352
    b'\xff\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00\x80(X\x03\x00\x00\x00a'
353
    b'bcq\x04h\x04c__main__\nC\nq\x05'
354
    b')\x81q\x06}q\x07(X\x03\x00\x00\x00fooq\x08K\x01'
355
    b'X\x03\x00\x00\x00barq\tK\x02ubh\x06tq\nh'
356
    b'\nK\x05e.'
357
)
358

359
# Disassembly of DATA2
360
DATA2_DIS = """\
6✔
361
    0: \x80 PROTO      2
362
    2: ]    EMPTY_LIST
363
    3: q    BINPUT     0
364
    5: (    MARK
365
    6: K        BININT1    0
366
    8: K        BININT1    1
367
   10: G        BINFLOAT   2.0
368
   19: c        GLOBAL     'builtins complex'
369
   37: q        BINPUT     1
370
   39: G        BINFLOAT   3.0
371
   48: G        BINFLOAT   0.0
372
   57: \x86     TUPLE2
373
   58: q        BINPUT     2
374
   60: R        REDUCE
375
   61: q        BINPUT     3
376
   63: K        BININT1    1
377
   65: J        BININT     -1
378
   70: K        BININT1    255
379
   72: J        BININT     -255
380
   77: J        BININT     -256
381
   82: M        BININT2    65535
382
   85: J        BININT     -65535
383
   90: J        BININT     -65536
384
   95: J        BININT     2147483647
385
  100: J        BININT     -2147483647
386
  105: J        BININT     -2147483648
387
  110: (        MARK
388
  111: X            BINUNICODE 'abc'
389
  119: q            BINPUT     4
390
  121: h            BINGET     4
391
  123: c            GLOBAL     '__main__ C'
392
  135: q            BINPUT     5
393
  137: )            EMPTY_TUPLE
394
  138: \x81         NEWOBJ
395
  139: q            BINPUT     6
396
  141: }            EMPTY_DICT
397
  142: q            BINPUT     7
398
  144: (            MARK
399
  145: X                BINUNICODE 'foo'
400
  153: q                BINPUT     8
401
  155: K                BININT1    1
402
  157: X                BINUNICODE 'bar'
403
  165: q                BINPUT     9
404
  167: K                BININT1    2
405
  169: u                SETITEMS   (MARK at 144)
406
  170: b            BUILD
407
  171: h            BINGET     6
408
  173: t            TUPLE      (MARK at 110)
409
  174: q        BINPUT     10
410
  176: h        BINGET     10
411
  178: K        BININT1    5
412
  180: e        APPENDS    (MARK at 5)
413
  181: .    STOP
414
highest protocol among opcodes = 2
415
"""
416

417
# set([1,2]) pickled from 2.x with protocol 2
418
DATA3 = b'\x80\x02c__builtin__\nset\nq\x00]q\x01(K\x01K\x02e\x85q\x02Rq\x03.'
6✔
419

420
# xrange(5) pickled from 2.x with protocol 2
421
DATA4 = b'\x80\x02c__builtin__\nxrange\nq\x00K\x00K\x05K\x01\x87q\x01Rq\x02.'
6✔
422

423
# a SimpleCookie() object pickled from 2.x with protocol 2
424
DATA5 = (b'\x80\x02cCookie\nSimpleCookie\nq\x00)\x81q\x01U\x03key'
6✔
425
         b'q\x02cCookie\nMorsel\nq\x03)\x81q\x04(U\x07commentq\x05U'
426
         b'\x00q\x06U\x06domainq\x07h\x06U\x06secureq\x08h\x06U\x07'
427
         b'expiresq\th\x06U\x07max-ageq\nh\x06U\x07versionq\x0bh\x06U'
428
         b'\x04pathq\x0ch\x06U\x08httponlyq\rh\x06u}q\x0e(U\x0b'
429
         b'coded_valueq\x0fU\x05valueq\x10h\x10h\x10h\x02h\x02ubs}q\x11b.')
430

431
# set([3]) pickled from 2.x with protocol 2
432
DATA6 = b'\x80\x02c__builtin__\nset\nq\x00]q\x01K\x03a\x85q\x02Rq\x03.'
6✔
433
DATA6_PYPY = b'\x80\x02c__builtin__\nset\nq\x00K\x03\x85q\x01\x85q\x02Rq\x03.'
6✔
434

435
def create_data():
6✔
436
    c = C()
6✔
437
    c.foo = 1
6✔
438
    c.bar = 2
6✔
439
    x = [0, 1, 2.0, 3.0+0j]
6✔
440
    # Append some integer test cases at cPickle.c's internal size
441
    # cutoffs.
442
    uint1max = 0xff
6✔
443
    uint2max = 0xffff
6✔
444
    int4max = 0x7fffffff
6✔
445
    x.extend([1, -1,
6✔
446
              uint1max, -uint1max, -uint1max-1,
447
              uint2max, -uint2max, -uint2max-1,
448
               int4max,  -int4max,  -int4max-1])
449
    y = ('abc', 'abc', c, c)
6✔
450
    x.append(y)
6✔
451
    x.append(y)
6✔
452
    x.append(5)
6✔
453
    return x
6✔
454

455
class AbstractPickleTests(unittest.TestCase):
6✔
456
    # Subclass must define self.dumps, self.loads.
457

458
    _testdata = create_data()
6✔
459

460
    def setUp(self):
6✔
461
        pass
6✔
462

463
    def test_misc(self):
6✔
464
        # test various datatypes not tested by testdata
465
        for proto in protocols:
6✔
466
            x = myint(4)
6✔
467
            s = self.dumps(x, proto)
6✔
468
            y = self.loads(s)
6✔
469
            self.assertEqual(x, y)
6✔
470

471
            x = (1, ())
6✔
472
            s = self.dumps(x, proto)
6✔
473
            y = self.loads(s)
6✔
474
            self.assertEqual(x, y)
6✔
475

476
            x = initarg(1, x)
6✔
477
            s = self.dumps(x, proto)
6✔
478
            y = self.loads(s)
6✔
479
            self.assertEqual(x, y)
6✔
480

481
        # XXX test __reduce__ protocol?
482

483
    def test_roundtrip_equality(self):
6✔
484
        expected = self._testdata
6✔
485
        for proto in protocols:
6✔
486
            s = self.dumps(expected, proto)
6✔
487
            got = self.loads(s)
6✔
488
            self.assertEqual(expected, got)
6✔
489

490
    def test_load_from_data0(self):
6✔
491
        self.assertEqual(self._testdata, self.loads(DATA0))
6✔
492

493
    def test_load_from_data1(self):
6✔
494
        self.assertEqual(self._testdata, self.loads(DATA1))
6✔
495

496
    def test_load_from_data2(self):
6✔
497
        self.assertEqual(self._testdata, self.loads(DATA2))
6✔
498

499
    def test_load_classic_instance(self):
6✔
500
        # See issue5180.  Test loading 2.x pickles that
501
        # contain an instance of old style class.
502
        for X, args in [(C, ()), (D, ('x',)), (E, ())]:
6✔
503
            xname = X.__name__.encode('ascii')
6✔
504
            # Protocol 0 (text mode pickle):
505
            """
2✔
506
            0: (    MARK
507
            1: i        INST       '__main__ X' (MARK at 0)
508
            15: p    PUT        0
509
            18: (    MARK
510
            19: d        DICT       (MARK at 18)
511
            20: p    PUT        1
512
            23: b    BUILD
513
            24: .    STOP
514
            """
515
            pickle0 = (b"(i__main__\n"
6✔
516
                       b"X\n"
517
                       b"p0\n"
518
                       b"(dp1\nb.").replace(b'X', xname)
519
            self.assertEqual(X(*args), self.loads(pickle0))
6✔
520

521
            # Protocol 1 (binary mode pickle)
522
            """
2✔
523
            0: (    MARK
524
            1: c        GLOBAL     '__main__ X'
525
            15: q        BINPUT     0
526
            17: o        OBJ        (MARK at 0)
527
            18: q    BINPUT     1
528
            20: }    EMPTY_DICT
529
            21: q    BINPUT     2
530
            23: b    BUILD
531
            24: .    STOP
532
            """
533
            pickle1 = (b'(c__main__\n'
6✔
534
                       b'X\n'
535
                       b'q\x00oq\x01}q\x02b.').replace(b'X', xname)
536
            self.assertEqual(X(*args), self.loads(pickle1))
6✔
537

538
            # Protocol 2 (pickle2 = b'\x80\x02' + pickle1)
539
            """
2✔
540
            0: \x80 PROTO      2
541
            2: (    MARK
542
            3: c        GLOBAL     '__main__ X'
543
            17: q        BINPUT     0
544
            19: o        OBJ        (MARK at 2)
545
            20: q    BINPUT     1
546
            22: }    EMPTY_DICT
547
            23: q    BINPUT     2
548
            25: b    BUILD
549
            26: .    STOP
550
            """
551
            pickle2 = (b'\x80\x02(c__main__\n'
6✔
552
                       b'X\n'
553
                       b'q\x00oq\x01}q\x02b.').replace(b'X', xname)
554
            self.assertEqual(X(*args), self.loads(pickle2))
6✔
555

556
    # There are gratuitous differences between pickles produced by
557
    # pickle and cPickle, largely because cPickle starts PUT indices at
558
    # 1 and pickle starts them at 0.  See XXX comment in cPickle's put2() --
559
    # there's a comment with an exclamation point there whose meaning
560
    # is a mystery.  cPickle also suppresses PUT for objects with a refcount
561
    # of 1.
562
    def dont_test_disassembly(self):
6✔
563
        from io import StringIO
×
564
        from pickletools import dis
×
565

566
        for proto, expected in (0, DATA0_DIS), (1, DATA1_DIS):
×
567
            s = self.dumps(self._testdata, proto)
×
568
            filelike = StringIO()
×
569
            dis(s, out=filelike)
×
570
            got = filelike.getvalue()
×
571
            self.assertEqual(expected, got)
×
572

573
    def test_recursive_list(self):
6✔
574
        l = []
6✔
575
        l.append(l)
6✔
576
        for proto in protocols:
6✔
577
            s = self.dumps(l, proto)
6✔
578
            x = self.loads(s)
6✔
579
            self.assertEqual(len(x), 1)
6✔
580
            self.assertTrue(x is x[0])
6✔
581

582
    def test_recursive_tuple(self):
6✔
583
        t = ([],)
6✔
584
        t[0].append(t)
6✔
585
        for proto in protocols:
6✔
586
            s = self.dumps(t, proto)
6✔
587
            x = self.loads(s)
6✔
588
            self.assertEqual(len(x), 1)
6✔
589
            self.assertEqual(len(x[0]), 1)
6✔
590
            self.assertTrue(x is x[0][0])
6✔
591

592
    def test_recursive_dict(self):
6✔
593
        d = {}
6✔
594
        d[1] = d
6✔
595
        for proto in protocols:
6✔
596
            s = self.dumps(d, proto)
6✔
597
            x = self.loads(s)
6✔
598
            self.assertEqual(list(x.keys()), [1])
6✔
599
            self.assertTrue(x[1] is x)
6✔
600

601
    def test_recursive_inst(self):
6✔
602
        i = C()
6✔
603
        i.attr = i
6✔
604
        for proto in protocols:
6✔
605
            s = self.dumps(i, proto)
6✔
606
            x = self.loads(s)
6✔
607
            self.assertEqual(dir(x), dir(i))
6✔
608
            self.assertIs(x.attr, x)
6✔
609

610
    def test_recursive_multi(self):
6✔
611
        l = []
6✔
612
        d = {1:l}
6✔
613
        i = C()
6✔
614
        i.attr = d
6✔
615
        l.append(i)
6✔
616
        for proto in protocols:
6✔
617
            s = self.dumps(l, proto)
6✔
618
            x = self.loads(s)
6✔
619
            self.assertEqual(len(x), 1)
6✔
620
            self.assertEqual(dir(x[0]), dir(i))
6✔
621
            self.assertEqual(list(x[0].attr.keys()), [1])
6✔
622
            self.assertTrue(x[0].attr[1] is x)
6✔
623

624
    def test_get(self):
6✔
625
        self.assertRaises(KeyError, self.loads, b'g0\np0')
6✔
626
        self.assertEqual(self.loads(b'((Kdtp0\nh\x00l.))'), [(100,), (100,)])
6✔
627

628
    def test_insecure_strings(self):
6✔
629
        # XXX Some of these tests are temporarily disabled
630
        insecure = [b"abc", b"2 + 2", # not quoted
6✔
631
                    ## b"'abc' + 'def'", # not a single quoted string
632
                    b"'abc", # quote is not closed
633
                    b"'abc\"", # open quote and close quote don't match
634
                    b"'abc'   ?", # junk after close quote
635
                    b"'\\'", # trailing backslash
636
                    # Variations on issue #17710
637
                    b"'",
638
                    b'"',
639
                    b"' ",
640
                    b"'  ",
641
                    b"'   ",
642
                    b"'    ",
643
                    b'"    ',
644
                    # some tests of the quoting rules
645
                    ## b"'abc\"\''",
646
                    ## b"'\\\\a\'\'\'\\\'\\\\\''",
647
                    ]
648
        for b in insecure:
6✔
649
            buf = b"S" + b + b"\012p0\012."
6✔
650
            self.assertRaises(ValueError, self.loads, buf)
6✔
651

652
    def test_unicode(self):
6✔
653
        endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
6✔
654
                    '<\\>', '<\\\U00012345>',
655
                    # surrogates
656
                    '<\udc80>']
657
        for proto in protocols:
6✔
658
            for u in endcases:
6✔
659
                p = self.dumps(u, proto)
6✔
660
                u2 = self.loads(p)
6✔
661
                self.assertEqual(u2, u)
6✔
662

663
    def test_unicode_high_plane(self):
6✔
664
        t = '\U00012345'
6✔
665
        for proto in protocols:
6✔
666
            p = self.dumps(t, proto)
6✔
667
            t2 = self.loads(p)
6✔
668
            self.assertEqual(t2, t)
6✔
669

670
    def test_bytes(self):
6✔
671
        for proto in protocols:
6✔
672
            for s in b'', b'xyz', b'xyz'*100:
6✔
673
                p = self.dumps(s, proto)
6✔
674
                self.assertEqual(self.loads(p), s)
6✔
675
            for s in [bytes([i]) for i in range(256)]:
6✔
676
                p = self.dumps(s, proto)
6✔
677
                self.assertEqual(self.loads(p), s)
6✔
678
            for s in [bytes([i, i]) for i in range(256)]:
6✔
679
                p = self.dumps(s, proto)
6✔
680
                self.assertEqual(self.loads(p), s)
6✔
681

682
    def test_ints(self):
6✔
683
        import sys
6✔
684
        for proto in protocols:
6✔
685
            n = sys.maxsize
6✔
686
            while n:
6✔
687
                for expected in (-n, n):
6✔
688
                    s = self.dumps(expected, proto)
6✔
689
                    n2 = self.loads(s)
6✔
690
                    self.assertEqual(expected, n2)
6✔
691
                n = n >> 1
6✔
692

693
    def test_maxint64(self):
6✔
694
        maxint64 = (1 << 63) - 1
6✔
695
        data = b'I' + str(maxint64).encode("ascii") + b'\n.'
6✔
696
        got = self.loads(data)
6✔
697
        self.assertEqual(got, maxint64)
6✔
698

699
        # Try too with a bogus literal.
700
        data = b'I' + str(maxint64).encode("ascii") + b'JUNK\n.'
6✔
701
        self.assertRaises(ValueError, self.loads, data)
6✔
702

703
    def test_long(self):
6✔
704
        for proto in protocols:
6✔
705
            # 256 bytes is where LONG4 begins.
706
            for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257:
6✔
707
                nbase = 1 << nbits
6✔
708
                for npos in nbase-1, nbase, nbase+1:
6✔
709
                    for n in npos, -npos:
6✔
710
                        pickle = self.dumps(n, proto)
6✔
711
                        got = self.loads(pickle)
6✔
712
                        self.assertEqual(n, got)
6✔
713
        # Try a monster.  This is quadratic-time in protos 0 & 1, so don't
714
        # bother with those.
715
        nbase = int("deadbeeffeedface", 16)
6✔
716
        nbase += nbase << 1000000
6✔
717
        for n in nbase, -nbase:
6✔
718
            p = self.dumps(n, 2)
6✔
719
            got = self.loads(p)
6✔
720
            self.assertEqual(n, got)
6✔
721

722
    def test_float(self):
6✔
723
        test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5,
6✔
724
                       3.14, 263.44582062374053, 6.022e23, 1e30]
725
        test_values = test_values + [-x for x in test_values]
6✔
726
        for proto in protocols:
6✔
727
            for value in test_values:
6✔
728
                pickle = self.dumps(value, proto)
6✔
729
                got = self.loads(pickle)
6✔
730
                self.assertEqual(value, got)
6✔
731

732
    @run_with_locale('LC_ALL', 'de_DE', 'fr_FR')
6✔
733
    def test_float_format(self):
4✔
734
        # make sure that floats are formatted locale independent with proto 0
735
        self.assertEqual(self.dumps(1.2, 0)[0:3], b'F1.')
6✔
736

737
    def test_reduce(self):
6✔
738
        pass
6✔
739

740
    def test_getinitargs(self):
6✔
741
        pass
6✔
742

743
    def test_pop_empty_stack(self):
6✔
744
        # Test issue7455
745
        s = b'0'
6✔
746
        self.assertRaises((pickle.UnpicklingError, IndexError), self.loads, s)
6✔
747

748
    def test_metaclass(self):
6✔
749
        a = use_metaclass()
6✔
750
        for proto in protocols:
6✔
751
            s = self.dumps(a, proto)
6✔
752
            b = self.loads(s)
6✔
753
            self.assertEqual(a.__class__, b.__class__)
6✔
754

755
    def test_dynamic_class(self):
6✔
756
        a = create_dynamic_class("my_dynamic_class", (object,))
6✔
757
        copyreg.pickle(pickling_metaclass, pickling_metaclass.__reduce__)
6✔
758
        for proto in protocols:
6✔
759
            s = self.dumps(a, proto)
6✔
760
            b = self.loads(s)
6✔
761
            self.assertEqual(a, b)
6✔
762

763
    def test_structseq(self):
6✔
764
        import time
6✔
765
        import os
6✔
766

767
        t = time.localtime()
6✔
768
        for proto in protocols:
6✔
769
            s = self.dumps(t, proto)
6✔
770
            u = self.loads(s)
6✔
771
            self.assertEqual(t, u)
6✔
772
            if hasattr(os, "stat"):
6!
773
                t = os.stat(os.curdir)
6✔
774
                s = self.dumps(t, proto)
6✔
775
                u = self.loads(s)
6✔
776
                self.assertEqual(t, u)
6✔
777
            if hasattr(os, "statvfs"):
6!
778
                t = os.statvfs(os.curdir)
6✔
779
                s = self.dumps(t, proto)
6✔
780
                u = self.loads(s)
6✔
781
                self.assertEqual(t, u)
6✔
782

783
    def test_ellipsis(self):
6✔
784
        for proto in protocols:
6✔
785
            s = self.dumps(..., proto)
6✔
786
            u = self.loads(s)
6✔
787
            self.assertEqual(..., u)
6✔
788

789
    def test_notimplemented(self):
6✔
790
        for proto in protocols:
6✔
791
            s = self.dumps(NotImplemented, proto)
6✔
792
            u = self.loads(s)
6✔
793
            self.assertEqual(NotImplemented, u)
6✔
794

795
    # Tests for protocol 2
796

797
    def test_proto(self):
6✔
798
        build_none = pickle.NONE + pickle.STOP
6✔
799
        for proto in protocols:
6✔
800
            expected = build_none
6✔
801
            if proto >= 2:
6✔
802
                expected = pickle.PROTO + bytes([proto]) + expected
6✔
803
            p = self.dumps(None, proto)
6✔
804
            self.assertEqual(p, expected)
6✔
805

806
        oob = protocols[-1] + 1     # a future protocol
6✔
807
        badpickle = pickle.PROTO + bytes([oob]) + build_none
6✔
808
        try:
6✔
809
            self.loads(badpickle)
6✔
810
        except ValueError as detail:
6✔
811
            self.assertTrue(str(detail).startswith(
6✔
812
                                            "unsupported pickle protocol"))
813
        else:
814
            self.fail("expected bad protocol number to raise ValueError")
815

816
    def test_long1(self):
6✔
817
        x = 12345678910111213141516178920
6✔
818
        for proto in protocols:
6✔
819
            s = self.dumps(x, proto)
6✔
820
            y = self.loads(s)
6✔
821
            self.assertEqual(x, y)
6✔
822
            self.assertEqual(opcode_in_pickle(pickle.LONG1, s), proto >= 2)
6✔
823

824
    def test_long4(self):
6✔
825
        x = 12345678910111213141516178920 << (256*8)
6✔
826
        for proto in protocols:
6✔
827
            s = self.dumps(x, proto)
6✔
828
            y = self.loads(s)
6✔
829
            self.assertEqual(x, y)
6✔
830
            self.assertEqual(opcode_in_pickle(pickle.LONG4, s), proto >= 2)
6✔
831

832
    def test_short_tuples(self):
6✔
833
        # Map (proto, len(tuple)) to expected opcode.
834
        expected_opcode = {(0, 0): pickle.TUPLE,
6✔
835
                           (0, 1): pickle.TUPLE,
836
                           (0, 2): pickle.TUPLE,
837
                           (0, 3): pickle.TUPLE,
838
                           (0, 4): pickle.TUPLE,
839

840
                           (1, 0): pickle.EMPTY_TUPLE,
841
                           (1, 1): pickle.TUPLE,
842
                           (1, 2): pickle.TUPLE,
843
                           (1, 3): pickle.TUPLE,
844
                           (1, 4): pickle.TUPLE,
845

846
                           (2, 0): pickle.EMPTY_TUPLE,
847
                           (2, 1): pickle.TUPLE1,
848
                           (2, 2): pickle.TUPLE2,
849
                           (2, 3): pickle.TUPLE3,
850
                           (2, 4): pickle.TUPLE,
851

852
                           (3, 0): pickle.EMPTY_TUPLE,
853
                           (3, 1): pickle.TUPLE1,
854
                           (3, 2): pickle.TUPLE2,
855
                           (3, 3): pickle.TUPLE3,
856
                           (3, 4): pickle.TUPLE,
857
                          }
858
        a = ()
6✔
859
        b = (1,)
6✔
860
        c = (1, 2)
6✔
861
        d = (1, 2, 3)
6✔
862
        e = (1, 2, 3, 4)
6✔
863
        for proto in protocols:
6✔
864
            for x in a, b, c, d, e:
6✔
865
                s = self.dumps(x, proto)
6✔
866
                y = self.loads(s)
6✔
867
                self.assertEqual(x, y, (proto, x, s, y))
6✔
868
                expected = expected_opcode[proto, len(x)]
6✔
869
                self.assertEqual(opcode_in_pickle(expected, s), True)
6✔
870

871
    def test_singletons(self):
6✔
872
        # Map (proto, singleton) to expected opcode.
873
        expected_opcode = {(0, None): pickle.NONE,
6✔
874
                           (1, None): pickle.NONE,
875
                           (2, None): pickle.NONE,
876
                           (3, None): pickle.NONE,
877

878
                           (0, True): pickle.INT,
879
                           (1, True): pickle.INT,
880
                           (2, True): pickle.NEWTRUE,
881
                           (3, True): pickle.NEWTRUE,
882

883
                           (0, False): pickle.INT,
884
                           (1, False): pickle.INT,
885
                           (2, False): pickle.NEWFALSE,
886
                           (3, False): pickle.NEWFALSE,
887
                          }
888
        for proto in protocols:
6✔
889
            for x in None, False, True:
6✔
890
                s = self.dumps(x, proto)
6✔
891
                y = self.loads(s)
6✔
892
                self.assertTrue(x is y, (proto, x, s, y))
6✔
893
                expected = expected_opcode[proto, x]
6✔
894
                self.assertEqual(opcode_in_pickle(expected, s), True)
6✔
895

896
    def test_newobj_tuple(self):
6✔
897
        x = MyTuple([1, 2, 3])
6✔
898
        x.foo = 42
6✔
899
        x.bar = "hello"
6✔
900
        for proto in protocols:
6✔
901
            s = self.dumps(x, proto)
6✔
902
            y = self.loads(s)
6✔
903
            self.assertEqual(tuple(x), tuple(y))
6✔
904
            self.assertEqual(x.__dict__, y.__dict__)
6✔
905

906
    def test_newobj_list(self):
6✔
907
        x = MyList([1, 2, 3])
6✔
908
        x.foo = 42
6✔
909
        x.bar = "hello"
6✔
910
        for proto in protocols:
6✔
911
            s = self.dumps(x, proto)
6✔
912
            y = self.loads(s)
6✔
913
            self.assertEqual(list(x), list(y))
6✔
914
            self.assertEqual(x.__dict__, y.__dict__)
6✔
915

916
    def test_newobj_generic(self):
6✔
917
        for proto in protocols:
6✔
918
            for C in myclasses:
6✔
919
                B = C.__base__
6✔
920
                x = C(C.sample)
6✔
921
                x.foo = 42
6✔
922
                s = self.dumps(x, proto)
6✔
923
                y = self.loads(s)
6✔
924
                detail = (proto, C, B, x, y, type(y))
6✔
925
                self.assertEqual(B(x), B(y), detail)
6✔
926
                self.assertEqual(x.__dict__, y.__dict__, detail)
6✔
927

928
    def test_newobj_proxies(self):
6✔
929
        # NEWOBJ should use the __class__ rather than the raw type
930
        classes = myclasses[:]
6✔
931
        # Cannot create weakproxies to these classes
932
        for c in (MyInt, MyTuple):
6✔
933
            classes.remove(c)
6✔
934
        for proto in protocols:
6✔
935
            for C in classes:
6✔
936
                B = C.__base__
6✔
937
                x = C(C.sample)
6✔
938
                x.foo = 42
6✔
939
                p = weakref.proxy(x)
6✔
940
                s = self.dumps(p, proto)
6✔
941
                y = self.loads(s)
6✔
942
                self.assertEqual(type(y), type(x))  # rather than type(p)
6✔
943
                detail = (proto, C, B, x, y, type(y))
6✔
944
                self.assertEqual(B(x), B(y), detail)
6✔
945
                self.assertEqual(x.__dict__, y.__dict__, detail)
6✔
946

947
    # Register a type with copyreg, with extension code extcode.  Pickle
948
    # an object of that type.  Check that the resulting pickle uses opcode
949
    # (EXT[124]) under proto 2, and not in proto 1.
950

951
    def produce_global_ext(self, extcode, opcode):
6✔
952
        e = ExtensionSaver(extcode)
6✔
953
        try:
6✔
954
            copyreg.add_extension(__name__, "MyList", extcode)
6✔
955
            x = MyList([1, 2, 3])
6✔
956
            x.foo = 42
6✔
957
            x.bar = "hello"
6✔
958

959
            # Dump using protocol 1 for comparison.
960
            s1 = self.dumps(x, 1)
6✔
961
            self.assertIn(__name__.encode("utf-8"), s1)
6✔
962
            self.assertIn(b"MyList", s1)
6✔
963
            self.assertEqual(opcode_in_pickle(opcode, s1), False)
6✔
964

965
            y = self.loads(s1)
6✔
966
            self.assertEqual(list(x), list(y))
6✔
967
            self.assertEqual(x.__dict__, y.__dict__)
6✔
968

969
            # Dump using protocol 2 for test.
970
            s2 = self.dumps(x, 2)
6✔
971
            self.assertNotIn(__name__.encode("utf-8"), s2)
6✔
972
            self.assertNotIn(b"MyList", s2)
6✔
973
            self.assertEqual(opcode_in_pickle(opcode, s2), True, repr(s2))
6✔
974

975
            y = self.loads(s2)
6✔
976
            self.assertEqual(list(x), list(y))
6✔
977
            self.assertEqual(x.__dict__, y.__dict__)
6✔
978

979
        finally:
980
            e.restore()
6✔
981

982
    def test_global_ext1(self):
6✔
983
        self.produce_global_ext(0x00000001, pickle.EXT1)  # smallest EXT1 code
6✔
984
        self.produce_global_ext(0x000000ff, pickle.EXT1)  # largest EXT1 code
6✔
985

986
    def test_global_ext2(self):
6✔
987
        self.produce_global_ext(0x00000100, pickle.EXT2)  # smallest EXT2 code
6✔
988
        self.produce_global_ext(0x0000ffff, pickle.EXT2)  # largest EXT2 code
6✔
989
        self.produce_global_ext(0x0000abcd, pickle.EXT2)  # check endianness
6✔
990

991
    def test_global_ext4(self):
6✔
992
        self.produce_global_ext(0x00010000, pickle.EXT4)  # smallest EXT4 code
6✔
993
        self.produce_global_ext(0x7fffffff, pickle.EXT4)  # largest EXT4 code
6✔
994
        self.produce_global_ext(0x12abcdef, pickle.EXT4)  # check endianness
6✔
995

996
    def test_list_chunking(self):
6✔
997
        n = 10  # too small to chunk
6✔
998
        x = list(range(n))
6✔
999
        for proto in protocols:
6✔
1000
            s = self.dumps(x, proto)
6✔
1001
            y = self.loads(s)
6✔
1002
            self.assertEqual(x, y)
6✔
1003
            num_appends = count_opcode(pickle.APPENDS, s)
6✔
1004
            self.assertEqual(num_appends, proto > 0)
6✔
1005

1006
        n = 2500  # expect at least two chunks when proto > 0
6✔
1007
        x = list(range(n))
6✔
1008
        for proto in protocols:
6✔
1009
            s = self.dumps(x, proto)
6✔
1010
            y = self.loads(s)
6✔
1011
            self.assertEqual(x, y)
6✔
1012
            num_appends = count_opcode(pickle.APPENDS, s)
6✔
1013
            if proto == 0:
6✔
1014
                self.assertEqual(num_appends, 0)
6✔
1015
            else:
1016
                self.assertTrue(num_appends >= 2)
6✔
1017

1018
    def test_dict_chunking(self):
6✔
1019
        n = 10  # too small to chunk
6✔
1020
        x = dict.fromkeys(range(n))
6✔
1021
        for proto in protocols:
6✔
1022
            s = self.dumps(x, proto)
6✔
1023
            self.assertIsInstance(s, bytes_types)
6✔
1024
            y = self.loads(s)
6✔
1025
            self.assertEqual(x, y)
6✔
1026
            num_setitems = count_opcode(pickle.SETITEMS, s)
6✔
1027
            self.assertEqual(num_setitems, proto > 0)
6✔
1028

1029
        n = 2500  # expect at least two chunks when proto > 0
6✔
1030
        x = dict.fromkeys(range(n))
6✔
1031
        for proto in protocols:
6✔
1032
            s = self.dumps(x, proto)
6✔
1033
            y = self.loads(s)
6✔
1034
            self.assertEqual(x, y)
6✔
1035
            num_setitems = count_opcode(pickle.SETITEMS, s)
6✔
1036
            if proto == 0:
6✔
1037
                self.assertEqual(num_setitems, 0)
6✔
1038
            else:
1039
                self.assertTrue(num_setitems >= 2)
6✔
1040

1041
    def test_simple_newobj(self):
6✔
1042
        x = object.__new__(SimpleNewObj)  # avoid __init__
6✔
1043
        x.abc = 666
6✔
1044
        for proto in protocols:
6✔
1045
            s = self.dumps(x, proto)
6✔
1046
            self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s), proto >= 2)
6✔
1047
            y = self.loads(s)   # will raise TypeError if __init__ called
6✔
1048
            self.assertEqual(y.abc, 666)
6✔
1049
            self.assertEqual(x.__dict__, y.__dict__)
6✔
1050

1051
    def test_newobj_list_slots(self):
6✔
1052
        x = SlotList([1, 2, 3])
6✔
1053
        x.foo = 42
6✔
1054
        x.bar = "hello"
6✔
1055
        s = self.dumps(x, 2)
6✔
1056
        y = self.loads(s)
6✔
1057
        self.assertEqual(list(x), list(y))
6✔
1058
        self.assertEqual(x.__dict__, y.__dict__)
6✔
1059
        self.assertEqual(x.foo, y.foo)
6✔
1060
        self.assertEqual(x.bar, y.bar)
6✔
1061

1062
    def test_reduce_overrides_default_reduce_ex(self):
6✔
1063
        for proto in protocols:
6✔
1064
            x = REX_one()
6✔
1065
            self.assertEqual(x._reduce_called, 0)
6✔
1066
            s = self.dumps(x, proto)
6✔
1067
            self.assertEqual(x._reduce_called, 1)
6✔
1068
            y = self.loads(s)
6✔
1069
            self.assertEqual(y._reduce_called, 0)
6✔
1070

1071
    def test_reduce_ex_called(self):
6✔
1072
        for proto in protocols:
6✔
1073
            x = REX_two()
6✔
1074
            self.assertEqual(x._proto, None)
6✔
1075
            s = self.dumps(x, proto)
6✔
1076
            self.assertEqual(x._proto, proto)
6✔
1077
            y = self.loads(s)
6✔
1078
            self.assertEqual(y._proto, None)
6✔
1079

1080
    def test_reduce_ex_overrides_reduce(self):
6✔
1081
        for proto in protocols:
6✔
1082
            x = REX_three()
6✔
1083
            self.assertEqual(x._proto, None)
6✔
1084
            s = self.dumps(x, proto)
6✔
1085
            self.assertEqual(x._proto, proto)
6✔
1086
            y = self.loads(s)
6✔
1087
            self.assertEqual(y._proto, None)
6✔
1088

1089
    def test_reduce_ex_calls_base(self):
6✔
1090
        for proto in protocols:
6✔
1091
            x = REX_four()
6✔
1092
            self.assertEqual(x._proto, None)
6✔
1093
            s = self.dumps(x, proto)
6✔
1094
            self.assertEqual(x._proto, proto)
6✔
1095
            y = self.loads(s)
6✔
1096
            self.assertEqual(y._proto, proto)
6✔
1097

1098
    def test_reduce_calls_base(self):
6✔
1099
        for proto in protocols:
6✔
1100
            x = REX_five()
6✔
1101
            self.assertEqual(x._reduce_called, 0)
6✔
1102
            s = self.dumps(x, proto)
6✔
1103
            self.assertEqual(x._reduce_called, 1)
6✔
1104
            y = self.loads(s)
6✔
1105
            self.assertEqual(y._reduce_called, 1)
6✔
1106

1107
    @no_tracing
6✔
1108
    def test_bad_getattr(self):
4✔
1109
        x = BadGetattr()
×
1110

1111
        if _PY311b1:
×
1112
            # https://github.com/python/cpython/pull/2821 fixed runtime error
1113
            # problem for protocol version 2 and above it landed in 3.11.0b1.
1114
            proto_versions_with_runtime_error = (0, 1)
×
1115
            proto_versions_without_runtime_error = (2,)
×
1116
        else:
1117
            proto_versions_with_runtime_error = (0, 1, 2)
×
1118
            proto_versions_without_runtime_error = ()
×
1119

1120
        for proto in proto_versions_with_runtime_error:
×
1121
            with self.assertRaises(RuntimeError, msg='proto=%s' % proto):
×
1122
                self.dumps(x, proto)
×
1123
        for proto in proto_versions_without_runtime_error:
×
1124
            self.dumps(x, proto)
×
1125

1126
    def test_reduce_bad_iterator(self):
6✔
1127
        # Issue4176: crash when 4th and 5th items of __reduce__()
1128
        # are not iterators
1129
        class C:
6✔
1130
            def __reduce__(self):
6✔
1131
                # 4th item is not an iterator
1132
                return list, (), None, [], None
6✔
1133
        class D:
6✔
1134
            def __reduce__(self):
6✔
1135
                # 5th item is not an iterator
1136
                return dict, (), None, None, []
6✔
1137

1138
        # Protocol 0 is less strict and also accept iterables.
1139
        for proto in protocols:
6✔
1140
            try:
6✔
1141
                self.dumps(C(), proto)
6✔
1142
            except (pickle.PickleError):
5✔
1143
                pass
5✔
1144
            try:
6✔
1145
                self.dumps(D(), proto)
6✔
1146
            except (pickle.PickleError):
5✔
1147
                pass
5✔
1148

1149
    def test_many_puts_and_gets(self):
6✔
1150
        # Test that internal data structures correctly deal with lots of
1151
        # puts/gets.
1152
        keys = ("aaa" + str(i) for i in range(100))
6✔
1153
        large_dict = {k: [4, 5, 6] for k in keys}
6✔
1154
        obj = [dict(large_dict), dict(large_dict), dict(large_dict)]
6✔
1155

1156
        for proto in protocols:
6✔
1157
            dumped = self.dumps(obj, proto)
6✔
1158
            loaded = self.loads(dumped)
6✔
1159
            self.assertEqual(loaded, obj,
6✔
1160
                             "Failed protocol %d: %r != %r"
1161
                             % (proto, obj, loaded))
1162

1163
    @unittest.skipIf(_is_pypy,
6✔
1164
                     'PyPy does not guarantee the identity of strings. '
1165
                     'See the discussion on '
1166
                     'http://pypy.readthedocs.org/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id')
1167
    def test_attribute_name_interning(self):
4✔
1168
        # Test that attribute names of pickled objects are interned when
1169
        # unpickling.
1170
        for proto in protocols:
5✔
1171
            x = C()
5✔
1172
            x.foo = 42
5✔
1173
            x.bar = "hello"
5✔
1174
            s = self.dumps(x, proto)
5✔
1175
            y = self.loads(s)
5✔
1176
            x_keys = sorted(x.__dict__)
5✔
1177
            y_keys = sorted(y.__dict__)
5✔
1178
            for x_key, y_key in zip(x_keys, y_keys):
5✔
1179
                self.assertIs(x_key, y_key)
5✔
1180

1181
    def test_unpickle_from_2x(self):
6✔
1182
        # Unpickle non-trivial data from Python 2.x.
1183
        loaded = self.loads(DATA3)
6✔
1184
        self.assertEqual(loaded, {1, 2})
6✔
1185
        loaded = self.loads(DATA4)
6✔
1186
        self.assertEqual(type(loaded), type(range(0)))
6✔
1187
        self.assertEqual(list(loaded), list(range(5)))
6✔
1188
        loaded = self.loads(DATA5)
6✔
1189
        self.assertEqual(type(loaded), SimpleCookie)
6✔
1190
        self.assertEqual(list(loaded.keys()), ["key"])
6✔
1191
        self.assertEqual(loaded["key"].value, "value")
6✔
1192

1193
    def test_pickle_to_2x(self):
6✔
1194
        # Pickle non-trivial data with protocol 2, expecting that it yields
1195
        # the same result as Python 2.x did.
1196
        # NOTE: this test is a bit too strong since we can produce different
1197
        # bytecode that 2.x will still understand.
1198
        dumped = self.dumps(range(5), 2)
6✔
1199
        self.assertEqual(dumped, DATA4)
6✔
1200

1201
        dumped = self.dumps({3}, 2)
6✔
1202
        if not _is_pypy:
6✔
1203
            # The integer in the set is pickled differently under PyPy
1204
            # due to the differing identity semantics (?)
1205
            self.assertEqual(dumped, DATA6)
5✔
1206
        else:
1207
            self.assertEqual(dumped, DATA6_PYPY)
1✔
1208

1209
    def test_large_pickles(self):
6✔
1210
        # Test the correctness of internal buffering routines when handling
1211
        # large data.
1212
        for proto in protocols:
6✔
1213
            data = (1, min, b'xy' * (30 * 1024), len)
6✔
1214
            dumped = self.dumps(data, proto)
6✔
1215
            loaded = self.loads(dumped)
6✔
1216
            self.assertEqual(len(loaded), len(data))
6✔
1217
            self.assertEqual(loaded, data)
6✔
1218

1219
    def test_empty_bytestring(self):
6✔
1220
        # issue 11286
1221
        empty = self.loads(b'\x80\x03U\x00q\x00.', encoding='koi8-r')
6✔
1222
        self.assertEqual(empty, '')
6✔
1223

1224
    def test_int_pickling_efficiency(self):
6✔
1225
        # Test compacity of int representation (see issue #12744)
1226
        for proto in protocols:
6✔
1227
            sizes = [len(self.dumps(2**n, proto)) for n in range(70)]
6✔
1228
            # the size function is monotonic
1229
            self.assertEqual(sorted(sizes), sizes)
6✔
1230
            if proto >= 2:
6✔
1231
                self.assertLessEqual(sizes[-1], 14)
6✔
1232

1233
    def check_negative_32b_binXXX(self, dumped):
6✔
1234
        if sys.maxsize > 2**32:
6!
1235
            self.skipTest("test is only meaningful on 32-bit builds")
6✔
1236
        # XXX Pure Python pickle reads lengths as signed and passes
1237
        # them directly to read() (hence the EOFError)
1238
        with self.assertRaises((pickle.UnpicklingError, EOFError,
×
1239
                                ValueError, OverflowError)):
1240
            self.loads(dumped)
×
1241

1242
    def test_negative_32b_binbytes(self):
6✔
1243
        # On 32-bit builds, a BINBYTES of 2**31 or more is refused
1244
        self.check_negative_32b_binXXX(b'\x80\x03B\xff\xff\xff\xffxyzq\x00.')
6✔
1245

1246
    def test_negative_32b_binunicode(self):
6✔
1247
        # On 32-bit builds, a BINUNICODE of 2**31 or more is refused
1248
        self.check_negative_32b_binXXX(b'\x80\x03X\xff\xff\xff\xffxyzq\x00.')
6✔
1249

1250
    def test_negative_put(self):
6✔
1251
        # Issue #12847
1252
        dumped = b'Va\np-1\n.'
6✔
1253
        self.assertRaises(ValueError, self.loads, dumped)
6✔
1254

1255
    def test_negative_32b_binput(self):
6✔
1256
        # Issue #12847
1257
        if sys.maxsize > 2**32:
6!
1258
            self.skipTest("test is only meaningful on 32-bit builds")
6✔
1259
        dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.'
×
1260
        self.assertRaises(ValueError, self.loads, dumped)
×
1261

1262
    def _check_pickling_with_opcode(self, obj, opcode, proto):
6✔
1263
        pickled = self.dumps(obj, proto)
6✔
1264
        self.assertTrue(opcode_in_pickle(opcode, pickled))
6✔
1265
        unpickled = self.loads(pickled)
6✔
1266
        self.assertEqual(obj, unpickled)
6✔
1267

1268
    def test_appends_on_non_lists(self):
6✔
1269
        # Issue #17720
1270
        obj = REX_six([1, 2, 3])
6✔
1271
        for proto in protocols:
6✔
1272
            if proto == 0:
6✔
1273
                self._check_pickling_with_opcode(obj, pickle.APPEND, proto)
6✔
1274
            else:
1275
                self._check_pickling_with_opcode(obj, pickle.APPENDS, proto)
6✔
1276

1277
    def test_setitems_on_non_dicts(self):
6✔
1278
        obj = REX_seven({1: -1, 2: -2, 3: -3})
6✔
1279
        for proto in protocols:
6✔
1280
            if proto == 0:
6✔
1281
                self._check_pickling_with_opcode(obj, pickle.SETITEM, proto)
6✔
1282
            else:
1283
                self._check_pickling_with_opcode(obj, pickle.SETITEMS, proto)
6✔
1284

1285
    def test_corrupted_pickle(self):
6✔
1286
        # Former C implementation produced corrupted pickles on these samples.
1287
        # See https://github.com/zopefoundation/zodbpickle/pull/47
1288
        sample1 = ['a'] * 17509
6✔
1289
        dumped = self.dumps(sample1, 0)
6✔
1290
        loaded = self.loads(dumped)
6✔
1291
        self.assertEqual(loaded, sample1)
6✔
1292

1293
        sample2 = ['a'] * 34992
6✔
1294
        dumped = self.dumps(sample2, 1)
6✔
1295
        loaded = self.loads(dumped)
6✔
1296
        self.assertEqual(loaded, sample2)
6✔
1297

1298
        sample3 = ['a'] * 34991
6✔
1299
        dumped = self.dumps(sample3, 2)
6✔
1300
        loaded = self.loads(dumped)
6✔
1301
        self.assertEqual(loaded, sample3)
6✔
1302

1303
        sample4 = ['a'] * 34991
6✔
1304
        dumped = self.dumps(sample4, 3)
6✔
1305
        loaded = self.loads(dumped)
6✔
1306
        self.assertEqual(loaded, sample4)
6✔
1307

1308

1309
class AbstractBytestrTests(unittest.TestCase):
6✔
1310
    def unpickleEqual(self, data, unpickled):
6✔
1311
        loaded = self.loads(data, encoding="bytes")
6✔
1312
        self.assertEqual(loaded, unpickled)
6✔
1313

1314
    def test_load_str_protocol_0(self):
6✔
1315
        """ Test str from protocol=0
1316
            python 2: pickle.dumps('bytestring \x00\xa0', protocol=0) """
1317
        self.unpickleEqual(
6✔
1318
                b"S'bytestring \\x00\\xa0'\np0\n.",
1319
                b'bytestring \x00\xa0')
1320

1321
    def test_load_str_protocol_1(self):
6✔
1322
        """ Test str from protocol=1
1323
        python 2: pickle.dumps('bytestring \x00\xa0', protocol=1) """
1324
        self.unpickleEqual(
6✔
1325
                b'U\rbytestring \x00\xa0q\x00.',
1326
                b'bytestring \x00\xa0')
1327

1328
    def test_load_str_protocol_2(self):
6✔
1329
        """ Test str from protocol=2
1330
        python 2: pickle.dumps('bytestring \x00\xa0', protocol=2) """
1331
        self.unpickleEqual(
6✔
1332
                b'\x80\x02U\rbytestring \x00\xa0q\x00.',
1333
                b'bytestring \x00\xa0')
1334

1335
    def test_load_unicode_protocol_0(self):
6✔
1336
        """ Test unicode with protocol=0
1337
        python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=0) """
1338
        self.unpickleEqual(
6✔
1339
                b'V\\u041a\\u043e\\u043c\\u043f\\u044c\\u044e\\u0442\\u0435\\u0440\np0\n.',
1340
                '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440')
1341

1342
    def test_load_unicode_protocol_1(self):
6✔
1343
        """ Test unicode with protocol=1
1344
        python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=1) """
1345
        self.unpickleEqual(
6✔
1346
                b'X\x12\x00\x00\x00\xd0\x9a\xd0\xbe\xd0\xbc\xd0\xbf\xd1\x8c\xd1\x8e\xd1\x82\xd0\xb5\xd1\x80q\x00.',
1347
                '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440')
1348

1349
    def test_load_unicode_protocol_2(self):
6✔
1350
        """ Test unicode with protocol=1
1351
        python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=2) """
1352
        self.unpickleEqual(
6✔
1353
                b'\x80\x02X\x12\x00\x00\x00\xd0\x9a\xd0\xbe\xd0\xbc\xd0\xbf\xd1\x8c\xd1\x8e\xd1\x82\xd0\xb5\xd1\x80q\x00.',
1354
                '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440')
1355

1356
    def test_load_long_str_protocol_1(self):
6✔
1357
        """ Test long str with protocol=1
1358
        python 2: pickle.dumps('x'*300, protocol=1) """
1359
        self.unpickleEqual(
6✔
1360
                b'T,\x01\x00\x00xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxq\x00.',
1361
                b'x'*300)
1362

1363
class AbstractBytesFallbackTests(unittest.TestCase):
6✔
1364
    def unpickleEqual(self, data, unpickled):
6✔
1365
        loaded = self.loads(data, errors="bytes")
6✔
1366
        self.assertEqual(loaded, unpickled)
6✔
1367

1368
    def test_load_instance(self):
6✔
1369
        r"""Test instance pickle.
1370

1371
        Python 2: pickle.dumps({'x': 'ascii', 'y': '\xff'}) """
1372
        self.unpickleEqual(
6✔
1373
                b"(dp0\nS'y'\np1\nS'\\xff'\np2\nsS'x'\np3\nS'ascii'\np4\ns.",
1374
                {'x': 'ascii', 'y': b'\xff'})
1375

1376

1377
class BigmemPickleTests(unittest.TestCase):
6✔
1378

1379
    # Binary protocols can serialize longs of up to 2GB-1
1380

1381
    @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False)
6✔
1382
    def test_huge_long_32b(self, size):
4✔
1383
        data = 1 << (8 * size)
×
1384
        try:
×
1385
            for proto in protocols:
×
1386
                if proto < 2:
×
1387
                    continue
×
1388
                with self.assertRaises((ValueError, OverflowError)):
×
1389
                    self.dumps(data, protocol=proto)
×
1390
        finally:
1391
            data = None
×
1392

1393
    # Protocol 3 can serialize up to 4GB-1 as a bytes object
1394
    # (older protocols don't have a dedicated opcode for bytes and are
1395
    # too inefficient)
1396

1397
    @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False)
6✔
1398
    def test_huge_bytes_32b(self, size):
4✔
1399
        data = b"abcd" * (size // 4)
×
1400
        try:
×
1401
            for proto in protocols:
×
1402
                if proto < 3:
×
1403
                    continue
×
1404
                try:
×
1405
                    pickled = self.dumps(data, protocol=proto)
×
1406
                    self.assertTrue(b"abcd" in pickled[:15])
×
1407
                    self.assertTrue(b"abcd" in pickled[-15:])
×
1408
                finally:
1409
                    pickled = None
×
1410
        finally:
1411
            data = None
×
1412

1413
    @bigmemtest(size=_4G, memuse=1 + 1, dry_run=False)
6✔
1414
    def test_huge_bytes_64b(self, size):
4✔
1415
        data = b"a" * size
×
1416
        try:
×
1417
            for proto in protocols:
×
1418
                if proto < 3:
×
1419
                    continue
×
1420
                with self.assertRaises((ValueError, OverflowError)):
×
1421
                    self.dumps(data, protocol=proto)
×
1422
        finally:
1423
            data = None
×
1424

1425
    # All protocols use 1-byte per printable ASCII character; we add another
1426
    # byte because the encoded form has to be copied into the internal buffer.
1427

1428
    @bigmemtest(size=_2G, memuse=2 + ascii_char_size, dry_run=False)
6✔
1429
    def test_huge_str_32b(self, size):
4✔
1430
        data = "abcd" * (size // 4)
×
1431
        try:
×
1432
            for proto in protocols:
×
1433
                try:
×
1434
                    pickled = self.dumps(data, protocol=proto)
×
1435
                    self.assertTrue(b"abcd" in pickled[:15])
×
1436
                    self.assertTrue(b"abcd" in pickled[-15:])
×
1437
                finally:
1438
                    pickled = None
×
1439
        finally:
1440
            data = None
×
1441

1442
    # BINUNICODE (protocols 1, 2 and 3) cannot carry more than
1443
    # 2**32 - 1 bytes of utf-8 encoded unicode.
1444

1445
    @bigmemtest(size=_4G, memuse=1 + ascii_char_size, dry_run=False)
6✔
1446
    def test_huge_str_64b(self, size):
4✔
1447
        data = "a" * size
×
1448
        try:
×
1449
            for proto in protocols:
×
1450
                if proto == 0:
×
1451
                    continue
×
1452
                with self.assertRaises((ValueError, OverflowError)):
×
1453
                    self.dumps(data, protocol=proto)
×
1454
        finally:
1455
            data = None
×
1456

1457

1458
# Test classes for reduce_ex
1459

1460
class REX_one:
6✔
1461
    """No __reduce_ex__ here, but inheriting it from object"""
1462
    _reduce_called = 0
6✔
1463
    def __reduce__(self):
6✔
1464
        self._reduce_called = 1
6✔
1465
        return REX_one, ()
6✔
1466

1467
class REX_two:
6✔
1468
    """No __reduce__ here, but inheriting it from object"""
1469
    _proto = None
6✔
1470
    def __reduce_ex__(self, proto):
6✔
1471
        self._proto = proto
6✔
1472
        return REX_two, ()
6✔
1473

1474
class REX_three:
6✔
1475
    _proto = None
6✔
1476
    def __reduce_ex__(self, proto):
6✔
1477
        self._proto = proto
6✔
1478
        return REX_two, ()
6✔
1479
    def __reduce__(self):
6✔
1480
        raise TestFailed("This __reduce__ shouldn't be called")
×
1481

1482
class REX_four:
6✔
1483
    """Calling base class method should succeed"""
1484
    _proto = None
6✔
1485
    def __reduce_ex__(self, proto):
6✔
1486
        self._proto = proto
6✔
1487
        return object.__reduce_ex__(self, proto)
6✔
1488

1489
class REX_five:
6✔
1490
    """This one used to fail with infinite recursion"""
1491
    _reduce_called = 0
6✔
1492
    def __reduce__(self):
6✔
1493
        self._reduce_called = 1
6✔
1494
        return object.__reduce__(self)
6✔
1495

1496
class REX_six:
6✔
1497
    """This class is used to check the 4th argument (list iterator) of the reduce
1498
    protocol.
1499
    """
1500
    def __init__(self, items=None):
6✔
1501
        self.items = items if items is not None else []
6✔
1502
    def __eq__(self, other):
6✔
1503
        return type(self) is type(other) and self.items == self.items
6✔
1504
    def append(self, item):
6✔
1505
        self.items.append(item)
6✔
1506
    def __reduce__(self):
6✔
1507
        return type(self), (), None, iter(self.items), None
6✔
1508

1509
class REX_seven:
6✔
1510
    """This class is used to check the 5th argument (dict iterator) of the reduce
1511
    protocol.
1512
    """
1513
    def __init__(self, table=None):
6✔
1514
        self.table = table if table is not None else {}
6✔
1515
    def __eq__(self, other):
6✔
1516
        return type(self) is type(other) and self.table == self.table
6✔
1517
    def __setitem__(self, key, value):
6✔
1518
        self.table[key] = value
6✔
1519
    def __reduce__(self):
6✔
1520
        return type(self), (), None, None, iter(self.table.items())
6✔
1521

1522

1523
# Test classes for newobj
1524

1525
class MyInt(int):
6✔
1526
    sample = 1
6✔
1527

1528
class MyFloat(float):
6✔
1529
    sample = 1.0
6✔
1530

1531
class MyComplex(complex):
6✔
1532
    sample = 1.0 + 0.0j
6✔
1533

1534
class MyStr(str):
6✔
1535
    sample = "hello"
6✔
1536

1537
class MyUnicode(str):
6✔
1538
    sample = "hello \u1234"
6✔
1539

1540
class MyTuple(tuple):
6✔
1541
    sample = (1, 2, 3)
6✔
1542

1543
class MyList(list):
6✔
1544
    sample = [1, 2, 3]
6✔
1545

1546
class MyDict(dict):
6✔
1547
    sample = {"a": 1, "b": 2}
6✔
1548

1549
myclasses = [MyInt, MyFloat,
6✔
1550
             MyComplex,
1551
             MyStr, MyUnicode,
1552
             MyTuple, MyList, MyDict]
1553

1554

1555
class SlotList(MyList):
6✔
1556
    __slots__ = ["foo"]
6✔
1557

1558
class SimpleNewObj:
6✔
1559
    def __init__(self, a, b, c):
6✔
1560
        # raise an error, to make sure this isn't called
1561
        raise TypeError("SimpleNewObj.__init__() didn't expect to get called")
×
1562

1563
class BadGetattr:
6✔
1564
    def __getattr__(self, key):
6✔
1565
        self.foo
×
1566

1567

1568
class AbstractPickleModuleTests(unittest.TestCase):
6✔
1569

1570
    def test_dump_closed_file(self):
6✔
1571
        import os
6✔
1572
        f = open(TESTFN, "wb")
6✔
1573
        try:
6✔
1574
            f.close()
6✔
1575
            self.assertRaises(ValueError, pickle.dump, 123, f)
6✔
1576
        finally:
1577
            os.remove(TESTFN)
6✔
1578

1579
    def test_load_closed_file(self):
6✔
1580
        import os
6✔
1581
        f = open(TESTFN, "wb")
6✔
1582
        try:
6✔
1583
            f.close()
6✔
1584
            self.assertRaises(ValueError, pickle.dump, 123, f)
6✔
1585
        finally:
1586
            os.remove(TESTFN)
6✔
1587

1588
    def test_load_from_and_dump_to_file(self):
6✔
1589
        stream = io.BytesIO()
6✔
1590
        data = [123, {}, 124]
6✔
1591
        pickle.dump(data, stream)
6✔
1592
        stream.seek(0)
6✔
1593
        unpickled = pickle.load(stream)
6✔
1594
        self.assertEqual(unpickled, data)
6✔
1595

1596
    def test_highest_protocol(self):
6✔
1597
        # Of course this needs to be changed when HIGHEST_PROTOCOL changes.
1598
        self.assertEqual(pickle.HIGHEST_PROTOCOL, 3)
6✔
1599

1600
    def test_callapi(self):
6✔
1601
        f = io.BytesIO()
6✔
1602
        # With and without keyword arguments
1603
        pickle.dump(123, f, -1)
6✔
1604
        pickle.dump(123, file=f, protocol=-1)
6✔
1605
        pickle.dumps(123, -1)
6✔
1606
        pickle.dumps(123, protocol=-1)
6✔
1607
        pickle.Pickler(f, -1)
6✔
1608
        pickle.Pickler(f, protocol=-1)
6✔
1609

1610
    def test_bad_init(self):
6✔
1611
        # Test issue3664 (pickle can segfault from a badly initialized Pickler).
1612
        # Override initialization without calling __init__() of the superclass.
1613
        class BadPickler(pickle.Pickler):
6✔
1614
            def __init__(self): pass
6✔
1615

1616
        class BadUnpickler(pickle.Unpickler):
6✔
1617
            def __init__(self): pass
6✔
1618

1619
        self.assertRaises(pickle.PicklingError, BadPickler().dump, 0)
6✔
1620
        self.assertRaises(pickle.UnpicklingError, BadUnpickler().load)
6✔
1621

1622
    def test_bad_input(self):
6✔
1623
        # Test issue4298
1624
        s = bytes([0x58, 0, 0, 0, 0x54])
6✔
1625
        self.assertRaises(EOFError, pickle.loads, s)
6✔
1626

1627

1628
class AbstractPersistentPicklerTests(unittest.TestCase):
6✔
1629

1630
    # This class defines persistent_id() and persistent_load()
1631
    # functions that should be used by the pickler.  All even integers
1632
    # are pickled using persistent ids.
1633

1634
    def persistent_id(self, object):
6✔
1635
        if isinstance(object, int) and object % 2 == 0:
6✔
1636
            self.id_count += 1
6✔
1637
            return str(object)
6✔
1638
        else:
1639
            return None
6✔
1640

1641
    def persistent_load(self, oid):
6✔
1642
        self.load_count += 1
6✔
1643
        object = int(oid)
6✔
1644
        assert object % 2 == 0
6✔
1645
        return object
6✔
1646

1647
    def test_persistence(self):
6✔
1648
        self.id_count = 0
6✔
1649
        self.load_count = 0
6✔
1650
        L = list(range(10))
6✔
1651
        self.assertEqual(self.loads(self.dumps(L)), L)
6✔
1652
        self.assertEqual(self.id_count, 5)
6✔
1653
        self.assertEqual(self.load_count, 5)
6✔
1654

1655
    def test_bin_persistence(self):
6✔
1656
        self.id_count = 0
6✔
1657
        self.load_count = 0
6✔
1658
        L = list(range(10))
6✔
1659
        self.assertEqual(self.loads(self.dumps(L, 1)), L)
6✔
1660
        self.assertEqual(self.id_count, 5)
6✔
1661
        self.assertEqual(self.load_count, 5)
6✔
1662

1663

1664
class AbstractPicklerUnpicklerObjectTests(unittest.TestCase):
6✔
1665

1666
    pickler_class = None
6✔
1667
    unpickler_class = None
6✔
1668

1669
    def setUp(self):
6✔
1670
        assert self.pickler_class
5✔
1671
        assert self.unpickler_class
5✔
1672

1673
    def test_clear_pickler_memo(self):
6✔
1674
        # To test whether clear_memo() has any effect, we pickle an object,
1675
        # then pickle it again without clearing the memo; the two serialized
1676
        # forms should be different. If we clear_memo() and then pickle the
1677
        # object again, the third serialized form should be identical to the
1678
        # first one we obtained.
1679
        data = ["abcdefg", "abcdefg", 44]
5✔
1680
        f = io.BytesIO()
5✔
1681
        pickler = self.pickler_class(f)
5✔
1682

1683
        pickler.dump(data)
5✔
1684
        first_pickled = f.getvalue()
5✔
1685

1686
        # Reset StringIO object.
1687
        f.seek(0)
5✔
1688
        f.truncate()
5✔
1689

1690
        pickler.dump(data)
5✔
1691
        second_pickled = f.getvalue()
5✔
1692

1693
        # Reset the Pickler and StringIO objects.
1694
        pickler.clear_memo()
5✔
1695
        f.seek(0)
5✔
1696
        f.truncate()
5✔
1697

1698
        pickler.dump(data)
5✔
1699
        third_pickled = f.getvalue()
5✔
1700

1701
        self.assertNotEqual(first_pickled, second_pickled)
5✔
1702
        self.assertEqual(first_pickled, third_pickled)
5✔
1703

1704
    def test_priming_pickler_memo(self):
6✔
1705
        # Verify that we can set the Pickler's memo attribute.
1706
        data = ["abcdefg", "abcdefg", 44]
5✔
1707
        f = io.BytesIO()
5✔
1708
        pickler = self.pickler_class(f)
5✔
1709

1710
        pickler.dump(data)
5✔
1711
        first_pickled = f.getvalue()
5✔
1712

1713
        f = io.BytesIO()
5✔
1714
        primed = self.pickler_class(f)
5✔
1715
        primed.memo = pickler.memo
5✔
1716

1717
        primed.dump(data)
5✔
1718
        primed_pickled = f.getvalue()
5✔
1719

1720
        self.assertNotEqual(first_pickled, primed_pickled)
5✔
1721

1722
    def test_priming_unpickler_memo(self):
6✔
1723
        # Verify that we can set the Unpickler's memo attribute.
1724
        data = ["abcdefg", "abcdefg", 44]
5✔
1725
        f = io.BytesIO()
5✔
1726
        pickler = self.pickler_class(f)
5✔
1727

1728
        pickler.dump(data)
5✔
1729
        first_pickled = f.getvalue()
5✔
1730

1731
        f = io.BytesIO()
5✔
1732
        primed = self.pickler_class(f)
5✔
1733
        primed.memo = pickler.memo
5✔
1734

1735
        primed.dump(data)
5✔
1736
        primed_pickled = f.getvalue()
5✔
1737

1738
        unpickler = self.unpickler_class(io.BytesIO(first_pickled))
5✔
1739
        unpickled_data1 = unpickler.load()
5✔
1740

1741
        self.assertEqual(unpickled_data1, data)
5✔
1742

1743
        primed = self.unpickler_class(io.BytesIO(primed_pickled))
5✔
1744
        primed.memo = unpickler.memo
5✔
1745
        unpickled_data2 = primed.load()
5✔
1746

1747
        primed.memo.clear()
5✔
1748

1749
        self.assertEqual(unpickled_data2, data)
5✔
1750
        self.assertTrue(unpickled_data2 is unpickled_data1)
5✔
1751

1752
    def test_reusing_unpickler_objects(self):
6✔
1753
        data1 = ["abcdefg", "abcdefg", 44]
5✔
1754
        f = io.BytesIO()
5✔
1755
        pickler = self.pickler_class(f)
5✔
1756
        pickler.dump(data1)
5✔
1757
        pickled1 = f.getvalue()
5✔
1758

1759
        data2 = ["abcdefg", 44, 44]
5✔
1760
        f = io.BytesIO()
5✔
1761
        pickler = self.pickler_class(f)
5✔
1762
        pickler.dump(data2)
5✔
1763
        pickled2 = f.getvalue()
5✔
1764

1765
        f = io.BytesIO()
5✔
1766
        f.write(pickled1)
5✔
1767
        f.seek(0)
5✔
1768
        unpickler = self.unpickler_class(f)
5✔
1769
        self.assertEqual(unpickler.load(), data1)
5✔
1770

1771
        f.seek(0)
5✔
1772
        f.truncate()
5✔
1773
        f.write(pickled2)
5✔
1774
        f.seek(0)
5✔
1775
        self.assertEqual(unpickler.load(), data2)
5✔
1776

1777
    def _check_multiple_unpicklings(self, ioclass):
6✔
1778
        for proto in protocols:
5✔
1779
            data1 = [(x, str(x)) for x in range(2000)] + [b"abcde", len]
5✔
1780
            f = ioclass()
5✔
1781
            pickler = self.pickler_class(f, protocol=proto)
5✔
1782
            pickler.dump(data1)
5✔
1783
            pickled = f.getvalue()
5✔
1784

1785
            N = 5
5✔
1786
            f = ioclass(pickled * N)
5✔
1787
            unpickler = self.unpickler_class(f)
5✔
1788
            for i in range(N):
5✔
1789
                if f.seekable():
5✔
1790
                    pos = f.tell()
5✔
1791
                self.assertEqual(unpickler.load(), data1)
5✔
1792
                if f.seekable():
5✔
1793
                    self.assertEqual(f.tell(), pos + len(pickled))
5✔
1794
            self.assertRaises(EOFError, unpickler.load)
5✔
1795

1796
    def test_multiple_unpicklings_seekable(self):
6✔
1797
        self._check_multiple_unpicklings(io.BytesIO)
5✔
1798

1799
    def test_multiple_unpicklings_unseekable(self):
6✔
1800
        self._check_multiple_unpicklings(UnseekableIO)
5✔
1801

1802
    def test_unpickling_buffering_readline(self):
6✔
1803
        # Issue #12687: the unpickler's buffering logic could fail with
1804
        # text mode opcodes.
1805
        data = list(range(10))
5✔
1806
        for proto in protocols:
5✔
1807
            for buf_size in range(1, 11):
5✔
1808
                f = io.BufferedRandom(io.BytesIO(), buffer_size=buf_size)
5✔
1809
                pickler = self.pickler_class(f, protocol=proto)
5✔
1810
                pickler.dump(data)
5✔
1811
                f.seek(0)
5✔
1812
                unpickler = self.unpickler_class(f)
5✔
1813
                self.assertEqual(unpickler.load(), data)
5✔
1814

1815
    def test_noload_object(self):
6✔
1816
        global _NOLOAD_OBJECT
1817
        after = {}
5✔
1818
        _NOLOAD_OBJECT = object()
5✔
1819
        aaa = AAA()
5✔
1820
        bbb = BBB()
5✔
1821
        ccc = 1
5✔
1822
        ddd = 1.0
5✔
1823
        eee = ('eee', 1)
5✔
1824
        fff = ['fff']
5✔
1825
        ggg = {'ggg': 0}
5✔
1826
        unpickler = self.unpickler_class
5✔
1827
        f = io.BytesIO()
5✔
1828
        pickler = self.pickler_class(f, protocol=2)
5✔
1829
        pickler.dump(_NOLOAD_OBJECT)
5✔
1830
        after['_NOLOAD_OBJECT'] = f.tell()
5✔
1831
        pickler.dump(aaa)
5✔
1832
        after['aaa'] = f.tell()
5✔
1833
        pickler.dump(bbb)
5✔
1834
        after['bbb'] = f.tell()
5✔
1835
        pickler.dump(ccc)
5✔
1836
        after['ccc'] = f.tell()
5✔
1837
        pickler.dump(ddd)
5✔
1838
        after['ddd'] = f.tell()
5✔
1839
        pickler.dump(eee)
5✔
1840
        after['eee'] = f.tell()
5✔
1841
        pickler.dump(fff)
5✔
1842
        after['fff'] = f.tell()
5✔
1843
        pickler.dump(ggg)
5✔
1844
        after['ggg'] = f.tell()
5✔
1845
        f.seek(0)
5✔
1846
        unpickler = self.unpickler_class(f)
5✔
1847
        unpickler.noload() # read past _NOLOAD_OBJECT
5✔
1848
        self.assertEqual(f.tell(), after['_NOLOAD_OBJECT'])
5✔
1849

1850
        noload = unpickler.noload() # read past aaa
5✔
1851
        self.assertEqual(noload, None)
5✔
1852
        self.assertEqual(f.tell(), after['aaa'])
5✔
1853

1854
        unpickler.noload() # read past bbb
5✔
1855
        self.assertEqual(f.tell(), after['bbb'])
5✔
1856

1857
        noload = unpickler.noload() # read past ccc
5✔
1858
        self.assertEqual(noload, ccc)
5✔
1859
        self.assertEqual(f.tell(), after['ccc'])
5✔
1860

1861
        noload = unpickler.noload() # read past ddd
5✔
1862
        self.assertEqual(noload, ddd)
5✔
1863
        self.assertEqual(f.tell(), after['ddd'])
5✔
1864

1865
        noload = unpickler.noload() # read past eee
5✔
1866
        self.assertEqual(noload, eee)
5✔
1867
        self.assertEqual(f.tell(), after['eee'])
5✔
1868

1869
        noload = unpickler.noload() # read past fff
5✔
1870
        self.assertEqual(noload, fff)
5✔
1871
        self.assertEqual(f.tell(), after['fff'])
5✔
1872

1873
        noload = unpickler.noload() # read past ggg
5✔
1874
        self.assertEqual(noload, ggg)
5✔
1875
        self.assertEqual(f.tell(), after['ggg'])
5✔
1876

1877
    def test_functional_noload_dict_subclass(self):
6✔
1878
        """noload() doesn't break or produce any output given a dict subclass"""
1879
        # See http://bugs.python.org/issue1101399
1880
        o = MyDict()
5✔
1881
        o['x'] = 1
5✔
1882
        f = io.BytesIO()
5✔
1883
        pickler = self.pickler_class(f, protocol=2)
5✔
1884
        pickler.dump(o)
5✔
1885
        f.seek(0)
5✔
1886
        unpickler = self.unpickler_class(f)
5✔
1887
        noload = unpickler.noload()
5✔
1888
        self.assertEqual(noload, None)
5✔
1889

1890

1891
    def test_functional_noload_list_subclass(self):
6✔
1892
        """noload() doesn't break or produce any output given a list subclass"""
1893
        # See http://bugs.python.org/issue1101399
1894
        o = MyList()
5✔
1895
        o.append(1)
5✔
1896
        f = io.BytesIO()
5✔
1897
        pickler = self.pickler_class(f, protocol=2)
5✔
1898
        pickler.dump(o)
5✔
1899
        f.seek(0)
5✔
1900
        unpickler = self.unpickler_class(f)
5✔
1901
        noload = unpickler.noload()
5✔
1902
        self.assertEqual(noload, None)
5✔
1903

1904
    def test_functional_noload_dict(self):
6✔
1905
        """noload() implements the Python 2.6 behaviour and fills in dicts"""
1906
        # See http://bugs.python.org/issue1101399
1907
        o = dict()
5✔
1908
        o['x'] = 1
5✔
1909
        f = io.BytesIO()
5✔
1910
        pickler = self.pickler_class(f, protocol=2)
5✔
1911
        pickler.dump(o)
5✔
1912
        f.seek(0)
5✔
1913
        unpickler = self.unpickler_class(f)
5✔
1914
        noload = unpickler.noload()
5✔
1915
        self.assertEqual(noload, o)
5✔
1916

1917

1918
    def test_functional_noload_list(self):
6✔
1919
        """noload() implements the Python 2.6 behaviour and fills in lists"""
1920
        # See http://bugs.python.org/issue1101399
1921
        o = list()
5✔
1922
        o.append(1)
5✔
1923
        f = io.BytesIO()
5✔
1924
        pickler = self.pickler_class(f, protocol=2)
5✔
1925
        pickler.dump(o)
5✔
1926
        f.seek(0)
5✔
1927
        unpickler = self.unpickler_class(f)
5✔
1928
        noload = unpickler.noload()
5✔
1929
        self.assertEqual(noload, o)
5✔
1930

1931

1932
# Tests for dispatch_table attribute
1933

1934
REDUCE_A = 'reduce_A'
6✔
1935

1936
class AAA:
6✔
1937
    def __reduce__(self):
6✔
1938
        return str, (REDUCE_A,)
6✔
1939

1940
class BBB:
6✔
1941
    pass
6✔
1942

1943
class AbstractDispatchTableTests(unittest.TestCase):
6✔
1944

1945
    def test_default_dispatch_table(self):
6✔
1946
        # No dispatch_table attribute by default
1947
        f = io.BytesIO()
6✔
1948
        p = self.pickler_class(f, 0)
6✔
1949
        with self.assertRaises(AttributeError):
6✔
1950
            p.dispatch_table
6✔
1951
        self.assertFalse(hasattr(p, 'dispatch_table'))
6✔
1952

1953
    def test_class_dispatch_table(self):
6✔
1954
        # A dispatch_table attribute can be specified class-wide
1955
        dt = self.get_dispatch_table()
6✔
1956

1957
        class MyPickler(self.pickler_class):
6✔
1958
            dispatch_table = dt
6✔
1959

1960
        def dumps(obj, protocol=None):
6✔
1961
            f = io.BytesIO()
6✔
1962
            p = MyPickler(f, protocol)
6✔
1963
            self.assertEqual(p.dispatch_table, dt)
6✔
1964
            p.dump(obj)
6✔
1965
            return f.getvalue()
6✔
1966

1967
        self._test_dispatch_table(dumps, dt)
6✔
1968

1969
    def test_instance_dispatch_table(self):
6✔
1970
        # A dispatch_table attribute can also be specified instance-wide
1971
        dt = self.get_dispatch_table()
6✔
1972

1973
        def dumps(obj, protocol=None):
6✔
1974
            f = io.BytesIO()
6✔
1975
            p = self.pickler_class(f, protocol)
6✔
1976
            p.dispatch_table = dt
6✔
1977
            self.assertEqual(p.dispatch_table, dt)
6✔
1978
            p.dump(obj)
6✔
1979
            return f.getvalue()
6✔
1980

1981
        self._test_dispatch_table(dumps, dt)
6✔
1982

1983
    def _test_dispatch_table(self, dumps, dispatch_table):
6✔
1984
        def custom_load_dump(obj):
6✔
1985
            return pickle.loads(dumps(obj, 0))
6✔
1986

1987
        def default_load_dump(obj):
6✔
1988
            return pickle.loads(pickle.dumps(obj, 0))
6✔
1989

1990
        # pickling complex numbers using protocol 0 relies on copyreg
1991
        # so check pickling a complex number still works
1992
        z = 1 + 2j
6✔
1993
        self.assertEqual(custom_load_dump(z), z)
6✔
1994
        self.assertEqual(default_load_dump(z), z)
6✔
1995

1996
        # modify pickling of complex
1997
        REDUCE_1 = 'reduce_1'
6✔
1998
        def reduce_1(obj):
6✔
1999
            return str, (REDUCE_1,)
6✔
2000
        dispatch_table[complex] = reduce_1
6✔
2001
        self.assertEqual(custom_load_dump(z), REDUCE_1)
6✔
2002
        self.assertEqual(default_load_dump(z), z)
6✔
2003

2004
        # check picklability of AAA and BBB
2005
        a = AAA()
6✔
2006
        b = BBB()
6✔
2007
        self.assertEqual(custom_load_dump(a), REDUCE_A)
6✔
2008
        self.assertIsInstance(custom_load_dump(b), BBB)
6✔
2009
        self.assertEqual(default_load_dump(a), REDUCE_A)
6✔
2010
        self.assertIsInstance(default_load_dump(b), BBB)
6✔
2011

2012
        # modify pickling of BBB
2013
        dispatch_table[BBB] = reduce_1
6✔
2014
        self.assertEqual(custom_load_dump(a), REDUCE_A)
6✔
2015
        self.assertEqual(custom_load_dump(b), REDUCE_1)
6✔
2016
        self.assertEqual(default_load_dump(a), REDUCE_A)
6✔
2017
        self.assertIsInstance(default_load_dump(b), BBB)
6✔
2018

2019
        # revert pickling of BBB and modify pickling of AAA
2020
        REDUCE_2 = 'reduce_2'
6✔
2021
        def reduce_2(obj):
6✔
2022
            return str, (REDUCE_2,)
6✔
2023
        dispatch_table[AAA] = reduce_2
6✔
2024
        del dispatch_table[BBB]
6✔
2025
        self.assertEqual(custom_load_dump(a), REDUCE_2)
6✔
2026
        self.assertIsInstance(custom_load_dump(b), BBB)
6✔
2027
        self.assertEqual(default_load_dump(a), REDUCE_A)
6✔
2028
        self.assertIsInstance(default_load_dump(b), BBB)
6✔
2029

2030

2031
if __name__ == "__main__":
6!
2032
    # Print some stuff that can be used to rewrite DATA{0,1,2}
2033
    from pickletools import dis
×
2034
    x = create_data()
×
2035
    for i in range(3):
×
2036
        p = pickle.dumps(x, i)
×
NEW
2037
        print(f"DATA{i} = (")
×
2038
        for j in range(0, len(p), 20):
×
2039
            b = bytes(p[j:j+20])
×
NEW
2040
            print(f"    {b!r}")
×
2041
        print(")")
×
2042
        print()
×
NEW
2043
        print(f"# Disassembly of DATA{i}")
×
NEW
2044
        print(f"DATA{i}_DIS = \"\"\"\\")
×
2045
        dis(p)
×
2046
        print("\"\"\"")
×
2047
        print()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc