From 9a241529bdc2d632a4fab2138c3b25400ec31894 Mon Sep 17 00:00:00 2001 From: "antoine.pitrou" Date: Sat, 10 Oct 2009 20:52:11 +0000 Subject: [PATCH] Issue #7055: test___all__ now greedily detects all modules which have an __all__ attribute, rather than using a hardcoded and incomplete list. git-svn-id: http://svn.python.org/projects/python/trunk@75312 6015fed2-1504-0410-9fe1-9d1591cc4771 --- Lib/test/test___all__.py | 303 +++++++++++++++++++---------------------------- Misc/NEWS | 3 + 2 files changed, 122 insertions(+), 184 deletions(-) rewrite Lib/test/test___all__.py (81%) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py dissimilarity index 81% index 71fdba43af..8662bcb2ce 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -1,184 +1,119 @@ -import unittest -from test.test_support import run_unittest -import sys -import warnings - - - -class AllTest(unittest.TestCase): - - def check_all(self, modname): - names = {} - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", ".* (module|package)", - DeprecationWarning) - try: - exec "import %s" % modname in names - except ImportError: - # Silent fail here seems the best route since some modules - # may not be available in all environments. - return - self.assertTrue(hasattr(sys.modules[modname], "__all__"), - "%s has no __all__ attribute" % modname) - names = {} - exec "from %s import *" % modname in names - if "__builtins__" in names: - del names["__builtins__"] - keys = set(names) - all = set(sys.modules[modname].__all__) - self.assertEqual(keys, all) - - def test_all(self): - if not sys.platform.startswith('java'): - # In case _socket fails to build, make this test fail more gracefully - # than an AttributeError somewhere deep in CGIHTTPServer. - import _socket - - self.check_all("BaseHTTPServer") - self.check_all("Bastion") - self.check_all("CGIHTTPServer") - self.check_all("ConfigParser") - self.check_all("Cookie") - self.check_all("MimeWriter") - self.check_all("Queue") - self.check_all("SimpleHTTPServer") - self.check_all("SocketServer") - self.check_all("StringIO") - self.check_all("UserString") - self.check_all("aifc") - self.check_all("atexit") - self.check_all("audiodev") - self.check_all("base64") - self.check_all("bdb") - self.check_all("binhex") - self.check_all("calendar") - self.check_all("cgi") - self.check_all("cmd") - self.check_all("code") - self.check_all("codecs") - self.check_all("codeop") - self.check_all("colorsys") - self.check_all("commands") - self.check_all("compileall") - self.check_all("copy") - self.check_all("copy_reg") - self.check_all("csv") - self.check_all("dbhash") - self.check_all("decimal") - self.check_all("difflib") - self.check_all("dircache") - self.check_all("dis") - self.check_all("doctest") - self.check_all("dummy_thread") - self.check_all("dummy_threading") - self.check_all("filecmp") - self.check_all("fileinput") - self.check_all("fnmatch") - self.check_all("fpformat") - self.check_all("ftplib") - self.check_all("getopt") - self.check_all("getpass") - self.check_all("gettext") - self.check_all("glob") - self.check_all("gzip") - self.check_all("heapq") - self.check_all("htmllib") - self.check_all("httplib") - self.check_all("ihooks") - self.check_all("imaplib") - self.check_all("imghdr") - self.check_all("imputil") - self.check_all("keyword") - self.check_all("linecache") - self.check_all("locale") - self.check_all("logging") - self.check_all("macpath") - self.check_all("macurl2path") - self.check_all("mailbox") - self.check_all("mailcap") - self.check_all("mhlib") - self.check_all("mimetools") - self.check_all("mimetypes") - self.check_all("mimify") - self.check_all("multifile") - self.check_all("netrc") - self.check_all("nntplib") - self.check_all("ntpath") - self.check_all("opcode") - self.check_all("optparse") - self.check_all("os") - self.check_all("os2emxpath") - self.check_all("pdb") - self.check_all("pickle") - self.check_all("pickletools") - self.check_all("pipes") - self.check_all("popen2") - self.check_all("poplib") - self.check_all("posixpath") - self.check_all("pprint") - self.check_all("profile") - self.check_all("pstats") - self.check_all("pty") - self.check_all("py_compile") - self.check_all("pyclbr") - self.check_all("quopri") - self.check_all("random") - self.check_all("re") - self.check_all("repr") - self.check_all("rexec") - self.check_all("rfc822") - self.check_all("rlcompleter") - self.check_all("robotparser") - self.check_all("sched") - self.check_all("sets") - self.check_all("sgmllib") - self.check_all("shelve") - self.check_all("shlex") - self.check_all("shutil") - self.check_all("smtpd") - self.check_all("smtplib") - self.check_all("sndhdr") - self.check_all("socket") - self.check_all("_strptime") - self.check_all("symtable") - self.check_all("tabnanny") - self.check_all("tarfile") - self.check_all("telnetlib") - self.check_all("tempfile") - self.check_all("test.test_support") - self.check_all("textwrap") - self.check_all("threading") - self.check_all("timeit") - self.check_all("toaiff") - self.check_all("tokenize") - self.check_all("traceback") - self.check_all("tty") - self.check_all("unittest") - self.check_all("urllib") - self.check_all("urlparse") - self.check_all("uu") - self.check_all("warnings") - self.check_all("wave") - self.check_all("weakref") - self.check_all("webbrowser") - self.check_all("xdrlib") - self.check_all("zipfile") - - # rlcompleter needs special consideration; it import readline which - # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( - try: - self.check_all("rlcompleter") - finally: - try: - import locale - except ImportError: - pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') - - -def test_main(): - run_unittest(AllTest) - -if __name__ == "__main__": - test_main() +from __future__ import print_function + +import unittest +from test import test_support as support +import os +import sys +import warnings + + +class NoAll(RuntimeError): + pass + +class FailedImport(RuntimeError): + pass + + +class AllTest(unittest.TestCase): + + def check_all(self, modname): + names = {} + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", ".* (module|package)", + DeprecationWarning) + try: + exec "import %s" % modname in names + except: + # Silent fail here seems the best route since some modules + # may not be available or not initialize properly in all + # environments. + raise FailedImport(modname) + if not hasattr(sys.modules[modname], "__all__"): + raise NoAll(modname) + names = {} + try: + exec "from %s import *" % modname in names + except Exception as e: + # Include the module name in the exception string + self.fail("__all__ failure in {}: {}: {}".format( + modname, e.__class__.__name__, e)) + if "__builtins__" in names: + del names["__builtins__"] + keys = set(names) + all = set(sys.modules[modname].__all__) + self.assertEqual(keys, all) + + def walk_modules(self, basedir, modpath): + for fn in sorted(os.listdir(basedir)): + path = os.path.join(basedir, fn) + if os.path.isdir(path): + pkg_init = os.path.join(path, '__init__.py') + if os.path.exists(pkg_init): + yield pkg_init, modpath + fn + for p, m in self.walk_modules(path, modpath + fn + "."): + yield p, m + continue + if not fn.endswith('.py') or fn == '__init__.py': + continue + yield path, modpath + fn[:-3] + + def test_all(self): + # Blacklisted modules and packages + blacklist = set([ + # Will raise a SyntaxError when compiling the exec statement + '__future__', + ]) + + if not sys.platform.startswith('java'): + # In case _socket fails to build, make this test fail more gracefully + # than an AttributeError somewhere deep in CGIHTTPServer. + import _socket + + # rlcompleter needs special consideration; it import readline which + # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + try: + import rlcompleter + import locale + except ImportError: + pass + else: + locale.setlocale(locale.LC_CTYPE, 'C') + + ignored = [] + failed_imports = [] + lib_dir = os.path.dirname(os.path.dirname(__file__)) + for path, modname in self.walk_modules(lib_dir, ""): + m = modname + blacklisted = False + while m: + if m in blacklist: + blacklisted = True + break + m = m.rpartition('.')[0] + if blacklisted: + continue + if support.verbose: + print(modname) + try: + # This heuristic speeds up the process by removing, de facto, + # most test modules (and avoiding the auto-executing ones). + with open(path, "rb") as f: + if "__all__" not in f.read(): + raise NoAll(modname) + self.check_all(modname) + except NoAll: + ignored.append(modname) + except FailedImport: + failed_imports.append(modname) + + if support.verbose: + print('Following modules have no __all__ and have been ignored:', + ignored) + print('Following modules failed to be imported:', failed_imports) + + +def test_main(): + support.run_unittest(AllTest) + +if __name__ == "__main__": + test_main() diff --git a/Misc/NEWS b/Misc/NEWS index bdd657c5cf..ddd909f62f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1452,6 +1452,9 @@ Extension Modules Tests ----- +- Issue #7055: test___all__ now greedily detects all modules which have an + __all__ attribute, rather than using a hardcoded and incomplete list. + - Issue #7058: Added save/restore for argv and os.environ to runtest_inner in regrtest, with warnings if the called test modifies them. -- 2.11.4.GIT