1 import unittest 2 from test import support 3 import os 4 import sys 5 6 7 class NoAll(RuntimeError): 8 pass 9 10 class FailedImport(RuntimeError): 11 pass 12 13 14 class 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 108 if __name__ == "__main__": 109 unittest.main() 110