You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
4.5 KiB

  1. import unittest
  2. from test import support
  3. from test.support import warnings_helper
  4. import os
  5. import sys
  6. if support.check_sanitizer(address=True, memory=True):
  7. # bpo-46633: test___all__ is skipped because importing some modules
  8. # directly can trigger known problems with ASAN (like tk or crypt).
  9. raise unittest.SkipTest("workaround ASAN build issues on loading tests "
  10. "like tk or crypt")
  11. class NoAll(RuntimeError):
  12. pass
  13. class FailedImport(RuntimeError):
  14. pass
  15. class AllTest(unittest.TestCase):
  16. def check_all(self, modname):
  17. names = {}
  18. with warnings_helper.check_warnings(
  19. (".* (module|package)", DeprecationWarning),
  20. (".* (module|package)", PendingDeprecationWarning),
  21. ("", ResourceWarning),
  22. quiet=True):
  23. try:
  24. exec("import %s" % modname, names)
  25. except:
  26. # Silent fail here seems the best route since some modules
  27. # may not be available or not initialize properly in all
  28. # environments.
  29. raise FailedImport(modname)
  30. if not hasattr(sys.modules[modname], "__all__"):
  31. raise NoAll(modname)
  32. names = {}
  33. with self.subTest(module=modname):
  34. with warnings_helper.check_warnings(
  35. ("", DeprecationWarning),
  36. ("", ResourceWarning),
  37. quiet=True):
  38. try:
  39. exec("from %s import *" % modname, names)
  40. except Exception as e:
  41. # Include the module name in the exception string
  42. self.fail("__all__ failure in {}: {}: {}".format(
  43. modname, e.__class__.__name__, e))
  44. if "__builtins__" in names:
  45. del names["__builtins__"]
  46. if '__annotations__' in names:
  47. del names['__annotations__']
  48. if "__warningregistry__" in names:
  49. del names["__warningregistry__"]
  50. keys = set(names)
  51. all_list = sys.modules[modname].__all__
  52. all_set = set(all_list)
  53. self.assertCountEqual(all_set, all_list, "in module {}".format(modname))
  54. self.assertEqual(keys, all_set, "in module {}".format(modname))
  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. def test_all(self):
  69. # List of denied modules and packages
  70. denylist = set([
  71. # Will raise a SyntaxError when compiling the exec statement
  72. '__future__',
  73. ])
  74. if not sys.platform.startswith('java'):
  75. # In case _socket fails to build, make this test fail more gracefully
  76. # than an AttributeError somewhere deep in CGIHTTPServer.
  77. import _socket
  78. ignored = []
  79. failed_imports = []
  80. lib_dir = os.path.dirname(os.path.dirname(__file__))
  81. for path, modname in self.walk_modules(lib_dir, ""):
  82. m = modname
  83. denied = False
  84. while m:
  85. if m in denylist:
  86. denied = True
  87. break
  88. m = m.rpartition('.')[0]
  89. if denied:
  90. continue
  91. if support.verbose:
  92. print(modname)
  93. try:
  94. # This heuristic speeds up the process by removing, de facto,
  95. # most test modules (and avoiding the auto-executing ones).
  96. with open(path, "rb") as f:
  97. if b"__all__" not in f.read():
  98. raise NoAll(modname)
  99. self.check_all(modname)
  100. except NoAll:
  101. ignored.append(modname)
  102. except FailedImport:
  103. failed_imports.append(modname)
  104. if support.verbose:
  105. print('Following modules have no __all__ and have been ignored:',
  106. ignored)
  107. print('Following modules failed to be imported:', failed_imports)
  108. if __name__ == "__main__":
  109. unittest.main()