◐ Shell
clean mode source ↗

Issue 25373: test.regrtest: -jN (with N != 1) + --slow + child error or interruption = TypeError

Function runtest() (used by single-process mode) always returns tuple with test result as integer and test time as float.
This tuple is passed as second argument to function accumulate_result(), which has (in Python 3.6):
    def accumulate_result(self, test, result):
        ok, test_time = result
        self.test_times.append((test_time, test))

test_times is later used by code, which expects that times are floats:
        if self.ns.print_slow:
            self.test_times.sort(reverse=True)
            print("10 slowest tests:")
            for time, test in self.test_times[:10]:
                print("%s: %.1fs" % (test, time))

Code used by multi-process mode can return tuple with integer and string (describing error in subprocess), which with --slow option would cause TypeError.


Example:

In terminal 1:
$ LD_LIBRARY_PATH="$(pwd)" ./python -m test.regrtest -j2 --slow test_lib2to3

In terminal 2 (sufficiently quickly):
$ kill -SIGINT $(ps aux | grep '"test_lib2to3"' | grep -v grep | awk '{print $2}')

Output in terminal 1:

Test suite interrupted by signal SIGINT.
1 test omitted:
    test_lib2to3
10 slowest tests:
Traceback (most recent call last):
  File "/tmp/cpython/Lib/runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "/tmp/cpython/Lib/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmp/cpython/Lib/test/regrtest.py", line 39, in <module>
    main_in_temp_cwd()
  File "/tmp/cpython/Lib/test/libregrtest/main.py", line 451, in main_in_temp_cwd
    main()
  File "/tmp/cpython/Lib/test/libregrtest/main.py", line 429, in main
    Regrtest().main(tests=tests, **kwargs)
  File "/tmp/cpython/Lib/test/libregrtest/main.py", line 389, in main
    self.display_result()
  File "/tmp/cpython/Lib/test/libregrtest/main.py", line 261, in display_result
    print("%s: %.1fs" % (test, time))
TypeError: a float is required


My suggested fix is to return string describing error as third element of that tuple.
Apparently problem was only reproducible in Python 3, because in Python 3, in "while finished < use_mp" loop, accumulate_result() is called early before checking if result[0] is INTERRUPTED or CHILD_ERROR, while in Python 2, accumulate_result() is called after check for result[0].