Skip to content

Commit f4758a4

Browse files
Support Python 3.2+.
1 parent 3c75f48 commit f4758a4

File tree

3 files changed

+136
-41
lines changed

3 files changed

+136
-41
lines changed

Lib/test/pickletester.py

Lines changed: 123 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2800,7 +2800,7 @@ def test_recursive_multi(self):
28002800
self.assertEqual(list(x[0].attr.keys()), [1])
28012801
self.assertIs(x[0].attr[1], x)
28022802

2803-
def _test_recursive_collection_and_inst(self, factory):
2803+
def _test_recursive_collection_and_inst(self, factory, oldminproto=0):
28042804
# Mutable object containing a collection containing the original
28052805
# object.
28062806
o = Object()
@@ -2818,6 +2818,8 @@ def _test_recursive_collection_and_inst(self, factory):
28182818
# collection.
28192819
o = o.attr
28202820
for proto in protocols:
2821+
if self.py_version < (3, 4) and proto < oldminproto:
2822+
continue
28212823
s = self.dumps(o, proto)
28222824
x = self.loads(s)
28232825
self.assertIsInstance(x, t)
@@ -2835,25 +2837,25 @@ def test_recursive_dict_and_inst(self):
28352837
self._test_recursive_collection_and_inst(dict.fromkeys)
28362838

28372839
def test_recursive_set_and_inst(self):
2838-
self._test_recursive_collection_and_inst(set)
2840+
self._test_recursive_collection_and_inst(set, oldminproto=4)
28392841

28402842
def test_recursive_frozenset_and_inst(self):
2841-
self._test_recursive_collection_and_inst(frozenset)
2843+
self._test_recursive_collection_and_inst(frozenset, oldminproto=4)
28422844

28432845
def test_recursive_list_subclass_and_inst(self):
2844-
self._test_recursive_collection_and_inst(MyList)
2846+
self._test_recursive_collection_and_inst(MyList, oldminproto=2)
28452847

28462848
def test_recursive_tuple_subclass_and_inst(self):
2847-
self._test_recursive_collection_and_inst(MyTuple)
2849+
self._test_recursive_collection_and_inst(MyTuple, oldminproto=4)
28482850

28492851
def test_recursive_dict_subclass_and_inst(self):
2850-
self._test_recursive_collection_and_inst(MyDict.fromkeys)
2852+
self._test_recursive_collection_and_inst(MyDict.fromkeys, oldminproto=2)
28512853

28522854
def test_recursive_set_subclass_and_inst(self):
2853-
self._test_recursive_collection_and_inst(MySet)
2855+
self._test_recursive_collection_and_inst(MySet, oldminproto=4)
28542856

28552857
def test_recursive_frozenset_subclass_and_inst(self):
2856-
self._test_recursive_collection_and_inst(MyFrozenSet)
2858+
self._test_recursive_collection_and_inst(MyFrozenSet, oldminproto=4)
28572859

28582860
def test_recursive_inst_state(self):
28592861
# Mutable object containing itself.
@@ -2926,8 +2928,11 @@ def test_bytes(self):
29262928
self.assert_is_copy(s, self.loads(p))
29272929

29282930
def test_bytes_memoization(self):
2931+
array_types = [bytes]
2932+
if self.py_version >= (3, 4):
2933+
array_types += [ZeroCopyBytes]
29292934
for proto in protocols:
2930-
for array_type in [bytes, ZeroCopyBytes]:
2935+
for array_type in array_types:
29312936
for s in b'', b'xyz', b'xyz'*100:
29322937
with self.subTest(proto=proto, array_type=array_type, s=s, independent=False):
29332938
b = array_type(s)
@@ -2964,8 +2969,11 @@ def test_bytearray(self):
29642969
self.assertTrue(opcode_in_pickle(pickle.BYTEARRAY8, p))
29652970

29662971
def test_bytearray_memoization(self):
2972+
array_types = [bytearray]
2973+
if self.py_version >= (3, 4):
2974+
array_types += [ZeroCopyBytearray]
29672975
for proto in protocols:
2968-
for array_type in [bytearray, ZeroCopyBytearray]:
2976+
for array_type in array_types:
29692977
for s in b'', b'xyz', b'xyz'*100:
29702978
with self.subTest(proto=proto, array_type=array_type, s=s, independent=False):
29712979
b = array_type(s)
@@ -3039,10 +3047,13 @@ def test_float_format(self):
30393047

30403048
def test_reduce(self):
30413049
for proto in protocols:
3042-
inst = AAA()
3043-
dumped = self.dumps(inst, proto)
3044-
loaded = self.loads(dumped)
3045-
self.assertEqual(loaded, REDUCE_A)
3050+
if self.py_version < (3, 4) and proto < 3:
3051+
continue
3052+
with self.subTest(proto=proto):
3053+
inst = AAA()
3054+
dumped = self.dumps(inst, proto)
3055+
loaded = self.loads(dumped)
3056+
self.assertEqual(loaded, REDUCE_A)
30463057

30473058
def test_getinitargs(self):
30483059
for proto in protocols:
@@ -3076,6 +3087,8 @@ def test_structseq(self):
30763087
s = self.dumps(t, proto)
30773088
u = self.loads(s)
30783089
self.assert_is_copy(t, u)
3090+
if self.py_version < (3, 4):
3091+
continue
30793092
t = os.stat(os.curdir)
30803093
s = self.dumps(t, proto)
30813094
u = self.loads(s)
@@ -3087,19 +3100,25 @@ def test_structseq(self):
30873100
self.assert_is_copy(t, u)
30883101

30893102
def test_ellipsis(self):
3103+
if self.py_version < (3, 3):
3104+
self.skipTest('not supported in Python < 3.3')
30903105
for proto in protocols:
30913106
s = self.dumps(..., proto)
30923107
u = self.loads(s)
30933108
self.assertIs(..., u)
30943109

30953110
def test_notimplemented(self):
3111+
if self.py_version < (3, 3):
3112+
self.skipTest('not supported in Python < 3.3')
30963113
for proto in protocols:
30973114
s = self.dumps(NotImplemented, proto)
30983115
u = self.loads(s)
30993116
self.assertIs(NotImplemented, u)
31003117

31013118
def test_singleton_types(self):
31023119
# Issue #6477: Test that types of built-in singletons can be pickled.
3120+
if self.py_version < (3, 3):
3121+
self.skipTest('not supported in Python < 3.3')
31033122
singletons = [None, ..., NotImplemented]
31043123
for singleton in singletons:
31053124
for proto in protocols:
@@ -3110,12 +3129,34 @@ def test_singleton_types(self):
31103129
def test_builtin_types(self):
31113130
for t in builtins.__dict__.values():
31123131
if isinstance(t, type) and not issubclass(t, BaseException):
3132+
if t is str and self.py_version < (3, 4):
3133+
continue
3134+
if t.__name__ == 'BuiltinImporter' and self.py_version < (3, 3):
3135+
continue
31133136
for proto in protocols:
3114-
s = self.dumps(t, proto)
3115-
self.assertIs(self.loads(s), t)
3137+
with self.subTest(name=t.__name__, proto=proto):
3138+
s = self.dumps(t, proto)
3139+
self.assertIs(self.loads(s), t)
31163140

31173141
def test_builtin_exceptions(self):
31183142
new_names = {
3143+
'BlockingIOError': (3, 3),
3144+
'BrokenPipeError': (3, 3),
3145+
'ChildProcessError': (3, 3),
3146+
'ConnectionError': (3, 3),
3147+
'ConnectionAbortedError': (3, 3),
3148+
'ConnectionRefusedError': (3, 3),
3149+
'ConnectionResetError': (3, 3),
3150+
'FileExistsError': (3, 3),
3151+
'FileNotFoundError': (3, 3),
3152+
'InterruptedError': (3, 3),
3153+
'IsADirectoryError': (3, 3),
3154+
'NotADirectoryError': (3, 3),
3155+
'PermissionError': (3, 3),
3156+
'ProcessLookupError': (3, 3),
3157+
'TimeoutError': (3, 3),
3158+
'RecursionError': (3, 5),
3159+
'StopAsyncIteration': (3, 5),
31193160
'ModuleNotFoundError': (3, 6),
31203161
'EncodingWarning': (3, 10),
31213162
'BaseExceptionGroup': (3, 11),
@@ -3128,14 +3169,17 @@ def test_builtin_exceptions(self):
31283169
if t.__name__ in new_names and self.py_version < new_names[t.__name__]:
31293170
continue
31303171
for proto in protocols:
3131-
s = self.dumps(t, proto)
3132-
u = self.loads(s)
3133-
if proto <= 2 and issubclass(t, OSError) and t is not BlockingIOError:
3134-
self.assertIs(u, OSError)
3135-
elif proto <= 2 and issubclass(t, ImportError):
3136-
self.assertIs(u, ImportError)
3137-
else:
3138-
self.assertIs(u, t)
3172+
if self.py_version < (3, 3) and proto < 3:
3173+
continue
3174+
with self.subTest(name=t.__name__, proto=proto):
3175+
s = self.dumps(t, proto)
3176+
u = self.loads(s)
3177+
if proto <= 2 and issubclass(t, OSError) and t is not BlockingIOError:
3178+
self.assertIs(u, OSError)
3179+
elif proto <= 2 and issubclass(t, ImportError):
3180+
self.assertIs(u, ImportError)
3181+
else:
3182+
self.assertIs(u, t)
31393183

31403184
def test_builtin_functions(self):
31413185
new_names = {'breakpoint': (3, 7), 'aiter': (3, 10), 'anext': (3, 10)}
@@ -3144,8 +3188,9 @@ def test_builtin_functions(self):
31443188
if t.__name__ in new_names and self.py_version < new_names[t.__name__]:
31453189
continue
31463190
for proto in protocols:
3147-
s = self.dumps(t, proto)
3148-
self.assertIs(self.loads(s), t)
3191+
with self.subTest(name=t.__name__, proto=proto):
3192+
s = self.dumps(t, proto)
3193+
self.assertIs(self.loads(s), t)
31493194

31503195
# Tests for protocol 2
31513196

@@ -3160,7 +3205,7 @@ def test_proto(self):
31603205

31613206
def test_bad_proto(self):
31623207
if self.py_version < (3, 8):
3163-
self.skipTest('No protocol validation in this version')
3208+
self.skipTest('no protocol validation in Python < 3.8')
31643209
oob = protocols[-1] + 1 # a future protocol
31653210
build_none = pickle.NONE + pickle.STOP
31663211
badpickle = pickle.PROTO + bytes([oob]) + build_none
@@ -3272,6 +3317,8 @@ def test_newobj_list(self):
32723317
def test_newobj_generic(self):
32733318
for proto in protocols:
32743319
for C in myclasses:
3320+
if self.py_version < (3, 4) and proto < 3 and C in (MyStr, MyUnicode):
3321+
continue
32753322
B = C.__base__
32763323
x = C(C.sample)
32773324
x.foo = 42
@@ -3290,6 +3337,8 @@ def test_newobj_proxies(self):
32903337
classes.remove(c)
32913338
for proto in protocols:
32923339
for C in classes:
3340+
if self.py_version < (3, 4) and proto < 3 and C in (MyStr, MyUnicode):
3341+
continue
32933342
B = C.__base__
32943343
x = C(C.sample)
32953344
x.foo = 42
@@ -3314,6 +3363,8 @@ def test_newobj_overridden_new(self):
33143363

33153364
def test_newobj_not_class(self):
33163365
# Issue 24552
3366+
if self.py_version < (3, 4):
3367+
self.skipTest('not supported in Python < 3.4')
33173368
o = SimpleNewObj.__new__(SimpleNewObj)
33183369
b = self.dumps(o, 4)
33193370
with support.swap_attr(picklecommon, 'SimpleNewObj', 42):
@@ -3448,9 +3499,10 @@ def test_simple_newobj(self):
34483499
self.assertIn(b'64206', s) # INT or LONG
34493500
else:
34503501
self.assertIn(b'M\xce\xfa', s) # BININT2
3451-
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
3452-
2 <= proto)
3453-
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
3502+
if not (self.py_version < (3, 5) and proto == 4):
3503+
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
3504+
2 <= proto)
3505+
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
34543506
y = self.loads(s) # will raise TypeError if __init__ called
34553507
self.assert_is_copy(x, y)
34563508

@@ -3471,9 +3523,10 @@ def test_complex_newobj(self):
34713523
self.assertIn(b'X\x04\x00\x00\x00FACE', s) # BINUNICODE
34723524
else:
34733525
self.assertIn(b'\x8c\x04FACE', s) # SHORT_BINUNICODE
3474-
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
3475-
2 <= proto)
3476-
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
3526+
if not (self.py_version < (3, 5) and proto == 4):
3527+
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
3528+
2 <= proto)
3529+
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ_EX, s))
34773530
y = self.loads(s) # will raise TypeError if __init__ called
34783531
self.assert_is_copy(x, y)
34793532

@@ -3608,6 +3661,8 @@ def test_large_pickles(self):
36083661

36093662
def test_int_pickling_efficiency(self):
36103663
# Test compacity of int representation (see issue #12744)
3664+
if self.py_version < (3, 3):
3665+
self.skipTest('not supported in Python < 3.3')
36113666
for proto in protocols:
36123667
with self.subTest(proto=proto):
36133668
pickles = [self.dumps(2**n, proto) for n in range(70)]
@@ -3852,7 +3907,12 @@ def concatenate_chunks(self):
38523907
chunk_sizes)
38533908

38543909
def test_nested_names(self):
3910+
if self.py_version < (3, 4):
3911+
self.skipTest('not supported in Python < 3.4')
3912+
# required protocol 4 in Python 3.4
38553913
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
3914+
if self.py_version < (3, 5) and proto < 4:
3915+
continue
38563916
for obj in [Nested.A, Nested.A.B, Nested.A.B.C]:
38573917
with self.subTest(proto=proto, obj=obj):
38583918
unpickled = self.loads(self.dumps(obj, proto))
@@ -3883,10 +3943,21 @@ class Recursive:
38833943
del Recursive.ref # break reference loop
38843944

38853945
def test_py_methods(self):
3946+
if self.py_version < (3, 4):
3947+
self.skipTest('not supported in Python < 3.4')
38863948
py_methods = (
3887-
PyMethodsTest.cheese,
38883949
PyMethodsTest.wine,
38893950
PyMethodsTest().biscuits,
3951+
)
3952+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
3953+
for method in py_methods:
3954+
with self.subTest(proto=proto, method=method):
3955+
unpickled = self.loads(self.dumps(method, proto))
3956+
self.assertEqual(method(), unpickled())
3957+
3958+
# required protocol 4 in Python 3.4
3959+
py_methods = (
3960+
PyMethodsTest.cheese,
38903961
PyMethodsTest.Nested.ketchup,
38913962
PyMethodsTest.Nested.maple,
38923963
PyMethodsTest.Nested().pie
@@ -3896,6 +3967,8 @@ def test_py_methods(self):
38963967
(PyMethodsTest.Nested.pie, PyMethodsTest.Nested)
38973968
)
38983969
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
3970+
if self.py_version < (3, 5) and proto < 4:
3971+
continue
38993972
for method in py_methods:
39003973
with self.subTest(proto=proto, method=method):
39013974
unpickled = self.loads(self.dumps(method, proto))
@@ -3916,6 +3989,8 @@ def test_py_methods(self):
39163989
self.assertRaises(TypeError, self.dumps, descr, proto)
39173990

39183991
def test_c_methods(self):
3992+
if self.py_version < (3, 4):
3993+
self.skipTest('not supported in Python < 3.4')
39193994
c_methods = (
39203995
# bound built-in method
39213996
("abcd".index, ("c",)),
@@ -3936,7 +4011,6 @@ def test_c_methods(self):
39364011
# subclass methods
39374012
(Subclass([1,2,2]).count, (2,)),
39384013
(Subclass.count, (Subclass([1,2,2]), 2)),
3939-
(Subclass.Nested("sweet").count, ("e",)),
39404014
(Subclass.Nested.count, (Subclass.Nested("sweet"), "e")),
39414015
)
39424016
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
@@ -3945,6 +4019,18 @@ def test_c_methods(self):
39454019
unpickled = self.loads(self.dumps(method, proto))
39464020
self.assertEqual(method(*args), unpickled(*args))
39474021

4022+
# required protocol 4 in Python 3.4
4023+
c_methods = (
4024+
(Subclass.Nested("sweet").count, ("e",)),
4025+
)
4026+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
4027+
if self.py_version < (3, 5) and proto < 4:
4028+
continue
4029+
for method, args in c_methods:
4030+
with self.subTest(proto=proto, method=method):
4031+
unpickled = self.loads(self.dumps(method, proto))
4032+
self.assertEqual(method(*args), unpickled(*args))
4033+
39484034
descriptors = (
39494035
bytearray.__dict__['maketrans'], # built-in static method descriptor
39504036
dict.__dict__['fromkeys'], # built-in class method descriptor
@@ -3955,6 +4041,8 @@ def test_c_methods(self):
39554041
self.assertRaises(TypeError, self.dumps, descr, proto)
39564042

39574043
def test_compat_pickle(self):
4044+
if self.py_version < (3, 4):
4045+
self.skipTest("doesn't work in Python < 3.4'")
39584046
tests = [
39594047
(range(1, 7), '__builtin__', 'xrange'),
39604048
(map(int, '123'), 'itertools', 'imap'),

Lib/test/test_xpickle.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This test covers backwards compatibility with
2-
# previous version of Python by bouncing pickled objects through Python 3.5
2+
# previous version of Python by bouncing pickled objects through Python 3.2
33
# and the current version by running xpickle_worker.py.
44
import io
55
import os
@@ -222,7 +222,7 @@ def make_test(py_version, base):
222222
def load_tests(loader, tests, pattern):
223223
major = sys.version_info.major
224224
assert major == 3
225-
for minor in range(5, sys.version_info.minor):
225+
for minor in range(2, sys.version_info.minor):
226226
test_class = make_test((major, minor), PyPicklePythonCompat)
227227
tests.addTest(loader.loadTestsFromTestCase(test_class))
228228
if has_c_implementation:

0 commit comments

Comments
 (0)