After running my parameterized tests with -vvv there was a sequence of mixed ?1;2c and ^[[ characters in terminal promt and test output. It looks like in the screen snippet (output from given example code):

The reason is explained here and it occurs because character \x05 is interpreted in special way by terminal when running e.g. cat.
Also notice that \x05 character is missing but \xff is printed correctly.
I'm aware that may not be pytest issue but I don't know exacly which upstream should know about it. If you have any suggestions please tell me and I will report them there.
import pytest
import struct
@pytest.mark.parametrize('val, ex_bytes', [
pytest.param(1, b'\x01', id="This doesn't test for \x05 presence."),
(5, b'\x05'),
(255, b'\xff'),
])
def test_b(val, ex_bytes):
assert struct.pack('B', val) == ex_bytes
[ ] pip list of the virtual environment you are using
Python 3.6.2
pytest 3.9.1
[ ] pytest and operating system versions
ArchLinux, 4.12.13-1-ARCH
TERM=rxvt-unicode-256color
this is a "critical" bug with nodeids - we let them be nonprintable bytes by accident and have quite a few issues due to that (like incorrect data in the environment variables that express node metada)
a workaround would be to just forego automated id generation and using explicit node ids there
when we drop python2 we will revisit expressing bytes there in order to ensure they are safely encoded
I think this is fixable without dropping python2.x -- just need to adjust which characters we consider "ascii escaped" in this code
Here's a start of a patch, I might finish it up later:
diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py
index ead9ffd8..9f1a39fe 100644
--- a/src/_pytest/compat.py
+++ b/src/_pytest/compat.py
@@ -182,6 +182,15 @@ def get_default_arg_names(function):
)
+_non_printable_ascii_translate_table = {
+ i: u'\\x{:02x}'.format(i) for i in range(128) if i not in range(32, 127)
+}
+
+
+def _translate_non_printable(s):
+ return s.translate(_non_printable_ascii_translate_table)
+
+
if _PY3:
STRING_TYPES = bytes, str
UNICODE_TYPES = six.text_type
@@ -221,9 +230,10 @@ if _PY3:
"""
if isinstance(val, bytes):
- return _bytes_to_ascii(val)
+ ret = _bytes_to_ascii(val)
else:
- return val.encode("unicode_escape").decode("ascii")
+ ret = val.encode("unicode_escape").decode("ascii")
+ return _translate_non_printable(ret)
else:
@@ -241,11 +251,12 @@ else:
"""
if isinstance(val, bytes):
try:
- return val.encode("ascii")
+ ret = val.decode("ascii")
except UnicodeDecodeError:
- return val.encode("string-escape")
+ ret = val.encode("string-escape").decode("ascii")
else:
- return val.encode("unicode-escape")
+ ret = val.encode("unicode-escape").decode("ascii")
+ return _translate_non_printable(ret)
class _PytestWrapper(object):
$ pytest -v t.py
============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-4.0.1.dev1+g9dec146e.d20181115, py-1.7.0, pluggy-0.8.0 -- /tmp/pytest/venv/bin/python3
cachedir: .pytest_cache
rootdir: /tmp/pytest, inifile: tox.ini
collected 3 items
t.py::test_b[This doesn't test for presence.] PASSED [ 33%]
t.py::test_b[5-\x05] PASSED [ 66%]
t.py::test_b[255-\xff] PASSED [100%]
=========================== 3 passed in 0.01 seconds ===========================
we're still not escaping the \x05 in the manually passed id, so I'll need to track that down
via #4418
this'll make it into the next minor release -- if you'd like to try it early, pip install from the features branch.
Thanks again for this issue! It was a fun one to solve :tada:
Most helpful comment
via #4418
this'll make it into the next minor release -- if you'd like to try it early, pip install from the
featuresbranch.Thanks again for this issue! It was a fun one to solve :tada: