From 836dc451f46f63ea7ae0f1ec0132b507838466f2 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 25 May 2017 17:08:32 -0300 Subject: [PATCH] Fix unicode issue while running doctests in Python 2 Fix #2434 --- CHANGELOG.rst | 4 +++- _pytest/doctest.py | 29 +++++++++++++++++++++++++++++ testing/test_doctest.py | 22 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9133d5f5b..03e2fe294 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,7 +1,9 @@ 3.1.1 (unreleased) ================== -* Fix encoding errors for unicode warnings in Python 2. +* Fix encoding errors for unicode warnings in Python 2. (towncrier: 2436.bugfix) + +* Fix issue with non-ascii contents in doctest text files. (towncrier: 2434.bugfix) 3.1.0 (2017-05-22) diff --git a/_pytest/doctest.py b/_pytest/doctest.py index f9299be72..46b49d212 100644 --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -181,6 +181,7 @@ class DoctestTextfile(pytest.Module): optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + _fix_spoof_python2(runner, encoding) parser = doctest.DocTestParser() test = parser.get_doctest(text, globs, name, filename, 0) @@ -216,6 +217,10 @@ class DoctestModule(pytest.Module): optionflags = get_optionflags(self) runner = doctest.DebugRunner(verbose=0, optionflags=optionflags, checker=_get_checker()) + + encoding = self.config.getini("doctest_encoding") + _fix_spoof_python2(runner, encoding) + for test in finder.find(module, module.__name__): if test.examples: # skip empty doctests yield DoctestItem(test.name, self, runner, test) @@ -324,6 +329,30 @@ def _get_report_choice(key): DOCTEST_REPORT_CHOICE_NONE: 0, }[key] + +def _fix_spoof_python2(runner, encoding): + """ + Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. + + This fixes the problem related in issue #2434. + """ + from _pytest.compat import _PY2 + if not _PY2: + return + + from doctest import _SpoofOut + + class UnicodeSpoof(_SpoofOut): + + def getvalue(self): + result = _SpoofOut.getvalue(self) + if encoding: + result = result.decode(encoding) + return result + + runner._fakeout = UnicodeSpoof() + + @pytest.fixture(scope='session') def doctest_namespace(): """ diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 82597b477..e22976c75 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -505,6 +505,28 @@ class TestDoctests(object): "--junit-xml=junit.xml") reprec.assertoutcome(failed=1) + def test_unicode_doctest(self, testdir): + """ + Test case for issue 2434: DecodeError on Python 2 when doctest contains non-ascii + characters. + """ + p = testdir.maketxtfile(test_unicode_doctest=""" + .. doctest:: + + >>> print( + ... "Hi\\n\\nByé") + Hi + ... + Byé + >>> 1/0 # Byé + 1 + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + '*UNEXPECTED EXCEPTION: ZeroDivisionError*', + '*1 failed*', + ]) + class TestLiterals(object):