diff --git a/_pytest/python.py b/_pytest/python.py index 4fbf35c5a..da41bf8e9 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1053,10 +1053,14 @@ if _PY3: want to return escaped bytes for any byte, even if they match a utf-8 string. """ - # source: http://goo.gl/bGsnwC - import codecs - encoded_bytes, _ = codecs.escape_encode(val) - return encoded_bytes.decode('ascii') + if val: + # source: http://goo.gl/bGsnwC + import codecs + encoded_bytes, _ = codecs.escape_encode(val) + return encoded_bytes.decode('ascii') + else: + # empty bytes crashes codecs.escape_encode (#1087) + return '' else: def _escape_bytes(val): """ @@ -1064,7 +1068,7 @@ else: is a full ascii string, otherwise escape it into its binary form. """ try: - return val.encode('ascii') + return val.decode('ascii') except UnicodeDecodeError: return val.encode('string-escape') diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 3a05af9b7..111ca615a 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -137,6 +137,23 @@ class TestMetafunc: for val, expected in values: assert _idval(val, 'a', 6, None) == expected + def test_bytes_idval(self): + """unittest for the expected behavior to obtain ids for parametrized + bytes values: + - python2: non-ascii strings are considered bytes and formatted using + "binary escape", where any byte < 127 is escaped into its hex form. + - python3: bytes objects are always escaped using "binary escape". + """ + from _pytest.python import _idval + values = [ + (b'', ''), + (b'\xc3\xb4\xff\xe4', '\\xc3\\xb4\\xff\\xe4'), + (b'ascii', 'ascii'), + (u'αρά'.encode('utf-8'), '\\xce\\xb1\\xcf\\x81\\xce\\xac'), + ] + for val, expected in values: + assert _idval(val, 'a', 6, None) == expected + @pytest.mark.issue250 def test_idmaker_autoname(self): from _pytest.python import idmaker