blob: 6b9731543885b409d03892fd37a45fb5a5674567 [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'),
242}
243
244ALT_NAME_MAPPING = {
245 ('__builtin__', 'basestring', 'builtins', 'str'),
246 ('exceptions', 'StandardError', 'builtins', 'Exception'),
247 ('UserDict', 'UserDict', 'collections', 'UserDict'),
248 ('socket', '_socketobject', 'socket', 'SocketType'),
249}
250
251def mapping(module, name):
252 if (module, name) in NAME_MAPPING:
253 module, name = NAME_MAPPING[(module, name)]
254 elif module in IMPORT_MAPPING:
255 module = IMPORT_MAPPING[module]
256 return module, name
257
258def reverse_mapping(module, name):
259 if (module, name) in REVERSE_NAME_MAPPING:
260 module, name = REVERSE_NAME_MAPPING[(module, name)]
261 elif module in REVERSE_IMPORT_MAPPING:
262 module = REVERSE_IMPORT_MAPPING[module]
263 return module, name
264
265def getmodule(module):
266 try:
267 return sys.modules[module]
268 except KeyError:
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300269 try:
270 __import__(module)
271 except AttributeError as exc:
272 if support.verbose:
273 print("Can't import module %r: %s" % (module, exc))
274 raise ImportError
275 except ImportError as exc:
276 if support.verbose:
277 print(exc)
278 raise
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300279 return sys.modules[module]
280
281def getattribute(module, name):
282 obj = getmodule(module)
283 for n in name.split('.'):
284 obj = getattr(obj, n)
285 return obj
286
287def get_exceptions(mod):
288 for name in dir(mod):
289 attr = getattr(mod, name)
290 if isinstance(attr, type) and issubclass(attr, BaseException):
291 yield name, attr
292
293class CompatPickleTests(unittest.TestCase):
294 def test_import(self):
295 modules = set(IMPORT_MAPPING.values())
296 modules |= set(REVERSE_IMPORT_MAPPING)
297 modules |= {module for module, name in REVERSE_NAME_MAPPING}
298 modules |= {module for module, name in NAME_MAPPING.values()}
299 for module in modules:
300 try:
301 getmodule(module)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300302 except ImportError:
303 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300304
305 def test_import_mapping(self):
306 for module3, module2 in REVERSE_IMPORT_MAPPING.items():
307 with self.subTest((module3, module2)):
308 try:
309 getmodule(module3)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300310 except ImportError:
311 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300312 if module3[:1] != '_':
313 self.assertIn(module2, IMPORT_MAPPING)
314 self.assertEqual(IMPORT_MAPPING[module2], module3)
315
316 def test_name_mapping(self):
317 for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
318 with self.subTest(((module3, name3), (module2, name2))):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300319 if (module2, name2) == ('exceptions', 'OSError'):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300320 attr = getattribute(module3, name3)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300321 self.assertTrue(issubclass(attr, OSError))
322 else:
323 module, name = mapping(module2, name2)
324 if module3[:1] != '_':
325 self.assertEqual((module, name), (module3, name3))
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300326 try:
327 attr = getattribute(module3, name3)
328 except ImportError:
329 pass
330 else:
331 self.assertEqual(getattribute(module, name), attr)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300332
333 def test_reverse_import_mapping(self):
334 for module2, module3 in IMPORT_MAPPING.items():
335 with self.subTest((module2, module3)):
336 try:
337 getmodule(module3)
338 except ImportError as exc:
339 if support.verbose:
340 print(exc)
341 if ((module2, module3) not in ALT_IMPORT_MAPPING and
342 REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
343 for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
344 if (module3, module2) == (m3, m2):
345 break
346 else:
347 self.fail('No reverse mapping from %r to %r' %
348 (module3, module2))
349 module = REVERSE_IMPORT_MAPPING.get(module3, module3)
350 module = IMPORT_MAPPING.get(module, module)
351 self.assertEqual(module, module3)
352
353 def test_reverse_name_mapping(self):
354 for (module2, name2), (module3, name3) in NAME_MAPPING.items():
355 with self.subTest(((module2, name2), (module3, name3))):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300356 try:
357 attr = getattribute(module3, name3)
358 except ImportError:
359 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300360 module, name = reverse_mapping(module3, name3)
361 if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
362 self.assertEqual((module, name), (module2, name2))
363 module, name = mapping(module, name)
364 self.assertEqual((module, name), (module3, name3))
365
366 def test_exceptions(self):
367 self.assertEqual(mapping('exceptions', 'StandardError'),
368 ('builtins', 'Exception'))
369 self.assertEqual(mapping('exceptions', 'Exception'),
370 ('builtins', 'Exception'))
371 self.assertEqual(reverse_mapping('builtins', 'Exception'),
372 ('exceptions', 'Exception'))
373 self.assertEqual(mapping('exceptions', 'OSError'),
374 ('builtins', 'OSError'))
375 self.assertEqual(reverse_mapping('builtins', 'OSError'),
376 ('exceptions', 'OSError'))
377
378 for name, exc in get_exceptions(builtins):
379 with self.subTest(name):
Yury Selivanov75445082015-05-11 22:57:16 -0400380 if exc in (BlockingIOError,
381 ResourceWarning,
Yury Selivanovf488fb42015-07-03 01:04:23 -0400382 StopAsyncIteration,
383 RecursionError):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300384 continue
385 if exc is not OSError and issubclass(exc, OSError):
386 self.assertEqual(reverse_mapping('builtins', name),
387 ('exceptions', 'OSError'))
388 else:
389 self.assertEqual(reverse_mapping('builtins', name),
390 ('exceptions', name))
391 self.assertEqual(mapping('exceptions', name),
392 ('builtins', name))
393
Serhiy Storchaka7b2cfc42015-10-10 20:10:07 +0300394 def test_multiprocessing_exceptions(self):
395 module = support.import_module('multiprocessing.context')
396 for name, exc in get_exceptions(module):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300397 with self.subTest(name):
398 self.assertEqual(reverse_mapping('multiprocessing.context', name),
399 ('multiprocessing', name))
400 self.assertEqual(mapping('multiprocessing', name),
401 ('multiprocessing.context', name))
402
403
Fred Drake694ed092001-12-19 16:42:15 +0000404def test_main():
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300405 tests = [PickleTests, PyUnpicklerTests, PyPicklerTests, PyPersPicklerTests,
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300406 PyDispatchTableTests, PyChainDispatchTableTests,
407 CompatPickleTests]
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000408 if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300409 tests.extend([CUnpicklerTests, CPicklerTests, CPersPicklerTests,
Collin Winter771d8342009-04-16 03:18:06 +0000410 CDumpPickle_LoadPickle, DumpPickle_CLoadPickle,
411 PyPicklerUnpicklerObjectTests,
Antoine Pitrouea99c5c2010-09-09 18:33:21 +0000412 CPicklerUnpicklerObjectTests,
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100413 CDispatchTableTests, CChainDispatchTableTests,
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200414 InMemoryPickleTests, SizeofTests])
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000415 support.run_unittest(*tests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000416 support.run_doctest(pickle)
Fred Drake694ed092001-12-19 16:42:15 +0000417
Jeremy Hylton66426532001-10-15 21:38:56 +0000418if __name__ == "__main__":
Fred Drake694ed092001-12-19 16:42:15 +0000419 test_main()