diff --git a/src/_pytest/_io/terminalwriter.py b/src/_pytest/_io/terminalwriter.py index 0168dc13d..5ffc550db 100644 --- a/src/_pytest/_io/terminalwriter.py +++ b/src/_pytest/_io/terminalwriter.py @@ -149,7 +149,18 @@ class TerminalWriter: msg = self.markup(msg, **markup) - self._file.write(msg) + try: + self._file.write(msg) + except UnicodeEncodeError: + # Some environments don't support printing general Unicode + # strings, due to misconfiguration or otherwise; in that case, + # print the string escaped to ASCII. + # When the Unicode situation improves we should consider + # letting the error propagate instead of masking it (see #7475 + # for one brief attempt). + msg = msg.encode("unicode-escape").decode("ascii") + self._file.write(msg) + if flush: self.flush() diff --git a/testing/io/test_terminalwriter.py b/testing/io/test_terminalwriter.py index b36a7bb6a..db0ccf06a 100644 --- a/testing/io/test_terminalwriter.py +++ b/testing/io/test_terminalwriter.py @@ -49,6 +49,15 @@ def test_terminalwriter_dumb_term_no_markup(monkeypatch: MonkeyPatch) -> None: assert not tw.hasmarkup +def test_terminalwriter_not_unicode() -> None: + """If the file doesn't support Unicode, the string is unicode-escaped (#7475).""" + buffer = io.BytesIO() + file = io.TextIOWrapper(buffer, encoding="cp1252") + tw = terminalwriter.TerminalWriter(file) + tw.write("hello 🌀 wôrld אבג", flush=True) + assert buffer.getvalue() == br"hello \U0001f300 w\xf4rld \u05d0\u05d1\u05d2" + + win32 = int(sys.platform == "win32")