blob: ba92de94c5911d386b85d3de8125266ade84c519 [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
Tim Peters47a6b132003-01-28 22:34:11 +000013from test.pickletester import AbstractPickleTests
Tim Peters47a6b132003-01-28 22:34:11 +000014from test.pickletester import AbstractPickleModuleTests
15from test.pickletester import AbstractPersistentPicklerTests
Collin Winter771d8342009-04-16 03:18:06 +000016from test.pickletester import AbstractPicklerUnpicklerObjectTests
Antoine Pitrou8d3c2902012-03-04 18:31:48 +010017from test.pickletester import AbstractDispatchTableTests
Antoine Pitrou82be19f2011-08-29 23:09:33 +020018from test.pickletester import BigmemPickleTests
Tim Peters47a6b132003-01-28 22:34:11 +000019
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000020try:
21 import _pickle
22 has_c_implementation = True
23except ImportError:
24 has_c_implementation = False
Jeremy Hylton66426532001-10-15 21:38:56 +000025
Guido van Rossum98297ee2007-11-06 21:34:58 +000026
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000027class PickleTests(AbstractPickleModuleTests):
28 pass
Guido van Rossum5d9113d2003-01-29 17:58:45 +000029
Tim Peterse0c446b2001-10-18 21:57:37 +000030
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000031class PyPicklerTests(AbstractPickleTests):
Jeremy Hylton66426532001-10-15 21:38:56 +000032
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000033 pickler = pickle._Pickler
34 unpickler = pickle._Unpickler
Jeremy Hylton66426532001-10-15 21:38:56 +000035
Guido van Rossumf4169812008-03-17 22:56:06 +000036 def dumps(self, arg, proto=None):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000037 f = io.BytesIO()
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000038 p = self.pickler(f, proto)
Jeremy Hylton66426532001-10-15 21:38:56 +000039 p.dump(arg)
40 f.seek(0)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000041 return bytes(f.read())
Jeremy Hylton66426532001-10-15 21:38:56 +000042
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000043 def loads(self, buf, **kwds):
Guido van Rossumcfe5f202007-05-08 21:26:54 +000044 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000045 u = self.unpickler(f, **kwds)
Jeremy Hylton66426532001-10-15 21:38:56 +000046 return u.load()
47
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000048
Antoine Pitrou82be19f2011-08-29 23:09:33 +020049class InMemoryPickleTests(AbstractPickleTests, BigmemPickleTests):
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000050
51 pickler = pickle._Pickler
52 unpickler = pickle._Unpickler
53
Antoine Pitrou82be19f2011-08-29 23:09:33 +020054 def dumps(self, arg, protocol=None):
55 return pickle.dumps(arg, protocol)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000056
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000057 def loads(self, buf, **kwds):
58 return pickle.loads(buf, **kwds)
Antoine Pitrouea99c5c2010-09-09 18:33:21 +000059
60
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000061class PyPersPicklerTests(AbstractPersistentPicklerTests):
62
63 pickler = pickle._Pickler
64 unpickler = pickle._Unpickler
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000065
Guido van Rossumf4169812008-03-17 22:56:06 +000066 def dumps(self, arg, proto=None):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000067 class PersPickler(self.pickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000068 def persistent_id(subself, obj):
69 return self.persistent_id(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000070 f = io.BytesIO()
Guido van Rossum9d32bb12003-01-28 03:51:53 +000071 p = PersPickler(f, proto)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000072 p.dump(arg)
73 f.seek(0)
74 return f.read()
75
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000076 def loads(self, buf, **kwds):
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000077 class PersUnpickler(self.unpickler):
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000078 def persistent_load(subself, obj):
79 return self.persistent_load(obj)
Guido van Rossumcfe5f202007-05-08 21:26:54 +000080 f = io.BytesIO(buf)
Alexander Belopolskyec8f0df2011-02-24 20:34:38 +000081 u = PersUnpickler(f, **kwds)
Jeremy Hylton5e0f4e72002-11-13 22:01:27 +000082 return u.load()
83
Alexandre Vassalottica2d6102008-06-12 18:26:05 +000084
Collin Winter771d8342009-04-16 03:18:06 +000085class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
86
87 pickler_class = pickle._Pickler
88 unpickler_class = pickle._Unpickler
89
90
Antoine Pitrou8d3c2902012-03-04 18:31:48 +010091class PyDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -080092
Antoine Pitrou8d3c2902012-03-04 18:31:48 +010093 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -080094
Antoine Pitrou8d3c2902012-03-04 18:31:48 +010095 def get_dispatch_table(self):
96 return pickle.dispatch_table.copy()
97
98
99class PyChainDispatchTableTests(AbstractDispatchTableTests):
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800100
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100101 pickler_class = pickle._Pickler
Alexandre Vassalottid05c9ff2013-12-07 01:09:27 -0800102
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100103 def get_dispatch_table(self):
104 return collections.ChainMap({}, pickle.dispatch_table)
105
106
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000107if has_c_implementation:
108 class CPicklerTests(PyPicklerTests):
109 pickler = _pickle.Pickler
110 unpickler = _pickle.Unpickler
111
112 class CPersPicklerTests(PyPersPicklerTests):
113 pickler = _pickle.Pickler
114 unpickler = _pickle.Unpickler
115
Collin Winter771d8342009-04-16 03:18:06 +0000116 class CDumpPickle_LoadPickle(PyPicklerTests):
117 pickler = _pickle.Pickler
118 unpickler = pickle._Unpickler
119
120 class DumpPickle_CLoadPickle(PyPicklerTests):
121 pickler = pickle._Pickler
122 unpickler = _pickle.Unpickler
123
124 class CPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests):
125 pickler_class = _pickle.Pickler
126 unpickler_class = _pickle.Unpickler
127
Christian Heimesa24b4d22013-07-01 15:17:45 +0200128 def test_issue18339(self):
129 unpickler = self.unpickler_class(io.BytesIO())
Christian Heimes21782482013-07-01 23:00:13 +0200130 with self.assertRaises(TypeError):
131 unpickler.memo = object
Christian Heimesa24b4d22013-07-01 15:17:45 +0200132 # used to cause a segfault
Christian Heimes21782482013-07-01 23:00:13 +0200133 with self.assertRaises(ValueError):
134 unpickler.memo = {-1: None}
Christian Heimesa24b4d22013-07-01 15:17:45 +0200135 unpickler.memo = {1: None}
136
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100137 class CDispatchTableTests(AbstractDispatchTableTests):
138 pickler_class = pickle.Pickler
139 def get_dispatch_table(self):
140 return pickle.dispatch_table.copy()
141
142 class CChainDispatchTableTests(AbstractDispatchTableTests):
143 pickler_class = pickle.Pickler
144 def get_dispatch_table(self):
145 return collections.ChainMap({}, pickle.dispatch_table)
146
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200147 @support.cpython_only
148 class SizeofTests(unittest.TestCase):
149 check_sizeof = support.check_sizeof
150
151 def test_pickler(self):
152 basesize = support.calcobjsize('5P2n3i2n3iP')
153 p = _pickle.Pickler(io.BytesIO())
154 self.assertEqual(object.__sizeof__(p), basesize)
155 MT_size = struct.calcsize('3nP0n')
156 ME_size = struct.calcsize('Pn0P')
157 check = self.check_sizeof
158 check(p, basesize +
159 MT_size + 8 * ME_size + # Minimal memo table size.
160 sys.getsizeof(b'x'*4096)) # Minimal write buffer size.
161 for i in range(6):
162 p.dump(chr(i))
163 check(p, basesize +
164 MT_size + 32 * ME_size + # Size of memo table required to
165 # save references to 6 objects.
166 0) # Write buffer is cleared after every dump().
167
168 def test_unpickler(self):
169 basesize = support.calcobjsize('2Pn2P 2P2n2i5P 2P3n6P2n2i')
170 unpickler = _pickle.Unpickler
171 P = struct.calcsize('P') # Size of memo table entry.
172 n = struct.calcsize('n') # Size of mark table entry.
173 check = self.check_sizeof
174 for encoding in 'ASCII', 'UTF-16', 'latin-1':
175 for errors in 'strict', 'replace':
176 u = unpickler(io.BytesIO(),
177 encoding=encoding, errors=errors)
178 self.assertEqual(object.__sizeof__(u), basesize)
179 check(u, basesize +
180 32 * P + # Minimal memo table size.
181 len(encoding) + 1 + len(errors) + 1)
182
183 stdsize = basesize + len('ASCII') + 1 + len('strict') + 1
184 def check_unpickler(data, memo_size, marks_size):
185 dump = pickle.dumps(data)
186 u = unpickler(io.BytesIO(dump),
187 encoding='ASCII', errors='strict')
188 u.load()
189 check(u, stdsize + memo_size * P + marks_size * n)
190
191 check_unpickler(0, 32, 0)
192 # 20 is minimal non-empty mark stack size.
193 check_unpickler([0] * 100, 32, 20)
194 # 128 is memo table size required to save references to 100 objects.
195 check_unpickler([chr(i) for i in range(100)], 128, 20)
196 def recurse(deep):
197 data = 0
198 for i in range(deep):
199 data = [data, data]
200 return data
201 check_unpickler(recurse(0), 32, 0)
202 check_unpickler(recurse(1), 32, 20)
203 check_unpickler(recurse(20), 32, 58)
204 check_unpickler(recurse(50), 64, 58)
205 check_unpickler(recurse(100), 128, 134)
206
207 u = unpickler(io.BytesIO(pickle.dumps('a', 0)),
208 encoding='ASCII', errors='strict')
209 u.load()
210 check(u, stdsize + 32 * P + 2 + 1)
211
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000212
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300213ALT_IMPORT_MAPPING = {
214 ('_elementtree', 'xml.etree.ElementTree'),
215 ('cPickle', 'pickle'),
216}
217
218ALT_NAME_MAPPING = {
219 ('__builtin__', 'basestring', 'builtins', 'str'),
220 ('exceptions', 'StandardError', 'builtins', 'Exception'),
221 ('UserDict', 'UserDict', 'collections', 'UserDict'),
222 ('socket', '_socketobject', 'socket', 'SocketType'),
223}
224
225def mapping(module, name):
226 if (module, name) in NAME_MAPPING:
227 module, name = NAME_MAPPING[(module, name)]
228 elif module in IMPORT_MAPPING:
229 module = IMPORT_MAPPING[module]
230 return module, name
231
232def reverse_mapping(module, name):
233 if (module, name) in REVERSE_NAME_MAPPING:
234 module, name = REVERSE_NAME_MAPPING[(module, name)]
235 elif module in REVERSE_IMPORT_MAPPING:
236 module = REVERSE_IMPORT_MAPPING[module]
237 return module, name
238
239def getmodule(module):
240 try:
241 return sys.modules[module]
242 except KeyError:
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300243 try:
244 __import__(module)
245 except AttributeError as exc:
246 if support.verbose:
247 print("Can't import module %r: %s" % (module, exc))
248 raise ImportError
249 except ImportError as exc:
250 if support.verbose:
251 print(exc)
252 raise
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300253 return sys.modules[module]
254
255def getattribute(module, name):
256 obj = getmodule(module)
257 for n in name.split('.'):
258 obj = getattr(obj, n)
259 return obj
260
261def get_exceptions(mod):
262 for name in dir(mod):
263 attr = getattr(mod, name)
264 if isinstance(attr, type) and issubclass(attr, BaseException):
265 yield name, attr
266
267class CompatPickleTests(unittest.TestCase):
268 def test_import(self):
269 modules = set(IMPORT_MAPPING.values())
270 modules |= set(REVERSE_IMPORT_MAPPING)
271 modules |= {module for module, name in REVERSE_NAME_MAPPING}
272 modules |= {module for module, name in NAME_MAPPING.values()}
273 for module in modules:
274 try:
275 getmodule(module)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300276 except ImportError:
277 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300278
279 def test_import_mapping(self):
280 for module3, module2 in REVERSE_IMPORT_MAPPING.items():
281 with self.subTest((module3, module2)):
282 try:
283 getmodule(module3)
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300284 except ImportError:
285 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300286 if module3[:1] != '_':
287 self.assertIn(module2, IMPORT_MAPPING)
288 self.assertEqual(IMPORT_MAPPING[module2], module3)
289
290 def test_name_mapping(self):
291 for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
292 with self.subTest(((module3, name3), (module2, name2))):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300293 if (module2, name2) == ('exceptions', 'OSError'):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300294 attr = getattribute(module3, name3)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300295 self.assertTrue(issubclass(attr, OSError))
296 else:
297 module, name = mapping(module2, name2)
298 if module3[:1] != '_':
299 self.assertEqual((module, name), (module3, name3))
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300300 try:
301 attr = getattribute(module3, name3)
302 except ImportError:
303 pass
304 else:
305 self.assertEqual(getattribute(module, name), attr)
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300306
307 def test_reverse_import_mapping(self):
308 for module2, module3 in IMPORT_MAPPING.items():
309 with self.subTest((module2, module3)):
310 try:
311 getmodule(module3)
312 except ImportError as exc:
313 if support.verbose:
314 print(exc)
315 if ((module2, module3) not in ALT_IMPORT_MAPPING and
316 REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
317 for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
318 if (module3, module2) == (m3, m2):
319 break
320 else:
321 self.fail('No reverse mapping from %r to %r' %
322 (module3, module2))
323 module = REVERSE_IMPORT_MAPPING.get(module3, module3)
324 module = IMPORT_MAPPING.get(module, module)
325 self.assertEqual(module, module3)
326
327 def test_reverse_name_mapping(self):
328 for (module2, name2), (module3, name3) in NAME_MAPPING.items():
329 with self.subTest(((module2, name2), (module3, name3))):
Serhiy Storchakab9100e52015-03-31 16:49:26 +0300330 try:
331 attr = getattribute(module3, name3)
332 except ImportError:
333 pass
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300334 module, name = reverse_mapping(module3, name3)
335 if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
336 self.assertEqual((module, name), (module2, name2))
337 module, name = mapping(module, name)
338 self.assertEqual((module, name), (module3, name3))
339
340 def test_exceptions(self):
341 self.assertEqual(mapping('exceptions', 'StandardError'),
342 ('builtins', 'Exception'))
343 self.assertEqual(mapping('exceptions', 'Exception'),
344 ('builtins', 'Exception'))
345 self.assertEqual(reverse_mapping('builtins', 'Exception'),
346 ('exceptions', 'Exception'))
347 self.assertEqual(mapping('exceptions', 'OSError'),
348 ('builtins', 'OSError'))
349 self.assertEqual(reverse_mapping('builtins', 'OSError'),
350 ('exceptions', 'OSError'))
351
352 for name, exc in get_exceptions(builtins):
353 with self.subTest(name):
Yury Selivanov75445082015-05-11 22:57:16 -0400354 if exc in (BlockingIOError,
355 ResourceWarning,
Yury Selivanovf488fb42015-07-03 01:04:23 -0400356 StopAsyncIteration,
357 RecursionError):
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300358 continue
359 if exc is not OSError and issubclass(exc, OSError):
360 self.assertEqual(reverse_mapping('builtins', name),
361 ('exceptions', 'OSError'))
362 else:
363 self.assertEqual(reverse_mapping('builtins', name),
364 ('exceptions', name))
365 self.assertEqual(mapping('exceptions', name),
366 ('builtins', name))
367
368 import multiprocessing.context
369 for name, exc in get_exceptions(multiprocessing.context):
370 with self.subTest(name):
371 self.assertEqual(reverse_mapping('multiprocessing.context', name),
372 ('multiprocessing', name))
373 self.assertEqual(mapping('multiprocessing', name),
374 ('multiprocessing.context', name))
375
376
Fred Drake694ed092001-12-19 16:42:15 +0000377def test_main():
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100378 tests = [PickleTests, PyPicklerTests, PyPersPicklerTests,
Serhiy Storchakabfe18242015-03-31 13:12:37 +0300379 PyDispatchTableTests, PyChainDispatchTableTests,
380 CompatPickleTests]
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000381 if has_c_implementation:
Collin Winter771d8342009-04-16 03:18:06 +0000382 tests.extend([CPicklerTests, CPersPicklerTests,
383 CDumpPickle_LoadPickle, DumpPickle_CLoadPickle,
384 PyPicklerUnpicklerObjectTests,
Antoine Pitrouea99c5c2010-09-09 18:33:21 +0000385 CPicklerUnpicklerObjectTests,
Antoine Pitrou8d3c2902012-03-04 18:31:48 +0100386 CDispatchTableTests, CChainDispatchTableTests,
Serhiy Storchaka5bbd2312014-12-16 19:39:08 +0200387 InMemoryPickleTests, SizeofTests])
Alexandre Vassalottica2d6102008-06-12 18:26:05 +0000388 support.run_unittest(*tests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000389 support.run_doctest(pickle)
Fred Drake694ed092001-12-19 16:42:15 +0000390
Jeremy Hylton66426532001-10-15 21:38:56 +0000391if __name__ == "__main__":
Fred Drake694ed092001-12-19 16:42:15 +0000392 test_main()