From 7ce5873da23ea0dc6f796c4d608731e25191d756 Mon Sep 17 00:00:00 2001 From: Martin Prusse Date: Fri, 8 Apr 2016 11:24:12 -0300 Subject: [PATCH] Perform a "unicode aware" check for maximum recursion depth error Avoid errors `UnicodeErrosr`s due non maximum recursion depth errors when checking for those errors. --- AUTHORS | 1 + CHANGELOG.rst | 9 +++++++++ _pytest/_code/code.py | 16 +++++++++++++--- testing/code/test_excinfo.py | 18 +++++++++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 92750acc36b..14bb4e3c18f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -61,6 +61,7 @@ Marc Schlaich Mark Abramowitz Markus Unterwaditzer Martijn Faassen +Martin Prusse Matt Bachmann Michael Aquilina Michael Birtwell diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a64d64a1251..2b6780ad8a8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,10 @@ * +* Fix maximum recursion depth detection when raised error class is not aware + of unicode/encoded bytes. + Thanks `@prusse-martin`_ for the PR (`#1506`_). + * Fix ``pytest.mark.skip`` mark when used in strict mode. Thanks `@pquentin`_ for the PR and `@RonnyPfannschmidt`_ for showing how to fix the bug. @@ -15,6 +19,11 @@ Thanks `@omarkohl`_ for the PR. +.. _#1506: https://github.com/pytest-dev/pytest/pull/1506 + +.. _@prusse-martin: https://github.com/prusse-martin + + 2.9.1 ===== diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py index bc68aac5548..31a3eda2dfe 100644 --- a/_pytest/_code/code.py +++ b/_pytest/_code/code.py @@ -579,9 +579,8 @@ def repr_traceback(self, excinfo): if self.tbfilter: traceback = traceback.filter() recursionindex = None - if excinfo.errisinstance(RuntimeError): - if "maximum recursion depth exceeded" in str(excinfo.value): - recursionindex = traceback.recursionindex() + if is_recursion_error(excinfo): + recursionindex = traceback.recursionindex() last = traceback[-1] entries = [] extraline = None @@ -793,3 +792,14 @@ def getrawcode(obj, trycall=True): return x return obj +if sys.version_info[:2] >= (3, 5): # RecursionError introduced in 3.5 + def is_recursion_error(excinfo): + return excinfo.errisinstance(RecursionError) # noqa +else: + def is_recursion_error(excinfo): + if not excinfo.errisinstance(RuntimeError): + return False + try: + return "maximum recursion depth exceeded" in str(excinfo.value) + except UnicodeError: + return False diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 2defa31035b..47ad50b066c 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -3,7 +3,7 @@ import _pytest import py import pytest -from _pytest._code.code import FormattedExcinfo, ReprExceptionInfo +from _pytest._code.code import ExceptionInfo, FormattedExcinfo, ReprExceptionInfo queue = py.builtin._tryimport('queue', 'Queue') @@ -909,3 +909,19 @@ def i(): assert tw.lines[14] == "E ValueError" assert tw.lines[15] == "" assert tw.lines[16].endswith("mod.py:9: ValueError") + + +@pytest.mark.parametrize("style", ["short", "long"]) +@pytest.mark.parametrize("encoding", [None, "utf8", "utf16"]) +def test_repr_traceback_with_unicode(style, encoding): + msg = u'☹' + if encoding is not None: + msg = msg.encode(encoding) + try: + raise RuntimeError(msg) + except RuntimeError: + e_info = ExceptionInfo() + formatter = FormattedExcinfo(style=style) + repr_traceback = formatter.repr_traceback(e_info) + assert repr_traceback is not None +