17db96d56Sopenharmony_ciimport unittest
27db96d56Sopenharmony_cifrom test import support
37db96d56Sopenharmony_cifrom test.support import warnings_helper
47db96d56Sopenharmony_ciimport os
57db96d56Sopenharmony_ciimport sys
67db96d56Sopenharmony_ciimport types
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_citry:
97db96d56Sopenharmony_ci    import _multiprocessing
107db96d56Sopenharmony_ciexcept ModuleNotFoundError:
117db96d56Sopenharmony_ci    _multiprocessing = None
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciif support.check_sanitizer(address=True, memory=True):
157db96d56Sopenharmony_ci    # bpo-46633: test___all__ is skipped because importing some modules
167db96d56Sopenharmony_ci    # directly can trigger known problems with ASAN (like tk or crypt).
177db96d56Sopenharmony_ci    raise unittest.SkipTest("workaround ASAN build issues on loading tests "
187db96d56Sopenharmony_ci                            "like tk or crypt")
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ciclass NoAll(RuntimeError):
227db96d56Sopenharmony_ci    pass
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ciclass FailedImport(RuntimeError):
257db96d56Sopenharmony_ci    pass
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ciclass AllTest(unittest.TestCase):
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci    def setUp(self):
317db96d56Sopenharmony_ci        # concurrent.futures uses a __getattr__ hook. Its __all__ triggers
327db96d56Sopenharmony_ci        # import of a submodule, which fails when _multiprocessing is not
337db96d56Sopenharmony_ci        # available.
347db96d56Sopenharmony_ci        if _multiprocessing is None:
357db96d56Sopenharmony_ci            sys.modules["_multiprocessing"] = types.ModuleType("_multiprocessing")
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci    def tearDown(self):
387db96d56Sopenharmony_ci        if _multiprocessing is None:
397db96d56Sopenharmony_ci            sys.modules.pop("_multiprocessing")
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci    def check_all(self, modname):
427db96d56Sopenharmony_ci        names = {}
437db96d56Sopenharmony_ci        with warnings_helper.check_warnings(
447db96d56Sopenharmony_ci            (f".*{modname}", DeprecationWarning),
457db96d56Sopenharmony_ci            (".* (module|package)", DeprecationWarning),
467db96d56Sopenharmony_ci            (".* (module|package)", PendingDeprecationWarning),
477db96d56Sopenharmony_ci            ("", ResourceWarning),
487db96d56Sopenharmony_ci            quiet=True):
497db96d56Sopenharmony_ci            try:
507db96d56Sopenharmony_ci                exec("import %s" % modname, names)
517db96d56Sopenharmony_ci            except:
527db96d56Sopenharmony_ci                # Silent fail here seems the best route since some modules
537db96d56Sopenharmony_ci                # may not be available or not initialize properly in all
547db96d56Sopenharmony_ci                # environments.
557db96d56Sopenharmony_ci                raise FailedImport(modname)
567db96d56Sopenharmony_ci        if not hasattr(sys.modules[modname], "__all__"):
577db96d56Sopenharmony_ci            raise NoAll(modname)
587db96d56Sopenharmony_ci        names = {}
597db96d56Sopenharmony_ci        with self.subTest(module=modname):
607db96d56Sopenharmony_ci            with warnings_helper.check_warnings(
617db96d56Sopenharmony_ci                ("", DeprecationWarning),
627db96d56Sopenharmony_ci                ("", ResourceWarning),
637db96d56Sopenharmony_ci                quiet=True):
647db96d56Sopenharmony_ci                try:
657db96d56Sopenharmony_ci                    exec("from %s import *" % modname, names)
667db96d56Sopenharmony_ci                except Exception as e:
677db96d56Sopenharmony_ci                    # Include the module name in the exception string
687db96d56Sopenharmony_ci                    self.fail("__all__ failure in {}: {}: {}".format(
697db96d56Sopenharmony_ci                              modname, e.__class__.__name__, e))
707db96d56Sopenharmony_ci                if "__builtins__" in names:
717db96d56Sopenharmony_ci                    del names["__builtins__"]
727db96d56Sopenharmony_ci                if '__annotations__' in names:
737db96d56Sopenharmony_ci                    del names['__annotations__']
747db96d56Sopenharmony_ci                if "__warningregistry__" in names:
757db96d56Sopenharmony_ci                    del names["__warningregistry__"]
767db96d56Sopenharmony_ci                keys = set(names)
777db96d56Sopenharmony_ci                all_list = sys.modules[modname].__all__
787db96d56Sopenharmony_ci                all_set = set(all_list)
797db96d56Sopenharmony_ci                self.assertCountEqual(all_set, all_list, "in module {}".format(modname))
807db96d56Sopenharmony_ci                self.assertEqual(keys, all_set, "in module {}".format(modname))
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci    def walk_modules(self, basedir, modpath):
837db96d56Sopenharmony_ci        for fn in sorted(os.listdir(basedir)):
847db96d56Sopenharmony_ci            path = os.path.join(basedir, fn)
857db96d56Sopenharmony_ci            if os.path.isdir(path):
867db96d56Sopenharmony_ci                pkg_init = os.path.join(path, '__init__.py')
877db96d56Sopenharmony_ci                if os.path.exists(pkg_init):
887db96d56Sopenharmony_ci                    yield pkg_init, modpath + fn
897db96d56Sopenharmony_ci                    for p, m in self.walk_modules(path, modpath + fn + "."):
907db96d56Sopenharmony_ci                        yield p, m
917db96d56Sopenharmony_ci                continue
927db96d56Sopenharmony_ci            if not fn.endswith('.py') or fn == '__init__.py':
937db96d56Sopenharmony_ci                continue
947db96d56Sopenharmony_ci            yield path, modpath + fn[:-3]
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci    def test_all(self):
977db96d56Sopenharmony_ci        # List of denied modules and packages
987db96d56Sopenharmony_ci        denylist = set([
997db96d56Sopenharmony_ci            # Will raise a SyntaxError when compiling the exec statement
1007db96d56Sopenharmony_ci            '__future__',
1017db96d56Sopenharmony_ci        ])
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci        if not sys.platform.startswith('java'):
1047db96d56Sopenharmony_ci            # In case _socket fails to build, make this test fail more gracefully
1057db96d56Sopenharmony_ci            # than an AttributeError somewhere deep in CGIHTTPServer.
1067db96d56Sopenharmony_ci            import _socket
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_ci        ignored = []
1097db96d56Sopenharmony_ci        failed_imports = []
1107db96d56Sopenharmony_ci        lib_dir = os.path.dirname(os.path.dirname(__file__))
1117db96d56Sopenharmony_ci        for path, modname in self.walk_modules(lib_dir, ""):
1127db96d56Sopenharmony_ci            m = modname
1137db96d56Sopenharmony_ci            denied = False
1147db96d56Sopenharmony_ci            while m:
1157db96d56Sopenharmony_ci                if m in denylist:
1167db96d56Sopenharmony_ci                    denied = True
1177db96d56Sopenharmony_ci                    break
1187db96d56Sopenharmony_ci                m = m.rpartition('.')[0]
1197db96d56Sopenharmony_ci            if denied:
1207db96d56Sopenharmony_ci                continue
1217db96d56Sopenharmony_ci            if support.verbose:
1227db96d56Sopenharmony_ci                print(modname)
1237db96d56Sopenharmony_ci            try:
1247db96d56Sopenharmony_ci                # This heuristic speeds up the process by removing, de facto,
1257db96d56Sopenharmony_ci                # most test modules (and avoiding the auto-executing ones).
1267db96d56Sopenharmony_ci                with open(path, "rb") as f:
1277db96d56Sopenharmony_ci                    if b"__all__" not in f.read():
1287db96d56Sopenharmony_ci                        raise NoAll(modname)
1297db96d56Sopenharmony_ci                    self.check_all(modname)
1307db96d56Sopenharmony_ci            except NoAll:
1317db96d56Sopenharmony_ci                ignored.append(modname)
1327db96d56Sopenharmony_ci            except FailedImport:
1337db96d56Sopenharmony_ci                failed_imports.append(modname)
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci        if support.verbose:
1367db96d56Sopenharmony_ci            print('Following modules have no __all__ and have been ignored:',
1377db96d56Sopenharmony_ci                  ignored)
1387db96d56Sopenharmony_ci            print('Following modules failed to be imported:', failed_imports)
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ciif __name__ == "__main__":
1427db96d56Sopenharmony_ci    unittest.main()
143