diff options
Diffstat (limited to 'Lib/test/regrtest.py')
-rwxr-xr-x | Lib/test/regrtest.py | 888 |
1 files changed, 513 insertions, 375 deletions
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index dd47cc36e01..84beb8dee5c 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1,9 +1,9 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 """ Usage: -python -m test.regrtest [options] [test_name1 [test_name2 ...]] +python -m test [options] [test_name1 [test_name2 ...]] python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]] @@ -14,7 +14,7 @@ them in alphabetical order (but see -M and -u, below, for exceptions). For more rigorous testing, it is useful to use the following command line: -python -E -tt -Wd -3 -m test.regrtest [options] [test_name1 ...] +python -E -Wd -m test [options] [test_name1 ...] Options: @@ -25,9 +25,10 @@ Verbosity -v/--verbose -- run tests in verbose mode with output to stdout -w/--verbose2 -- re-run failed tests in verbose mode --W/--verbose3 -- re-run failed tests in verbose mode immediately +-W/--verbose3 -- display test output on failure +-d/--debug -- print traceback for failed tests -q/--quiet -- no output unless one or more tests fail --S/--slow -- print the slowest 10 tests +-o/--slow -- print the slowest 10 tests --header -- print header with interpreter info Selecting tests @@ -37,6 +38,8 @@ Selecting tests -f/--fromfile -- read names of tests to run from a file (see below) -x/--exclude -- arguments are tests to *exclude* -s/--single -- single step through a set of tests (see below) +-m/--match PAT -- match test cases and methods with glob pattern PAT +-G/--failfast -- fail as soon as a test fails (only with -v or -W) -u/--use RES1,RES2,... -- specify which special resource intensive tests to run -M/--memlimit LIMIT @@ -56,6 +59,7 @@ Special runs -N/--nocoverdir -- Put coverage files alongside modules -t/--threshold THRESHOLD -- call gc.set_threshold(THRESHOLD) +-n/--nowindows -- suppress error message boxes on Windows -F/--forever -- run the specified tests in a loop, until an error happens @@ -76,6 +80,12 @@ is possible to single step through the test files. This is useful when doing memory analysis on the Python interpreter, which process tends to consume too many resources to run the full regression test non-stop. +-S is used to continue running tests after an aborted run. It will +maintain the order a standard run (ie, this assumes -r is not used). +This is useful after the tests have prematurely stopped for some external +reason and you want to start running from where you left off rather +than starting from the beginning. + -f reads the names of tests from the file given as f's argument, one or more test names per line. Whitespace is ignored. Blank lines and lines beginning with '#' are ignored. This is especially useful for @@ -129,9 +139,6 @@ resources to test. Currently only the following are defined: network - It is okay to run tests that use external network resource, e.g. testing SSL support for sockets. - bsddb - It is okay to run the bsddb testsuite, which takes - a long time to complete. - decimal - Test the decimal module against a large suite that verifies compliance with standards. @@ -143,30 +150,39 @@ resources to test. Currently only the following are defined: gui - Run tests that require a running GUI. - xpickle - Test pickle and cPickle against Python 2.4, 2.5 and 2.6 to - test backwards compatibility. These tests take a long time - to run. - To enable all resources except one, use '-uall,-<resource>'. For -example, to run all the tests except for the bsddb tests, give the -option '-uall,-bsddb'. +example, to run all the tests except for the gui tests, give the +option '-uall,-gui'. """ -import StringIO +import builtins +import errno import getopt +import io import json +import logging import os +import platform import random import re +import shutil import sys +import sysconfig +import tempfile import time import traceback -import warnings import unittest -import tempfile -import imp -import platform -import sysconfig +import warnings +from inspect import isabstract + +try: + import threading +except ImportError: + threading = None +try: + import multiprocessing.process +except ImportError: + multiprocessing = None # Some times __path__ and __file__ are not absolute (e.g. while running from @@ -179,7 +195,7 @@ import sysconfig # (site.py absolutize them), the __file__ and __path__ will be absolute too. # Therefore it is necessary to absolutize manually the __file__ and __path__ of # the packages to prevent later imports to fail when the CWD is different. -for module in sys.modules.itervalues(): +for module in sys.modules.values(): if hasattr(module, '__path__'): module.__path__ = [os.path.abspath(path) for path in module.__path__] if hasattr(module, '__file__'): @@ -210,19 +226,17 @@ SKIPPED = -2 RESOURCE_DENIED = -3 INTERRUPTED = -4 -from test import test_support +from test import support -RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network', 'bsddb', - 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', - 'xpickle') +RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network', + 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui') TEMPDIR = os.path.abspath(tempfile.gettempdir()) - -def usage(code, msg=''): - print __doc__ - if msg: print msg - sys.exit(code) +def usage(msg): + print(msg, file=sys.stderr) + print("Use --help for usage", file=sys.stderr) + sys.exit(2) def main(tests=None, testdir=None, verbose=0, quiet=False, @@ -230,7 +244,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, random_seed=None, use_mp=None, verbose3=False, forever=False, - header=False): + header=False, failfast=False, match_tests=None): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -254,39 +268,51 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, on the command line. """ - test_support.record_original_stdout(sys.stdout) + replace_stdout() + + support.record_original_stdout(sys.stdout) try: - opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:FwWM:j:', + opts, args = getopt.getopt(sys.argv[1:], 'hvqxsoS:rf:lu:t:TD:NLR:FdwWM:nj:Gm:', ['help', 'verbose', 'verbose2', 'verbose3', 'quiet', 'exclude', 'single', 'slow', 'randomize', 'fromfile=', 'findleaks', - 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', + 'use=', 'threshold=', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', - 'multiprocess=', 'slaveargs=', 'forever', 'header']) - except getopt.error, msg: - usage(2, msg) + 'multiprocess=', 'coverage', 'slaveargs=', 'forever', 'debug', + 'start=', 'nowindows', 'header', 'failfast', 'match=']) + except getopt.error as msg: + usage(msg) # Defaults if random_seed is None: random_seed = random.randrange(10000000) if use_resources is None: use_resources = [] + debug = False + start = None for o, a in opts: if o in ('-h', '--help'): - usage(0) + print(__doc__) + return elif o in ('-v', '--verbose'): verbose += 1 elif o in ('-w', '--verbose2'): verbose2 = True + elif o in ('-d', '--debug'): + debug = True elif o in ('-W', '--verbose3'): verbose3 = True + elif o in ('-G', '--failfast'): + failfast = True elif o in ('-q', '--quiet'): quiet = True; verbose = 0 elif o in ('-x', '--exclude'): exclude = True + elif o in ('-S', '--start'): + start = a elif o in ('-s', '--single'): single = True - elif o in ('-S', '--slow'): + elif o in ('-o', '--slow'): print_slow = True elif o in ('-r', '--randomize'): randomize = True @@ -294,6 +320,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, random_seed = int(a) elif o in ('-f', '--fromfile'): fromfile = a + elif o in ('-m', '--match'): + match_tests = a elif o in ('-l', '--findleaks'): findleaks = True elif o in ('-L', '--runleaks'): @@ -310,8 +338,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, elif o in ('-R', '--huntrleaks'): huntrleaks = a.split(':') if len(huntrleaks) not in (2, 3): - print a, huntrleaks - usage(2, '-R takes 2 or 3 colon-separated arguments') + print(a, huntrleaks) + usage('-R takes 2 or 3 colon-separated arguments') if not huntrleaks[0]: huntrleaks[0] = 5 else: @@ -322,8 +350,11 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, huntrleaks[1] = int(huntrleaks[1]) if len(huntrleaks) == 2 or not huntrleaks[2]: huntrleaks[2:] = ["reflog.txt"] + # Avoid false positives due to the character cache in + # stringobject.c filling slowly with random data + warm_char_cache() elif o in ('-M', '--memlimit'): - test_support.set_memlimit(a) + support.set_memlimit(a) elif o in ('-u', '--use'): u = [x.lower() for x in a.split(',')] for r in u: @@ -335,12 +366,27 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, remove = True r = r[1:] if r not in RESOURCE_NAMES: - usage(1, 'Invalid -u/--use option: ' + a) + usage('Invalid -u/--use option: ' + a) if remove: if r in use_resources: use_resources.remove(r) elif r not in use_resources: use_resources.append(r) + elif o in ('-n', '--nowindows'): + import msvcrt + msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS| + msvcrt.SEM_NOALIGNMENTFAULTEXCEPT| + msvcrt.SEM_NOGPFAULTERRORBOX| + msvcrt.SEM_NOOPENFILEERRORBOX) + try: + msvcrt.CrtSetReportMode + except AttributeError: + # release build + pass + else: + for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: + msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) + msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) elif o in ('-F', '--forever'): forever = True elif o in ('-j', '--multiprocess'): @@ -351,21 +397,26 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, args, kwargs = json.loads(a) try: result = runtest(*args, **kwargs) - except BaseException, e: + except BaseException as e: result = INTERRUPTED, e.__class__.__name__ - print # Force a newline (just in case) - print json.dumps(result) + sys.stdout.flush() + print() # Force a newline (just in case) + print(json.dumps(result)) sys.exit(0) else: - print >>sys.stderr, ("No handler for option {}. Please " - "report this as a bug at http://bugs.python.org.").format(o) + print(("No handler for option {}. Please report this as a bug " + "at http://bugs.python.org.").format(o), file=sys.stderr) sys.exit(1) if single and fromfile: - usage(2, "-s and -f don't go together!") + usage("-s and -f don't go together!") if use_mp and trace: - usage(2, "-T and -j don't go together!") + usage("-T and -j don't go together!") if use_mp and findleaks: - usage(2, "-l and -j don't go together!") + usage("-l and -j don't go together!") + if use_mp and support.max_memuse: + usage("-M and -j don't go together!") + if failfast and not (verbose or verbose3): + usage("-G/--failfast needs either -v or -W") good = [] bad = [] @@ -378,7 +429,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, try: import gc except ImportError: - print 'No GC available, disabling findleaks.' + print('No GC available, disabling findleaks.') findleaks = False else: # Uncomment the line below to report garbage that is not @@ -399,8 +450,10 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, if fromfile: tests = [] - fp = open(os.path.join(test_support.SAVEDCWD, fromfile)) + fp = open(os.path.join(support.SAVEDCWD, fromfile)) + count_pat = re.compile(r'\[\s*\d+/\s*\d+\]') for line in fp: + line = count_pat.sub('', line) guts = line.split() # assuming no test has whitespace in its name if guts and not guts[0].startswith('#'): tests.extend(guts) @@ -422,12 +475,11 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, # For a partial run, we do not need to clutter the output. if verbose or header or not (quiet or single or tests or args): # Print basic platform information - print "==", platform.python_implementation(), \ - " ".join(sys.version.split()) - print "== ", platform.platform(aliased=True), \ - "%s-endian" % sys.byteorder - print "== ", os.getcwd() - print "Testing with flags:", sys.flags + print("==", platform.python_implementation(), *sys.version.split()) + print("== ", platform.platform(aliased=True), + "%s-endian" % sys.byteorder) + print("== ", os.getcwd()) + print("Testing with flags:", sys.flags) alltests = findtests(testdir, stdtests, nottests) selected = tests or args or alltests @@ -437,17 +489,25 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, next_single_test = alltests[alltests.index(selected[0])+1] except IndexError: next_single_test = None + # Remove all the selected tests that precede start if it's set. + if start: + try: + del selected[:selected.index(start)] + except ValueError: + print("Couldn't find starting test (%s), using all tests" % start) if randomize: random.seed(random_seed) - print "Using random seed", random_seed + print("Using random seed", random_seed) random.shuffle(selected) if trace: - import trace - tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix], + import trace, tempfile + tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix, + tempfile.gettempdir()], trace=False, count=True) test_times = [] - test_support.use_resources = use_resources + support.verbose = verbose # Tell tests to be moderately quiet + support.use_resources = use_resources save_modules = sys.modules.keys() def accumulate_result(test, result): @@ -458,7 +518,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, elif ok == FAILED: bad.append(test) elif ok == ENV_CHANGED: - bad.append(test) environment_changed.append(test) elif ok == SKIPPED: skipped.append(test) @@ -474,43 +533,50 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, if bad: return tests = test_forever() + test_count = '' + test_count_width = 3 else: tests = iter(selected) + test_count = '/{}'.format(len(selected)) + test_count_width = len(test_count) - 1 if use_mp: try: from threading import Thread except ImportError: - print "Multiprocess option requires thread support" + print("Multiprocess option requires thread support") sys.exit(2) - from Queue import Queue + from queue import Queue from subprocess import Popen, PIPE debug_output_pat = re.compile(r"\[\d+ refs\]$") output = Queue() - def tests_and_args(): - for test in tests: - args_tuple = ( - (test, verbose, quiet), - dict(huntrleaks=huntrleaks, use_resources=use_resources) - ) - yield (test, args_tuple) - pending = tests_and_args() - opt_args = test_support.args_from_interpreter_flags() + pending = MultiprocessTests(tests) + opt_args = support.args_from_interpreter_flags() base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] def work(): # A worker thread. try: while True: try: - test, args_tuple = next(pending) + test = next(pending) except StopIteration: output.put((None, None, None, None)) return + args_tuple = ( + (test, verbose, quiet), + dict(huntrleaks=huntrleaks, use_resources=use_resources, + debug=debug, output_on_failure=verbose3, + failfast=failfast, match_tests=match_tests) + ) # -E is needed by some tests, e.g. test_import + # Running the child from the same working directory ensures + # that TEMPDIR for the child is the same when + # sysconfig.is_python_build() is true. See issue 15300. popen = Popen(base_cmd + ['--slaveargs', json.dumps(args_tuple)], stdout=PIPE, stderr=PIPE, universal_newlines=True, - close_fds=(os.name != 'nt')) + close_fds=(os.name != 'nt'), + cwd=support.SAVEDCWD) stdout, stderr = popen.communicate() # Strip last refcount output line if it exists, since it # comes from the shutdown of the interpreter in the subcommand. @@ -520,8 +586,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, output.put((None, None, None, None)) return result = json.loads(result) - if not quiet: - stdout = test+'\n'+stdout output.put((test, stdout.rstrip(), stderr.rstrip(), result)) except BaseException: output.put((None, None, None, None)) @@ -530,31 +594,40 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, for worker in workers: worker.start() finished = 0 + test_index = 1 try: while finished < use_mp: test, stdout, stderr, result = output.get() if test is None: finished += 1 continue + accumulate_result(test, result) + if not quiet: + fmt = "[{1:{0}}{2}/{3}] {4}" if bad else "[{1:{0}}{2}] {4}" + print(fmt.format( + test_count_width, test_index, test_count, + len(bad), test)) if stdout: - print stdout + print(stdout) if stderr: - print >>sys.stderr, stderr + print(stderr, file=sys.stderr) sys.stdout.flush() sys.stderr.flush() if result[0] == INTERRUPTED: assert result[1] == 'KeyboardInterrupt' raise KeyboardInterrupt # What else? - accumulate_result(test, result) + test_index += 1 except KeyboardInterrupt: interrupted = True - pending.close() + pending.interrupted = True for worker in workers: worker.join() else: - for test in tests: + for test_index, test in enumerate(tests, 1): if not quiet: - print test + fmt = "[{1:{0}}{2}/{3}] {4}" if bad else "[{1:{0}}{2}] {4}" + print(fmt.format( + test_count_width, test_index, test_count, len(bad), test)) sys.stdout.flush() if trace: # If we're tracing code coverage, then we don't exit with status @@ -563,11 +636,10 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, globals=globals(), locals=vars()) else: try: - result = runtest(test, verbose, quiet, huntrleaks) + result = runtest(test, verbose, quiet, huntrleaks, debug, + output_on_failure=verbose3, + failfast=failfast, match_tests=match_tests) accumulate_result(test, result) - if verbose3 and result[0] == FAILED: - print "Re-running test %r in verbose mode" % test - runtest(test, True, quiet, huntrleaks) except KeyboardInterrupt: interrupted = True break @@ -576,8 +648,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, if findleaks: gc.collect() if gc.garbage: - print "Warning: test created", len(gc.garbage), - print "uncollectable object(s)." + print("Warning: test created", len(gc.garbage), end=' ') + print("uncollectable object(s).") # move the uncollectable objects somewhere so we don't see # them again found_garbage.extend(gc.garbage) @@ -585,35 +657,35 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, # Unload the newly imported modules (best effort finalization) for module in sys.modules.keys(): if module not in save_modules and module.startswith("test."): - test_support.unload(module) + support.unload(module) if interrupted: # print a newline after ^C - print - print "Test suite interrupted by signal SIGINT." + print() + print("Test suite interrupted by signal SIGINT.") omitted = set(selected) - set(good) - set(bad) - set(skipped) - print count(len(omitted), "test"), "omitted:" + print(count(len(omitted), "test"), "omitted:") printlist(omitted) if good and not quiet: if not bad and not skipped and not interrupted and len(good) > 1: - print "All", - print count(len(good), "test"), "OK." + print("All", end=' ') + print(count(len(good), "test"), "OK.") if print_slow: test_times.sort(reverse=True) - print "10 slowest tests:" + print("10 slowest tests:") for time, test in test_times[:10]: - print "%s: %.1fs" % (test, time) + print("%s: %.1fs" % (test, time)) if bad: - bad = set(bad) - set(environment_changed) + bad = sorted(set(bad) - set(environment_changed)) if bad: - print count(len(bad), "test"), "failed:" + print(count(len(bad), "test"), "failed:") printlist(bad) - if environment_changed: - print "{} altered the execution environment:".format( - count(len(environment_changed), "test")) - printlist(environment_changed) + if environment_changed: + print("{} altered the execution environment:".format( + count(len(environment_changed), "test"))) + printlist(environment_changed) if skipped and not quiet: - print count(len(skipped), "test"), "skipped:" + print(count(len(skipped), "test"), "skipped:") printlist(skipped) e = _ExpectedSkips() @@ -621,26 +693,26 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, if e.isvalid(): surprise = set(skipped) - e.getexpected() - set(resource_denieds) if surprise: - print count(len(surprise), "skip"), \ - "unexpected on", plat + ":" + print(count(len(surprise), "skip"), \ + "unexpected on", plat + ":") printlist(surprise) else: - print "Those skips are all expected on", plat + "." + print("Those skips are all expected on", plat + ".") else: - print "Ask someone to teach regrtest.py about which tests are" - print "expected to get skipped on", plat + "." + print("Ask someone to teach regrtest.py about which tests are") + print("expected to get skipped on", plat + ".") if verbose2 and bad: - print "Re-running failed tests in verbose mode" + print("Re-running failed tests in verbose mode") for test in bad: - print "Re-running test %r in verbose mode" % test + print("Re-running test %r in verbose mode" % test) sys.stdout.flush() try: - test_support.verbose = True - ok = runtest(test, True, quiet, huntrleaks) + verbose = True + ok = runtest(test, True, quiet, huntrleaks, debug) except KeyboardInterrupt: # print a newline separate from the ^C - print + print() break except: raise @@ -675,7 +747,6 @@ STDTESTS = [ ] NOTTESTS = { - 'test_support', 'test_future1', 'test_future2', } @@ -692,8 +763,48 @@ def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): tests.append(modname) return stdtests + sorted(tests) +# We do not use a generator so multiple threads can call next(). +class MultiprocessTests(object): + + """A thread-safe iterator over tests for multiprocess mode.""" + + def __init__(self, tests): + self.interrupted = False + self.lock = threading.Lock() + self.tests = tests + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + if self.interrupted: + raise StopIteration('tests interrupted') + return next(self.tests) + +def replace_stdout(): + """Set stdout encoder error handler to backslashreplace (as stderr error + handler) to avoid UnicodeEncodeError when printing a traceback""" + if os.name == "nt": + # Replace sys.stdout breaks the stdout newlines on Windows: issue #8533 + return + + import atexit + + stdout = sys.stdout + sys.stdout = open(stdout.fileno(), 'w', + encoding=stdout.encoding, + errors="backslashreplace", + closefd=False) + + def restore_stdout(): + sys.stdout.close() + sys.stdout = stdout + atexit.register(restore_stdout) + def runtest(test, verbose, quiet, - huntrleaks=False, use_resources=None): + huntrleaks=False, debug=False, use_resources=None, + output_on_failure=False, failfast=False, match_tests=None): """Run a single test. test -- the name of the test @@ -702,6 +813,8 @@ def runtest(test, verbose, quiet, test_times -- a list of (time, test_name) pairs huntrleaks -- run multiple times to test for leaks; requires a debug build; a triple corresponding to -R's three arguments + output_on_failure -- if true, display test output on failure + Returns one of the test result constants: INTERRUPTED KeyboardInterrupt when run under -j RESOURCE_DENIED test skipped because resource denied @@ -711,14 +824,48 @@ def runtest(test, verbose, quiet, PASSED test passed """ - test_support.verbose = verbose # Tell tests to be moderately quiet if use_resources is not None: - test_support.use_resources = use_resources + support.use_resources = use_resources try: - return runtest_inner(test, verbose, quiet, huntrleaks) + support.match_tests = match_tests + if failfast: + support.failfast = True + if output_on_failure: + support.verbose = True + + # Reuse the same instance to all calls to runtest(). Some + # tests keep a reference to sys.stdout or sys.stderr + # (eg. test_argparse). + if runtest.stringio is None: + stream = io.StringIO() + runtest.stringio = stream + else: + stream = runtest.stringio + stream.seek(0) + stream.truncate() + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + try: + sys.stdout = stream + sys.stderr = stream + result = runtest_inner(test, verbose, quiet, huntrleaks, + debug, display_failure=False) + if result[0] == FAILED: + output = stream.getvalue() + orig_stderr.write(output) + orig_stderr.flush() + finally: + sys.stdout = orig_stdout + sys.stderr = orig_stderr + else: + support.verbose = verbose # Tell tests to be moderately quiet + result = runtest_inner(test, verbose, quiet, huntrleaks, debug, + display_failure=not verbose) + return result finally: cleanup_test_droppings(test, verbose) - +runtest.stringio = None # Unit tests are supposed to leave the execution environment unchanged # once they complete. But sometimes tests have bugs, especially when @@ -760,8 +907,13 @@ class saved_test_environment: # the corresponding method names. resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr', - 'os.environ', 'sys.path', 'asyncore.socket_map', - 'test_support.TESTFN', + 'os.environ', 'sys.path', 'sys.path_hooks', '__import__', + 'warnings.filters', 'asyncore.socket_map', + 'logging._handlers', 'logging._handlerList', + 'shutil.archive_formats', 'shutil.unpack_formats', + 'sys.warnoptions', 'threading._dangling', + 'multiprocessing.process._dangling', + 'support.TESTFN', ) def get_sys_argv(self): @@ -803,6 +955,23 @@ class saved_test_environment: sys.path = saved_path[1] sys.path[:] = saved_path[2] + def get_sys_path_hooks(self): + return id(sys.path_hooks), sys.path_hooks, sys.path_hooks[:] + def restore_sys_path_hooks(self, saved_hooks): + sys.path_hooks = saved_hooks[1] + sys.path_hooks[:] = saved_hooks[2] + + def get___import__(self): + return builtins.__import__ + def restore___import__(self, import_): + builtins.__import__ = import_ + + def get_warnings_filters(self): + return id(warnings.filters), warnings.filters, warnings.filters[:] + def restore_warnings_filters(self, saved_filters): + warnings.filters = saved_filters[1] + warnings.filters[:] = saved_filters[2] + def get_asyncore_socket_map(self): asyncore = sys.modules.get('asyncore') # XXX Making a copy keeps objects alive until __exit__ gets called. @@ -813,20 +982,82 @@ class saved_test_environment: asyncore.close_all(ignore_all=True) asyncore.socket_map.update(saved_map) - def get_test_support_TESTFN(self): - if os.path.isfile(test_support.TESTFN): + def get_shutil_archive_formats(self): + # we could call get_archives_formats() but that only returns the + # registry keys; we want to check the values too (the functions that + # are registered) + return shutil._ARCHIVE_FORMATS, shutil._ARCHIVE_FORMATS.copy() + def restore_shutil_archive_formats(self, saved): + shutil._ARCHIVE_FORMATS = saved[0] + shutil._ARCHIVE_FORMATS.clear() + shutil._ARCHIVE_FORMATS.update(saved[1]) + + def get_shutil_unpack_formats(self): + return shutil._UNPACK_FORMATS, shutil._UNPACK_FORMATS.copy() + def restore_shutil_unpack_formats(self, saved): + shutil._UNPACK_FORMATS = saved[0] + shutil._UNPACK_FORMATS.clear() + shutil._UNPACK_FORMATS.update(saved[1]) + + def get_logging__handlers(self): + # _handlers is a WeakValueDictionary + return id(logging._handlers), logging._handlers, logging._handlers.copy() + def restore_logging__handlers(self, saved_handlers): + # Can't easily revert the logging state + pass + + def get_logging__handlerList(self): + # _handlerList is a list of weakrefs to handlers + return id(logging._handlerList), logging._handlerList, logging._handlerList[:] + def restore_logging__handlerList(self, saved_handlerList): + # Can't easily revert the logging state + pass + + def get_sys_warnoptions(self): + return id(sys.warnoptions), sys.warnoptions, sys.warnoptions[:] + def restore_sys_warnoptions(self, saved_options): + sys.warnoptions = saved_options[1] + sys.warnoptions[:] = saved_options[2] + + # Controlling dangling references to Thread objects can make it easier + # to track reference leaks. + def get_threading__dangling(self): + if not threading: + return None + # This copies the weakrefs without making any strong reference + return threading._dangling.copy() + def restore_threading__dangling(self, saved): + if not threading: + return + threading._dangling.clear() + threading._dangling.update(saved) + + # Same for Process objects + def get_multiprocessing_process__dangling(self): + if not multiprocessing: + return None + # This copies the weakrefs without making any strong reference + return multiprocessing.process._dangling.copy() + def restore_multiprocessing_process__dangling(self, saved): + if not multiprocessing: + return + multiprocessing.process._dangling.clear() + multiprocessing.process._dangling.update(saved) + + def get_support_TESTFN(self): + if os.path.isfile(support.TESTFN): result = 'f' - elif os.path.isdir(test_support.TESTFN): + elif os.path.isdir(support.TESTFN): result = 'd' else: result = None return result - def restore_test_support_TESTFN(self, saved_value): + def restore_support_TESTFN(self, saved_value): if saved_value is None: - if os.path.isfile(test_support.TESTFN): - os.unlink(test_support.TESTFN) - elif os.path.isdir(test_support.TESTFN): - shutil.rmtree(test_support.TESTFN) + if os.path.isfile(support.TESTFN): + os.unlink(support.TESTFN) + elif os.path.isdir(support.TESTFN): + shutil.rmtree(support.TESTFN) def resource_info(self): for name in self.resources: @@ -851,96 +1082,72 @@ class saved_test_environment: self.changed = True restore(original) if not self.quiet: - print >>sys.stderr, ( - "Warning -- {} was modified by {}".format( - name, self.testname)) + print("Warning -- {} was modified by {}".format( + name, self.testname), + file=sys.stderr) if self.verbose > 1: - print >>sys.stderr, ( - " Before: {}\n After: {} ".format( - original, current)) - # XXX (ncoghlan): for most resources (e.g. sys.path) identity - # matters at least as much as value. For others (e.g. cwd), - # identity is irrelevant. Should we add a mechanism to check - # for substitution in the cases where it matters? + print(" Before: {}\n After: {} ".format( + original, current), + file=sys.stderr) return False -def runtest_inner(test, verbose, quiet, huntrleaks=False): - test_support.unload(test) - if verbose: - capture_stdout = None - else: - capture_stdout = StringIO.StringIO() +def runtest_inner(test, verbose, quiet, + huntrleaks=False, debug=False, display_failure=True): + support.unload(test) test_time = 0.0 refleak = False # True if the test leaked references. try: - save_stdout = sys.stdout - try: - if capture_stdout: - sys.stdout = capture_stdout - if test.startswith('test.'): - abstest = test - else: - # Always import it from the test package - abstest = 'test.' + test - with saved_test_environment(test, verbose, quiet) as environment: - start_time = time.time() - the_package = __import__(abstest, globals(), locals(), []) - the_module = getattr(the_package, test) - # Old tests run to completion simply as a side-effect of - # being imported. For tests based on unittest or doctest, - # explicitly invoke their test_main() function (if it exists). - indirect_test = getattr(the_module, "test_main", None) - if indirect_test is not None: - indirect_test() - if huntrleaks: - refleak = dash_R(the_module, test, indirect_test, - huntrleaks) - test_time = time.time() - start_time - finally: - sys.stdout = save_stdout - except test_support.ResourceDenied, msg: + if test.startswith('test.'): + abstest = test + else: + # Always import it from the test package + abstest = 'test.' + test + with saved_test_environment(test, verbose, quiet) as environment: + start_time = time.time() + the_package = __import__(abstest, globals(), locals(), []) + the_module = getattr(the_package, test) + # Old tests run to completion simply as a side-effect of + # being imported. For tests based on unittest or doctest, + # explicitly invoke their test_main() function (if it exists). + indirect_test = getattr(the_module, "test_main", None) + if indirect_test is not None: + indirect_test() + if huntrleaks: + refleak = dash_R(the_module, test, indirect_test, + huntrleaks) + test_time = time.time() - start_time + except support.ResourceDenied as msg: if not quiet: - print test, "skipped --", msg + print(test, "skipped --", msg) sys.stdout.flush() return RESOURCE_DENIED, test_time - except unittest.SkipTest, msg: + except unittest.SkipTest as msg: if not quiet: - print test, "skipped --", msg + print(test, "skipped --", msg) sys.stdout.flush() return SKIPPED, test_time except KeyboardInterrupt: raise - except test_support.TestFailed, msg: - print >>sys.stderr, "test", test, "failed --", msg + except support.TestFailed as msg: + if display_failure: + print("test", test, "failed --", msg, file=sys.stderr) + else: + print("test", test, "failed", file=sys.stderr) sys.stderr.flush() return FAILED, test_time except: - type, value = sys.exc_info()[:2] - print >>sys.stderr, "test", test, "crashed --", str(type) + ":", value + msg = traceback.format_exc() + print("test", test, "crashed --", msg, file=sys.stderr) sys.stderr.flush() - if verbose: - traceback.print_exc(file=sys.stderr) - sys.stderr.flush() return FAILED, test_time else: if refleak: return FAILED, test_time if environment.changed: return ENV_CHANGED, test_time - # Except in verbose mode, tests should not print anything - if verbose or huntrleaks: - return PASSED, test_time - output = capture_stdout.getvalue() - if not output: - return PASSED, test_time - print "test", test, "produced unexpected output:" - print "*" * 70 - print output - print "*" * 70 - sys.stdout.flush() - return FAILED, test_time + return PASSED, test_time def cleanup_test_droppings(testname, verbose): import shutil @@ -948,6 +1155,8 @@ def cleanup_test_droppings(testname, verbose): import gc # First kill any dangling references to open files etc. + # This can also issue some ResourceWarnings which would otherwise get + # triggered during the following test run, and possibly produce failures. gc.collect() # Try to clean up junk commonly left behind. While tests shouldn't leave @@ -956,7 +1165,7 @@ def cleanup_test_droppings(testname, verbose): # since if a test leaves a file open, it cannot be deleted by name (while # there's nothing we can do about that here either, we can display the # name of the offending test, which is a real help). - for name in (test_support.TESTFN, + for name in (support.TESTFN, "db_home", ): if not os.path.exists(name): @@ -971,16 +1180,16 @@ def cleanup_test_droppings(testname, verbose): "directory nor file" % name) if verbose: - print "%r left behind %s %r" % (testname, kind, name) + print("%r left behind %s %r" % (testname, kind, name)) try: # if we have chmod, fix possible permissions problems # that might prevent cleanup if (hasattr(os, 'chmod')): os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) nuker(name) - except Exception, msg: - print >> sys.stderr, ("%r left behind %s %r and it couldn't be " - "removed: %s" % (testname, kind, name, msg)) + except Exception as msg: + print(("%r left behind %s %r and it couldn't be " + "removed: %s" % (testname, kind, name, msg)), file=sys.stderr) def dash_R(the_module, test, indirect_test, huntrleaks): """Run a test multiple times, looking for reference leaks. @@ -989,7 +1198,7 @@ def dash_R(the_module, test, indirect_test, huntrleaks): False if the test didn't leak references; True if we detected refleaks. """ # This code is hackish and inelegant, but it seems to do the job. - import copy_reg, _abcoll, _pyio + import copyreg, _abcoll if not hasattr(sys, 'gettotalrefcount'): raise Exception("Tracking reference leaks requires a debug build " @@ -997,7 +1206,7 @@ def dash_R(the_module, test, indirect_test, huntrleaks): # Save current values for dash_R_cleanup() to restore. fs = warnings.filters[:] - ps = copy_reg.dispatch_table.copy() + ps = copyreg.dispatch_table.copy() pic = sys.path_importer_cache.copy() try: import zipimport @@ -1006,10 +1215,8 @@ def dash_R(the_module, test, indirect_test, huntrleaks): else: zdc = zipimport._zip_directory_cache.copy() abcs = {} - modules = _abcoll, _pyio - for abc in [getattr(mod, a) for mod in modules for a in mod.__all__]: - # XXX isinstance(abc, ABCMeta) leads to infinite recursion - if not hasattr(abc, '_abc_registry'): + for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]: + if not isabstract(abc): continue for obj in abc.__subclasses__() + [abc]: abcs[obj] = obj._abc_registry.copy() @@ -1019,40 +1226,44 @@ def dash_R(the_module, test, indirect_test, huntrleaks): indirect_test() else: def run_the_test(): - imp.reload(the_module) + del sys.modules[the_module.__name__] + exec('import ' + the_module.__name__) deltas = [] nwarmup, ntracked, fname = huntrleaks - fname = os.path.join(test_support.SAVEDCWD, fname) + fname = os.path.join(support.SAVEDCWD, fname) repcount = nwarmup + ntracked - print >> sys.stderr, "beginning", repcount, "repetitions" - print >> sys.stderr, ("1234567890"*(repcount//10 + 1))[:repcount] + print("beginning", repcount, "repetitions", file=sys.stderr) + print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr) + sys.stderr.flush() dash_R_cleanup(fs, ps, pic, zdc, abcs) for i in range(repcount): rc_before = sys.gettotalrefcount() run_the_test() sys.stderr.write('.') + sys.stderr.flush() dash_R_cleanup(fs, ps, pic, zdc, abcs) rc_after = sys.gettotalrefcount() if i >= nwarmup: deltas.append(rc_after - rc_before) - print >> sys.stderr + print(file=sys.stderr) if any(deltas): msg = '%s leaked %s references, sum=%s' % (test, deltas, sum(deltas)) - print >> sys.stderr, msg + print(msg, file=sys.stderr) + sys.stderr.flush() with open(fname, "a") as refrep: - print >> refrep, msg + print(msg, file=refrep) refrep.flush() return True return False def dash_R_cleanup(fs, ps, pic, zdc, abcs): - import gc, copy_reg + import gc, copyreg import _strptime, linecache - dircache = test_support.import_module('dircache', deprecated=True) - import urlparse, urllib, urllib2, mimetypes, doctest - import struct, filecmp + import urllib.parse, urllib.request, mimetypes, doctest + import struct, filecmp, _abcoll from distutils.dir_util import _path_created + from weakref import WeakSet # Clear the warnings registry, so they can be displayed again for mod in sys.modules.values(): @@ -1061,8 +1272,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): # Restore some original values. warnings.filters[:] = fs - copy_reg.dispatch_table.clear() - copy_reg.dispatch_table.update(ps) + copyreg.dispatch_table.clear() + copyreg.dispatch_table.update(ps) sys.path_importer_cache.clear() sys.path_importer_cache.update(pic) try: @@ -1077,19 +1288,26 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): sys._clear_type_cache() # Clear ABC registries, restoring previously saved ABC registries. - for abc, registry in abcs.items(): - abc._abc_registry = registry.copy() - abc._abc_cache.clear() - abc._abc_negative_cache.clear() + for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]: + if not isabstract(abc): + continue + for obj in abc.__subclasses__() + [abc]: + obj._abc_registry = abcs.get(obj, WeakSet()).copy() + obj._abc_cache.clear() + obj._abc_negative_cache.clear() + + # Flush standard output, so that buffered data is sent to the OS and + # associated Python objects are reclaimed. + for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__): + if stream is not None: + stream.flush() # Clear assorted module caches. _path_created.clear() re.purge() _strptime._regex_cache.clear() - urlparse.clear_cache() - urllib.urlcleanup() - urllib2.install_opener(None) - dircache.reset() + urllib.parse.clear_cache() + urllib.request.urlcleanup() linecache.clearcache() mimetypes._default_mime_types() filecmp._cache.clear() @@ -1106,6 +1324,11 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): # Collect cyclic trash. gc.collect() +def warm_char_cache(): + s = bytes(range(256)) + for i in range(256): + s[i:i+1] + def findtestdir(path=None): return path or os.path.dirname(__file__) or os.curdir @@ -1134,8 +1357,8 @@ def printlist(x, width=70, indent=4): from textwrap import fill blanks = ' ' * indent # Print the sorted list: 'x' may be a '--random' list or a set() - print fill(' '.join(str(elt) for elt in sorted(x)), width, - initial_indent=blanks, subsequent_indent=blanks) + print(fill(' '.join(str(elt) for elt in sorted(x)), width, + initial_indent=blanks, subsequent_indent=blanks)) # Map sys.platform to a string containing the basenames of tests # expected to be skipped on that platform. @@ -1155,22 +1378,18 @@ _expectations = { 'win32': """ test__locale - test_bsddb185 - test_bsddb3 - test_commands test_crypt test_curses test_dbm - test_dl test_fcntl test_fork1 test_epoll - test_gdbm + test_dbm_gnu + test_dbm_ndbm test_grp test_ioctl test_largefile test_kqueue - test_mhlib test_openpty test_ossaudiodev test_pipes @@ -1180,25 +1399,20 @@ _expectations = { test_pwd test_resource test_signal + test_syslog test_threadsignals - test_timing test_wait3 test_wait4 """, 'linux2': """ - test_bsddb185 test_curses - test_dl test_largefile test_kqueue test_ossaudiodev """, 'unixware7': """ - test_bsddb - test_bsddb185 - test_dl test_epoll test_largefile test_kqueue @@ -1210,9 +1424,6 @@ _expectations = { """, 'openunix8': """ - test_bsddb - test_bsddb185 - test_dl test_epoll test_largefile test_kqueue @@ -1225,9 +1436,6 @@ _expectations = { 'sco_sv3': """ test_asynchat - test_bsddb - test_bsddb185 - test_dl test_fork1 test_epoll test_gettext @@ -1245,64 +1453,26 @@ _expectations = { test_threadedtempfile test_threading """, - 'riscos': - """ - test_asynchat - test_atexit - test_bsddb - test_bsddb185 - test_bsddb3 - test_commands - test_crypt - test_dbm - test_dl - test_fcntl - test_fork1 - test_epoll - test_gdbm - test_grp - test_largefile - test_locale - test_kqueue - test_mmap - test_openpty - test_poll - test_popen2 - test_pty - test_pwd - test_strop - test_sundry - test_thread - test_threaded_import - test_threadedtempfile - test_threading - test_timing - """, 'darwin': """ test__locale - test_bsddb - test_bsddb3 test_curses test_epoll + test_dbm_gnu test_gdb - test_gdbm test_largefile test_locale - test_kqueue test_minidom test_ossaudiodev test_poll """, 'sunos5': """ - test_bsddb - test_bsddb185 test_curses test_dbm test_epoll test_kqueue - test_gdbm + test_dbm_gnu test_gzip test_openpty test_zipfile @@ -1310,12 +1480,9 @@ _expectations = { """, 'hp-ux11': """ - test_bsddb - test_bsddb185 test_curses - test_dl test_epoll - test_gdbm + test_dbm_gnu test_gzip test_largefile test_locale @@ -1327,26 +1494,8 @@ _expectations = { test_zipfile test_zlib """, - 'atheos': - """ - test_bsddb185 - test_curses - test_dl - test_gdbm - test_epoll - test_largefile - test_locale - test_kqueue - test_mhlib - test_mmap - test_poll - test_popen2 - test_resource - """, 'cygwin': """ - test_bsddb185 - test_bsddb3 test_curses test_dbm test_epoll @@ -1360,15 +1509,10 @@ _expectations = { 'os2emx': """ test_audioop - test_bsddb185 - test_bsddb3 - test_commands test_curses - test_dl test_epoll test_kqueue test_largefile - test_mhlib test_mmap test_openpty test_ossaudiodev @@ -1378,10 +1522,8 @@ _expectations = { """, 'freebsd4': """ - test_bsddb - test_bsddb3 test_epoll - test_gdbm + test_dbm_gnu test_locale test_ossaudiodev test_pep277 @@ -1397,13 +1539,9 @@ _expectations = { """, 'aix5': """ - test_bsddb - test_bsddb185 - test_bsddb3 test_bz2 - test_dl test_epoll - test_gdbm + test_dbm_gnu test_gzip test_kqueue test_ossaudiodev @@ -1416,13 +1554,9 @@ _expectations = { """, 'openbsd3': """ - test_ascii_formatd - test_bsddb - test_bsddb3 test_ctypes - test_dl test_epoll - test_gdbm + test_dbm_gnu test_locale test_normalization test_ossaudiodev @@ -1435,15 +1569,10 @@ _expectations = { """, 'netbsd3': """ - test_ascii_formatd - test_bsddb - test_bsddb185 - test_bsddb3 test_ctypes test_curses - test_dl test_epoll - test_gdbm + test_dbm_gnu test_locale test_ossaudiodev test_pep277 @@ -1469,49 +1598,39 @@ class _ExpectedSkips: s = _expectations[sys.platform] self.expected = set(s.split()) - # expected to be skipped on every platform, even Linux - self.expected.add('test_linuxaudiodev') + # These are broken tests, for now skipped on every platform. + # XXX Fix these! + self.expected.add('test_nis') + # expected to be skipped on every platform, even Linux if not os.path.supports_unicode_filenames: self.expected.add('test_pep277') + # doctest, profile and cProfile tests fail when the codec for the + # fs encoding isn't built in because PyUnicode_Decode() adds two + # calls into Python. + encs = ("utf-8", "latin-1", "ascii", "mbcs", "utf-16", "utf-32") + if sys.getfilesystemencoding().lower() not in encs: + self.expected.add('test_profile') + self.expected.add('test_cProfile') + self.expected.add('test_doctest') + if test_timeout.skip_expected: self.expected.add('test_timeout') - if sys.maxint == 9223372036854775807L: - self.expected.add('test_imageop') - - if sys.platform != "darwin": - MAC_ONLY = ["test_macos", "test_macostools", "test_aepack", - "test_plistlib", "test_scriptpackages", - "test_applesingle"] - for skip in MAC_ONLY: - self.expected.add(skip) - elif len(u'\0'.encode('unicode-internal')) == 4: - self.expected.add("test_macostools") - - if sys.platform != "win32": # test_sqlite is only reliable on Windows where the library # is distributed with Python - WIN_ONLY = ["test_unicode_file", "test_winreg", + WIN_ONLY = {"test_unicode_file", "test_winreg", "test_winsound", "test_startfile", - "test_sqlite", "test_msilib"] - for skip in WIN_ONLY: - self.expected.add(skip) - - if sys.platform != 'irix': - IRIX_ONLY = ["test_imageop", "test_al", "test_cd", "test_cl", - "test_gl", "test_imgfile"] - for skip in IRIX_ONLY: - self.expected.add(skip) + "test_sqlite", "test_msilib"} + self.expected |= WIN_ONLY if sys.platform != 'sunos5': - self.expected.add('test_sunaudiodev') self.expected.add('test_nis') - if not sys.py3kwarning: - self.expected.add('test_py3kwarn') + if support.python_is_optimized(): + self.expected.add("test_gdb") self.valid = True @@ -1528,24 +1647,18 @@ class _ExpectedSkips: assert self.isvalid() return self.expected -if __name__ == '__main__': - # findtestdir() gets the dirname out of __file__, so we have to make it - # absolute before changing the working directory. - # For example __file__ may be relative when running trace or profile. - # See issue #9323. - __file__ = os.path.abspath(__file__) - - # sanity check - assert __file__ == os.path.abspath(sys.argv[0]) - +def _make_temp_dir_for_build(TEMPDIR): # When tests are run from the Python build directory, it is best practice # to keep the test files in a subfolder. It eases the cleanup of leftover # files using command "make distclean". if sysconfig.is_python_build(): TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build') TEMPDIR = os.path.abspath(TEMPDIR) - if not os.path.exists(TEMPDIR): + try: os.mkdir(TEMPDIR) + except OSError as e: + if e.errno != errno.EEXIST: + raise # Define a writable temp dir that will be used as cwd while running # the tests. The name of the dir includes the pid to allow parallel @@ -1553,10 +1666,35 @@ if __name__ == '__main__': TESTCWD = 'test_python_{}'.format(os.getpid()) TESTCWD = os.path.join(TEMPDIR, TESTCWD) + return TEMPDIR, TESTCWD + +if __name__ == '__main__': + # Remove regrtest.py's own directory from the module search path. Despite + # the elimination of implicit relative imports, this is still needed to + # ensure that submodules of the test package do not inappropriately appear + # as top-level modules even when people (or buildbots!) invoke regrtest.py + # directly instead of using the -m switch + mydir = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0]))) + i = len(sys.path) + while i >= 0: + i -= 1 + if os.path.abspath(os.path.normpath(sys.path[i])) == mydir: + del sys.path[i] + + # findtestdir() gets the dirname out of __file__, so we have to make it + # absolute before changing the working directory. + # For example __file__ may be relative when running trace or profile. + # See issue #9323. + __file__ = os.path.abspath(__file__) + + # sanity check + assert __file__ == os.path.abspath(sys.argv[0]) + + TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR) # Run the tests in a context manager that temporary changes the CWD to a # temporary and writable directory. If it's not possible to create or # change the CWD, the original CWD will be used. The original CWD is - # available from test_support.SAVEDCWD. - with test_support.temp_cwd(TESTCWD, quiet=True): + # available from support.SAVEDCWD. + with support.temp_cwd(TESTCWD, quiet=True): main() |