blob: c077881511b8ce3b5128f5d7774fd294d11d1be6 [file] [log] [blame]
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +00001import unittest
Antoine Pitrou4de39cd2009-10-10 21:08:31 +00002from test import support
3import os
Skip Montanaroe99d5ea2001-01-20 19:54:20 +00004import sys
Tim Petersb05cd492002-04-11 20:04:12 +00005
Skip Montanaroe99d5ea2001-01-20 19:54:20 +00006
Antoine Pitrou4de39cd2009-10-10 21:08:31 +00007class NoAll(RuntimeError):
8 pass
9
10class FailedImport(RuntimeError):
11 pass
12
13
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000014class AllTest(unittest.TestCase):
15
16 def check_all(self, modname):
17 names = {}
Antoine Pitroua0d2f4d2010-10-29 11:53:34 +000018 with support.check_warnings(
19 (".* (module|package)", DeprecationWarning),
20 ("", ResourceWarning),
21 quiet=True):
Christian Heimes75ca4ea2008-05-06 23:48:04 +000022 try:
23 exec("import %s" % modname, names)
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000024 except:
Christian Heimes75ca4ea2008-05-06 23:48:04 +000025 # Silent fail here seems the best route since some modules
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000026 # 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)
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000031 names = {}
Ezio Melottied52f6c2013-05-01 14:58:09 +030032 with self.subTest(module=modname):
Andrew Svetlov23b4b692019-05-27 22:56:22 +030033 with support.check_warnings(
34 ("", DeprecationWarning),
35 ("", ResourceWarning),
36 quiet=True):
37 try:
38 exec("from %s import *" % modname, names)
39 except Exception as e:
40 # Include the module name in the exception string
41 self.fail("__all__ failure in {}: {}: {}".format(
42 modname, e.__class__.__name__, e))
43 if "__builtins__" in names:
44 del names["__builtins__"]
45 if '__annotations__' in names:
46 del names['__annotations__']
47 if "__warningregistry__" in names:
48 del names["__warningregistry__"]
49 keys = set(names)
50 all_list = sys.modules[modname].__all__
51 all_set = set(all_list)
52 self.assertCountEqual(all_set, all_list, "in module {}".format(modname))
53 self.assertEqual(keys, all_set, "in module {}".format(modname))
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000054
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000055 def walk_modules(self, basedir, modpath):
56 for fn in sorted(os.listdir(basedir)):
57 path = os.path.join(basedir, fn)
58 if os.path.isdir(path):
59 pkg_init = os.path.join(path, '__init__.py')
60 if os.path.exists(pkg_init):
61 yield pkg_init, modpath + fn
62 for p, m in self.walk_modules(path, modpath + fn + "."):
63 yield p, m
64 continue
65 if not fn.endswith('.py') or fn == '__init__.py':
66 continue
67 yield path, modpath + fn[:-3]
68
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000069 def test_all(self):
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000070 # Blacklisted modules and packages
71 blacklist = set([
72 # Will raise a SyntaxError when compiling the exec statement
73 '__future__',
74 ])
75
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000076 if not sys.platform.startswith('java'):
77 # In case _socket fails to build, make this test fail more gracefully
78 # than an AttributeError somewhere deep in CGIHTTPServer.
79 import _socket
Tim Petersab9ba272001-08-09 21:40:30 +000080
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000081 ignored = []
82 failed_imports = []
83 lib_dir = os.path.dirname(os.path.dirname(__file__))
84 for path, modname in self.walk_modules(lib_dir, ""):
85 m = modname
86 blacklisted = False
87 while m:
88 if m in blacklist:
89 blacklisted = True
90 break
91 m = m.rpartition('.')[0]
92 if blacklisted:
93 continue
94 if support.verbose:
95 print(modname)
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000096 try:
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000097 # This heuristic speeds up the process by removing, de facto,
98 # most test modules (and avoiding the auto-executing ones).
99 with open(path, "rb") as f:
100 if b"__all__" not in f.read():
101 raise NoAll(modname)
102 self.check_all(modname)
103 except NoAll:
104 ignored.append(modname)
105 except FailedImport:
106 failed_imports.append(modname)
107
108 if support.verbose:
109 print('Following modules have no __all__ and have been ignored:',
110 ignored)
111 print('Following modules failed to be imported:', failed_imports)
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +0000112
113
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +0000114if __name__ == "__main__":
Brett Cannonc9a1bfe2013-06-12 20:12:30 -0400115 unittest.main()