Home | History | Annotate | Download | only in test
      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