summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2023-10-21 18:02:00 (GMT)
committerGitHub <noreply@github.com>2023-10-21 18:02:00 (GMT)
commitfd60549c0ac6c81f05594a5141d24b4433ae39be (patch)
treec3bbcc9ee2a1be27256665ef6ba02c5639f264a2
parent5e7727b05232b43589d177c15263d7f4f8c584a0 (diff)
downloadcpython-fd60549c0ac6c81f05594a5141d24b4433ae39be.zip
cpython-fd60549c0ac6c81f05594a5141d24b4433ae39be.tar.gz
cpython-fd60549c0ac6c81f05594a5141d24b4433ae39be.tar.bz2
gh-111159: Fix `doctest` output comparison for exceptions with notes (#111160)
-rw-r--r--Lib/doctest.py15
-rw-r--r--Lib/test/test_doctest.py144
-rw-r--r--Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst1
3 files changed, 159 insertions, 1 deletions
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 46b4dd6..f00d935 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -1393,7 +1393,20 @@ class DocTestRunner:
# 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)
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 6e12e82..6a903ed 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -3212,6 +3212,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())
diff --git a/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst b/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst
new file mode 100644
index 0000000..bdec4f4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst
@@ -0,0 +1 @@
+Fix :mod:`doctest` output comparison for exceptions with notes.