blob: ee7a667d0614f2975c44e8f17dc0dd4ac99beda6 [file] [log] [blame]
Serhiy Storchakabfe18242015-03-31 13:12:37 +03001from _compat_pickle import (IMPORT_MAPPING, REVERSE_IMPORT_MAPPING,
2 NAME_MAPPING, REVERSE_NAME_MAPPING)
3import builtins
Jeremy Hyltonbe467e52000-09-15 15:14:51 +00004import pickle
Guido van Rossumcfe5f202007-05-08 21:26:54 +00005import io
Antoine Pitrou8d3c2902012-03-04 18:31:48 +01006import collections
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +02007import struct
8import sys
Tim Peters47a6b132003-01-28 22:34:11 +00009
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +020010import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
Jeremy Hylton66426532001-10-15 21:38:56 +000012
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030013from test.pickletester import AbstractUnpickleTests
Tim Peters47a6b132003-01-28 22:34:11 +000014from test.pickletester import AbstractPickleTests
Tim Peters47a6b132003-01-28 22:34:11 +000015from test.pickletester import AbstractPickleModuleTests
16from test.pickletester import AbstractPersistentPicklerTests
Collin Winter771d8342009-04-16 03:18:06 +000017from test.pickletester import AbstractPicklerUnpicklerObjectTests
Antoine Pitrou8d3c2902012-03-04 18:31:48 +010018from test.pickletester import AbstractDispatchTableTests
Antoine Pitrou82be19f2011-08-29 23:09:33 +020019from test.pickletester import BigmemPickleTests
Tim Peters47a6b132003-01-28 22:34:11 +000020
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000021try:
22 import _pickle
23 has_c_implementation = True
24except ImportError:
25 has_c_implementation = False
Jeremy Hylton66426532001-10-15 21:38:56 +000026
Guido van Rossum98297ee2007-11-06 21:34:58 +000027
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000028class PickleTests(AbstractPickleModuleTests):
29 pass
Guido van Rossum5d9113d2003-01-29 17:58:45 +000030
Tim Peterse0c446b2001-10-18 21:57:37 +000031
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030032class PyUnpicklerTests(AbstractUnpickleTests):
33
34 unpickler = pickle._Unpickler
Serhiy Storchakae9b30742015-11-23 15:17:43 +020035 bad_stack_errors = (IndexError,)
Serhiy Storchaka7279bef2015-11-29 13:12:10 +020036 bad_mark_errors = (IndexError, pickle.UnpicklingError,
37 TypeError, AttributeError, EOFError)
38 truncated_errors = (pickle.UnpicklingError, EOFError,
39 AttributeError, ValueError,
40 struct.error, IndexError, ImportError)
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030041
42 def loads(self, buf, **kwds):
43 f = io.BytesIO(buf)
44 u = self.unpickler(f, **kwds)
45 return u.load()
46
47
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000048class PyPicklerTests(AbstractPickleTests):
Jeremy Hylton66426532001-10-15 21:38:56 +000049
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000050 pickler = pickle._Pickler
51 unpickler = pickle._Unpickler
Jeremy Hylton66426532001-10-15 21:38:56 +000052
Guido van Rossumf4169812008-03-17 22:56:06 +000053 def dumps(self, arg, proto=None):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000054 f = io.BytesIO()
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000055 p = self.pickler(f, proto)
Jeremy Hylton66426532001-10-15 21:38:56 +000056 p.dump(arg)
57 f.seek(0)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000058 return bytes(f.read())
Jeremy Hylton66426532001-10-15 21:38:56 +000059
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000060 def loads(self, buf, **kwds):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000061 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000062 u = self.unpickler(f, **kwds)
Jeremy Hylton66426532001-10-15 21:38:56 +000063 return u.load()
64
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000065
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030066class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
67 BigmemPickleTests):
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000068
69 pickler = pickle._Pickler
70 unpickler = pickle._Unpickler
Serhiy Storchakae9b30742015-11-23 15:17:43 +020071 bad_stack_errors = (pickle.UnpicklingError, IndexError)
Serhiy Storchaka7279bef2015-11-29 13:12:10 +020072 bad_mark_errors = (pickle.UnpicklingError, IndexError,
73 TypeError, AttributeError, EOFError)
74 truncated_errors = (pickle.UnpicklingError, EOFError,
75 AttributeError, ValueError,
76 struct.error, IndexError, ImportError)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000077
Antoine Pitrou82be19f2011-08-29 23:09:33 +020078 def dumps(self, arg, protocol=None):
79 return pickle.dumps(arg, protocol)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000080
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000081 def loads(self, buf, **kwds):
82 return pickle.loads(buf, **kwds)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000083
84
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000085class PyPersPicklerTests(AbstractPersistentPicklerTests):
86
87 pickler = pickle._Pickler
88 unpickler = pickle._Unpickler
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000089
Guido van Rossumf4169812008-03-17 22:56:06 +000090 def dumps(self, arg, proto=None):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000091 class PersPickler(self.pickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000092 def persistent_id(subself, obj):
93 return self.persistent_id(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000094 f = io.BytesIO()
Guido van Rossum9d32bb12003-01-28 03:51:53 +000095 p = PersPickler(f, proto)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000096 p.dump(arg)
97 f.seek(0)
98 return f.read()
99
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +0000100 def loads(self, buf, **kwds):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000101 class PersUnpickler(self.unpickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +0000102 def persistent_load(subself, obj):
103 return self.persistent_load(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +0000104 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +0000105 u = PersUnpickler(f, **kwds)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +0000106 return u.load()
107
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000108
Collin Winter771d8342009-04-16 03:18:06 +0000109class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
110
111 pickler_class = pickle._Pickler
112 unpickler_class = pickle._Unpickler
113
114
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100115class PyDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800116
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100117 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800118
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100119 def get_dispatch_table(self):
120 return pickle.dispatch_table.copy()
121
122
123class PyChainDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800124
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100125 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800126
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100127 def get_dispatch_table(self):
128 return collections.ChainMap({}, pickle.dispatch_table)
129
130
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000131if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300132 class CUnpicklerTests(PyUnpicklerTests):
133 unpickler = _pickle.Unpickler
Serhiy Storchakae9b30742015-11-23 15:17:43 +0200134 bad_stack_errors = (pickle.UnpicklingError,)
Serhiy Storchaka7279bef2015-11-29 13:12:10 +0200135 bad_mark_errors = (EOFError,)
136 truncated_errors = (pickle.UnpicklingError, EOFError,
137 AttributeError, ValueError)
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300138
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000139 class CPicklerTests(PyPicklerTests):
140 pickler = _pickle.Pickler
141 unpickler = _pickle.Unpickler
142
143 class CPersPicklerTests(PyPersPicklerTests):
144 pickler = _pickle.Pickler
145 unpickler = _pickle.Unpickler
146
Collin Winter771d8342009-04-16 03:18:06 +0000147 class CDumpPickle_LoadPickle(PyPicklerTests):
148 pickler = _pickle.Pickler
149 unpickler = pickle._Unpickler
150
151 class DumpPickle_CLoadPickle(PyPicklerTests):
152 pickler = pickle._Pickler
153 unpickler = _pickle.Unpickler
154
155 class CPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
156 pickler_class = _pickle.Pickler
157 unpickler_class = _pickle.Unpickler
158
Christian Heimesa24b4d22013-07-01 15:17:45 +0200159 def test_issue18339(self):
160 unpickler = self.unpickler_class(io.BytesIO())
Christian Heimes21782482013-07-01 23:00:13 +0200161 with self.assertRaises(TypeError):
162 unpickler.memo = object
Christian Heimesa24b4d22013-07-01 15:17:45 +0200163 # used to cause a segfault
Christian Heimes21782482013-07-01 23:00:13 +0200164 with self.assertRaises(ValueError):
165 unpickler.memo = {-1: None}
Christian Heimesa24b4d22013-07-01 15:17:45 +0200166 unpickler.memo = {1: None}
167
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100168 class CDispatchTableTests(AbstractDispatchTableTests):
169 pickler_class = pickle.Pickler
170 def get_dispatch_table(self):
171 return pickle.dispatch_table.copy()
172
173 class CChainDispatchTableTests(AbstractDispatchTableTests):
174 pickler_class = pickle.Pickler
175 def get_dispatch_table(self):
176 return collections.ChainMap({}, pickle.dispatch_table)
177
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200178 @support.cpython_only
179 class SizeofTests(unittest.TestCase):
180 check_sizeof = support.check_sizeof
181
182 def test_pickler(self):
183 basesize = support.calcobjsize('5P2n3i2n3iP')
184 p = _pickle.Pickler(io.BytesIO())
185 self.assertEqual(object.__sizeof__(p), basesize)
186 MT_size = struct.calcsize('3nP0n')
187 ME_size = struct.calcsize('Pn0P')
188 check = self.check_sizeof
189 check(p, basesize +
190 MT_size + 8 * ME_size + # Minimal memo table size.
191 sys.getsizeof(b'x'*4096)) # Minimal write buffer size.
192 for i in range(6):
193 p.dump(chr(i))
194 check(p, basesize +
195 MT_size + 32 * ME_size + # Size of memo table required to
196 # save references to 6 objects.
197 0) # Write buffer is cleared after every dump().
198
199 def test_unpickler(self):
200 basesize = support.calcobjsize('2Pn2P 2P2n2i5P 2P3n6P2n2i')
201 unpickler = _pickle.Unpickler
202 P = struct.calcsize('P') # Size of memo table entry.
203 n = struct.calcsize('n') # Size of mark table entry.
204 check = self.check_sizeof
205 for encoding in 'ASCII', 'UTF-16', 'latin-1':
206 for errors in 'strict', 'replace':
207 u = unpickler(io.BytesIO(),
208 encoding=encoding, errors=errors)
209 self.assertEqual(object.__sizeof__(u), basesize)
210 check(u, basesize +
211 32 * P + # Minimal memo table size.
212 len(encoding) + 1 + len(errors) + 1)
213
214 stdsize = basesize + len('ASCII') + 1 + len('strict') + 1
215 def check_unpickler(data, memo_size, marks_size):
216 dump = pickle.dumps(data)
217 u = unpickler(io.BytesIO(dump),
218 encoding='ASCII', errors='strict')
219 u.load()
220 check(u, stdsize + memo_size * P + marks_size * n)
221
222 check_unpickler(0, 32, 0)
223 # 20 is minimal non-empty mark stack size.
224 check_unpickler([0] * 100, 32, 20)
225 # 128 is memo table size required to save references to 100 objects.
226 check_unpickler([chr(i) for i in range(100)], 128, 20)
227 def recurse(deep):
228 data = 0
229 for i in range(deep):
230 data = [data, data]
231 return data
232 check_unpickler(recurse(0), 32, 0)
233 check_unpickler(recurse(1), 32, 20)
234 check_unpickler(recurse(20), 32, 58)
235 check_unpickler(recurse(50), 64, 58)
236 check_unpickler(recurse(100), 128, 134)
237
238 u = unpickler(io.BytesIO(pickle.dumps('a', 0)),
239 encoding='ASCII', errors='strict')
240 u.load()
241 check(u, stdsize + 32 * P + 2 + 1)
242
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000243
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300244ALT_IMPORT_MAPPING = {
245 ('_elementtree', 'xml.etree.ElementTree'),
246 ('cPickle', 'pickle'),
Serhiy Storchaka5c1d9d22016-01-18 22:33:44 +0200247 ('StringIO', 'io'),
248 ('cStringIO', 'io'),
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300249}
250
251ALT_NAME_MAPPING = {
252 ('__builtin__', 'basestring', 'builtins', 'str'),
253 ('exceptions', 'StandardError', 'builtins', 'Exception'),
254 ('UserDict', 'UserDict', 'collections', 'UserDict'),
255 ('socket', '_socketobject', 'socket', 'SocketType'),
256}
257
258def mapping(module, name):
259 if (module, name) in NAME_MAPPING:
260 module, name = NAME_MAPPING[(module, name)]
261 elif module in IMPORT_MAPPING:
262 module = IMPORT_MAPPING[module]
263 return module, name
264
265def reverse_mapping(module, name):
266 if (module, name) in REVERSE_NAME_MAPPING:
267 module, name = REVERSE_NAME_MAPPING[(module, name)]
268 elif module in REVERSE_IMPORT_MAPPING:
269 module = REVERSE_IMPORT_MAPPING[module]
270 return module, name
271
272def getmodule(module):
273 try:
274 return sys.modules[module]
275 except KeyError:
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300276 try:
277 __import__(module)
278 except AttributeError as exc:
279 if support.verbose:
280 print("Can't import module %r: %s" % (module, exc))
281 raise ImportError
282 except ImportError as exc:
283 if support.verbose:
284 print(exc)
285 raise
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300286 return sys.modules[module]
287
288def getattribute(module, name):
289 obj = getmodule(module)
290 for n in name.split('.'):
291 obj = getattr(obj, n)
292 return obj
293
294def get_exceptions(mod):
295 for name in dir(mod):
296 attr = getattr(mod, name)
297 if isinstance(attr, type) and issubclass(attr, BaseException):
298 yield name, attr
299
300class CompatPickleTests(unittest.TestCase):
301 def test_import(self):
302 modules = set(IMPORT_MAPPING.values())
303 modules |= set(REVERSE_IMPORT_MAPPING)
304 modules |= {module for module, name in REVERSE_NAME_MAPPING}
305 modules |= {module for module, name in NAME_MAPPING.values()}
306 for module in modules:
307 try:
308 getmodule(module)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300309 except ImportError:
310 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300311
312 def test_import_mapping(self):
313 for module3, module2 in REVERSE_IMPORT_MAPPING.items():
314 with self.subTest((module3, module2)):
315 try:
316 getmodule(module3)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300317 except ImportError:
318 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300319 if module3[:1] != '_':
320 self.assertIn(module2, IMPORT_MAPPING)
321 self.assertEqual(IMPORT_MAPPING[module2], module3)
322
323 def test_name_mapping(self):
324 for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
325 with self.subTest(((module3, name3), (module2, name2))):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300326 if (module2, name2) == ('exceptions', 'OSError'):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300327 attr = getattribute(module3, name3)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300328 self.assertTrue(issubclass(attr, OSError))
329 else:
330 module, name = mapping(module2, name2)
331 if module3[:1] != '_':
332 self.assertEqual((module, name), (module3, name3))
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300333 try:
334 attr = getattribute(module3, name3)
335 except ImportError:
336 pass
337 else:
338 self.assertEqual(getattribute(module, name), attr)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300339
340 def test_reverse_import_mapping(self):
341 for module2, module3 in IMPORT_MAPPING.items():
342 with self.subTest((module2, module3)):
343 try:
344 getmodule(module3)
345 except ImportError as exc:
346 if support.verbose:
347 print(exc)
348 if ((module2, module3) not in ALT_IMPORT_MAPPING and
349 REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
350 for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
351 if (module3, module2) == (m3, m2):
352 break
353 else:
354 self.fail('No reverse mapping from %r to %r' %
355 (module3, module2))
356 module = REVERSE_IMPORT_MAPPING.get(module3, module3)
357 module = IMPORT_MAPPING.get(module, module)
358 self.assertEqual(module, module3)
359
360 def test_reverse_name_mapping(self):
361 for (module2, name2), (module3, name3) in NAME_MAPPING.items():
362 with self.subTest(((module2, name2), (module3, name3))):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300363 try:
364 attr = getattribute(module3, name3)
365 except ImportError:
366 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300367 module, name = reverse_mapping(module3, name3)
368 if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
369 self.assertEqual((module, name), (module2, name2))
370 module, name = mapping(module, name)
371 self.assertEqual((module, name), (module3, name3))
372
373 def test_exceptions(self):
374 self.assertEqual(mapping('exceptions', 'StandardError'),
375 ('builtins', 'Exception'))
376 self.assertEqual(mapping('exceptions', 'Exception'),
377 ('builtins', 'Exception'))
378 self.assertEqual(reverse_mapping('builtins', 'Exception'),
379 ('exceptions', 'Exception'))
380 self.assertEqual(mapping('exceptions', 'OSError'),
381 ('builtins', 'OSError'))
382 self.assertEqual(reverse_mapping('builtins', 'OSError'),
383 ('exceptions', 'OSError'))
384
385 for name, exc in get_exceptions(builtins):
386 with self.subTest(name):
Yury Selivanov75445082015-05-11 22:57:16 -0400387 if exc in (BlockingIOError,
388 ResourceWarning,
Yury Selivanovf488fb42015-07-03 01:04:23 -0400389 StopAsyncIteration,
390 RecursionError):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300391 continue
392 if exc is not OSError and issubclass(exc, OSError):
393 self.assertEqual(reverse_mapping('builtins', name),
394 ('exceptions', 'OSError'))
395 else:
396 self.assertEqual(reverse_mapping('builtins', name),
397 ('exceptions', name))
398 self.assertEqual(mapping('exceptions', name),
399 ('builtins', name))
400
Serhiy Storchaka7b2cfc42015-10-10 20:10:07 +0300401 def test_multiprocessing_exceptions(self):
402 module = support.import_module('multiprocessing.context')
403 for name, exc in get_exceptions(module):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300404 with self.subTest(name):
405 self.assertEqual(reverse_mapping('multiprocessing.context', name),
406 ('multiprocessing', name))
407 self.assertEqual(mapping('multiprocessing', name),
408 ('multiprocessing.context', name))
409
410
Fred Drake694ed092001-12-19 16:42:15 +0000411def test_main():
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300412 tests = [PickleTests, PyUnpicklerTests, PyPicklerTests, PyPersPicklerTests,
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300413 PyDispatchTableTests, PyChainDispatchTableTests,
414 CompatPickleTests]
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000415 if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300416 tests.extend([CUnpicklerTests, CPicklerTests, CPersPicklerTests,
Collin Winter771d8342009-04-16 03:18:06 +0000417 CDumpPickle_LoadPickle, DumpPickle_CLoadPickle,
418 PyPicklerUnpicklerObjectTests,
Antoine Pitrouea99c5c2010-09-09 18:33:21 +0000419 CPicklerUnpicklerObjectTests,
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100420 CDispatchTableTests, CChainDispatchTableTests,
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200421 InMemoryPickleTests, SizeofTests])
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000422 support.run_unittest(*tests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000423 support.run_doctest(pickle)
Fred Drake694ed092001-12-19 16:42:15 +0000424
Jeremy Hylton66426532001-10-15 21:38:56 +0000425if __name__ == "__main__":
Fred Drake694ed092001-12-19 16:42:15 +0000426 test_main()