summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/changelog/2969.bugfix.rst3
-rw-r--r--src/tox/execute/stream.py2
-rw-r--r--tests/execute/test_stream.py6
3 files changed, 10 insertions, 1 deletions
diff --git a/docs/changelog/2969.bugfix.rst b/docs/changelog/2969.bugfix.rst
new file mode 100644
index 00000000..29464086
--- /dev/null
+++ b/docs/changelog/2969.bugfix.rst
@@ -0,0 +1,3 @@
+Instead of raising ``UnicodeDecodeError`` when command output includes non-utf-8 bytes,
+``tox`` will now use ``surrogateescape`` error handling to convert the unrecognized bytes
+to escape sequences according to :pep:`383` - by :user:`masenf`.
diff --git a/src/tox/execute/stream.py b/src/tox/execute/stream.py
index 980c97ff..28c66be6 100644
--- a/src/tox/execute/stream.py
+++ b/src/tox/execute/stream.py
@@ -100,7 +100,7 @@ class SyncWrite:
@property
def text(self) -> str:
with self._content_lock:
- return self._content.decode("utf-8")
+ return self._content.decode("utf-8", errors="surrogateescape")
@property
def content(self) -> bytearray:
diff --git a/tests/execute/test_stream.py b/tests/execute/test_stream.py
index 6e870826..fe9dd563 100644
--- a/tests/execute/test_stream.py
+++ b/tests/execute/test_stream.py
@@ -8,3 +8,9 @@ from tox.execute.stream import SyncWrite
def test_sync_write_repr() -> None:
sync_write = SyncWrite(name="a", target=None, color=Fore.RED)
assert repr(sync_write) == f"SyncWrite(name='a', target=None, color={Fore.RED!r})"
+
+
+def test_sync_write_decode_surrogate() -> None:
+ sync_write = SyncWrite(name="a", target=None)
+ sync_write.handler(b"\xed\n")
+ assert sync_write.text == "\udced\n"