From 641d76fad084ba0545fc17b0344d1326e68202a2 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 27 Oct 2009 13:04:15 +0000 Subject: [PATCH] Backporting since it would have helped us find a regression. Merged revisions 75312 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r75312 | antoine.pitrou | 2009-10-10 22:52:11 +0200 (sam., 10 oct. 2009) | 4 lines Issue #7055: test___all__ now greedily detects all modules which have an __all__ attribute, rather than using a hardcoded and incomplete list. ........ --- Lib/test/test___all__.py | 225 ++++++++++++++------------------------- Misc/NEWS | 6 ++ 2 files changed, 86 insertions(+), 145 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py index 9cc37de7115..2a7bc63fdc4 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -1,9 +1,18 @@ +from __future__ import print_function + import unittest -from test.test_support import run_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): @@ -14,171 +23,97 @@ class AllTest(unittest.TestCase): DeprecationWarning) try: exec "import %s" % modname in names - except ImportError: + except: # Silent fail here seems the best route since some modules - # may not be available in all environments. - return - self.failUnless(hasattr(sys.modules[modname], "__all__"), - "%s has no __all__ attribute" % modname) + # 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 = {} - exec "from %s import *" % modname in 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 {0}: {1}: {2}".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 - 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: + 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: - import locale - except ImportError: - pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + # 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(): - run_unittest(AllTest) + support.run_unittest(AllTest) if __name__ == "__main__": test_main() diff --git a/Misc/NEWS b/Misc/NEWS index aaac9ef0d78..d265ef135d8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,12 @@ Core and Builtins Library ------- +Tests +----- + +- Issue #7055: test___all__ now greedily detects all modules which have an + __all__ attribute, rather than using a hardcoded and incomplete list. + What's New in Python 2.6.4 final? =================================