• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2from test import support
3import os
4import sys
5
6
7class NoAll(RuntimeError):
8    pass
9
10class FailedImport(RuntimeError):
11    pass
12
13
14class AllTest(unittest.TestCase):
15
16    def check_all(self, modname):
17        names = {}
18        with support.check_warnings(
19            (".* (module|package)", DeprecationWarning),
20            ("", ResourceWarning),
21            quiet=True):
22            try:
23                exec("import %s" % modname, names)
24            except:
25                # Silent fail here seems the best route since some modules
26                # may not be available or not initialize properly in all
27                # environments.
28                raise FailedImport(modname)
29        if not hasattr(sys.modules[modname], "__all__"):
30            raise NoAll(modname)
31        names = {}
32        with self.subTest(module=modname):
33            try:
34                exec("from %s import *" % modname, names)
35            except Exception as e:
36                # Include the module name in the exception string
37                self.fail("__all__ failure in {}: {}: {}".format(
38                          modname, e.__class__.__name__, e))
39            if "__builtins__" in names:
40                del names["__builtins__"]
41            if '__annotations__' in names:
42                del names['__annotations__']
43            keys = set(names)
44            all_list = sys.modules[modname].__all__
45            all_set = set(all_list)
46            self.assertCountEqual(all_set, all_list, "in module {}".format(modname))
47            self.assertEqual(keys, all_set, "in module {}".format(modname))
48
49    def walk_modules(self, basedir, modpath):
50        for fn in sorted(os.listdir(basedir)):
51            path = os.path.join(basedir, fn)
52            if os.path.isdir(path):
53                pkg_init = os.path.join(path, '__init__.py')
54                if os.path.exists(pkg_init):
55                    yield pkg_init, modpath + fn
56                    for p, m in self.walk_modules(path, modpath + fn + "."):
57                        yield p, m
58                continue
59            if not fn.endswith('.py') or fn == '__init__.py':
60                continue
61            yield path, modpath + fn[:-3]
62
63    def test_all(self):
64        # Blacklisted modules and packages
65        blacklist = set([
66            # Will raise a SyntaxError when compiling the exec statement
67            '__future__',
68        ])
69
70        if not sys.platform.startswith('java'):
71            # In case _socket fails to build, make this test fail more gracefully
72            # than an AttributeError somewhere deep in CGIHTTPServer.
73            import _socket
74
75        ignored = []
76        failed_imports = []
77        lib_dir = os.path.dirname(os.path.dirname(__file__))
78        for path, modname in self.walk_modules(lib_dir, ""):
79            m = modname
80            blacklisted = False
81            while m:
82                if m in blacklist:
83                    blacklisted = True
84                    break
85                m = m.rpartition('.')[0]
86            if blacklisted:
87                continue
88            if support.verbose:
89                print(modname)
90            try:
91                # This heuristic speeds up the process by removing, de facto,
92                # most test modules (and avoiding the auto-executing ones).
93                with open(path, "rb") as f:
94                    if b"__all__" not in f.read():
95                        raise NoAll(modname)
96                    self.check_all(modname)
97            except NoAll:
98                ignored.append(modname)
99            except FailedImport:
100                failed_imports.append(modname)
101
102        if support.verbose:
103            print('Following modules have no __all__ and have been ignored:',
104                  ignored)
105            print('Following modules failed to be imported:', failed_imports)
106
107
108if __name__ == "__main__":
109    unittest.main()
110