Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Doc/library/doctest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,8 @@ doctest decides whether actual output matches an example's expected output:
sequence of whitespace within the actual output. By default, whitespace must
match exactly. :const:`NORMALIZE_WHITESPACE` is especially useful when a line of
expected output is very long, and you want to wrap it across multiple lines in
your source.
your source. If the expected output does not contain any whitespace, consider
using :data:`IGNORE_LINEBREAK` or :data:`ELLIPSIS`.


.. index:: single: ...; in doctests
Expand Down Expand Up @@ -666,6 +667,31 @@ doctest decides whether actual output matches an example's expected output:
to the module containing the exception under test.


.. data:: IGNORE_LINEBREAK

When specified, single line breaks in the expected output are eliminated,
thereby allowing strings without whitespaces to span multiple lines.

.. doctest::
:no-trim-doctest-flags:

>>> "foobar123456" # doctest: +IGNORE_LINEBREAK
'foobar
123456'

Consider using :data:`NORMALIZE_WHITESPACE` when strings with whitespaces
need to be split across multiple lines:

.. doctest::
:no-trim-doctest-flags:

>>> "the string to split" # doctest: +NORMALIZE_WHITESPACE
'the string
to split'

.. versionadded:: next


.. data:: SKIP

When specified, do not run the example at all. This can be useful in contexts
Expand Down
17 changes: 17 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,23 @@ difflib
(Contributed by Jiahao Li in :gh:`134580`.)


doctest
-------

* Add :data:`~doctest.IGNORE_LINEBREAK` option to allow breaking expected
output strings without whitespaces into multiple lines:

.. doctest::
:no-trim-doctest-flags:

>>> import string
>>> print(string.ascii_letters) # doctest: +IGNORE_LINEBREAK
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ

(Contributed by Bénédikt Tran in :gh:`138135`.)


hashlib
-------

Expand Down
22 changes: 20 additions & 2 deletions Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def _test():
'DONT_ACCEPT_TRUE_FOR_1',
'DONT_ACCEPT_BLANKLINE',
'NORMALIZE_WHITESPACE',
'IGNORE_LINEBREAK',
'ELLIPSIS',
'SKIP',
'IGNORE_EXCEPTION_DETAIL',
Expand Down Expand Up @@ -156,6 +157,7 @@ def register_optionflag(name):
DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1')
DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE')
NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
IGNORE_LINEBREAK = register_optionflag('IGNORE_LINEBREAK')
ELLIPSIS = register_optionflag('ELLIPSIS')
SKIP = register_optionflag('SKIP')
IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL')
Expand Down Expand Up @@ -1751,9 +1753,18 @@ def check_output(self, want, got, optionflags):
if got == want:
return True

# This flag causes doctest to ignore '\n' in `want`.
# Note that this can be used in conjunction with
# the NORMALIZE_WHITESPACE and ELLIPSIS flags.
if optionflags & IGNORE_LINEBREAK:
# `want` originally ends with '\n' so we add it back
want = ''.join(want.split('\n')) + '\n'
if got == want:
return True

# This flag causes doctest to ignore any differences in the
# contents of whitespace strings. Note that this can be used
# in conjunction with the ELLIPSIS flag.
# in conjunction with the IGNORE_LINEBREAK and ELLIPSIS flags.
if optionflags & NORMALIZE_WHITESPACE:
got = ' '.join(got.split())
want = ' '.join(want.split())
Expand Down Expand Up @@ -2268,7 +2279,7 @@ def set_unittest_reportflags(flags):
>>> doctest.set_unittest_reportflags(ELLIPSIS)
Traceback (most recent call last):
...
ValueError: ('Only reporting flags allowed', 8)
ValueError: ('Only reporting flags allowed', 16)

>>> doctest.set_unittest_reportflags(old) == (REPORT_NDIFF |
... REPORT_ONLY_FIRST_FAILURE)
Expand Down Expand Up @@ -2924,6 +2935,13 @@ def get(self):
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29]
""",

"line break elimination": r"""
>>> "foobar" # doctest: +IGNORE_LINEBREAK
'foo
bar
'
""",
}


Expand Down
51 changes: 50 additions & 1 deletion Lib/test/test_doctest/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def test_Example(): r"""
... options={doctest.ELLIPSIS: True})
>>> (example.source, example.want, example.exc_msg,
... example.lineno, example.indent, example.options)
('[].pop()\n', '', 'IndexError: pop from an empty list\n', 5, 4, {8: True})
('[].pop()\n', '', 'IndexError: pop from an empty list\n', 5, 4, {16: True})

The constructor normalizes the `source` string to end in a newline:

Expand Down Expand Up @@ -1396,6 +1396,55 @@ def optionflags(): r"""
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

The IGNORE_LINEBREAK flag causes all sequences of newlines to be removed:

>>> def f(x):
... '\n>>> "foobar"\n\'foo\nbar\''

>>> # Without the flag:
>>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test)
... # doctest: +ELLIPSIS
**********************************************************************
File ..., line 3, in f
Failed example:
"foobar"
Expected:
'foo
bar'
Got:
'foobar'
TestResults(failed=1, attempted=1)

>>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0]
>>> flags = doctest.IGNORE_LINEBREAK
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test)
TestResults(failed=0, attempted=1)

... ignore surrounding new lines

>>> "foobar" # doctest: +IGNORE_LINEBREAK
'
foo
bar'
>>> "foobar" # doctest: +IGNORE_LINEBREAK
'foo
bar
'
>>> "foobar" # doctest: +IGNORE_LINEBREAK
'
foo
bar
'

... non-quoted output:

>>> import string
>>> print(string.ascii_letters) # doctest: +IGNORE_LINEBREAK
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ

The ELLIPSIS flag causes ellipsis marker ("...") in the expected
output to match any substring in the actual output:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:mod:`doctest`: Add :data:`~doctest.IGNORE_LINEBREAK` option to allow
breaking expected output strings without whitespaces into multiple lines.
Patch by Bénédikt Tran.
Loading