Home | History | Annotate | Download | only in tests
      1 """Support code for distutils test cases."""
      2 import os
      3 import sys
      4 import shutil
      5 import tempfile
      6 import unittest
      7 import sysconfig
      8 from copy import deepcopy
      9 
     10 from distutils import log
     11 from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
     12 from distutils.core import Distribution
     13 
     14 
     15 class LoggingSilencer(object):
     16 
     17     def setUp(self):
     18         super().setUp()
     19         self.threshold = log.set_threshold(log.FATAL)
     20         # catching warnings
     21         # when log will be replaced by logging
     22         # we won't need such monkey-patch anymore
     23         self._old_log = log.Log._log
     24         log.Log._log = self._log
     25         self.logs = []
     26 
     27     def tearDown(self):
     28         log.set_threshold(self.threshold)
     29         log.Log._log = self._old_log
     30         super().tearDown()
     31 
     32     def _log(self, level, msg, args):
     33         if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
     34             raise ValueError('%s wrong log level' % str(level))
     35         if not isinstance(msg, str):
     36             raise TypeError("msg should be str, not '%.200s'"
     37                             % (type(msg).__name__))
     38         self.logs.append((level, msg, args))
     39 
     40     def get_logs(self, *levels):
     41         def _format(msg, args):
     42             return msg % args
     43         return [msg % args for level, msg, args
     44                 in self.logs if level in levels]
     45 
     46     def clear_logs(self):
     47         self.logs = []
     48 
     49 
     50 class TempdirManager(object):
     51     """Mix-in class that handles temporary directories for test cases.
     52 
     53     This is intended to be used with unittest.TestCase.
     54     """
     55 
     56     def setUp(self):
     57         super().setUp()
     58         self.old_cwd = os.getcwd()
     59         self.tempdirs = []
     60 
     61     def tearDown(self):
     62         # Restore working dir, for Solaris and derivatives, where rmdir()
     63         # on the current directory fails.
     64         os.chdir(self.old_cwd)
     65         super().tearDown()
     66         while self.tempdirs:
     67             d = self.tempdirs.pop()
     68             shutil.rmtree(d, os.name in ('nt', 'cygwin'))
     69 
     70     def mkdtemp(self):
     71         """Create a temporary directory that will be cleaned up.
     72 
     73         Returns the path of the directory.
     74         """
     75         d = tempfile.mkdtemp()
     76         self.tempdirs.append(d)
     77         return d
     78 
     79     def write_file(self, path, content='xxx'):
     80         """Writes a file in the given path.
     81 
     82 
     83         path can be a string or a sequence.
     84         """
     85         if isinstance(path, (list, tuple)):
     86             path = os.path.join(*path)
     87         f = open(path, 'w')
     88         try:
     89             f.write(content)
     90         finally:
     91             f.close()
     92 
     93     def create_dist(self, pkg_name='foo', **kw):
     94         """Will generate a test environment.
     95 
     96         This function creates:
     97          - a Distribution instance using keywords
     98          - a temporary directory with a package structure
     99 
    100         It returns the package directory and the distribution
    101         instance.
    102         """
    103         tmp_dir = self.mkdtemp()
    104         pkg_dir = os.path.join(tmp_dir, pkg_name)
    105         os.mkdir(pkg_dir)
    106         dist = Distribution(attrs=kw)
    107 
    108         return pkg_dir, dist
    109 
    110 
    111 class DummyCommand:
    112     """Class to store options for retrieval via set_undefined_options()."""
    113 
    114     def __init__(self, **kwargs):
    115         for kw, val in kwargs.items():
    116             setattr(self, kw, val)
    117 
    118     def ensure_finalized(self):
    119         pass
    120 
    121 
    122 class EnvironGuard(object):
    123 
    124     def setUp(self):
    125         super(EnvironGuard, self).setUp()
    126         self.old_environ = deepcopy(os.environ)
    127 
    128     def tearDown(self):
    129         for key, value in self.old_environ.items():
    130             if os.environ.get(key) != value:
    131                 os.environ[key] = value
    132 
    133         for key in tuple(os.environ.keys()):
    134             if key not in self.old_environ:
    135                 del os.environ[key]
    136 
    137         super(EnvironGuard, self).tearDown()
    138 
    139 
    140 def copy_xxmodule_c(directory):
    141     """Helper for tests that need the xxmodule.c source file.
    142 
    143     Example use:
    144 
    145         def test_compile(self):
    146             copy_xxmodule_c(self.tmpdir)
    147             self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
    148 
    149     If the source file can be found, it will be copied to *directory*.  If not,
    150     the test will be skipped.  Errors during copy are not caught.
    151     """
    152     filename = _get_xxmodule_path()
    153     if filename is None:
    154         raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
    155                                 'the python build dir)')
    156     shutil.copy(filename, directory)
    157 
    158 
    159 def _get_xxmodule_path():
    160     srcdir = sysconfig.get_config_var('srcdir')
    161     candidates = [
    162         # use installed copy if available
    163         os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
    164         # otherwise try using copy from build directory
    165         os.path.join(srcdir, 'Modules', 'xxmodule.c'),
    166         # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
    167         # this file is run from its parent directory, so walk up the
    168         # tree to find the real srcdir
    169         os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
    170     ]
    171     for path in candidates:
    172         if os.path.exists(path):
    173             return path
    174 
    175 
    176 def fixup_build_ext(cmd):
    177     """Function needed to make build_ext tests pass.
    178 
    179     When Python was built with --enable-shared on Unix, -L. is not enough to
    180     find libpython<blah>.so, because regrtest runs in a tempdir, not in the
    181     source directory where the .so lives.
    182 
    183     When Python was built with in debug mode on Windows, build_ext commands
    184     need their debug attribute set, and it is not done automatically for
    185     some reason.
    186 
    187     This function handles both of these things.  Example use:
    188 
    189         cmd = build_ext(dist)
    190         support.fixup_build_ext(cmd)
    191         cmd.ensure_finalized()
    192 
    193     Unlike most other Unix platforms, Mac OS X embeds absolute paths
    194     to shared libraries into executables, so the fixup is not needed there.
    195     """
    196     if os.name == 'nt':
    197         cmd.debug = sys.executable.endswith('_d.exe')
    198     elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
    199         # To further add to the shared builds fun on Unix, we can't just add
    200         # library_dirs to the Extension() instance because that doesn't get
    201         # plumbed through to the final compiler command.
    202         runshared = sysconfig.get_config_var('RUNSHARED')
    203         if runshared is None:
    204             cmd.library_dirs = ['.']
    205         else:
    206             if sys.platform == 'darwin':
    207                 cmd.library_dirs = []
    208             else:
    209                 name, equals, value = runshared.partition('=')
    210                 cmd.library_dirs = [d for d in value.split(os.pathsep) if d]
    211