Skip to content

Commit

Permalink
Move get_signal_name() to test.support (python#121251)
Browse files Browse the repository at this point in the history
* Move get_signal_name() from test.libregrtest to test.support.
* Use get_signal_name() in support.script_helper.
* support.script_helper now decodes stdout and stderr from UTF-8,
  instead of ASCII, if a command failed.
  • Loading branch information
vstinner authored and Akasurde committed Jul 3, 2024
1 parent 0972089 commit 2783013
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 58 deletions.
4 changes: 2 additions & 2 deletions Lib/test/libregrtest/run_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .single import PROGRESS_MIN_TIME
from .utils import (
StrPath, TestName,
format_duration, print_warning, count, plural, get_signal_name)
format_duration, print_warning, count, plural)
from .worker import create_worker_process, USE_PROCESS_GROUP

if MS_WINDOWS:
Expand Down Expand Up @@ -366,7 +366,7 @@ def _runtest(self, test_name: TestName) -> MultiprocessResult:
err_msg=None,
state=State.TIMEOUT)
if retcode != 0:
name = get_signal_name(retcode)
name = support.get_signal_name(retcode)
if name:
retcode = f"{retcode} ({name})"
raise WorkerError(self.test_name, f"Exit code {retcode}", stdout,
Expand Down
29 changes: 0 additions & 29 deletions Lib/test/libregrtest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,35 +685,6 @@ def cleanup_temp_dir(tmp_dir: StrPath):
print("Remove file: %s" % name)
os_helper.unlink(name)

WINDOWS_STATUS = {
0xC0000005: "STATUS_ACCESS_VIOLATION",
0xC00000FD: "STATUS_STACK_OVERFLOW",
0xC000013A: "STATUS_CONTROL_C_EXIT",
}

def get_signal_name(exitcode):
if exitcode < 0:
signum = -exitcode
try:
return signal.Signals(signum).name
except ValueError:
pass

# Shell exit code (ex: WASI build)
if 128 < exitcode < 256:
signum = exitcode - 128
try:
return signal.Signals(signum).name
except ValueError:
pass

try:
return WINDOWS_STATUS[exitcode]
except KeyError:
pass

return None


ILLEGAL_XML_CHARS_RE = re.compile(
'['
Expand Down
32 changes: 32 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2632,3 +2632,35 @@ def initialized_with_pyrepl():
"""Detect whether PyREPL was used during Python initialization."""
# If the main module has a __file__ attribute it's a Python module, which means PyREPL.
return hasattr(sys.modules["__main__"], "__file__")


WINDOWS_STATUS = {
0xC0000005: "STATUS_ACCESS_VIOLATION",
0xC00000FD: "STATUS_STACK_OVERFLOW",
0xC000013A: "STATUS_CONTROL_C_EXIT",
}

def get_signal_name(exitcode):
import signal

if exitcode < 0:
signum = -exitcode
try:
return signal.Signals(signum).name
except ValueError:
pass

# Shell exit code (ex: WASI build)
if 128 < exitcode < 256:
signum = exitcode - 128
try:
return signal.Signals(signum).name
except ValueError:
pass

try:
return WINDOWS_STATUS[exitcode]
except KeyError:
pass

return None
36 changes: 19 additions & 17 deletions Lib/test/support/script_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,25 @@ def fail(self, cmd_line):
out = b'(... truncated stdout ...)' + out[-maxlen:]
if len(err) > maxlen:
err = b'(... truncated stderr ...)' + err[-maxlen:]
out = out.decode('ascii', 'replace').rstrip()
err = err.decode('ascii', 'replace').rstrip()
raise AssertionError("Process return code is %d\n"
"command line: %r\n"
"\n"
"stdout:\n"
"---\n"
"%s\n"
"---\n"
"\n"
"stderr:\n"
"---\n"
"%s\n"
"---"
% (self.rc, cmd_line,
out,
err))
out = out.decode('utf8', 'replace').rstrip()
err = err.decode('utf8', 'replace').rstrip()

exitcode = self.rc
signame = support.get_signal_name(exitcode)
if signame:
exitcode = f"{exitcode} ({signame})"
raise AssertionError(f"Process return code is {exitcode}\n"
f"command line: {cmd_line!r}\n"
f"\n"
f"stdout:\n"
f"---\n"
f"{out}\n"
f"---\n"
f"\n"
f"stderr:\n"
f"---\n"
f"{err}\n"
f"---")


# Executing the interpreter in a subprocess
Expand Down
10 changes: 0 additions & 10 deletions Lib/test/test_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2329,16 +2329,6 @@ def test_normalize_test_name(self):
self.assertIsNone(normalize('setUpModule (test.test_x)', is_error=True))
self.assertIsNone(normalize('tearDownModule (test.test_module)', is_error=True))

def test_get_signal_name(self):
for exitcode, expected in (
(-int(signal.SIGINT), 'SIGINT'),
(-int(signal.SIGSEGV), 'SIGSEGV'),
(128 + int(signal.SIGABRT), 'SIGABRT'),
(3221225477, "STATUS_ACCESS_VIOLATION"),
(0xC00000FD, "STATUS_STACK_OVERFLOW"),
):
self.assertEqual(utils.get_signal_name(exitcode), expected, exitcode)

def test_format_resources(self):
format_resources = utils.format_resources
ALL_RESOURCES = utils.ALL_RESOURCES
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io
import os
import shutil
import signal
import socket
import stat
import subprocess
Expand Down Expand Up @@ -732,6 +733,17 @@ def test_copy_python_src_ignore(self):
self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)),
ignored)

def test_get_signal_name(self):
for exitcode, expected in (
(-int(signal.SIGINT), 'SIGINT'),
(-int(signal.SIGSEGV), 'SIGSEGV'),
(128 + int(signal.SIGABRT), 'SIGABRT'),
(3221225477, "STATUS_ACCESS_VIOLATION"),
(0xC00000FD, "STATUS_STACK_OVERFLOW"),
):
self.assertEqual(support.get_signal_name(exitcode), expected,
exitcode)

# XXX -follows a list of untested API
# make_legacy_pyc
# is_resource_enabled
Expand Down

0 comments on commit 2783013

Please sign in to comment.