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 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)) 54 55 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 69 def test_all(self): 70 # Blacklisted modules and packages 71 blacklist = set([ 72 # Will raise a SyntaxError when compiling the exec statement 73 '__future__', 74 ]) 75 76 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 80 81 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) 96 try: 97 # 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) 112 113 114if __name__ == "__main__": 115 unittest.main() 116