[Python-checkins] distutils2: Move copies of stdlib test code from tests.__init__ to runtests.

eric.araujo python-checkins at python.org
Tue Nov 15 15:06:00 CET 2011


http://hg.python.org/distutils2/rev/7df0c83e795f
changeset:   1252:7df0c83e795f
parent:      1250:7eb32e910b85
user:        Éric Araujo <merwok at netwok.org>
date:        Tue Nov 15 10:50:16 2011 +0100
summary:
  Move copies of stdlib test code from tests.__init__ to runtests.

I deleted captured_stdout because its usage felt clumsy to me; better to
use stdlib’s test.support.captured_stdout in packaging and just write
out the code for d2.

I checked that adding the import of d2.tests.unittest at the top level
did not change the coverage accuracy (see comment in the source and the
history of the file for more info).

files:
  distutils2/tests/__init__.py           |  107 +--------
  distutils2/tests/test_command_bdist.py |   12 +-
  distutils2/tests/test_command_sdist.py |   11 +-
  distutils2/tests/test_dist.py          |    1 -
  runtests.py                            |  164 +++++++++---
  5 files changed, 145 insertions(+), 150 deletions(-)


diff --git a/distutils2/tests/__init__.py b/distutils2/tests/__init__.py
--- a/distutils2/tests/__init__.py
+++ b/distutils2/tests/__init__.py
@@ -7,24 +7,18 @@
 
 Utility code is included in distutils2.tests.support.
 
-Always import unittest from this module, it will be the right version
+Always import unittest from this module: it will be unittest from the
 standard library for packaging tests and unittest2 for distutils2 tests.
 """
 
 import os
 import sys
 import unittest2 as unittest
-from StringIO import StringIO
-
-# XXX move helpers to support, add tests for them, remove things that
-# duplicate test.support (or keep them for the backport; needs thinking)
-
-here = os.path.dirname(__file__) or os.curdir
-verbose = 1
 
 
 def test_suite():
     suite = unittest.TestSuite()
+    here = os.path.dirname(__file__) or os.curdir
     for fn in os.listdir(here):
         if fn.startswith("test") and fn.endswith(".py"):
             modname = "distutils2.tests." + fn[:-3]
@@ -32,100 +26,3 @@
             module = sys.modules[modname]
             suite.addTest(module.test_suite())
     return suite
-
-
-class Error(Exception):
-    """Base class for regression test exceptions."""
-
-
-class TestFailed(Error):
-    """Test failed."""
-
-
-class BasicTestRunner(object):
-    def run(self, test):
-        result = unittest.TestResult()
-        test(result)
-        return result
-
-
-def _run_suite(suite, verbose_=1):
-    """Run tests from a unittest.TestSuite-derived class."""
-    global verbose
-    verbose = verbose_
-    if verbose_:
-        runner = unittest.TextTestRunner(sys.stdout, verbosity=2)
-    else:
-        runner = BasicTestRunner()
-
-    result = runner.run(suite)
-    if not result.wasSuccessful():
-        if len(result.errors) == 1 and not result.failures:
-            err = result.errors[0][1]
-        elif len(result.failures) == 1 and not result.errors:
-            err = result.failures[0][1]
-        else:
-            err = "errors occurred; run in verbose mode for details"
-        raise TestFailed(err)
-
-
-def run_unittest(classes, verbose_=1):
-    """Run tests from unittest.TestCase-derived classes.
-
-    Originally extracted from stdlib test.test_support and modified to
-    support unittest2.
-    """
-    valid_types = (unittest.TestSuite, unittest.TestCase)
-    suite = unittest.TestSuite()
-    for cls in classes:
-        if isinstance(cls, basestring):
-            if cls in sys.modules:
-                suite.addTest(unittest.findTestCases(sys.modules[cls]))
-            else:
-                raise ValueError("str arguments must be keys in sys.modules")
-        elif isinstance(cls, valid_types):
-            suite.addTest(cls)
-        else:
-            suite.addTest(unittest.makeSuite(cls))
-    _run_suite(suite, verbose_)
-
-
-def reap_children():
-    """Use this function at the end of test_main() whenever sub-processes
-    are started.  This will help ensure that no extra children (zombies)
-    stick around to hog resources and create problems when looking
-    for refleaks.
-
-    Extracted from stdlib test.support.
-    """
-
-    # Reap all our dead child processes so we don't leave zombies around.
-    # These hog resources and might be causing some of the buildbots to die.
-    if hasattr(os, 'waitpid'):
-        any_process = -1
-        while True:
-            try:
-                # This will raise an exception on Windows.  That's ok.
-                pid, status = os.waitpid(any_process, os.WNOHANG)
-                if pid == 0:
-                    break
-            except:
-                break
-
-
-def captured_stdout(func, *args, **kw):
-    orig_stdout = getattr(sys, 'stdout')
-    setattr(sys, 'stdout', StringIO())
-    try:
-        res = func(*args, **kw)
-        sys.stdout.seek(0)
-        return res, sys.stdout.read()
-    finally:
-        setattr(sys, 'stdout', orig_stdout)
-
-
-def unload(name):
-    try:
-        del sys.modules[name]
-    except KeyError:
-        pass
diff --git a/distutils2/tests/test_command_bdist.py b/distutils2/tests/test_command_bdist.py
--- a/distutils2/tests/test_command_bdist.py
+++ b/distutils2/tests/test_command_bdist.py
@@ -1,7 +1,9 @@
 """Tests for distutils.command.bdist."""
 import os
+import sys
+from StringIO import StringIO
 from distutils2.command.bdist import bdist, show_formats
-from distutils2.tests import unittest, support, captured_stdout
+from distutils2.tests import unittest, support
 
 
 class BuildTestCase(support.TempdirManager,
@@ -42,7 +44,13 @@
                             '%s should take --skip-build from bdist' % name)
 
     def test_show_formats(self):
-        __, stdout = captured_stdout(show_formats)
+        saved = sys.stdout
+        sys.stdout = StringIO()
+        try:
+            show_formats()
+            stdout = sys.stdout.getvalue()
+        finally:
+            sys.stdout = saved
 
         # the output should be a header line + one line per format
         num_formats = len(bdist.format_commands)
diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py
--- a/distutils2/tests/test_command_sdist.py
+++ b/distutils2/tests/test_command_sdist.py
@@ -1,5 +1,6 @@
 """Tests for distutils2.command.sdist."""
 import os
+import sys
 import zipfile
 
 try:
@@ -10,6 +11,7 @@
     UID_GID_SUPPORT = False
 
 from os.path import join
+from StringIO import StringIO
 from distutils2.dist import Distribution
 from distutils2.util import find_executable
 from distutils2.errors import PackagingOptionError
@@ -18,7 +20,6 @@
 from distutils2._backport.shutil import get_archive_formats
 
 from distutils2.tests import support, unittest
-from distutils2.tests import captured_stdout
 from distutils2.tests.support import requires_zlib
 
 
@@ -243,7 +244,13 @@
         self.assertIn("'setup.cfg' file not found", warnings[1])
 
     def test_show_formats(self):
-        __, stdout = captured_stdout(show_formats)
+        saved = sys.stdout
+        sys.stdout = StringIO()
+        try:
+            show_formats()
+            stdout = sys.stdout.getvalue()
+        finally:
+            sys.stdout = saved
 
         # the output should be a header line + one line per format
         num_formats = len(get_archive_formats())
diff --git a/distutils2/tests/test_dist.py b/distutils2/tests/test_dist.py
--- a/distutils2/tests/test_dist.py
+++ b/distutils2/tests/test_dist.py
@@ -8,7 +8,6 @@
 from distutils2.dist import Distribution
 from distutils2.command.cmd import Command
 from distutils2.errors import PackagingModuleError, PackagingOptionError
-from distutils2.tests import captured_stdout
 from distutils2.tests import support, unittest
 from distutils2.tests.support import create_distribution, use_command
 from distutils2.tests.support import unload
diff --git a/runtests.py b/runtests.py
--- a/runtests.py
+++ b/runtests.py
@@ -1,15 +1,110 @@
 #!/usr/bin/env python
-"""Tests for distutils2.
+"""Test runner for distutils2.
 
 The tests for distutils2 are defined in the distutils2.tests package.
+They can also be executed with the unittest2 runner or nose.
 """
 
+import os
 import sys
 from os.path import dirname, islink, realpath, join, abspath
 from optparse import OptionParser
+from distutils2.tests import unittest
+
+
+# unittest machinery copied from stdlib's test.regrtest and test.support
+
+class TestFailed(Exception):
+    """Test failed."""
+
+
+class BasicTestRunner(object):
+    def run(self, test):
+        result = unittest.TestResult()
+        test(result)
+        return result
+
+
+def reap_children():
+    """Use this function at the end of test_main() whenever sub-processes
+    are started.  This will help ensure that no extra children (zombies)
+    stick around to hog resources and create problems when looking
+    for refleaks.
+    """
+
+    # Reap all our dead child processes so we don't leave zombies around.
+    # These hog resources and might be causing some of the buildbots to die.
+    if hasattr(os, 'waitpid'):
+        any_process = -1
+        while True:
+            try:
+                # This will raise an exception on Windows.  That's ok.
+                pid, status = os.waitpid(any_process, os.WNOHANG)
+                if pid == 0:
+                    break
+            except:
+                break
+
+
+def _run_suite(suite, verbose=True):
+    """Run tests from a unittest.TestSuite-derived class."""
+    if verbose:
+        runner = unittest.TextTestRunner(sys.stdout, verbosity=2)
+    else:
+        runner = BasicTestRunner()
+
+    result = runner.run(suite)
+    if not result.wasSuccessful():
+        if len(result.errors) == 1 and not result.failures:
+            err = result.errors[0][1]
+        elif len(result.failures) == 1 and not result.errors:
+            err = result.failures[0][1]
+        else:
+            err = "errors occurred; run in verbose mode for details"
+        raise TestFailed(err)
+
+
+def run_unittest(classes, verbose=True):
+    """Run tests from unittest.TestCase-derived classes.
+
+    Originally extracted from stdlib test.test_support and modified to
+    support unittest2.
+    """
+    valid_types = (unittest.TestSuite, unittest.TestCase)
+    suite = unittest.TestSuite()
+    for cls in classes:
+        if isinstance(cls, basestring):
+            if cls in sys.modules:
+                suite.addTest(unittest.findTestCases(sys.modules[cls]))
+            else:
+                raise ValueError("str arguments must be keys in sys.modules")
+        elif isinstance(cls, valid_types):
+            suite.addTest(cls)
+        else:
+            suite.addTest(unittest.makeSuite(cls))
+    _run_suite(suite, verbose)
+
+
+def run_tests(verbose):
+    # do NOT import those at the top level, coverage will be inaccurate if
+    # distutils2 modules are imported before coverage magic is started
+    from distutils2.tests import test_suite
+    from distutils2._backport.tests import test_suite as btest_suite
+    try:
+        try:
+            run_unittest([test_suite(), btest_suite()], verbose=verbose)
+            return 0
+        except TestFailed:
+            return 1
+    finally:
+        reap_children()
+
+
+# coverage-related code
 
 COVERAGE_FILE = join(dirname(abspath(__file__)), '.coverage')
 
+
 def get_coverage():
     """ Return a usable coverage object. """
     # deferred import because coverage is optional
@@ -19,52 +114,34 @@
         cov = coverage.coverage(COVERAGE_FILE)
     return cov
 
+
 def ignore_prefixes(module):
     """ Return a list of prefixes to ignore in the coverage report if
     we want to completely skip `module`.
     """
-    # A function like that is needed because some GNU/Linux
-    # distributions, such a Ubuntu, really like to build link farm in
-    # /usr/lib in order to save a few bytes on the disk.
+    # A function like that is needed because some operating systems like Debian
+    # and derivatives use symlinks directory in order to save disk space
     dirnames = [dirname(module.__file__)]
 
-    pymod = module.__file__.rstrip("c")
+    pymod = module.__file__.rstrip('co')
     if islink(pymod):
         dirnames.append(dirname(realpath(pymod)))
     return dirnames
 
 
-def parse_opts():
-    parser = OptionParser(usage="%prog [OPTIONS]",
-                          description="run the distutils2 unittests")
-
-    parser.add_option("-q", "--quiet", help="do not print verbose messages",
-                      action="store_true", default=False)
-    parser.add_option("-c", "--coverage", action="store_true", default=False,
-                      help="produce a coverage report at the end of the run")
-    parser.add_option("-r", "--report", action="store_true", default=False,
-                      help="produce a coverage report from the last test run")
-    parser.add_option("-m", "--show-missing", action="store_true",
-                      default=False,
-                      help=("Show line numbers of statements in each module "
-                            "that weren't executed."))
-
-    opts, args = parser.parse_args()
-    return opts, args
-
-
 def coverage_report(opts):
     from distutils2.tests.support import unittest
     cov = get_coverage()
     if hasattr(cov, "load"):
         # running coverage 3.x
         cov.load()
+        # morfs means modules or files
         morfs = None
     else:
         # running coverage 2.x
         cov.cache = COVERAGE_FILE
         cov.restore()
-        morfs = [m for m in list(cov.cexecuted.keys()) if "distutils2" in m]
+        morfs = [m for m in cov.cexecuted if "distutils2" in m]
 
     prefixes = ["runtests", "distutils2/tests", "distutils2/_backport"]
     prefixes += ignore_prefixes(unittest)
@@ -93,6 +170,28 @@
                    omit=[p + "*" for p in prefixes],
                    show_missing=opts.show_missing)
 
+
+# command-line parsing
+
+def parse_opts():
+    parser = OptionParser(usage="%prog [OPTIONS]",
+                          description="run the distutils2 unittests")
+
+    parser.add_option("-q", "--quiet", help="do not print verbose messages",
+                      action="store_true", default=False)
+    parser.add_option("-c", "--coverage", action="store_true", default=False,
+                      help="produce a coverage report at the end of the run")
+    parser.add_option("-r", "--report", action="store_true", default=False,
+                      help="produce a coverage report from the last test run")
+    parser.add_option("-m", "--show-missing", action="store_true",
+                      default=False,
+                      help=("Show line numbers of statements in each module "
+                            "that weren't executed."))
+
+    opts, args = parser.parse_args()
+    return opts, args
+
+
 def test_main():
     opts, args = parse_opts()
     # FIXME when we run with --quiet, we still want to see errors and failures
@@ -115,21 +214,6 @@
     return ret
 
 
-def run_tests(verbose):
-    # do NOT import those at the top level, coverage will be inaccurate if
-    # modules are imported before its magic is started
-    from distutils2.tests import run_unittest, test_suite, reap_children, TestFailed
-    from distutils2._backport.tests import test_suite as btest_suite
-    try:
-        try:
-            run_unittest([test_suite(), btest_suite()], verbose_=verbose)
-            return 0
-        except TestFailed:
-            return 1
-    finally:
-        reap_children()
-
-
 if __name__ == "__main__":
     if sys.version < '2.5':
         try:

-- 
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list