Skip to content

Commit

Permalink
[3.12] gh-111159: Fix doctest output comparison for exceptions with…
Browse files Browse the repository at this point in the history
… notes (GH-111160) (#111169)

gh-111159: Fix `doctest` output comparison for exceptions with notes (GH-111160)
(cherry picked from commit fd60549)

Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
  • Loading branch information
miss-islington and sobolevn committed Oct 21, 2023
1 parent 1ea9302 commit f6cde99
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 1 deletion.
15 changes: 14 additions & 1 deletion Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,20 @@ def __run(self, test, compileflags, out):

# The example raised an exception: check if it was expected.
else:
exc_msg = traceback.format_exception_only(*exception[:2])[-1]
formatted_ex = traceback.format_exception_only(*exception[:2])
if issubclass(exception[0], SyntaxError):
# SyntaxError / IndentationError is special:
# we don't care about the carets / suggestions / etc
# We only care about the error message and notes.
# They start with `SyntaxError:` (or any other class name)
exc_msg_index = next(
index
for index, line in enumerate(formatted_ex)
if line.startswith(f"{exception[0].__name__}:")
)
formatted_ex = formatted_ex[exc_msg_index:]

exc_msg = "".join(formatted_ex)
if not quiet:
got += _exception_traceback(exception)

Expand Down
144 changes: 144 additions & 0 deletions Lib/test/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3168,6 +3168,150 @@ def test_run_doctestsuite_multiple_times():
"""


def test_exception_with_note(note):
"""
>>> test_exception_with_note('Note')
Traceback (most recent call last):
...
ValueError: Text
Note
>>> test_exception_with_note('Note') # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ValueError: Text
Note
>>> test_exception_with_note('''Note
... multiline
... example''')
Traceback (most recent call last):
ValueError: Text
Note
multiline
example
Different note will fail the test:
>>> def f(x):
... r'''
... >>> exc = ValueError('message')
... >>> exc.add_note('note')
... >>> raise exc
... Traceback (most recent call last):
... ValueError: message
... wrong note
... '''
>>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test)
... # doctest: +ELLIPSIS
**********************************************************************
File "...", line 5, in f
Failed example:
raise exc
Expected:
Traceback (most recent call last):
ValueError: message
wrong note
Got:
Traceback (most recent call last):
...
ValueError: message
note
TestResults(failed=1, attempted=...)
"""
exc = ValueError('Text')
exc.add_note(note)
raise exc


def test_exception_with_multiple_notes():
"""
>>> test_exception_with_multiple_notes()
Traceback (most recent call last):
...
ValueError: Text
One
Two
"""
exc = ValueError('Text')
exc.add_note('One')
exc.add_note('Two')
raise exc


def test_syntax_error_with_note(cls, multiline=False):
"""
>>> test_syntax_error_with_note(SyntaxError)
Traceback (most recent call last):
...
SyntaxError: error
Note
>>> test_syntax_error_with_note(SyntaxError)
Traceback (most recent call last):
SyntaxError: error
Note
>>> test_syntax_error_with_note(SyntaxError)
Traceback (most recent call last):
...
File "x.py", line 23
bad syntax
SyntaxError: error
Note
>>> test_syntax_error_with_note(IndentationError)
Traceback (most recent call last):
...
IndentationError: error
Note
>>> test_syntax_error_with_note(TabError, multiline=True)
Traceback (most recent call last):
...
TabError: error
Note
Line
"""
exc = cls("error", ("x.py", 23, None, "bad syntax"))
exc.add_note('Note\nLine' if multiline else 'Note')
raise exc


def test_syntax_error_with_incorrect_expected_note():
"""
>>> def f(x):
... r'''
... >>> exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
... >>> exc.add_note('note1')
... >>> exc.add_note('note2')
... >>> raise exc
... Traceback (most recent call last):
... SyntaxError: error
... wrong note
... '''
>>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test)
... # doctest: +ELLIPSIS
**********************************************************************
File "...", line 6, in f
Failed example:
raise exc
Expected:
Traceback (most recent call last):
SyntaxError: error
wrong note
Got:
Traceback (most recent call last):
...
SyntaxError: error
note1
note2
TestResults(failed=1, attempted=...)
"""


def load_tests(loader, tests, pattern):
tests.addTest(doctest.DocTestSuite(doctest))
tests.addTest(doctest.DocTestSuite())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :mod:`doctest` output comparison for exceptions with notes.

0 comments on commit f6cde99

Please sign in to comment.