• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from _compat_pickle import (IMPORT_MAPPING, REVERSE_IMPORT_MAPPING,
2                            NAME_MAPPING, REVERSE_NAME_MAPPING)
3import builtins
4import pickle
5import io
6import collections
7import struct
8import sys
9import warnings
10import weakref
11
12import doctest
13import unittest
14from test import support
15from test.support import import_helper
16
17from test.pickletester import AbstractHookTests
18from test.pickletester import AbstractUnpickleTests
19from test.pickletester import AbstractPicklingErrorTests
20from test.pickletester import AbstractPickleTests
21from test.pickletester import AbstractPickleModuleTests
22from test.pickletester import AbstractPersistentPicklerTests
23from test.pickletester import AbstractIdentityPersistentPicklerTests
24from test.pickletester import AbstractPicklerUnpicklerObjectTests
25from test.pickletester import AbstractDispatchTableTests
26from test.pickletester import AbstractCustomPicklerClass
27from test.pickletester import BigmemPickleTests
28
29try:
30    import _pickle
31    has_c_implementation = True
32except ImportError:
33    has_c_implementation = False
34
35
36class PyPickleTests(AbstractPickleModuleTests, unittest.TestCase):
37    dump = staticmethod(pickle._dump)
38    dumps = staticmethod(pickle._dumps)
39    load = staticmethod(pickle._load)
40    loads = staticmethod(pickle._loads)
41    Pickler = pickle._Pickler
42    Unpickler = pickle._Unpickler
43
44
45class PyUnpicklerTests(AbstractUnpickleTests, unittest.TestCase):
46
47    unpickler = pickle._Unpickler
48    bad_stack_errors = (IndexError,)
49    truncated_errors = (pickle.UnpicklingError, EOFError,
50                        AttributeError, ValueError,
51                        struct.error, IndexError, ImportError)
52
53    def loads(self, buf, **kwds):
54        f = io.BytesIO(buf)
55        u = self.unpickler(f, **kwds)
56        return u.load()
57
58
59class PyPicklingErrorTests(AbstractPicklingErrorTests, unittest.TestCase):
60
61    pickler = pickle._Pickler
62
63    def dumps(self, arg, proto=None, **kwargs):
64        f = io.BytesIO()
65        p = self.pickler(f, proto, **kwargs)
66        p.dump(arg)
67        f.seek(0)
68        return bytes(f.read())
69
70
71class PyPicklerTests(AbstractPickleTests, unittest.TestCase):
72
73    pickler = pickle._Pickler
74    unpickler = pickle._Unpickler
75
76    def dumps(self, arg, proto=None, **kwargs):
77        f = io.BytesIO()
78        p = self.pickler(f, proto, **kwargs)
79        p.dump(arg)
80        f.seek(0)
81        return bytes(f.read())
82
83    def loads(self, buf, **kwds):
84        f = io.BytesIO(buf)
85        u = self.unpickler(f, **kwds)
86        return u.load()
87
88
89class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
90                          BigmemPickleTests, unittest.TestCase):
91
92    bad_stack_errors = (pickle.UnpicklingError, IndexError)
93    truncated_errors = (pickle.UnpicklingError, EOFError,
94                        AttributeError, ValueError,
95                        struct.error, IndexError, ImportError)
96
97    def dumps(self, arg, protocol=None, **kwargs):
98        return pickle.dumps(arg, protocol, **kwargs)
99
100    def loads(self, buf, **kwds):
101        return pickle.loads(buf, **kwds)
102
103    test_framed_write_sizes_with_delayed_writer = None
104    test_find_class = None
105    test_custom_find_class = None
106
107
108class PersistentPicklerUnpicklerMixin(object):
109
110    def dumps(self, arg, proto=None):
111        class PersPickler(self.pickler):
112            def persistent_id(subself, obj):
113                return self.persistent_id(obj)
114        f = io.BytesIO()
115        p = PersPickler(f, proto)
116        p.dump(arg)
117        return f.getvalue()
118
119    def loads(self, buf, **kwds):
120        class PersUnpickler(self.unpickler):
121            def persistent_load(subself, obj):
122                return self.persistent_load(obj)
123        f = io.BytesIO(buf)
124        u = PersUnpickler(f, **kwds)
125        return u.load()
126
127
128class PyPersPicklerTests(AbstractPersistentPicklerTests,
129                         PersistentPicklerUnpicklerMixin, unittest.TestCase):
130
131    pickler = pickle._Pickler
132    unpickler = pickle._Unpickler
133
134
135class PyIdPersPicklerTests(AbstractIdentityPersistentPicklerTests,
136                           PersistentPicklerUnpicklerMixin, unittest.TestCase):
137
138    pickler = pickle._Pickler
139    unpickler = pickle._Unpickler
140    persistent_load_error = pickle.UnpicklingError
141
142    @support.cpython_only
143    def test_pickler_reference_cycle(self):
144        def check(Pickler):
145            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
146                f = io.BytesIO()
147                pickler = Pickler(f, proto)
148                pickler.dump('abc')
149                self.assertEqual(self.loads(f.getvalue()), 'abc')
150            pickler = Pickler(io.BytesIO())
151            self.assertEqual(pickler.persistent_id('def'), 'def')
152            r = weakref.ref(pickler)
153            del pickler
154            self.assertIsNone(r())
155
156        class PersPickler(self.pickler):
157            def persistent_id(subself, obj):
158                return obj
159        check(PersPickler)
160
161        class PersPickler(self.pickler):
162            @classmethod
163            def persistent_id(cls, obj):
164                return obj
165        check(PersPickler)
166
167        class PersPickler(self.pickler):
168            @staticmethod
169            def persistent_id(obj):
170                return obj
171        check(PersPickler)
172
173    @support.cpython_only
174    def test_custom_pickler_dispatch_table_memleak(self):
175        # See https://github.com/python/cpython/issues/89988
176
177        class Pickler(self.pickler):
178            def __init__(self, *args, **kwargs):
179                self.dispatch_table = table
180                super().__init__(*args, **kwargs)
181
182        class DispatchTable:
183            pass
184
185        table = DispatchTable()
186        pickler = Pickler(io.BytesIO())
187        self.assertIs(pickler.dispatch_table, table)
188        table_ref = weakref.ref(table)
189        self.assertIsNotNone(table_ref())
190        del pickler
191        del table
192        support.gc_collect()
193        self.assertIsNone(table_ref())
194
195    @support.cpython_only
196    def test_unpickler_reference_cycle(self):
197        def check(Unpickler):
198            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
199                unpickler = Unpickler(io.BytesIO(self.dumps('abc', proto)))
200                self.assertEqual(unpickler.load(), 'abc')
201            unpickler = Unpickler(io.BytesIO())
202            self.assertEqual(unpickler.persistent_load('def'), 'def')
203            r = weakref.ref(unpickler)
204            del unpickler
205            self.assertIsNone(r())
206
207        class PersUnpickler(self.unpickler):
208            def persistent_load(subself, pid):
209                return pid
210        check(PersUnpickler)
211
212        class PersUnpickler(self.unpickler):
213            @classmethod
214            def persistent_load(cls, pid):
215                return pid
216        check(PersUnpickler)
217
218        class PersUnpickler(self.unpickler):
219            @staticmethod
220            def persistent_load(pid):
221                return pid
222        check(PersUnpickler)
223
224    def test_pickler_super(self):
225        class PersPickler(self.pickler):
226            def persistent_id(subself, obj):
227                called.append(obj)
228                self.assertIsNone(super().persistent_id(obj))
229                return obj
230
231        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
232            f = io.BytesIO()
233            pickler = PersPickler(f, proto)
234            called = []
235            pickler.dump('abc')
236            self.assertEqual(called, ['abc'])
237            self.assertEqual(self.loads(f.getvalue()), 'abc')
238
239    def test_unpickler_super(self):
240        class PersUnpickler(self.unpickler):
241            def persistent_load(subself, pid):
242                called.append(pid)
243                with self.assertRaises(self.persistent_load_error):
244                    super().persistent_load(pid)
245                return pid
246
247        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
248            unpickler = PersUnpickler(io.BytesIO(self.dumps('abc', proto)))
249            called = []
250            self.assertEqual(unpickler.load(), 'abc')
251            self.assertEqual(called, ['abc'])
252
253    def test_pickler_instance_attribute(self):
254        def persistent_id(obj):
255            called.append(obj)
256            return obj
257
258        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
259            f = io.BytesIO()
260            pickler = self.pickler(f, proto)
261            called = []
262            old_persistent_id = pickler.persistent_id
263            pickler.persistent_id = persistent_id
264            self.assertEqual(pickler.persistent_id, persistent_id)
265            pickler.dump('abc')
266            self.assertEqual(called, ['abc'])
267            self.assertEqual(self.loads(f.getvalue()), 'abc')
268            del pickler.persistent_id
269            self.assertEqual(pickler.persistent_id, old_persistent_id)
270
271    def test_unpickler_instance_attribute(self):
272        def persistent_load(pid):
273            called.append(pid)
274            return pid
275
276        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
277            unpickler = self.unpickler(io.BytesIO(self.dumps('abc', proto)))
278            called = []
279            old_persistent_load = unpickler.persistent_load
280            unpickler.persistent_load = persistent_load
281            self.assertEqual(unpickler.persistent_load, persistent_load)
282            self.assertEqual(unpickler.load(), 'abc')
283            self.assertEqual(called, ['abc'])
284            del unpickler.persistent_load
285            self.assertEqual(unpickler.persistent_load, old_persistent_load)
286
287    def test_pickler_super_instance_attribute(self):
288        class PersPickler(self.pickler):
289            def persistent_id(subself, obj):
290                raise AssertionError('should never be called')
291            def _persistent_id(subself, obj):
292                called.append(obj)
293                self.assertIsNone(super().persistent_id(obj))
294                return obj
295
296        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
297            f = io.BytesIO()
298            pickler = PersPickler(f, proto)
299            called = []
300            old_persistent_id = pickler.persistent_id
301            pickler.persistent_id = pickler._persistent_id
302            self.assertEqual(pickler.persistent_id, pickler._persistent_id)
303            pickler.dump('abc')
304            self.assertEqual(called, ['abc'])
305            self.assertEqual(self.loads(f.getvalue()), 'abc')
306            del pickler.persistent_id
307            self.assertEqual(pickler.persistent_id, old_persistent_id)
308
309    def test_unpickler_super_instance_attribute(self):
310        class PersUnpickler(self.unpickler):
311            def persistent_load(subself, pid):
312                raise AssertionError('should never be called')
313            def _persistent_load(subself, pid):
314                called.append(pid)
315                with self.assertRaises(self.persistent_load_error):
316                    super().persistent_load(pid)
317                return pid
318
319        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
320            unpickler = PersUnpickler(io.BytesIO(self.dumps('abc', proto)))
321            called = []
322            old_persistent_load = unpickler.persistent_load
323            unpickler.persistent_load = unpickler._persistent_load
324            self.assertEqual(unpickler.persistent_load, unpickler._persistent_load)
325            self.assertEqual(unpickler.load(), 'abc')
326            self.assertEqual(called, ['abc'])
327            del unpickler.persistent_load
328            self.assertEqual(unpickler.persistent_load, old_persistent_load)
329
330
331class PyPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests, unittest.TestCase):
332
333    pickler_class = pickle._Pickler
334    unpickler_class = pickle._Unpickler
335
336
337class PyDispatchTableTests(AbstractDispatchTableTests, unittest.TestCase):
338
339    pickler_class = pickle._Pickler
340
341    def get_dispatch_table(self):
342        return pickle.dispatch_table.copy()
343
344
345class PyChainDispatchTableTests(AbstractDispatchTableTests, unittest.TestCase):
346
347    pickler_class = pickle._Pickler
348
349    def get_dispatch_table(self):
350        return collections.ChainMap({}, pickle.dispatch_table)
351
352
353class PyPicklerHookTests(AbstractHookTests, unittest.TestCase):
354    class CustomPyPicklerClass(pickle._Pickler,
355                               AbstractCustomPicklerClass):
356        pass
357    pickler_class = CustomPyPicklerClass
358
359
360if has_c_implementation:
361    class CPickleTests(AbstractPickleModuleTests, unittest.TestCase):
362        from _pickle import dump, dumps, load, loads, Pickler, Unpickler
363
364    class CUnpicklerTests(PyUnpicklerTests):
365        unpickler = _pickle.Unpickler
366        bad_stack_errors = (pickle.UnpicklingError,)
367        truncated_errors = (pickle.UnpicklingError,)
368
369    class CPicklingErrorTests(PyPicklingErrorTests):
370        pickler = _pickle.Pickler
371
372    class CPicklerTests(PyPicklerTests):
373        pickler = _pickle.Pickler
374        unpickler = _pickle.Unpickler
375
376    class CPersPicklerTests(PyPersPicklerTests):
377        pickler = _pickle.Pickler
378        unpickler = _pickle.Unpickler
379
380    class CIdPersPicklerTests(PyIdPersPicklerTests):
381        pickler = _pickle.Pickler
382        unpickler = _pickle.Unpickler
383        persistent_load_error = _pickle.UnpicklingError
384
385    class CDumpPickle_LoadPickle(PyPicklerTests):
386        pickler = _pickle.Pickler
387        unpickler = pickle._Unpickler
388
389    class DumpPickle_CLoadPickle(PyPicklerTests):
390        pickler = pickle._Pickler
391        unpickler = _pickle.Unpickler
392
393    class CPicklerUnpicklerObjectTests(AbstractPicklerUnpicklerObjectTests, unittest.TestCase):
394        pickler_class = _pickle.Pickler
395        unpickler_class = _pickle.Unpickler
396
397        def test_issue18339(self):
398            unpickler = self.unpickler_class(io.BytesIO())
399            with self.assertRaises(TypeError):
400                unpickler.memo = object
401            # used to cause a segfault
402            with self.assertRaises(ValueError):
403                unpickler.memo = {-1: None}
404            unpickler.memo = {1: None}
405
406    class CDispatchTableTests(AbstractDispatchTableTests, unittest.TestCase):
407        pickler_class = pickle.Pickler
408        def get_dispatch_table(self):
409            return pickle.dispatch_table.copy()
410
411    class CChainDispatchTableTests(AbstractDispatchTableTests, unittest.TestCase):
412        pickler_class = pickle.Pickler
413        def get_dispatch_table(self):
414            return collections.ChainMap({}, pickle.dispatch_table)
415
416    class CPicklerHookTests(AbstractHookTests, unittest.TestCase):
417        class CustomCPicklerClass(_pickle.Pickler, AbstractCustomPicklerClass):
418            pass
419        pickler_class = CustomCPicklerClass
420
421    @support.cpython_only
422    class HeapTypesTests(unittest.TestCase):
423        def setUp(self):
424            pickler = _pickle.Pickler(io.BytesIO())
425            unpickler = _pickle.Unpickler(io.BytesIO())
426
427            self._types = (
428                _pickle.Pickler,
429                _pickle.Unpickler,
430                type(pickler.memo),
431                type(unpickler.memo),
432
433                # We cannot test the _pickle.Pdata;
434                # there's no way to get to it.
435            )
436
437        def test_have_gc(self):
438            import gc
439            for tp in self._types:
440                with self.subTest(tp=tp):
441                    self.assertTrue(gc.is_tracked(tp))
442
443        def test_immutable(self):
444            for tp in self._types:
445                with self.subTest(tp=tp):
446                    with self.assertRaisesRegex(TypeError, "immutable"):
447                        tp.foo = "bar"
448
449    @support.cpython_only
450    class SizeofTests(unittest.TestCase):
451        check_sizeof = support.check_sizeof
452
453        def test_pickler(self):
454            basesize = support.calcobjsize('7P2n3i2n3i2P')
455            p = _pickle.Pickler(io.BytesIO())
456            self.assertEqual(object.__sizeof__(p), basesize)
457            MT_size = struct.calcsize('3nP0n')
458            ME_size = struct.calcsize('Pn0P')
459            check = self.check_sizeof
460            check(p, basesize +
461                MT_size + 8 * ME_size +  # Minimal memo table size.
462                sys.getsizeof(b'x'*4096))  # Minimal write buffer size.
463            for i in range(6):
464                p.dump(chr(i))
465            check(p, basesize +
466                MT_size + 32 * ME_size +  # Size of memo table required to
467                                          # save references to 6 objects.
468                0)  # Write buffer is cleared after every dump().
469
470        def test_unpickler(self):
471            basesize = support.calcobjsize('2P2n2P 2P2n2i5P 2P3n8P2n2i')
472            unpickler = _pickle.Unpickler
473            P = struct.calcsize('P')  # Size of memo table entry.
474            n = struct.calcsize('n')  # Size of mark table entry.
475            check = self.check_sizeof
476            for encoding in 'ASCII', 'UTF-16', 'latin-1':
477                for errors in 'strict', 'replace':
478                    u = unpickler(io.BytesIO(),
479                                  encoding=encoding, errors=errors)
480                    self.assertEqual(object.__sizeof__(u), basesize)
481                    check(u, basesize +
482                             32 * P +  # Minimal memo table size.
483                             len(encoding) + 1 + len(errors) + 1)
484
485            stdsize = basesize + len('ASCII') + 1 + len('strict') + 1
486            def check_unpickler(data, memo_size, marks_size):
487                dump = pickle.dumps(data)
488                u = unpickler(io.BytesIO(dump),
489                              encoding='ASCII', errors='strict')
490                u.load()
491                check(u, stdsize + memo_size * P + marks_size * n)
492
493            check_unpickler(0, 32, 0)
494            # 20 is minimal non-empty mark stack size.
495            check_unpickler([0] * 100, 32, 20)
496            # 128 is memo table size required to save references to 100 objects.
497            check_unpickler([chr(i) for i in range(100)], 128, 20)
498            def recurse(deep):
499                data = 0
500                for i in range(deep):
501                    data = [data, data]
502                return data
503            check_unpickler(recurse(0), 32, 0)
504            check_unpickler(recurse(1), 32, 20)
505            check_unpickler(recurse(20), 32, 20)
506            check_unpickler(recurse(50), 64, 60)
507            if not (support.is_wasi and support.Py_DEBUG):
508                # stack depth too shallow in pydebug WASI.
509                check_unpickler(recurse(100), 128, 140)
510
511            u = unpickler(io.BytesIO(pickle.dumps('a', 0)),
512                          encoding='ASCII', errors='strict')
513            u.load()
514            check(u, stdsize + 32 * P + 2 + 1)
515
516
517ALT_IMPORT_MAPPING = {
518    ('_elementtree', 'xml.etree.ElementTree'),
519    ('cPickle', 'pickle'),
520    ('StringIO', 'io'),
521    ('cStringIO', 'io'),
522}
523
524ALT_NAME_MAPPING = {
525    ('__builtin__', 'basestring', 'builtins', 'str'),
526    ('exceptions', 'StandardError', 'builtins', 'Exception'),
527    ('UserDict', 'UserDict', 'collections', 'UserDict'),
528    ('socket', '_socketobject', 'socket', 'SocketType'),
529}
530
531def mapping(module, name):
532    if (module, name) in NAME_MAPPING:
533        module, name = NAME_MAPPING[(module, name)]
534    elif module in IMPORT_MAPPING:
535        module = IMPORT_MAPPING[module]
536    return module, name
537
538def reverse_mapping(module, name):
539    if (module, name) in REVERSE_NAME_MAPPING:
540        module, name = REVERSE_NAME_MAPPING[(module, name)]
541    elif module in REVERSE_IMPORT_MAPPING:
542        module = REVERSE_IMPORT_MAPPING[module]
543    return module, name
544
545def getmodule(module):
546    try:
547        return sys.modules[module]
548    except KeyError:
549        try:
550            with warnings.catch_warnings():
551                action = 'always' if support.verbose else 'ignore'
552                warnings.simplefilter(action, DeprecationWarning)
553                __import__(module)
554        except AttributeError as exc:
555            if support.verbose:
556                print("Can't import module %r: %s" % (module, exc))
557            raise ImportError
558        except ImportError as exc:
559            if support.verbose:
560                print(exc)
561            raise
562        return sys.modules[module]
563
564def getattribute(module, name):
565    obj = getmodule(module)
566    for n in name.split('.'):
567        obj = getattr(obj, n)
568    return obj
569
570def get_exceptions(mod):
571    for name in dir(mod):
572        attr = getattr(mod, name)
573        if isinstance(attr, type) and issubclass(attr, BaseException):
574            yield name, attr
575
576class CompatPickleTests(unittest.TestCase):
577    def test_import(self):
578        modules = set(IMPORT_MAPPING.values())
579        modules |= set(REVERSE_IMPORT_MAPPING)
580        modules |= {module for module, name in REVERSE_NAME_MAPPING}
581        modules |= {module for module, name in NAME_MAPPING.values()}
582        for module in modules:
583            try:
584                getmodule(module)
585            except ImportError:
586                pass
587
588    def test_import_mapping(self):
589        for module3, module2 in REVERSE_IMPORT_MAPPING.items():
590            with self.subTest((module3, module2)):
591                try:
592                    getmodule(module3)
593                except ImportError:
594                    pass
595                if module3[:1] != '_':
596                    self.assertIn(module2, IMPORT_MAPPING)
597                    self.assertEqual(IMPORT_MAPPING[module2], module3)
598
599    def test_name_mapping(self):
600        for (module3, name3), (module2, name2) in REVERSE_NAME_MAPPING.items():
601            with self.subTest(((module3, name3), (module2, name2))):
602                if (module2, name2) == ('exceptions', 'OSError'):
603                    attr = getattribute(module3, name3)
604                    self.assertTrue(issubclass(attr, OSError))
605                elif (module2, name2) == ('exceptions', 'ImportError'):
606                    attr = getattribute(module3, name3)
607                    self.assertTrue(issubclass(attr, ImportError))
608                else:
609                    module, name = mapping(module2, name2)
610                    if module3[:1] != '_':
611                        self.assertEqual((module, name), (module3, name3))
612                    try:
613                        attr = getattribute(module3, name3)
614                    except ImportError:
615                        pass
616                    else:
617                        self.assertEqual(getattribute(module, name), attr)
618
619    def test_reverse_import_mapping(self):
620        for module2, module3 in IMPORT_MAPPING.items():
621            with self.subTest((module2, module3)):
622                try:
623                    getmodule(module3)
624                except ImportError as exc:
625                    if support.verbose:
626                        print(exc)
627                if ((module2, module3) not in ALT_IMPORT_MAPPING and
628                    REVERSE_IMPORT_MAPPING.get(module3, None) != module2):
629                    for (m3, n3), (m2, n2) in REVERSE_NAME_MAPPING.items():
630                        if (module3, module2) == (m3, m2):
631                            break
632                    else:
633                        self.fail('No reverse mapping from %r to %r' %
634                                  (module3, module2))
635                module = REVERSE_IMPORT_MAPPING.get(module3, module3)
636                module = IMPORT_MAPPING.get(module, module)
637                self.assertEqual(module, module3)
638
639    def test_reverse_name_mapping(self):
640        for (module2, name2), (module3, name3) in NAME_MAPPING.items():
641            with self.subTest(((module2, name2), (module3, name3))):
642                try:
643                    attr = getattribute(module3, name3)
644                except ImportError:
645                    pass
646                module, name = reverse_mapping(module3, name3)
647                if (module2, name2, module3, name3) not in ALT_NAME_MAPPING:
648                    self.assertEqual((module, name), (module2, name2))
649                module, name = mapping(module, name)
650                self.assertEqual((module, name), (module3, name3))
651
652    def test_exceptions(self):
653        self.assertEqual(mapping('exceptions', 'StandardError'),
654                         ('builtins', 'Exception'))
655        self.assertEqual(mapping('exceptions', 'Exception'),
656                         ('builtins', 'Exception'))
657        self.assertEqual(reverse_mapping('builtins', 'Exception'),
658                         ('exceptions', 'Exception'))
659        self.assertEqual(mapping('exceptions', 'OSError'),
660                         ('builtins', 'OSError'))
661        self.assertEqual(reverse_mapping('builtins', 'OSError'),
662                         ('exceptions', 'OSError'))
663
664        for name, exc in get_exceptions(builtins):
665            with self.subTest(name):
666                if exc in (BlockingIOError,
667                           ResourceWarning,
668                           StopAsyncIteration,
669                           PythonFinalizationError,
670                           RecursionError,
671                           EncodingWarning,
672                           BaseExceptionGroup,
673                           ExceptionGroup,
674                           _IncompleteInputError):
675                    continue
676                if exc is not OSError and issubclass(exc, OSError):
677                    self.assertEqual(reverse_mapping('builtins', name),
678                                     ('exceptions', 'OSError'))
679                elif exc is not ImportError and issubclass(exc, ImportError):
680                    self.assertEqual(reverse_mapping('builtins', name),
681                                     ('exceptions', 'ImportError'))
682                    self.assertEqual(mapping('exceptions', name),
683                                     ('exceptions', name))
684                else:
685                    self.assertEqual(reverse_mapping('builtins', name),
686                                     ('exceptions', name))
687                    self.assertEqual(mapping('exceptions', name),
688                                     ('builtins', name))
689
690    def test_multiprocessing_exceptions(self):
691        module = import_helper.import_module('multiprocessing.context')
692        for name, exc in get_exceptions(module):
693            if issubclass(exc, Warning):
694                continue
695            with self.subTest(name):
696                self.assertEqual(reverse_mapping('multiprocessing.context', name),
697                                 ('multiprocessing', name))
698                self.assertEqual(mapping('multiprocessing', name),
699                                 ('multiprocessing.context', name))
700
701
702def load_tests(loader, tests, pattern):
703    tests.addTest(doctest.DocTestSuite())
704    return tests
705
706
707if __name__ == "__main__":
708    unittest.main()
709