From d8403d793fe336474b0d7aee5d3e41756780bb0e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 5 Mar 2016 16:58:44 -0300 Subject: [PATCH] Fix decoding issue while formatting SyntaxErrors during collection This happens only in Python 2, as in Python 3 we receive the "badline" in the exception is already properly encoded Fix #578 --- CHANGELOG.rst | 11 +++++++++++ _pytest/_code/_py2traceback.py | 4 +++- testing/code/test_code.py | 11 +++++++++++ testing/python/collect.py | 17 +++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 625c7edc5..bc68d34f0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,9 +10,20 @@ * +* Fix (`#578 `_): SyntaxErrors + containing non-ascii lines at the point of failure generated an internal + py.test error. + Thanks `@asottile`_ for the report and `@nicoddemus`_ for the PR. + +* + +* + .. _#469: https://github.com/pytest-dev/pytest/issues/469 .. _#1431: https://github.com/pytest-dev/pytest/pull/1431 +.. _@asottile: https://github.com/asottile + 2.9.0 ===== diff --git a/_pytest/_code/_py2traceback.py b/_pytest/_code/_py2traceback.py index d65e27cb7..a830d9899 100644 --- a/_pytest/_code/_py2traceback.py +++ b/_pytest/_code/_py2traceback.py @@ -47,7 +47,9 @@ def format_exception_only(etype, value): filename = filename or "" lines.append(' File "%s", line %d\n' % (filename, lineno)) if badline is not None: - lines.append(' %s\n' % badline.strip()) + if isinstance(badline, bytes): # python 2 only + badline = badline.decode('utf-8', 'replace') + lines.append(u' %s\n' % badline.strip()) if offset is not None: caretspace = badline.rstrip('\n')[:offset].lstrip() # non-space whitespace (likes tabs) must be kept for alignment diff --git a/testing/code/test_code.py b/testing/code/test_code.py index e9c7f7ab1..0db4ad2ab 100644 --- a/testing/code/test_code.py +++ b/testing/code/test_code.py @@ -93,6 +93,17 @@ def test_unicode_handling(): if sys.version_info[0] < 3: unicode(excinfo) + +@pytest.mark.skipif(sys.version_info[0] >= 3, reason='python 2 only issue') +def test_unicode_handling_syntax_error(): + value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8') + def f(): + raise SyntaxError('invalid syntax', (None, 1, 3, value)) + excinfo = pytest.raises(Exception, f) + str(excinfo) + if sys.version_info[0] < 3: + unicode(excinfo) + def test_code_getargs(): def f1(x): pass diff --git a/testing/python/collect.py b/testing/python/collect.py index 7ba2574f2..22433da77 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import sys from textwrap import dedent @@ -1181,3 +1182,19 @@ def test_class_injection_does_not_break_collection(testdir): result = testdir.runpytest() assert "RuntimeError: dictionary changed size during iteration" not in result.stdout.str() result.stdout.fnmatch_lines(['*1 passed*']) + + +def test_syntax_error_with_non_ascii_chars(testdir): + """Fix decoding issue while formatting SyntaxErrors during collection (#578) + """ + testdir.makepyfile(u""" + # -*- coding: UTF-8 -*- + + ☃ + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '*ERROR collecting*', + '*SyntaxError*', + '*1 error in*', + ])