diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -171,6 +171,7 @@ import platform import sysconfig import logging +from subprocess import Popen, PIPE # Some times __path__ and __file__ are not absolute (e.g. while running from @@ -490,6 +491,51 @@ support.use_resources = use_resources save_modules = sys.modules.keys() + opt_args = support.args_from_interpreter_flags() + base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] + debug_output_pat = re.compile(r"\[\d+ refs\]$") + + def get_args_tuple(test, verbose, quiet, debug, huntrleaks, use_resources, + rerun_failed): + return ( + (test, verbose, quiet), + dict(debug=debug, huntrleaks=huntrleaks, + use_resources=use_resources, rerun_failed=rerun_failed) + ) + + def _runtest(test, verbose, quiet, huntrleaks=False, debug=False, + use_resources=None, rerun_failed=False): + if test in ("test_pydoc",): + args_tuple = get_args_tuple(test, verbose, quiet, debug, huntrleaks, + use_resources, rerun_failed) + popen = Popen(base_cmd + ['--slaveargs', json.dumps(args_tuple)], + stdout=PIPE, stderr=PIPE, + universal_newlines=True, + close_fds=(os.name != 'nt')) + stdout, stderr = popen.communicate() + # Strip last refcount output line if it exists, since it + # comes from the shutdown of the interpreter in the subcommand. + stderr = debug_output_pat.sub("", stderr) + stdout, _, result = stdout.strip().rpartition("\n") + result = json.loads(result) + if stdout: + print(stdout) + if stderr: + print(stderr, file=sys.stderr) + if result[0] == INTERRUPTED: + assert result[1] == 'KeyboardInterrupt' + raise KeyboardInterrupt + if result[0] == FAILED and rerun_failed: + sys.stdout.flush() + sys.stderr.flush() + print("Re-running test {} in verbose mode".format(test)) + _runtest(test, verbose, quiet, huntrleaks, debug, use_resources) + return result + else: + return runtest(test, verbose, quiet, huntrleaks=huntrleaks, + debug=debug, use_resources=use_resources, + rerun_failed=rerun_failed) + def accumulate_result(test, result): ok, test_time = result test_times.append((test_time, test)) @@ -528,20 +574,14 @@ print("Multiprocess option requires thread support") sys.exit(2) 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, - debug=debug, rerun_failed=verbose3) - ) + args_tuple = get_args_tuple(test, verbose, quiet, debug, + huntrleaks, use_resources, + rerun_failed=verbose3) yield (test, args_tuple) pending = tests_and_args() - opt_args = support.args_from_interpreter_flags() - base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] def work(): # A worker thread. try: @@ -609,12 +649,12 @@ if trace: # If we're tracing code coverage, then we don't exit with status # if on a false return value from main. - tracer.runctx('runtest(test, verbose, quiet)', + tracer.runctx('_runtest(test, verbose, quiet)', globals=globals(), locals=vars()) else: try: - result = runtest(test, verbose, quiet, huntrleaks, debug, - rerun_failed=verbose3) + result = _runtest(test, verbose, quiet, huntrleaks, debug, + rerun_failed=verbose3) accumulate_result(test, result) except KeyboardInterrupt: interrupted = True @@ -685,7 +725,7 @@ sys.stdout.flush() try: verbose = True - ok = runtest(test, True, quiet, huntrleaks, debug) + ok = _runtest(test, True, quiet, huntrleaks, debug) except KeyboardInterrupt: # print a newline separate from the ^C print()