blob: 44fcd6b7d8441800b747b2343824eb0b8a3e5a5f [file] [log] [blame]
Fred Drakeb8ab8b62004-06-17 20:14:50 +00001"""Support code for distutils test cases."""
Tarek Ziadéc1375d52009-02-14 14:35:51 +00002import os
Éric Araujo6e3ad872011-08-21 17:02:07 +02003import sys
Fred Drakeb8ab8b62004-06-17 20:14:50 +00004import shutil
5import tempfile
Éric Araujodef15da2011-08-20 06:27:18 +02006import unittest
7import sysconfig
Tarek Ziadé430fb632009-10-18 11:34:51 +00008from copy import deepcopy
Fred Drakeb8ab8b62004-06-17 20:14:50 +00009
Fred Drakeedcac8f2004-08-03 18:53:07 +000010from distutils import log
Tarek Ziadé31d46072009-09-21 13:55:19 +000011from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
Tarek Ziadébaf51802009-03-31 21:37:16 +000012from distutils.core import Distribution
Fred Drakeedcac8f2004-08-03 18:53:07 +000013
Éric Araujodef15da2011-08-20 06:27:18 +020014
Fred Drakeedcac8f2004-08-03 18:53:07 +000015class LoggingSilencer(object):
16
17 def setUp(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000018 super().setUp()
Fred Drakeedcac8f2004-08-03 18:53:07 +000019 self.threshold = log.set_threshold(log.FATAL)
Tarek Ziadé5af55c62009-05-16 16:52:13 +000020 # 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 = []
Fred Drakeedcac8f2004-08-03 18:53:07 +000026
27 def tearDown(self):
28 log.set_threshold(self.threshold)
Tarek Ziadé5af55c62009-05-16 16:52:13 +000029 log.Log._log = self._old_log
Guido van Rossumcd16bf62007-06-13 18:07:49 +000030 super().tearDown()
Fred Drakeedcac8f2004-08-03 18:53:07 +000031
Tarek Ziadé5af55c62009-05-16 16:52:13 +000032 def _log(self, level, msg, args):
Tarek Ziadé31d46072009-09-21 13:55:19 +000033 if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
34 raise ValueError('%s wrong log level' % str(level))
Tarek Ziadé5af55c62009-05-16 16:52:13 +000035 self.logs.append((level, msg, args))
36
37 def get_logs(self, *levels):
38 def _format(msg, args):
39 if len(args) == 0:
40 return msg
41 return msg % args
42 return [_format(msg, args) for level, msg, args
43 in self.logs if level in levels]
44
45 def clear_logs(self):
46 self.logs = []
Fred Drakeb8ab8b62004-06-17 20:14:50 +000047
Éric Araujodef15da2011-08-20 06:27:18 +020048
Fred Drakeb8ab8b62004-06-17 20:14:50 +000049class TempdirManager(object):
50 """Mix-in class that handles temporary directories for test cases.
51
52 This is intended to be used with unittest.TestCase.
53 """
54
55 def setUp(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000056 super().setUp()
Antoine Pitrou4fc80b62011-08-25 18:32:02 +020057 self.old_cwd = os.getcwd()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000058 self.tempdirs = []
59
60 def tearDown(self):
Antoine Pitrou4fc80b62011-08-25 18:32:02 +020061 # Restore working dir, for Solaris and derivatives, where rmdir()
62 # on the current directory fails.
63 os.chdir(self.old_cwd)
Guido van Rossumcd16bf62007-06-13 18:07:49 +000064 super().tearDown()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000065 while self.tempdirs:
66 d = self.tempdirs.pop()
Tarek Ziadéc1375d52009-02-14 14:35:51 +000067 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
Fred Drakeb8ab8b62004-06-17 20:14:50 +000068
69 def mkdtemp(self):
70 """Create a temporary directory that will be cleaned up.
71
72 Returns the path of the directory.
73 """
74 d = tempfile.mkdtemp()
75 self.tempdirs.append(d)
76 return d
77
Tarek Ziadébaf51802009-03-31 21:37:16 +000078 def write_file(self, path, content='xxx'):
Tarek Ziadé0d0506e2009-02-16 21:49:12 +000079 """Writes a file in the given path.
80
81
82 path can be a string or a sequence.
83 """
84 if isinstance(path, (list, tuple)):
85 path = os.path.join(*path)
86 f = open(path, 'w')
87 try:
88 f.write(content)
89 finally:
90 f.close()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000091
Tarek Ziadébaf51802009-03-31 21:37:16 +000092 def create_dist(self, pkg_name='foo', **kw):
93 """Will generate a test environment.
94
95 This function creates:
96 - a Distribution instance using keywords
97 - a temporary directory with a package structure
98
99 It returns the package directory and the distribution
100 instance.
101 """
102 tmp_dir = self.mkdtemp()
103 pkg_dir = os.path.join(tmp_dir, pkg_name)
104 os.mkdir(pkg_dir)
105 dist = Distribution(attrs=kw)
106
107 return pkg_dir, dist
108
Éric Araujodef15da2011-08-20 06:27:18 +0200109
Fred Drakeb8ab8b62004-06-17 20:14:50 +0000110class DummyCommand:
111 """Class to store options for retrieval via set_undefined_options()."""
112
113 def __init__(self, **kwargs):
114 for kw, val in kwargs.items():
115 setattr(self, kw, val)
116
117 def ensure_finalized(self):
118 pass
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000119
Éric Araujodef15da2011-08-20 06:27:18 +0200120
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000121class EnvironGuard(object):
122
123 def setUp(self):
124 super(EnvironGuard, self).setUp()
Tarek Ziadé430fb632009-10-18 11:34:51 +0000125 self.old_environ = deepcopy(os.environ)
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000126
127 def tearDown(self):
Tarek Ziadé430fb632009-10-18 11:34:51 +0000128 for key, value in self.old_environ.items():
129 if os.environ.get(key) != value:
130 os.environ[key] = value
131
132 for key in tuple(os.environ.keys()):
133 if key not in self.old_environ:
134 del os.environ[key]
135
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000136 super(EnvironGuard, self).tearDown()
Éric Araujodef15da2011-08-20 06:27:18 +0200137
138
139def copy_xxmodule_c(directory):
140 """Helper for tests that need the xxmodule.c source file.
141
142 Example use:
143
Éric Araujoe1e13312011-08-20 07:25:39 +0200144 def test_compile(self):
145 copy_xxmodule_c(self.tmpdir)
Éric Araujo52b201f2011-08-21 12:53:37 +0200146 self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
Éric Araujodef15da2011-08-20 06:27:18 +0200147
148 If the source file can be found, it will be copied to *directory*. If not,
149 the test will be skipped. Errors during copy are not caught.
150 """
151 filename = _get_xxmodule_path()
152 if filename is None:
153 raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
154 'the python build dir)')
155 shutil.copy(filename, directory)
156
157
158def _get_xxmodule_path():
159 srcdir = sysconfig.get_config_var('srcdir')
160 candidates = [
161 # use installed copy if available
162 os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
163 # otherwise try using copy from build directory
164 os.path.join(srcdir, 'Modules', 'xxmodule.c'),
165 # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
166 # this file is run from its parent directory, so walk up the
167 # tree to find the real srcdir
168 os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
169 ]
170 for path in candidates:
171 if os.path.exists(path):
172 return path
Éric Araujo6e3ad872011-08-21 17:02:07 +0200173
174
175def fixup_build_ext(cmd):
Éric Araujo175eb992011-08-24 01:29:10 +0200176 """Function needed to make build_ext tests pass.
Éric Araujo6e3ad872011-08-21 17:02:07 +0200177
Éric Araujo175eb992011-08-24 01:29:10 +0200178 When Python was build with --enable-shared on Unix, -L. is not good
179 enough to find the libpython<blah>.so. This is because regrtest runs
180 it under a tempdir, not in the top level where the .so lives. By the
181 time we've gotten here, Python's already been chdir'd to the tempdir.
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:
Éric Araujo6e3ad872011-08-21 17:02:07 +0200188
189 cmd = build_ext(dist)
190 support.fixup_build_ext(cmd)
191 cmd.ensure_finalized()
192 """
Éric Araujo175eb992011-08-24 01:29:10 +0200193 if os.name == 'nt':
194 cmd.debug = sys.executable.endswith('_d.exe')
195 elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
196 # To further add to the shared builds fun on Unix, we can't just add
197 # library_dirs to the Extension() instance because that doesn't get
198 # plumbed through to the final compiler command.
Éric Araujo6e3ad872011-08-21 17:02:07 +0200199 runshared = sysconfig.get_config_var('RUNSHARED')
200 if runshared is None:
201 cmd.library_dirs = ['.']
202 else:
203 name, equals, value = runshared.partition('=')
204 cmd.library_dirs = value.split(os.pathsep)