blob: 8dc93d2a5bf2e6f0389af41058a640d733bc41b1 [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
35
36 def loads(self, buf, **kwds):
37 f = io.BytesIO(buf)
38 u = self.unpickler(f, **kwds)
39 return u.load()
40
41
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000042class PyPicklerTests(AbstractPickleTests):
Jeremy Hylton66426532001-10-15 21:38:56 +000043
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000044 pickler = pickle._Pickler
45 unpickler = pickle._Unpickler
Jeremy Hylton66426532001-10-15 21:38:56 +000046
Guido van Rossumf4169812008-03-17 22:56:06 +000047 def dumps(self, arg, proto=None):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000048 f = io.BytesIO()
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000049 p = self.pickler(f, proto)
Jeremy Hylton66426532001-10-15 21:38:56 +000050 p.dump(arg)
51 f.seek(0)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000052 return bytes(f.read())
Jeremy Hylton66426532001-10-15 21:38:56 +000053
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000054 def loads(self, buf, **kwds):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000055 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000056 u = self.unpickler(f, **kwds)
Jeremy Hylton66426532001-10-15 21:38:56 +000057 return u.load()
58
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000059
Serhiy Storchakac6b54b42015-09-29 15:33:24 +030060class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
61 BigmemPickleTests):
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000062
63 pickler = pickle._Pickler
64 unpickler = pickle._Unpickler
65
Antoine Pitrou82be19f2011-08-29 23:09:33 +020066 def dumps(self, arg, protocol=None):
67 return pickle.dumps(arg, protocol)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000068
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000069 def loads(self, buf, **kwds):
70 return pickle.loads(buf, **kwds)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000071
72
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000073class PyPersPicklerTests(AbstractPersistentPicklerTests):
74
75 pickler = pickle._Pickler
76 unpickler = pickle._Unpickler
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000077
Guido van Rossumf4169812008-03-17 22:56:06 +000078 def dumps(self, arg, proto=None):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000079 class PersPickler(self.pickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000080 def persistent_id(subself, obj):
81 return self.persistent_id(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000082 f = io.BytesIO()
Guido van Rossum9d32bb12003-01-28 03:51:53 +000083 p = PersPickler(f, proto)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000084 p.dump(arg)
85 f.seek(0)
86 return f.read()
87
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000088 def loads(self, buf, **kwds):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000089 class PersUnpickler(self.unpickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000090 def persistent_load(subself, obj):
91 return self.persistent_load(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000092 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000093 u = PersUnpickler(f, **kwds)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000094 return u.load()
95
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000096
Collin Winter771d8342009-04-16 03:18:06 +000097class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
98
99 pickler_class = pickle._Pickler
100 unpickler_class = pickle._Unpickler
101
102
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100103class PyDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800104
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100105 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800106
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100107 def get_dispatch_table(self):
108 return pickle.dispatch_table.copy()
109
110
111class PyChainDispatchTableTests(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 collections.ChainMap({}, pickle.dispatch_table)
117
118
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000119if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300120 class CUnpicklerTests(PyUnpicklerTests):
121 unpickler = _pickle.Unpickler
122
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000123 class CPicklerTests(PyPicklerTests):
124 pickler = _pickle.Pickler
125 unpickler = _pickle.Unpickler
126
127 class CPersPicklerTests(PyPersPicklerTests):
128 pickler = _pickle.Pickler
129 unpickler = _pickle.Unpickler
130
Collin Winter771d8342009-04-16 03:18:06 +0000131 class CDumpPickle_LoadPickle(PyPicklerTests):
132 pickler = _pickle.Pickler
133 unpickler = pickle._Unpickler
134
135 class DumpPickle_CLoadPickle(PyPicklerTests):
136 pickler = pickle._Pickler
137 unpickler = _pickle.Unpickler
138
139 class CPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
140 pickler_class = _pickle.Pickler
141 unpickler_class = _pickle.Unpickler
142
Christian Heimesa24b4d22013-07-01 15:17:45 +0200143 def test_issue18339(self):
144 unpickler = self.unpickler_class(io.BytesIO())
Christian Heimes21782482013-07-01 23:00:13 +0200145 with self.assertRaises(TypeError):
146 unpickler.memo = object
Christian Heimesa24b4d22013-07-01 15:17:45 +0200147 # used to cause a segfault
Christian Heimes21782482013-07-01 23:00:13 +0200148 with self.assertRaises(ValueError):
149 unpickler.memo = {-1: None}
Christian Heimesa24b4d22013-07-01 15:17:45 +0200150 unpickler.memo = {1: None}
151
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100152 class CDispatchTableTests(AbstractDispatchTableTests):
153 pickler_class = pickle.Pickler
154 def get_dispatch_table(self):
155 return pickle.dispatch_table.copy()
156
157 class CChainDispatchTableTests(AbstractDispatchTableTests):
158 pickler_class = pickle.Pickler
159 def get_dispatch_table(self):
160 return collections.ChainMap({}, pickle.dispatch_table)
161
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200162 @support.cpython_only
163 class SizeofTests(unittest.TestCase):
164 check_sizeof = support.check_sizeof
165
166 def test_pickler(self):
167 basesize = support.calcobjsize('5P2n3i2n3iP')
168 p = _pickle.Pickler(io.BytesIO())
169 self.assertEqual(object.__sizeof__(p), basesize)
170 MT_size = struct.calcsize('3nP0n')
171 ME_size = struct.calcsize('Pn0P')
172 check = self.check_sizeof
173 check(p, basesize +
174 MT_size + 8 * ME_size + # Minimal memo table size.
175 sys.getsizeof(b'x'*4096)) # Minimal write buffer size.
176 for i in range(6):
177 p.dump(chr(i))
178 check(p, basesize +
179 MT_size + 32 * ME_size + # Size of memo table required to
180 # save references to 6 objects.
181 0) # Write buffer is cleared after every dump().
182
183 def test_unpickler(self):
184 basesize = support.calcobjsize('2Pn2P 2P2n2i5P 2P3n6P2n2i')
185 unpickler = _pickle.Unpickler
186 P = struct.calcsize('P') # Size of memo table entry.
187 n = struct.calcsize('n') # Size of mark table entry.
188 check = self.check_sizeof
189 for encoding in 'ASCII', 'UTF-16', 'latin-1':
190 for errors in 'strict', 'replace':
191 u = unpickler(io.BytesIO(),
192 encoding=encoding, errors=errors)
193 self.assertEqual(object.__sizeof__(u), basesize)
194 check(u, basesize +
195 32 * P + # Minimal memo table size.
196 len(encoding) + 1 + len(errors) + 1)
197
198 stdsize = basesize + len('ASCII') + 1 + len('strict') + 1
199 def check_unpickler(data, memo_size, marks_size):
200 dump = pickle.dumps(data)
201 u = unpickler(io.BytesIO(dump),
202 encoding='ASCII', errors='strict')
203 u.load()
204 check(u, stdsize + memo_size * P + marks_size * n)
205
206 check_unpickler(0, 32, 0)
207 # 20 is minimal non-empty mark stack size.
208 check_unpickler([0] * 100, 32, 20)
209 # 128 is memo table size required to save references to 100 objects.
210 check_unpickler([chr(i) for i in range(100)], 128, 20)
211 def recurse(deep):
212 data = 0
213 for i in range(deep):
214 data = [data, data]
215 return data
216 check_unpickler(recurse(0), 32, 0)
217 check_unpickler(recurse(1), 32, 20)
218 check_unpickler(recurse(20), 32, 58)
219 check_unpickler(recurse(50), 64, 58)
220 check_unpickler(recurse(100), 128, 134)
221
222 u = unpickler(io.BytesIO(pickle.dumps('a', 0)),
223 encoding='ASCII', errors='strict')
224 u.load()
225 check(u, stdsize + 32 * P + 2 + 1)
226
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000227
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300228ALT_IMPORT_MAPPING = {
229 ('_elementtree', 'xml.etree.ElementTree'),
230 ('cPickle', 'pickle'),
231}
232
233ALT_NAME_MAPPING = {
234 ('__builtin__', 'basestring', 'builtins', 'str'),
235 ('exceptions', 'StandardError', 'builtins', 'Exception'),
236 ('UserDict', 'UserDict', 'collections', 'UserDict'),
237 ('socket', '_socketobject', 'socket', 'SocketType'),
238}
239
240def mapping(module, name):
241 if (module, name) in NAME_MAPPING:
242 module, name = NAME_MAPPING[(module, name)]
243 elif module in IMPORT_MAPPING:
244 module = IMPORT_MAPPING[module]
245 return module, name
246
247def reverse_mapping(module, name):
248 if (module, name) in REVERSE_NAME_MAPPING:
249 module, name = REVERSE_NAME_MAPPING[(module, name)]
250 elif module in REVERSE_IMPORT_MAPPING:
251 module = REVERSE_IMPORT_MAPPING[module]
252 return module, name
253
254def getmodule(module):
255 try:
256 return sys.modules[module]
257 except KeyError:
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300258 try:
259 __import__(module)
260 except AttributeError as exc:
261 if support.verbose:
262 print("Can't import module %r: %s" % (module, exc))
263 raise ImportError
264 except ImportError as exc:
265 if support.verbose:
266 print(exc)
267 raise
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300268 return sys.modules[module]
269
270def getattribute(module, name):
271 obj = getmodule(module)
272 for n in name.split('.'):
273 obj = getattr(obj, n)
274 return obj
275
276def get_exceptions(mod):
277 for name in dir(mod):
278 attr = getattr(mod, name)
279 if isinstance(attr, type) and issubclass(attr, BaseException):
280 yield name, attr
281
282class CompatPickleTests(unittest.TestCase):
283 def test_import(self):
284 modules = set(IMPORT_MAPPING.values())
285 modules |= set(REVERSE_IMPORT_MAPPING)
286 modules |= {module for module, name in REVERSE_NAME_MAPPING}
287 modules |= {module for module, name in NAME_MAPPING.values()}
288 for module in modules:
289 try:
290 getmodule(module)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300291 except ImportError:
292 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300293
294 def test_import_mapping(self):
295 for module3, module2 in REVERSE_IMPORT_MAPPING.items():
296 with self.subTest((module3, module2)):
297 try:
298 getmodule(module3)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300299 except ImportError:
300 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300301 if module3[:1] != '_':
302 self.assertIn(module2, IMPORT_MAPPING)
303 self.assertEqual(IMPORT_MAPPING[module2], module3)
304
305 def test_name_mapping(self):
306 for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
307 with self.subTest(((module3, name3), (module2, name2))):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300308 if (module2, name2) == ('exceptions', 'OSError'):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300309 attr = getattribute(module3, name3)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300310 self.assertTrue(issubclass(attr, OSError))
311 else:
312 module, name = mapping(module2, name2)
313 if module3[:1] != '_':
314 self.assertEqual((module, name), (module3, name3))
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300315 try:
316 attr = getattribute(module3, name3)
317 except ImportError:
318 pass
319 else:
320 self.assertEqual(getattribute(module, name), attr)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300321
322 def test_reverse_import_mapping(self):
323 for module2, module3 in IMPORT_MAPPING.items():
324 with self.subTest((module2, module3)):
325 try:
326 getmodule(module3)
327 except ImportError as exc:
328 if support.verbose:
329 print(exc)
330 if ((module2, module3) not in ALT_IMPORT_MAPPING and
331 REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
332 for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
333 if (module3, module2) == (m3, m2):
334 break
335 else:
336 self.fail('No reverse mapping from %r to %r' %
337 (module3, module2))
338 module = REVERSE_IMPORT_MAPPING.get(module3, module3)
339 module = IMPORT_MAPPING.get(module, module)
340 self.assertEqual(module, module3)
341
342 def test_reverse_name_mapping(self):
343 for (module2, name2), (module3, name3) in NAME_MAPPING.items():
344 with self.subTest(((module2, name2), (module3, name3))):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300345 try:
346 attr = getattribute(module3, name3)
347 except ImportError:
348 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300349 module, name = reverse_mapping(module3, name3)
350 if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
351 self.assertEqual((module, name), (module2, name2))
352 module, name = mapping(module, name)
353 self.assertEqual((module, name), (module3, name3))
354
355 def test_exceptions(self):
356 self.assertEqual(mapping('exceptions', 'StandardError'),
357 ('builtins', 'Exception'))
358 self.assertEqual(mapping('exceptions', 'Exception'),
359 ('builtins', 'Exception'))
360 self.assertEqual(reverse_mapping('builtins', 'Exception'),
361 ('exceptions', 'Exception'))
362 self.assertEqual(mapping('exceptions', 'OSError'),
363 ('builtins', 'OSError'))
364 self.assertEqual(reverse_mapping('builtins', 'OSError'),
365 ('exceptions', 'OSError'))
366
367 for name, exc in get_exceptions(builtins):
368 with self.subTest(name):
369 if exc in (BlockingIOError, ResourceWarning):
370 continue
371 if exc is not OSError and issubclass(exc, OSError):
372 self.assertEqual(reverse_mapping('builtins', name),
373 ('exceptions', 'OSError'))
374 else:
375 self.assertEqual(reverse_mapping('builtins', name),
376 ('exceptions', name))
377 self.assertEqual(mapping('exceptions', name),
378 ('builtins', name))
379
Serhiy Storchaka7b2cfc42015-10-10 20:10:07 +0300380 def test_multiprocessing_exceptions(self):
381 module = support.import_module('multiprocessing.context')
382 for name, exc in get_exceptions(module):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300383 with self.subTest(name):
384 self.assertEqual(reverse_mapping('multiprocessing.context', name),
385 ('multiprocessing', name))
386 self.assertEqual(mapping('multiprocessing', name),
387 ('multiprocessing.context', name))
388
389
Fred Drake694ed092001-12-19 16:42:15 +0000390def test_main():
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300391 tests = [PickleTests, PyUnpicklerTests, PyPicklerTests, PyPersPicklerTests,
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300392 PyDispatchTableTests, PyChainDispatchTableTests,
393 CompatPickleTests]
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000394 if has_c_implementation:
Serhiy Storchakac6b54b42015-09-29 15:33:24 +0300395 tests.extend([CUnpicklerTests, CPicklerTests, CPersPicklerTests,
Collin Winter771d8342009-04-16 03:18:06 +0000396 CDumpPickle_LoadPickle, DumpPickle_CLoadPickle,
397 PyPicklerUnpicklerObjectTests,
Antoine Pitrouea99c5c2010-09-09 18:33:21 +0000398 CPicklerUnpicklerObjectTests,
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100399 CDispatchTableTests, CChainDispatchTableTests,
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200400 InMemoryPickleTests, SizeofTests])
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000401 support.run_unittest(*tests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000402 support.run_doctest(pickle)
Fred Drake694ed092001-12-19 16:42:15 +0000403
Jeremy Hylton66426532001-10-15 21:38:56 +0000404if __name__ == "__main__":
Fred Drake694ed092001-12-19 16:42:15 +0000405 test_main()