diff --git a/Lib/doctest.py b/Lib/doctest.py index d6fb504eeaa..18bdc0ae72a 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -218,8 +218,8 @@ def _load_testfile(filename, package, module_relative, encoding): def _indent(s, indent=4): """ - Add the given number of space characters to the beginning every - non-blank line in `s`, and return the result. + Add the given number of space characters to the beginning of + every non-blank line in `s`, and return the result. """ # This regexp matches the start of non-blank lines: return re.sub('(?m)^(?!$)', indent*' ', s) @@ -1354,7 +1354,14 @@ class DocTestRunner: save_stdout = sys.stdout if out is None: - out = save_stdout.write + encoding = save_stdout.encoding + if encoding is None or encoding.lower() == 'utf-8': + out = save_stdout.write + else: + # Use backslashreplace error handling on write + def out(s): + s = str(s.encode(encoding, 'backslashreplace'), encoding) + save_stdout.write(s) sys.stdout = self._fakeout # Patch pdb.set_trace to restore sys.stdout during interactive diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 8dcc8a4f458..c9b1b855875 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -2147,6 +2147,13 @@ doctest examples in a given file. In its simple invokation, it is called with the name of a file, which is taken to be relative to the calling module. The return value is (#failures, #tests). +We don't want `-v` in sys.argv for these tests. + + >>> save_argv = sys.argv + >>> if '-v' in sys.argv: + ... sys.argv = [arg for arg in save_argv if arg != '-v'] + + >>> doctest.testfile('test_doctest.txt') # doctest: +ELLIPSIS ********************************************************************** File "...", line 6, in test_doctest.txt @@ -2286,6 +2293,28 @@ using the optional keyword argument `encoding`: >>> doctest.testfile('test_doctest4.txt', encoding='utf-8') TestResults(failed=0, attempted=2) >>> doctest.master = None # Reset master. + +Test the verbose output: + + >>> doctest.testfile('test_doctest4.txt', encoding='utf-8', verbose=True) + Trying: + 'föö' + Expecting: + 'f\xf6\xf6' + ok + Trying: + 'bąr' + Expecting: + 'b\u0105r' + ok + 1 items passed all tests: + 2 tests in test_doctest4.txt + 2 tests in 1 items. + 2 passed and 0 failed. + Test passed. + TestResults(failed=0, attempted=2) + >>> doctest.master = None # Reset master. + >>> sys.argv = save_argv """ def test_testmod(): r""" @@ -2295,7 +2324,7 @@ fail with a UnicodeDecodeError because doctest tried to read the "source" lines out of the binary module. >>> import unicodedata - >>> doctest.testmod(unicodedata) + >>> doctest.testmod(unicodedata, verbose=False) TestResults(failed=0, attempted=0) """ diff --git a/Misc/NEWS b/Misc/NEWS index 9e0bc6ad0df..c42cef545c1 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,8 @@ Core and Builtins Library ------- +- Issue #1729305: Fix doctest to handle encode error with "backslashreplace". + - Issue #691291: codecs.open() should not convert end of lines on reading and writing.