Skip to content

Commit 66a19ef

Browse files
Enable more tests.
1 parent c00dbc2 commit 66a19ef

File tree

3 files changed

+109
-116
lines changed

3 files changed

+109
-116
lines changed

Lib/test/picklecommon.py

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -295,89 +295,6 @@ def _reconstruct(cls, obj):
295295
return cls(obj)
296296

297297

298-
try:
299-
import _testbuffer
300-
except ImportError:
301-
_testbuffer = None
302-
303-
if _testbuffer is not None:
304-
305-
class PicklableNDArray:
306-
# A not-really-zero-copy picklable ndarray, as the ndarray()
307-
# constructor doesn't allow for it
308-
309-
zero_copy_reconstruct = False
310-
311-
def __init__(self, *args, **kwargs):
312-
self.array = _testbuffer.ndarray(*args, **kwargs)
313-
314-
def __getitem__(self, idx):
315-
cls = type(self)
316-
new = cls.__new__(cls)
317-
new.array = self.array[idx]
318-
return new
319-
320-
@property
321-
def readonly(self):
322-
return self.array.readonly
323-
324-
@property
325-
def c_contiguous(self):
326-
return self.array.c_contiguous
327-
328-
@property
329-
def f_contiguous(self):
330-
return self.array.f_contiguous
331-
332-
def __eq__(self, other):
333-
if not isinstance(other, PicklableNDArray):
334-
return NotImplemented
335-
return (other.array.format == self.array.format and
336-
other.array.shape == self.array.shape and
337-
other.array.strides == self.array.strides and
338-
other.array.readonly == self.array.readonly and
339-
other.array.tobytes() == self.array.tobytes())
340-
341-
def __ne__(self, other):
342-
if not isinstance(other, PicklableNDArray):
343-
return NotImplemented
344-
return not (self == other)
345-
346-
def __repr__(self):
347-
return ("{name}(shape={array.shape},"
348-
"strides={array.strides}, "
349-
"bytes={array.tobytes()})").format(
350-
name=type(self).__name__, array=self.array.shape)
351-
352-
def __reduce_ex__(self, protocol):
353-
if not self.array.contiguous:
354-
raise NotImplementedError("Reconstructing a non-contiguous "
355-
"ndarray does not seem possible")
356-
ndarray_kwargs = {"shape": self.array.shape,
357-
"strides": self.array.strides,
358-
"format": self.array.format,
359-
"flags": (0 if self.readonly
360-
else _testbuffer.ND_WRITABLE)}
361-
import pickle
362-
pb = pickle.PickleBuffer(self.array)
363-
if protocol >= 5:
364-
return (type(self)._reconstruct,
365-
(pb, ndarray_kwargs))
366-
else:
367-
# Need to serialize the bytes in physical order
368-
with pb.raw() as m:
369-
return (type(self)._reconstruct,
370-
(m.tobytes(), ndarray_kwargs))
371-
372-
@classmethod
373-
def _reconstruct(cls, obj, kwargs):
374-
with memoryview(obj) as m:
375-
# For some reason, ndarray() wants a list of integers...
376-
# XXX This only works if format == 'B'
377-
items = list(m.tobytes())
378-
return cls(items, **kwargs)
379-
380-
381298
# For test_nested_names
382299
class Nested:
383300
class A:

Lib/test/pickletester.py

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,83 @@ def create_dynamic_class(name, bases):
158158
return result
159159

160160

161+
if _testbuffer is not None:
162+
163+
class PicklableNDArray:
164+
# A not-really-zero-copy picklable ndarray, as the ndarray()
165+
# constructor doesn't allow for it
166+
167+
zero_copy_reconstruct = False
168+
169+
def __init__(self, *args, **kwargs):
170+
self.array = _testbuffer.ndarray(*args, **kwargs)
171+
172+
def __getitem__(self, idx):
173+
cls = type(self)
174+
new = cls.__new__(cls)
175+
new.array = self.array[idx]
176+
return new
177+
178+
@property
179+
def readonly(self):
180+
return self.array.readonly
181+
182+
@property
183+
def c_contiguous(self):
184+
return self.array.c_contiguous
185+
186+
@property
187+
def f_contiguous(self):
188+
return self.array.f_contiguous
189+
190+
def __eq__(self, other):
191+
if not isinstance(other, PicklableNDArray):
192+
return NotImplemented
193+
return (other.array.format == self.array.format and
194+
other.array.shape == self.array.shape and
195+
other.array.strides == self.array.strides and
196+
other.array.readonly == self.array.readonly and
197+
other.array.tobytes() == self.array.tobytes())
198+
199+
def __ne__(self, other):
200+
if not isinstance(other, PicklableNDArray):
201+
return NotImplemented
202+
return not (self == other)
203+
204+
def __repr__(self):
205+
return ("{name}(shape={array.shape},"
206+
"strides={array.strides}, "
207+
"bytes={array.tobytes()})").format(
208+
name=type(self).__name__, array=self.array.shape)
209+
210+
def __reduce_ex__(self, protocol):
211+
if not self.array.contiguous:
212+
raise NotImplementedError("Reconstructing a non-contiguous "
213+
"ndarray does not seem possible")
214+
ndarray_kwargs = {"shape": self.array.shape,
215+
"strides": self.array.strides,
216+
"format": self.array.format,
217+
"flags": (0 if self.readonly
218+
else _testbuffer.ND_WRITABLE)}
219+
pb = pickle.PickleBuffer(self.array)
220+
if protocol >= 5:
221+
return (type(self)._reconstruct,
222+
(pb, ndarray_kwargs))
223+
else:
224+
# Need to serialize the bytes in physical order
225+
with pb.raw() as m:
226+
return (type(self)._reconstruct,
227+
(m.tobytes(), ndarray_kwargs))
228+
229+
@classmethod
230+
def _reconstruct(cls, obj, kwargs):
231+
with memoryview(obj) as m:
232+
# For some reason, ndarray() wants a list of integers...
233+
# XXX This only works if format == 'B'
234+
items = list(m.tobytes())
235+
return cls(items, **kwargs)
236+
237+
161238
# DATA0 .. DATA4 are the pickles we expect under the various protocols, for
162239
# the object returned by create_data().
163240

@@ -3082,6 +3159,8 @@ def test_proto(self):
30823159
self.assertEqual(count_opcode(pickle.PROTO, pickled), 0)
30833160

30843161
def test_bad_proto(self):
3162+
if self.py_version < (3, 8):
3163+
self.skipTest('No protocol validation in this version')
30853164
oob = protocols[-1] + 1 # a future protocol
30863165
build_none = pickle.NONE + pickle.STOP
30873166
badpickle = pickle.PROTO + bytes([oob]) + build_none
@@ -3363,7 +3442,10 @@ def test_simple_newobj(self):
33633442
with self.subTest(proto=proto):
33643443
s = self.dumps(x, proto)
33653444
if proto < 1:
3366-
self.assertIn(b'\nI64206', s) # INT
3445+
if self.py_version >= (3, 7):
3446+
self.assertIn(b'\nI64206', s) # INT
3447+
else: # for test_xpickle
3448+
self.assertIn(b'64206', s) # INT or LONG
33673449
else:
33683450
self.assertIn(b'M\xce\xfa', s) # BININT2
33693451
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s),
@@ -3379,7 +3461,10 @@ def test_complex_newobj(self):
33793461
with self.subTest(proto=proto):
33803462
s = self.dumps(x, proto)
33813463
if proto < 1:
3382-
self.assertIn(b'\nI64206', s) # INT
3464+
if self.py_version >= (3, 7):
3465+
self.assertIn(b'\nI64206', s) # INT
3466+
else: # for test_xpickle
3467+
self.assertIn(b'64206', s) # INT or LONG
33833468
elif proto < 2:
33843469
self.assertIn(b'M\xce\xfa', s) # BININT2
33853470
elif proto < 4:
@@ -3395,11 +3480,14 @@ def test_complex_newobj(self):
33953480
def test_complex_newobj_ex(self):
33963481
x = ComplexNewObjEx.__new__(ComplexNewObjEx, 0xface) # avoid __init__
33973482
x.abc = 666
3398-
for proto in protocols:
3483+
for proto in protocols if self.py_version >= (3, 6) else protocols[4:]:
33993484
with self.subTest(proto=proto):
34003485
s = self.dumps(x, proto)
34013486
if proto < 1:
3402-
self.assertIn(b'\nI64206', s) # INT
3487+
if self.py_version >= (3, 7):
3488+
self.assertIn(b'\nI64206', s) # INT
3489+
else: # for test_xpickle
3490+
self.assertIn(b'64206', s) # INT or LONG
34033491
elif proto < 2:
34043492
self.assertIn(b'M\xce\xfa', s) # BININT2
34053493
elif proto < 4:
@@ -3648,11 +3736,12 @@ def test_framing_large_objects(self):
36483736
[len(x) for x in unpickled])
36493737
# Perform full equality check if the lengths match.
36503738
self.assertEqual(obj, unpickled)
3651-
n_frames = count_opcode(pickle.FRAME, pickled)
3652-
# A single frame for small objects between
3653-
# first two large objects.
3654-
self.assertEqual(n_frames, 1)
3655-
self.check_frame_opcodes(pickled)
3739+
if self.py_version >= (3, 7):
3740+
n_frames = count_opcode(pickle.FRAME, pickled)
3741+
# A single frame for small objects between
3742+
# first two large objects.
3743+
self.assertEqual(n_frames, 1)
3744+
self.check_frame_opcodes(pickled)
36563745

36573746
def test_optional_frames(self):
36583747
if pickle.HIGHEST_PROTOCOL < 4:

Lib/test/test_xpickle.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def have_python_version(py_version):
8282
return py_executable_map.get(py_version, None)
8383

8484

85+
@support.requires_resource('cpu')
8586
class AbstractCompatTests(pickletester.AbstractPickleTests):
8687
py_version = None
8788
_OLD_HIGHEST_PROTOCOL = pickle.HIGHEST_PROTOCOL
@@ -197,6 +198,16 @@ def test_bytes(self):
197198
# Expected exception is raised during unpickling in a subprocess.
198199
test_pickle_setstate_None = None
199200

201+
# Other Python version may not have NumPy.
202+
test_buffers_numpy = None
203+
204+
# Skip tests that require buffer_callback arguments since
205+
# there isn't a reliable way to marshal/pickle the callback and ensure
206+
# it works in a different Python version.
207+
test_in_band_buffers = None
208+
test_buffers_error = None
209+
test_oob_buffers = None
210+
test_oob_buffers_writable_to_readonly = None
200211

201212
class PyPicklePythonCompat(AbstractCompatTests):
202213
pickler = pickle._Pickler
@@ -208,32 +219,8 @@ class CPicklePythonCompat(AbstractCompatTests):
208219
unpickler = _pickle.Unpickler
209220

210221

211-
skip_tests = {
212-
(3, 6): [
213-
# This version has changes in framing using protocol 4
214-
'test_framing_large_objects',
215-
216-
# These fail for protocol 0
217-
'test_simple_newobj',
218-
'test_complex_newobj',
219-
'test_complex_newobj_ex',
220-
],
221-
(3, 7): [
222-
# This version does not support buffers
223-
'test_in_band_buffers',
224-
225-
# No protocol validation in this version
226-
'test_bad_proto',
227-
],
228-
}
229-
230-
231222
def make_test(py_version, base):
232223
class_dict = {'py_version': py_version}
233-
for key, value in skip_tests.items():
234-
if py_version <= key:
235-
for test_name in value:
236-
class_dict[test_name] = None
237224
name = base.__name__.replace('Python', 'Python%d%d' % py_version)
238225
return type(name, (base, unittest.TestCase), class_dict)
239226

0 commit comments

Comments
 (0)