mirror of
https://github.com/python/cpython.git
synced 2025-11-02 11:08:57 +00:00
gh-109276, gh-109508: Fix libregrtest stdout (#109903)
Remove replace_stdout(): call sys.stdout.reconfigure() instead of set the error handler to backslashreplace. display_header() logs an empty line and flush stdout. Remove encoding workaround in display_header() since stdout error handler is now set to backslashreplace earlier.
This commit is contained in:
parent
ae1d99c2ed
commit
b1e4f6e83e
4 changed files with 26 additions and 53 deletions
|
|
@ -965,7 +965,7 @@ Main Makefile targets
|
||||||
this the default target of the ``make`` command (``make all`` or just
|
this the default target of the ``make`` command (``make all`` or just
|
||||||
``make``).
|
``make``).
|
||||||
|
|
||||||
* ``make test``: Build Python and run the Python test suite with ``--slow-ci``
|
* ``make test``: Build Python and run the Python test suite with ``--fast-ci``
|
||||||
option. Variables:
|
option. Variables:
|
||||||
|
|
||||||
* ``TESTOPTS``: additional regrtest command line options.
|
* ``TESTOPTS``: additional regrtest command line options.
|
||||||
|
|
|
||||||
|
|
@ -513,9 +513,11 @@ class Regrtest:
|
||||||
print_warning(f"Failed to reexecute Python: {exc!r}\n"
|
print_warning(f"Failed to reexecute Python: {exc!r}\n"
|
||||||
f"Command: {cmd_text}")
|
f"Command: {cmd_text}")
|
||||||
|
|
||||||
def main(self, tests: TestList | None = None):
|
def _init(self):
|
||||||
if self.want_reexec and self.ci_mode:
|
# Set sys.stdout encoder error handler to backslashreplace,
|
||||||
self._reexecute_python()
|
# similar to sys.stderr error handler, to avoid UnicodeEncodeError
|
||||||
|
# when printing a traceback or any other non-encodable character.
|
||||||
|
sys.stdout.reconfigure(errors="backslashreplace")
|
||||||
|
|
||||||
if self.junit_filename and not os.path.isabs(self.junit_filename):
|
if self.junit_filename and not os.path.isabs(self.junit_filename):
|
||||||
self.junit_filename = os.path.abspath(self.junit_filename)
|
self.junit_filename = os.path.abspath(self.junit_filename)
|
||||||
|
|
@ -524,6 +526,12 @@ class Regrtest:
|
||||||
|
|
||||||
self.tmp_dir = get_temp_dir(self.tmp_dir)
|
self.tmp_dir = get_temp_dir(self.tmp_dir)
|
||||||
|
|
||||||
|
def main(self, tests: TestList | None = None):
|
||||||
|
if self.want_reexec and self.ci_mode:
|
||||||
|
self._reexecute_python()
|
||||||
|
|
||||||
|
self._init()
|
||||||
|
|
||||||
if self.want_cleanup:
|
if self.want_cleanup:
|
||||||
cleanup_temp_dir(self.tmp_dir)
|
cleanup_temp_dir(self.tmp_dir)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII
|
||||||
from .runtests import RunTests
|
from .runtests import RunTests
|
||||||
from .utils import (
|
from .utils import (
|
||||||
setup_unraisable_hook, setup_threading_excepthook, fix_umask,
|
setup_unraisable_hook, setup_threading_excepthook, fix_umask,
|
||||||
replace_stdout, adjust_rlimit_nofile)
|
adjust_rlimit_nofile)
|
||||||
|
|
||||||
|
|
||||||
UNICODE_GUARD_ENV = "PYTHONREGRTEST_UNICODE_GUARD"
|
UNICODE_GUARD_ENV = "PYTHONREGRTEST_UNICODE_GUARD"
|
||||||
|
|
@ -49,7 +49,7 @@ def setup_process():
|
||||||
faulthandler.register(signum, chain=True, file=stderr_fd)
|
faulthandler.register(signum, chain=True, file=stderr_fd)
|
||||||
|
|
||||||
adjust_rlimit_nofile()
|
adjust_rlimit_nofile()
|
||||||
replace_stdout()
|
|
||||||
support.record_original_stdout(sys.stdout)
|
support.record_original_stdout(sys.stdout)
|
||||||
|
|
||||||
# Some times __path__ and __file__ are not absolute (e.g. while running from
|
# Some times __path__ and __file__ are not absolute (e.g. while running from
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import atexit
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import faulthandler
|
import faulthandler
|
||||||
import locale
|
import locale
|
||||||
|
|
@ -495,32 +494,6 @@ def normalize_test_name(test_full_name, *, is_error=False):
|
||||||
return short_name
|
return short_name
|
||||||
|
|
||||||
|
|
||||||
def replace_stdout():
|
|
||||||
"""Set stdout encoder error handler to backslashreplace (as stderr error
|
|
||||||
handler) to avoid UnicodeEncodeError when printing a traceback"""
|
|
||||||
stdout = sys.stdout
|
|
||||||
try:
|
|
||||||
fd = stdout.fileno()
|
|
||||||
except ValueError:
|
|
||||||
# On IDLE, sys.stdout has no file descriptor and is not a TextIOWrapper
|
|
||||||
# object. Leaving sys.stdout unchanged.
|
|
||||||
#
|
|
||||||
# Catch ValueError to catch io.UnsupportedOperation on TextIOBase
|
|
||||||
# and ValueError on a closed stream.
|
|
||||||
return
|
|
||||||
|
|
||||||
sys.stdout = open(fd, 'w',
|
|
||||||
encoding=stdout.encoding,
|
|
||||||
errors="backslashreplace",
|
|
||||||
closefd=False,
|
|
||||||
newline='\n')
|
|
||||||
|
|
||||||
def restore_stdout():
|
|
||||||
sys.stdout.close()
|
|
||||||
sys.stdout = stdout
|
|
||||||
atexit.register(restore_stdout)
|
|
||||||
|
|
||||||
|
|
||||||
def adjust_rlimit_nofile():
|
def adjust_rlimit_nofile():
|
||||||
"""
|
"""
|
||||||
On macOS the default fd limit (RLIMIT_NOFILE) is sometimes too low (256)
|
On macOS the default fd limit (RLIMIT_NOFILE) is sometimes too low (256)
|
||||||
|
|
@ -548,20 +521,12 @@ def adjust_rlimit_nofile():
|
||||||
|
|
||||||
|
|
||||||
def display_header(use_resources: tuple[str, ...]):
|
def display_header(use_resources: tuple[str, ...]):
|
||||||
encoding = sys.stdout.encoding
|
|
||||||
|
|
||||||
# Print basic platform information
|
# Print basic platform information
|
||||||
print("==", platform.python_implementation(), *sys.version.split())
|
print("==", platform.python_implementation(), *sys.version.split())
|
||||||
print("==", platform.platform(aliased=True),
|
print("==", platform.platform(aliased=True),
|
||||||
"%s-endian" % sys.byteorder)
|
"%s-endian" % sys.byteorder)
|
||||||
print("== Python build:", ' '.join(get_build_info()))
|
print("== Python build:", ' '.join(get_build_info()))
|
||||||
|
print("== cwd:", os.getcwd())
|
||||||
cwd = os.getcwd()
|
|
||||||
# gh-109508: support.os_helper.FS_NONASCII, used by get_work_dir(), cannot
|
|
||||||
# be encoded to the filesystem encoding on purpose, escape non-encodable
|
|
||||||
# characters with backslashreplace error handler.
|
|
||||||
formatted_cwd = cwd.encode(encoding, "backslashreplace").decode(encoding)
|
|
||||||
print("== cwd:", formatted_cwd)
|
|
||||||
|
|
||||||
cpu_count = os.cpu_count()
|
cpu_count = os.cpu_count()
|
||||||
if cpu_count:
|
if cpu_count:
|
||||||
|
|
@ -588,9 +553,7 @@ def display_header(use_resources: tuple[str, ...]):
|
||||||
sanitizers.append("memory")
|
sanitizers.append("memory")
|
||||||
if ubsan:
|
if ubsan:
|
||||||
sanitizers.append("undefined behavior")
|
sanitizers.append("undefined behavior")
|
||||||
if not sanitizers:
|
if sanitizers:
|
||||||
return
|
|
||||||
|
|
||||||
print(f"== sanitizers: {', '.join(sanitizers)}")
|
print(f"== sanitizers: {', '.join(sanitizers)}")
|
||||||
for sanitizer, env_var in (
|
for sanitizer, env_var in (
|
||||||
(asan, "ASAN_OPTIONS"),
|
(asan, "ASAN_OPTIONS"),
|
||||||
|
|
@ -601,6 +564,8 @@ def display_header(use_resources: tuple[str, ...]):
|
||||||
if sanitizer and options is not None:
|
if sanitizer and options is not None:
|
||||||
print(f"== {env_var}={options!r}")
|
print(f"== {env_var}={options!r}")
|
||||||
|
|
||||||
|
print(flush=True)
|
||||||
|
|
||||||
|
|
||||||
def cleanup_temp_dir(tmp_dir: StrPath):
|
def cleanup_temp_dir(tmp_dir: StrPath):
|
||||||
import glob
|
import glob
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue