blob: e2ba1ad77a0a2c4f89459bf2104568e6d36a27e3 [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 truncated_errors = (pickle.UnpicklingError, EOFError,
37 AttributeError, ValueError,
38 struct.error, IndexError, ImportError)
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030039
40 def loads(self, buf, **kwds):
41 f = io.BytesIO(buf)
42 u = self.unpickler(f, **kwds)
43 return u.load()
44
45
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000046class PyPicklerTests(AbstractPickleTests):
Jeremy Hylton66426532001-10-15 21:38:56 +000047
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000048 pickler = pickle._Pickler
49 unpickler = pickle._Unpickler
Jeremy Hylton66426532001-10-15 21:38:56 +000050
Guido van Rossumf4169812008-03-17 22:56:06 +000051 def dumps(self, arg, proto=None):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000052 f = io.BytesIO()
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000053 p = self.pickler(f, proto)
Jeremy Hylton66426532001-10-15 21:38:56 +000054 p.dump(arg)
55 f.seek(0)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000056 return bytes(f.read())
Jeremy Hylton66426532001-10-15 21:38:56 +000057
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000058 def loads(self, buf, **kwds):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000059 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000060 u = self.unpickler(f, **kwds)
Jeremy Hylton66426532001-10-15 21:38:56 +000061 return u.load()
62
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000063
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030064class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
65 BigmemPickleTests):
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000066
67 pickler = pickle._Pickler
68 unpickler = pickle._Unpickler
Serhiy Storchakae9b30742015-11-23 15:17:43 +020069 bad_stack_errors = (pickle.UnpicklingError, IndexError)
Serhiy Storchaka7279bef2015-11-29 13:12:10 +020070 truncated_errors = (pickle.UnpicklingError, EOFError,
71 AttributeError, ValueError,
72 struct.error, IndexError, ImportError)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000073
Antoine Pitrou82be19f2011-08-29 23:09:33 +020074 def dumps(self, arg, protocol=None):
75 return pickle.dumps(arg, protocol)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000076
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000077 def loads(self, buf, **kwds):
78 return pickle.loads(buf, **kwds)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000079
80
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000081class PyPersPicklerTests(AbstractPersistentPicklerTests):
82
83 pickler = pickle._Pickler
84 unpickler = pickle._Unpickler
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000085
Guido van Rossumf4169812008-03-17 22:56:06 +000086 def dumps(self, arg, proto=None):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000087 class PersPickler(self.pickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000088 def persistent_id(subself, obj):
89 return self.persistent_id(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000090 f = io.BytesIO()
Guido van Rossum9d32bb12003-01-28 03:51:53 +000091 p = PersPickler(f, proto)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000092 p.dump(arg)
93 f.seek(0)
94 return f.read()
95
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000096 def loads(self, buf, **kwds):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000097 class PersUnpickler(self.unpickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000098 def persistent_load(subself, obj):
99 return self.persistent_load(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +0000100 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +0000101 u = PersUnpickler(f, **kwds)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +0000102 return u.load()
103
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000104
Collin Winter771d8342009-04-16 03:18:06 +0000105class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
106
107 pickler_class = pickle._Pickler
108 unpickler_class = pickle._Unpickler
109
110
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100111class PyDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800112
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100113 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800114
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100115 def get_dispatch_table(self):
116 return pickle.dispatch_table.copy()
117
118
119class PyChainDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800120
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100121 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800122
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100123 def get_dispatch_table(self):
124 return collections.ChainMap({}, pickle.dispatch_table)
125
126
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000127if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300128 class CUnpicklerTests(PyUnpicklerTests):
129 unpickler = _pickle.Unpickler
Serhiy Storchakae9b30742015-11-23 15:17:43 +0200130 bad_stack_errors = (pickle.UnpicklingError,)
Serhiy Storchaka7279bef2015-11-29 13:12:10 +0200131 truncated_errors = (pickle.UnpicklingError, EOFError,
132 AttributeError, ValueError)
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300133
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000134 class CPicklerTests(PyPicklerTests):
135 pickler = _pickle.Pickler
136 unpickler = _pickle.Unpickler
137
138 class CPersPicklerTests(PyPersPicklerTests):
139 pickler = _pickle.Pickler
140 unpickler = _pickle.Unpickler
141
Collin Winter771d8342009-04-16 03:18:06 +0000142 class CDumpPickle_LoadPickle(PyPicklerTests):
143 pickler = _pickle.Pickler
144 unpickler = pickle._Unpickler
145
146 class DumpPickle_CLoadPickle(PyPicklerTests):
147 pickler = pickle._Pickler
148 unpickler = _pickle.Unpickler
149
150 class CPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
151 pickler_class = _pickle.Pickler
152 unpickler_class = _pickle.Unpickler
153
Christian Heimesa24b4d22013-07-01 15:17:45 +0200154 def test_issue18339(self):
155 unpickler = self.unpickler_class(io.BytesIO())
Christian Heimes21782482013-07-01 23:00:13 +0200156 with self.assertRaises(TypeError):
157 unpickler.memo = object
Christian Heimesa24b4d22013-07-01 15:17:45 +0200158 # used to cause a segfault
Christian Heimes21782482013-07-01 23:00:13 +0200159 with self.assertRaises(ValueError):
160 unpickler.memo = {-1: None}
Christian Heimesa24b4d22013-07-01 15:17:45 +0200161 unpickler.memo = {1: None}
162
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100163 class CDispatchTableTests(AbstractDispatchTableTests):
164 pickler_class = pickle.Pickler
165 def get_dispatch_table(self):
166 return pickle.dispatch_table.copy()
167
168 class CChainDispatchTableTests(AbstractDispatchTableTests):
169 pickler_class = pickle.Pickler
170 def get_dispatch_table(self):
171 return collections.ChainMap({}, pickle.dispatch_table)
172
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200173 @support.cpython_only
174 class SizeofTests(unittest.TestCase):
175 check_sizeof = support.check_sizeof
176
177 def test_pickler(self):
178 basesize = support.calcobjsize('5P2n3i2n3iP')
179 p = _pickle.Pickler(io.BytesIO())
180 self.assertEqual(object.__sizeof__(p), basesize)
181 MT_size = struct.calcsize('3nP0n')
182 ME_size = struct.calcsize('Pn0P')
183 check = self.check_sizeof
184 check(p, basesize +
185 MT_size + 8 * ME_size + # Minimal memo table size.
186 sys.getsizeof(b'x'*4096)) # Minimal write buffer size.
187 for i in range(6):
188 p.dump(chr(i))
189 check(p, basesize +
190 MT_size + 32 * ME_size + # Size of memo table required to
191 # save references to 6 objects.
192 0) # Write buffer is cleared after every dump().
193
194 def test_unpickler(self):
195 basesize = support.calcobjsize('2Pn2P 2P2n2i5P 2P3n6P2n2i')
196 unpickler = _pickle.Unpickler
197 P = struct.calcsize('P') # Size of memo table entry.
198 n = struct.calcsize('n') # Size of mark table entry.
199 check = self.check_sizeof
200 for encoding in 'ASCII', 'UTF-16', 'latin-1':
201 for errors in 'strict', 'replace':
202 u = unpickler(io.BytesIO(),
203 encoding=encoding, errors=errors)
204 self.assertEqual(object.__sizeof__(u), basesize)
205 check(u, basesize +
206 32 * P + # Minimal memo table size.
207 len(encoding) + 1 + len(errors) + 1)
208
209 stdsize = basesize + len('ASCII') + 1 + len('strict') + 1
210 def check_unpickler(data, memo_size, marks_size):
211 dump = pickle.dumps(data)
212 u = unpickler(io.BytesIO(dump),
213 encoding='ASCII', errors='strict')
214 u.load()
215 check(u, stdsize + memo_size * P + marks_size * n)
216
217 check_unpickler(0, 32, 0)
218 # 20 is minimal non-empty mark stack size.
219 check_unpickler([0] * 100, 32, 20)
220 # 128 is memo table size required to save references to 100 objects.
221 check_unpickler([chr(i) for i in range(100)], 128, 20)
222 def recurse(deep):
223 data = 0
224 for i in range(deep):
225 data = [data, data]
226 return data
227 check_unpickler(recurse(0), 32, 0)
228 check_unpickler(recurse(1), 32, 20)
229 check_unpickler(recurse(20), 32, 58)
230 check_unpickler(recurse(50), 64, 58)
231 check_unpickler(recurse(100), 128, 134)
232
233 u = unpickler(io.BytesIO(pickle.dumps('a', 0)),
234 encoding='ASCII', errors='strict')
235 u.load()
236 check(u, stdsize + 32 * P + 2 + 1)
237
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000238
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300239ALT_IMPORT_MAPPING = {
240 ('_elementtree', 'xml.etree.ElementTree'),
241 ('cPickle', 'pickle'),
Serhiy Storchaka5c1d9d22016-01-18 22:33:44 +0200242 ('StringIO', 'io'),
243 ('cStringIO', 'io'),
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300244}
245
246ALT_NAME_MAPPING = {
247 ('__builtin__', 'basestring', 'builtins', 'str'),
248 ('exceptions', 'StandardError', 'builtins', 'Exception'),
249 ('UserDict', 'UserDict', 'collections', 'UserDict'),
250 ('socket', '_socketobject', 'socket', 'SocketType'),
251}
252
253def mapping(module, name):
254 if (module, name) in NAME_MAPPING:
255 module, name = NAME_MAPPING[(module, name)]
256 elif module in IMPORT_MAPPING:
257 module = IMPORT_MAPPING[module]
258 return module, name
259
260def reverse_mapping(module, name):
261 if (module, name) in REVERSE_NAME_MAPPING:
262 module, name = REVERSE_NAME_MAPPING[(module, name)]
263 elif module in REVERSE_IMPORT_MAPPING:
264 module = REVERSE_IMPORT_MAPPING[module]
265 return module, name
266
267def getmodule(module):
268 try:
269 return sys.modules[module]
270 except KeyError:
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300271 try:
272 __import__(module)
273 except AttributeError as exc:
274 if support.verbose:
275 print("Can't import module %r: %s" % (module, exc))
276 raise ImportError
277 except ImportError as exc:
278 if support.verbose:
279 print(exc)
280 raise
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300281 return sys.modules[module]
282
283def getattribute(module, name):
284 obj = getmodule(module)
285 for n in name.split('.'):
286 obj = getattr(obj, n)
287 return obj
288
289def get_exceptions(mod):
290 for name in dir(mod):
291 attr = getattr(mod, name)
292 if isinstance(attr, type) and issubclass(attr, BaseException):
293 yield name, attr
294
295class CompatPickleTests(unittest.TestCase):
296 def test_import(self):
297 modules = set(IMPORT_MAPPING.values())
298 modules |= set(REVERSE_IMPORT_MAPPING)
299 modules |= {module for module, name in REVERSE_NAME_MAPPING}
300 modules |= {module for module, name in NAME_MAPPING.values()}
301 for module in modules:
302 try:
303 getmodule(module)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300304 except ImportError:
305 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300306
307 def test_import_mapping(self):
308 for module3, module2 in REVERSE_IMPORT_MAPPING.items():
309 with self.subTest((module3, module2)):
310 try:
311 getmodule(module3)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300312 except ImportError:
313 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300314 if module3[:1] != '_':
315 self.assertIn(module2, IMPORT_MAPPING)
316 self.assertEqual(IMPORT_MAPPING[module2], module3)
317
318 def test_name_mapping(self):
319 for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
320 with self.subTest(((module3, name3), (module2, name2))):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300321 if (module2, name2) == ('exceptions', 'OSError'):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300322 attr = getattribute(module3, name3)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300323 self.assertTrue(issubclass(attr, OSError))
324 else:
325 module, name = mapping(module2, name2)
326 if module3[:1] != '_':
327 self.assertEqual((module, name), (module3, name3))
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300328 try:
329 attr = getattribute(module3, name3)
330 except ImportError:
331 pass
332 else:
333 self.assertEqual(getattribute(module, name), attr)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300334
335 def test_reverse_import_mapping(self):
336 for module2, module3 in IMPORT_MAPPING.items():
337 with self.subTest((module2, module3)):
338 try:
339 getmodule(module3)
340 except ImportError as exc:
341 if support.verbose:
342 print(exc)
343 if ((module2, module3) not in ALT_IMPORT_MAPPING and
344 REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
345 for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
346 if (module3, module2) == (m3, m2):
347 break
348 else:
349 self.fail('No reverse mapping from %r to %r' %
350 (module3, module2))
351 module = REVERSE_IMPORT_MAPPING.get(module3, module3)
352 module = IMPORT_MAPPING.get(module, module)
353 self.assertEqual(module, module3)
354
355 def test_reverse_name_mapping(self):
356 for (module2, name2), (module3, name3) in NAME_MAPPING.items():
357 with self.subTest(((module2, name2), (module3, name3))):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300358 try:
359 attr = getattribute(module3, name3)
360 except ImportError:
361 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300362 module, name = reverse_mapping(module3, name3)
363 if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
364 self.assertEqual((module, name), (module2, name2))
365 module, name = mapping(module, name)
366 self.assertEqual((module, name), (module3, name3))
367
368 def test_exceptions(self):
369 self.assertEqual(mapping('exceptions', 'StandardError'),
370 ('builtins', 'Exception'))
371 self.assertEqual(mapping('exceptions', 'Exception'),
372 ('builtins', 'Exception'))
373 self.assertEqual(reverse_mapping('builtins', 'Exception'),
374 ('exceptions', 'Exception'))
375 self.assertEqual(mapping('exceptions', 'OSError'),
376 ('builtins', 'OSError'))
377 self.assertEqual(reverse_mapping('builtins', 'OSError'),
378 ('exceptions', 'OSError'))
379
380 for name, exc in get_exceptions(builtins):
381 with self.subTest(name):
Yury Selivanov75445082015-05-11 22:57:16 -0400382 if exc in (BlockingIOError,
383 ResourceWarning,
Yury Selivanovf488fb42015-07-03 01:04:23 -0400384 StopAsyncIteration,
385 RecursionError):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300386 continue
387 if exc is not OSError and issubclass(exc, OSError):
388 self.assertEqual(reverse_mapping('builtins', name),
389 ('exceptions', 'OSError'))
390 else:
391 self.assertEqual(reverse_mapping('builtins', name),
392 ('exceptions', name))
393 self.assertEqual(mapping('exceptions', name),
394 ('builtins', name))
395
Serhiy Storchaka7b2cfc42015-10-10 20:10:07 +0300396 def test_multiprocessing_exceptions(self):
397 module = support.import_module('multiprocessing.context')
398 for name, exc in get_exceptions(module):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300399 with self.subTest(name):
400 self.assertEqual(reverse_mapping('multiprocessing.context', name),
401 ('multiprocessing', name))
402 self.assertEqual(mapping('multiprocessing', name),
403 ('multiprocessing.context', name))
404
405
Fred Drake694ed092001-12-19 16:42:15 +0000406def test_main():
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300407 tests = [PickleTests, PyUnpicklerTests, PyPicklerTests, PyPersPicklerTests,
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300408 PyDispatchTableTests, PyChainDispatchTableTests,
409 CompatPickleTests]
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000410 if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300411 tests.extend([CUnpicklerTests, CPicklerTests, CPersPicklerTests,
Collin Winter771d8342009-04-16 03:18:06 +0000412 CDumpPickle_LoadPickle, DumpPickle_CLoadPickle,
413 PyPicklerUnpicklerObjectTests,
Antoine Pitrouea99c5c2010-09-09 18:33:21 +0000414 CPicklerUnpicklerObjectTests,
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100415 CDispatchTableTests, CChainDispatchTableTests,
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200416 InMemoryPickleTests, SizeofTests])
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000417 support.run_unittest(*tests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000418 support.run_doctest(pickle)
Fred Drake694ed092001-12-19 16:42:15 +0000419
Jeremy Hylton66426532001-10-15 21:38:56 +0000420if __name__ == "__main__":
Fred Drake694ed092001-12-19 16:42:15 +0000421 test_main()