Skip to content

[3.12] gh-111159: Fix doctest output comparison for exceptions with notes (GH-111160) #111169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
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.