blob: de08f32d270e3b4a561bbbcca5b56f0e69bc94ef [file] [log] [blame]
Victor Stinner24f949e2016-03-22 15:14:09 +01001import datetime
Victor Stinner5f9d3ac2015-10-03 00:21:12 +02002import faulthandler
Victor Stinner3844fe52015-09-26 10:38:01 +02003import os
Victor Stinner3844fe52015-09-26 10:38:01 +02004import platform
Victor Stinnerdad20e42015-09-29 22:48:52 +02005import random
6import re
Victor Stinnerdad20e42015-09-29 22:48:52 +02007import sys
8import sysconfig
9import tempfile
10import textwrap
Victor Stinner24f949e2016-03-22 15:14:09 +010011import time
Victor Stinner3909e582015-10-11 10:37:25 +020012from test.libregrtest.cmdline import _parse_args
Victor Stinner3844fe52015-09-26 10:38:01 +020013from test.libregrtest.runtest import (
Victor Stinner6f20a2e2015-09-30 02:32:11 +020014 findtests, runtest,
Victor Stinner3909e582015-10-11 10:37:25 +020015 STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
Victor Stinner69649f22016-03-23 12:14:10 +010016 INTERRUPTED, CHILD_ERROR,
17 PROGRESS_MIN_TIME)
Victor Stinnera2045022015-09-30 02:17:28 +020018from test.libregrtest.setup import setup_tests
Victor Stinner3844fe52015-09-26 10:38:01 +020019from test import support
20try:
Victor Stinnerdad20e42015-09-29 22:48:52 +020021 import gc
22except ImportError:
23 gc = None
Victor Stinner3844fe52015-09-26 10:38:01 +020024
25
Victor Stinner3844fe52015-09-26 10:38:01 +020026# When tests are run from the Python build directory, it is best practice
27# to keep the test files in a subfolder. This eases the cleanup of leftover
28# files using the "make distclean" command.
29if sysconfig.is_python_build():
30 TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
31else:
32 TEMPDIR = tempfile.gettempdir()
33TEMPDIR = os.path.abspath(TEMPDIR)
34
35
Victor Stinnerdad20e42015-09-29 22:48:52 +020036class Regrtest:
Victor Stinner3844fe52015-09-26 10:38:01 +020037 """Execute a test suite.
38
39 This also parses command-line options and modifies its behavior
40 accordingly.
41
42 tests -- a list of strings containing test names (optional)
43 testdir -- the directory in which to look for tests (optional)
44
45 Users other than the Python test suite will certainly want to
46 specify testdir; if it's omitted, the directory containing the
47 Python test suite is searched for.
48
49 If the tests argument is omitted, the tests listed on the
50 command-line will be used. If that's empty, too, then all *.py
51 files beginning with test_ will be used.
52
53 The other default arguments (verbose, quiet, exclude,
54 single, randomize, findleaks, use_resources, trace, coverdir,
55 print_slow, and random_seed) allow programmers calling main()
56 directly to set the values that would normally be set by flags
57 on the command line.
58 """
Victor Stinnerdad20e42015-09-29 22:48:52 +020059 def __init__(self):
60 # Namespace of command line options
61 self.ns = None
Victor Stinner3844fe52015-09-26 10:38:01 +020062
Victor Stinnerdad20e42015-09-29 22:48:52 +020063 # tests
64 self.tests = []
65 self.selected = []
Victor Stinner3844fe52015-09-26 10:38:01 +020066
Victor Stinnerdad20e42015-09-29 22:48:52 +020067 # test results
68 self.good = []
69 self.bad = []
70 self.skipped = []
71 self.resource_denieds = []
72 self.environment_changed = []
73 self.interrupted = False
Victor Stinner3844fe52015-09-26 10:38:01 +020074
Victor Stinnerdad20e42015-09-29 22:48:52 +020075 # used by --slow
76 self.test_times = []
Victor Stinner3844fe52015-09-26 10:38:01 +020077
Victor Stinnerdad20e42015-09-29 22:48:52 +020078 # used by --coverage, trace.Trace instance
79 self.tracer = None
Victor Stinner3844fe52015-09-26 10:38:01 +020080
Victor Stinnerdad20e42015-09-29 22:48:52 +020081 # used by --findleaks, store for gc.garbage
82 self.found_garbage = []
Victor Stinner3844fe52015-09-26 10:38:01 +020083
Victor Stinnerdad20e42015-09-29 22:48:52 +020084 # used to display the progress bar "[ 3/100]"
Victor Stinner24f949e2016-03-22 15:14:09 +010085 self.start_time = time.monotonic()
Victor Stinnerdad20e42015-09-29 22:48:52 +020086 self.test_count = ''
87 self.test_count_width = 1
Victor Stinner3844fe52015-09-26 10:38:01 +020088
Victor Stinnerdad20e42015-09-29 22:48:52 +020089 # used by --single
90 self.next_single_test = None
91 self.next_single_filename = None
Victor Stinner3844fe52015-09-26 10:38:01 +020092
Victor Stinnerdad20e42015-09-29 22:48:52 +020093 def accumulate_result(self, test, result):
Victor Stinner3844fe52015-09-26 10:38:01 +020094 ok, test_time = result
Victor Stinner3909e582015-10-11 10:37:25 +020095 if ok not in (CHILD_ERROR, INTERRUPTED):
96 self.test_times.append((test_time, test))
Victor Stinner3844fe52015-09-26 10:38:01 +020097 if ok == PASSED:
Victor Stinnerdad20e42015-09-29 22:48:52 +020098 self.good.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +020099 elif ok == FAILED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200100 self.bad.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200101 elif ok == ENV_CHANGED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200102 self.environment_changed.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200103 elif ok == SKIPPED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200104 self.skipped.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200105 elif ok == RESOURCE_DENIED:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200106 self.skipped.append(test)
107 self.resource_denieds.append(test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200108
Victor Stinner24f949e2016-03-22 15:14:09 +0100109 def time_delta(self):
110 seconds = time.monotonic() - self.start_time
111 return datetime.timedelta(seconds=int(seconds))
112
Victor Stinnerdad20e42015-09-29 22:48:52 +0200113 def display_progress(self, test_index, test):
114 if self.ns.quiet:
115 return
Brett Cannon11faa212015-10-02 16:20:49 -0700116 if self.bad and not self.ns.pgo:
Victor Stinner24f949e2016-03-22 15:14:09 +0100117 fmt = "{time} [{test_index:{count_width}}{test_count}/{nbad}] {test_name}"
Brett Cannon11faa212015-10-02 16:20:49 -0700118 else:
Victor Stinner24f949e2016-03-22 15:14:09 +0100119 fmt = "{time} [{test_index:{count_width}}{test_count}] {test_name}"
120 line = fmt.format(count_width=self.test_count_width,
121 test_index=test_index,
122 test_count=self.test_count,
123 nbad=len(self.bad),
124 test_name=test,
125 time=self.time_delta())
126 print(line, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200127
Victor Stinner234cbef2015-09-30 01:13:53 +0200128 def parse_args(self, kwargs):
129 ns = _parse_args(sys.argv[1:], **kwargs)
130
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200131 if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'):
132 print("Warning: The timeout option requires "
133 "faulthandler.dump_traceback_later", file=sys.stderr)
134 ns.timeout = None
135
Victor Stinner234cbef2015-09-30 01:13:53 +0200136 if ns.threshold is not None and gc is None:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200137 print('No GC available, ignore --threshold.', file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200138 ns.threshold = None
139
140 if ns.findleaks:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200141 if gc is not None:
142 # Uncomment the line below to report garbage that is not
143 # freeable by reference counting alone. By default only
144 # garbage that is not collectable by the GC is reported.
145 pass
146 #gc.set_debug(gc.DEBUG_SAVEALL)
147 else:
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200148 print('No GC available, disabling --findleaks',
149 file=sys.stderr)
Victor Stinner234cbef2015-09-30 01:13:53 +0200150 ns.findleaks = False
Victor Stinnerdad20e42015-09-29 22:48:52 +0200151
Victor Stinnerdad20e42015-09-29 22:48:52 +0200152 # Strip .py extensions.
Victor Stinner234cbef2015-09-30 01:13:53 +0200153 removepy(ns.args)
154
155 return ns
Victor Stinnerdad20e42015-09-29 22:48:52 +0200156
Victor Stinnerdad20e42015-09-29 22:48:52 +0200157 def find_tests(self, tests):
158 self.tests = tests
159
160 if self.ns.single:
161 self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
162 try:
163 with open(self.next_single_filename, 'r') as fp:
164 next_test = fp.read().strip()
165 self.tests = [next_test]
166 except OSError:
167 pass
168
169 if self.ns.fromfile:
170 self.tests = []
Victor Stinner5de16e82016-03-24 09:43:00 +0100171 # regex to match 'test_builtin' in line:
172 # '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec'
173 regex = (r'^(?:[0-9]+:[0-9]+:[0-9]+ *)?'
174 r'(?:\[[0-9/ ]+\] *)?'
175 r'(test_[a-zA-Z0-9_]+)')
176 regex = re.compile(regex)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200177 with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200178 for line in fp:
Victor Stinner5de16e82016-03-24 09:43:00 +0100179 line = line.strip()
180 if line.startswith('#'):
181 continue
182 match = regex.match(line)
183 if match is None:
184 continue
185 self.tests.append(match.group(1))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200186
187 removepy(self.tests)
188
189 stdtests = STDTESTS[:]
190 nottests = NOTTESTS.copy()
191 if self.ns.exclude:
192 for arg in self.ns.args:
193 if arg in stdtests:
194 stdtests.remove(arg)
195 nottests.add(arg)
196 self.ns.args = []
197
Victor Stinnerdad20e42015-09-29 22:48:52 +0200198 # if testdir is set, then we are not running the python tests suite, so
199 # don't add default tests to be executed or skipped (pass empty values)
200 if self.ns.testdir:
201 alltests = findtests(self.ns.testdir, list(), set())
202 else:
203 alltests = findtests(self.ns.testdir, stdtests, nottests)
204
Victor Stinner5de16e82016-03-24 09:43:00 +0100205 if not self.ns.fromfile:
206 self.selected = self.tests or self.ns.args or alltests
207 else:
208 self.selected = self.tests
Victor Stinnerdad20e42015-09-29 22:48:52 +0200209 if self.ns.single:
210 self.selected = self.selected[:1]
211 try:
212 pos = alltests.index(self.selected[0])
213 self.next_single_test = alltests[pos + 1]
214 except IndexError:
215 pass
216
Victor Stinnerc7eab052015-09-30 00:59:35 +0200217 # Remove all the selected tests that precede start if it's set.
Victor Stinnerdad20e42015-09-29 22:48:52 +0200218 if self.ns.start:
219 try:
220 del self.selected[:self.selected.index(self.ns.start)]
221 except ValueError:
Victor Stinner6448b802015-09-29 23:43:33 +0200222 print("Couldn't find starting test (%s), using all tests"
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200223 % self.ns.start, file=sys.stderr)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200224
225 if self.ns.randomize:
226 if self.ns.random_seed is None:
227 self.ns.random_seed = random.randrange(10000000)
228 random.seed(self.ns.random_seed)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200229 random.shuffle(self.selected)
230
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200231 def list_tests(self):
232 for name in self.selected:
233 print(name)
234
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200235 def rerun_failed_tests(self):
236 self.ns.verbose = True
237 self.ns.failfast = False
238 self.ns.verbose3 = False
239 self.ns.match_tests = None
240
241 print("Re-running failed tests in verbose mode")
242 for test in self.bad[:]:
243 print("Re-running test %r in verbose mode" % test, flush=True)
244 try:
245 self.ns.verbose = True
246 ok = runtest(self.ns, test)
247 except KeyboardInterrupt:
248 # print a newline separate from the ^C
249 print()
250 break
251 else:
252 if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
253 self.bad.remove(test)
254 else:
255 if self.bad:
256 print(count(len(self.bad), 'test'), "failed again:")
257 printlist(self.bad)
258
Victor Stinnerdad20e42015-09-29 22:48:52 +0200259 def display_result(self):
260 if self.interrupted:
261 # print a newline after ^C
262 print()
263 print("Test suite interrupted by signal SIGINT.")
Victor Stinner6448b802015-09-29 23:43:33 +0200264 executed = set(self.good) | set(self.bad) | set(self.skipped)
265 omitted = set(self.selected) - executed
Victor Stinnerdad20e42015-09-29 22:48:52 +0200266 print(count(len(omitted), "test"), "omitted:")
267 printlist(omitted)
268
Brett Cannon11faa212015-10-02 16:20:49 -0700269 # If running the test suite for PGO then no one cares about
270 # results.
271 if self.ns.pgo:
272 return
273
Victor Stinnerdad20e42015-09-29 22:48:52 +0200274 if self.good and not self.ns.quiet:
Victor Stinner6448b802015-09-29 23:43:33 +0200275 if (not self.bad
276 and not self.skipped
277 and not self.interrupted
278 and len(self.good) > 1):
Victor Stinnerdad20e42015-09-29 22:48:52 +0200279 print("All", end=' ')
280 print(count(len(self.good), "test"), "OK.")
281
282 if self.ns.print_slow:
283 self.test_times.sort(reverse=True)
284 print("10 slowest tests:")
285 for time, test in self.test_times[:10]:
286 print("%s: %.1fs" % (test, time))
287
288 if self.bad:
289 print(count(len(self.bad), "test"), "failed:")
290 printlist(self.bad)
291
292 if self.environment_changed:
293 print("{} altered the execution environment:".format(
294 count(len(self.environment_changed), "test")))
295 printlist(self.environment_changed)
296
297 if self.skipped and not self.ns.quiet:
298 print(count(len(self.skipped), "test"), "skipped:")
299 printlist(self.skipped)
300
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200301 def run_tests_sequential(self):
Victor Stinnerc7eab052015-09-30 00:59:35 +0200302 if self.ns.trace:
303 import trace
Victor Stinnera53a8182015-10-01 00:53:09 +0200304 self.tracer = trace.Trace(trace=False, count=True)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200305
Victor Stinnerdad20e42015-09-29 22:48:52 +0200306 save_modules = sys.modules.keys()
307
Victor Stinner69649f22016-03-23 12:14:10 +0100308 previous_test = None
Victor Stinnerdad20e42015-09-29 22:48:52 +0200309 for test_index, test in enumerate(self.tests, 1):
Victor Stinner69649f22016-03-23 12:14:10 +0100310 start_time = time.monotonic()
311
312 text = test
313 if previous_test:
314 text = '%s -- %s' % (text, previous_test)
315 self.display_progress(test_index, text)
316
Victor Stinnerc7eab052015-09-30 00:59:35 +0200317 if self.tracer:
Victor Stinner3844fe52015-09-26 10:38:01 +0200318 # If we're tracing code coverage, then we don't exit with status
319 # if on a false return value from main.
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200320 cmd = ('result = runtest(self.ns, test); '
321 'self.accumulate_result(test, result)')
Victor Stinnerdad20e42015-09-29 22:48:52 +0200322 self.tracer.runctx(cmd, globals=globals(), locals=vars())
Victor Stinner3844fe52015-09-26 10:38:01 +0200323 else:
324 try:
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200325 result = runtest(self.ns, test)
Victor Stinner3844fe52015-09-26 10:38:01 +0200326 except KeyboardInterrupt:
Victor Stinner3909e582015-10-11 10:37:25 +0200327 self.accumulate_result(test, (INTERRUPTED, None))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200328 self.interrupted = True
Victor Stinner3844fe52015-09-26 10:38:01 +0200329 break
Victor Stinner3909e582015-10-11 10:37:25 +0200330 else:
331 self.accumulate_result(test, result)
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200332
Victor Stinner69649f22016-03-23 12:14:10 +0100333 test_time = time.monotonic() - start_time
334 if test_time >= PROGRESS_MIN_TIME:
335 previous_test = '%s took %.0f sec' % (test, test_time)
336 else:
337 previous_test = None
338
Victor Stinnerdad20e42015-09-29 22:48:52 +0200339 if self.ns.findleaks:
Victor Stinner3844fe52015-09-26 10:38:01 +0200340 gc.collect()
341 if gc.garbage:
342 print("Warning: test created", len(gc.garbage), end=' ')
343 print("uncollectable object(s).")
344 # move the uncollectable objects somewhere so we don't see
345 # them again
Victor Stinnerdad20e42015-09-29 22:48:52 +0200346 self.found_garbage.extend(gc.garbage)
Victor Stinner3844fe52015-09-26 10:38:01 +0200347 del gc.garbage[:]
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200348
Victor Stinner3844fe52015-09-26 10:38:01 +0200349 # Unload the newly imported modules (best effort finalization)
350 for module in sys.modules.keys():
351 if module not in save_modules and module.startswith("test."):
352 support.unload(module)
353
Victor Stinner69649f22016-03-23 12:14:10 +0100354 if previous_test:
355 print(previous_test)
356
Victor Stinnerb4084352015-09-30 02:39:22 +0200357 def _test_forever(self, tests):
358 while True:
359 for test in tests:
360 yield test
361 if self.bad:
362 return
Victor Stinner3844fe52015-09-26 10:38:01 +0200363
Victor Stinnerb4084352015-09-30 02:39:22 +0200364 def run_tests(self):
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200365 # For a partial run, we do not need to clutter the output.
366 if (self.ns.verbose
367 or self.ns.header
Brett Cannon11faa212015-10-02 16:20:49 -0700368 or not (self.ns.pgo or self.ns.quiet or self.ns.single
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200369 or self.tests or self.ns.args)):
370 # Print basic platform information
371 print("==", platform.python_implementation(), *sys.version.split())
372 print("== ", platform.platform(aliased=True),
373 "%s-endian" % sys.byteorder)
374 print("== ", "hash algorithm:", sys.hash_info.algorithm,
375 "64bit" if sys.maxsize > 2**32 else "32bit")
376 print("== ", os.getcwd())
377 print("Testing with flags:", sys.flags)
378
379 if self.ns.randomize:
380 print("Using random seed", self.ns.random_seed)
381
Victor Stinnerdad20e42015-09-29 22:48:52 +0200382 if self.ns.forever:
Victor Stinner9a142142015-09-30 13:51:17 +0200383 self.tests = self._test_forever(list(self.selected))
Victor Stinnerdad20e42015-09-29 22:48:52 +0200384 self.test_count = ''
385 self.test_count_width = 3
386 else:
387 self.tests = iter(self.selected)
388 self.test_count = '/{}'.format(len(self.selected))
389 self.test_count_width = len(self.test_count) - 1
390
391 if self.ns.use_mp:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200392 from test.libregrtest.runtest_mp import run_tests_multiprocess
393 run_tests_multiprocess(self)
Victor Stinnerdad20e42015-09-29 22:48:52 +0200394 else:
Victor Stinnerbd1a72c2015-09-29 23:36:27 +0200395 self.run_tests_sequential()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200396
397 def finalize(self):
398 if self.next_single_filename:
399 if self.next_single_test:
400 with open(self.next_single_filename, 'w') as fp:
401 fp.write(self.next_single_test + '\n')
Victor Stinner3844fe52015-09-26 10:38:01 +0200402 else:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200403 os.unlink(self.next_single_filename)
Victor Stinner3844fe52015-09-26 10:38:01 +0200404
Victor Stinnerc7eab052015-09-30 00:59:35 +0200405 if self.tracer:
Victor Stinnerdad20e42015-09-29 22:48:52 +0200406 r = self.tracer.results()
407 r.write_results(show_missing=True, summary=True,
408 coverdir=self.ns.coverdir)
Victor Stinner3844fe52015-09-26 10:38:01 +0200409
Victor Stinner24f949e2016-03-22 15:14:09 +0100410 print("Total duration: %s" % self.time_delta())
411
Victor Stinnerdad20e42015-09-29 22:48:52 +0200412 if self.ns.runleaks:
413 os.system("leaks %d" % os.getpid())
Victor Stinner3844fe52015-09-26 10:38:01 +0200414
Victor Stinnerdad20e42015-09-29 22:48:52 +0200415 def main(self, tests=None, **kwargs):
Victor Stinner234cbef2015-09-30 01:13:53 +0200416 self.ns = self.parse_args(kwargs)
417
Victor Stinnerdad20e42015-09-29 22:48:52 +0200418 if self.ns.slaveargs is not None:
Victor Stinner56e05dd2015-09-29 23:15:38 +0200419 from test.libregrtest.runtest_mp import run_tests_slave
420 run_tests_slave(self.ns.slaveargs)
Victor Stinnerecef6222015-09-30 01:39:28 +0200421
Victor Stinnerc7eab052015-09-30 00:59:35 +0200422 if self.ns.wait:
423 input("Press any key to continue...")
424
Victor Stinnera2045022015-09-30 02:17:28 +0200425 setup_tests(self.ns)
Victor Stinnerecef6222015-09-30 01:39:28 +0200426
Victor Stinnerdad20e42015-09-29 22:48:52 +0200427 self.find_tests(tests)
Victor Stinnerc7eab052015-09-30 00:59:35 +0200428
Victor Stinner5f9d3ac2015-10-03 00:21:12 +0200429 if self.ns.list_tests:
430 self.list_tests()
431 sys.exit(0)
432
433 self.run_tests()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200434 self.display_result()
Victor Stinner6f20a2e2015-09-30 02:32:11 +0200435
436 if self.ns.verbose2 and self.bad:
437 self.rerun_failed_tests()
438
Victor Stinnerdad20e42015-09-29 22:48:52 +0200439 self.finalize()
440 sys.exit(len(self.bad) > 0 or self.interrupted)
Victor Stinner3844fe52015-09-26 10:38:01 +0200441
442
Victor Stinner3844fe52015-09-26 10:38:01 +0200443def removepy(names):
444 if not names:
445 return
446 for idx, name in enumerate(names):
447 basename, ext = os.path.splitext(name)
448 if ext == '.py':
449 names[idx] = basename
450
451
452def count(n, word):
453 if n == 1:
454 return "%d %s" % (n, word)
455 else:
456 return "%d %ss" % (n, word)
457
458
459def printlist(x, width=70, indent=4):
460 """Print the elements of iterable x to stdout.
461
462 Optional arg width (default 70) is the maximum line length.
463 Optional arg indent (default 4) is the number of blanks with which to
464 begin each line.
465 """
466
Victor Stinner3844fe52015-09-26 10:38:01 +0200467 blanks = ' ' * indent
468 # Print the sorted list: 'x' may be a '--random' list or a set()
Victor Stinnerdad20e42015-09-29 22:48:52 +0200469 print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
470 initial_indent=blanks, subsequent_indent=blanks))
471
472
473def main(tests=None, **kwargs):
474 Regrtest().main(tests=tests, **kwargs)
Victor Stinner3844fe52015-09-26 10:38:01 +0200475
476
477def main_in_temp_cwd():
478 """Run main() in a temporary working directory."""
479 if sysconfig.is_python_build():
480 try:
481 os.mkdir(TEMPDIR)
482 except FileExistsError:
483 pass
484
485 # Define a writable temp dir that will be used as cwd while running
486 # the tests. The name of the dir includes the pid to allow parallel
487 # testing (see the -j option).
488 test_cwd = 'test_python_{}'.format(os.getpid())
489 test_cwd = os.path.join(TEMPDIR, test_cwd)
490
491 # Run the tests in a context manager that temporarily changes the CWD to a
492 # temporary and writable directory. If it's not possible to create or
493 # change the CWD, the original CWD will be used. The original CWD is
494 # available from support.SAVEDCWD.
495 with support.temp_cwd(test_cwd, quiet=True):
496 main()