blob: f6e82eb64ab02545c10b21c96325868db84d5357 [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):
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__"]
Yury Selivanovf8cb8a12016-09-08 20:50:03 -070041 if '__annotations__' in names:
42 del names['__annotations__']
Ezio Melottied52f6c2013-05-01 14:58:09 +030043 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))
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000048
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000049 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
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000063 def test_all(self):
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000064 # Blacklisted modules and packages
65 blacklist = set([
66 # Will raise a SyntaxError when compiling the exec statement
67 '__future__',
68 ])
69
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000070 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
Tim Petersab9ba272001-08-09 21:40:30 +000074
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000075 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)
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +000090 try:
Antoine Pitrou4de39cd2009-10-10 21:08:31 +000091 # 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)
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +0000106
107
Walter Dörwaldb1ded1e2003-04-15 11:10:33 +0000108if __name__ == "__main__":
Brett Cannonc9a1bfe2013-06-12 20:12:30 -0400109 unittest.main()