Skip to content

Commit 9592703

Browse files
sobolevnpull[bot]
authored andcommitted
gh-111159: Fix doctest output comparison for exceptions with notes (#111160)
1 parent 2f95ffd commit 9592703

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

Lib/doctest.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,20 @@ def __run(self, test, compileflags, out):
13931393

13941394
# The example raised an exception: check if it was expected.
13951395
else:
1396-
exc_msg = traceback.format_exception_only(*exception[:2])[-1]
1396+
formatted_ex = traceback.format_exception_only(*exception[:2])
1397+
if issubclass(exception[0], SyntaxError):
1398+
# SyntaxError / IndentationError is special:
1399+
# we don't care about the carets / suggestions / etc
1400+
# We only care about the error message and notes.
1401+
# They start with `SyntaxError:` (or any other class name)
1402+
exc_msg_index = next(
1403+
index
1404+
for index, line in enumerate(formatted_ex)
1405+
if line.startswith(f"{exception[0].__name__}:")
1406+
)
1407+
formatted_ex = formatted_ex[exc_msg_index:]
1408+
1409+
exc_msg = "".join(formatted_ex)
13971410
if not quiet:
13981411
got += _exception_traceback(exception)
13991412

Lib/test/test_doctest.py

+144
Original file line numberDiff line numberDiff line change
@@ -3212,6 +3212,150 @@ def test_run_doctestsuite_multiple_times():
32123212
"""
32133213

32143214

3215+
def test_exception_with_note(note):
3216+
"""
3217+
>>> test_exception_with_note('Note')
3218+
Traceback (most recent call last):
3219+
...
3220+
ValueError: Text
3221+
Note
3222+
3223+
>>> test_exception_with_note('Note') # doctest: +IGNORE_EXCEPTION_DETAIL
3224+
Traceback (most recent call last):
3225+
...
3226+
ValueError: Text
3227+
Note
3228+
3229+
>>> test_exception_with_note('''Note
3230+
... multiline
3231+
... example''')
3232+
Traceback (most recent call last):
3233+
ValueError: Text
3234+
Note
3235+
multiline
3236+
example
3237+
3238+
Different note will fail the test:
3239+
3240+
>>> def f(x):
3241+
... r'''
3242+
... >>> exc = ValueError('message')
3243+
... >>> exc.add_note('note')
3244+
... >>> raise exc
3245+
... Traceback (most recent call last):
3246+
... ValueError: message
3247+
... wrong note
3248+
... '''
3249+
>>> test = doctest.DocTestFinder().find(f)[0]
3250+
>>> doctest.DocTestRunner(verbose=False).run(test)
3251+
... # doctest: +ELLIPSIS
3252+
**********************************************************************
3253+
File "...", line 5, in f
3254+
Failed example:
3255+
raise exc
3256+
Expected:
3257+
Traceback (most recent call last):
3258+
ValueError: message
3259+
wrong note
3260+
Got:
3261+
Traceback (most recent call last):
3262+
...
3263+
ValueError: message
3264+
note
3265+
TestResults(failed=1, attempted=...)
3266+
"""
3267+
exc = ValueError('Text')
3268+
exc.add_note(note)
3269+
raise exc
3270+
3271+
3272+
def test_exception_with_multiple_notes():
3273+
"""
3274+
>>> test_exception_with_multiple_notes()
3275+
Traceback (most recent call last):
3276+
...
3277+
ValueError: Text
3278+
One
3279+
Two
3280+
"""
3281+
exc = ValueError('Text')
3282+
exc.add_note('One')
3283+
exc.add_note('Two')
3284+
raise exc
3285+
3286+
3287+
def test_syntax_error_with_note(cls, multiline=False):
3288+
"""
3289+
>>> test_syntax_error_with_note(SyntaxError)
3290+
Traceback (most recent call last):
3291+
...
3292+
SyntaxError: error
3293+
Note
3294+
3295+
>>> test_syntax_error_with_note(SyntaxError)
3296+
Traceback (most recent call last):
3297+
SyntaxError: error
3298+
Note
3299+
3300+
>>> test_syntax_error_with_note(SyntaxError)
3301+
Traceback (most recent call last):
3302+
...
3303+
File "x.py", line 23
3304+
bad syntax
3305+
SyntaxError: error
3306+
Note
3307+
3308+
>>> test_syntax_error_with_note(IndentationError)
3309+
Traceback (most recent call last):
3310+
...
3311+
IndentationError: error
3312+
Note
3313+
3314+
>>> test_syntax_error_with_note(TabError, multiline=True)
3315+
Traceback (most recent call last):
3316+
...
3317+
TabError: error
3318+
Note
3319+
Line
3320+
"""
3321+
exc = cls("error", ("x.py", 23, None, "bad syntax"))
3322+
exc.add_note('Note\nLine' if multiline else 'Note')
3323+
raise exc
3324+
3325+
3326+
def test_syntax_error_with_incorrect_expected_note():
3327+
"""
3328+
>>> def f(x):
3329+
... r'''
3330+
... >>> exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
3331+
... >>> exc.add_note('note1')
3332+
... >>> exc.add_note('note2')
3333+
... >>> raise exc
3334+
... Traceback (most recent call last):
3335+
... SyntaxError: error
3336+
... wrong note
3337+
... '''
3338+
>>> test = doctest.DocTestFinder().find(f)[0]
3339+
>>> doctest.DocTestRunner(verbose=False).run(test)
3340+
... # doctest: +ELLIPSIS
3341+
**********************************************************************
3342+
File "...", line 6, in f
3343+
Failed example:
3344+
raise exc
3345+
Expected:
3346+
Traceback (most recent call last):
3347+
SyntaxError: error
3348+
wrong note
3349+
Got:
3350+
Traceback (most recent call last):
3351+
...
3352+
SyntaxError: error
3353+
note1
3354+
note2
3355+
TestResults(failed=1, attempted=...)
3356+
"""
3357+
3358+
32153359
def load_tests(loader, tests, pattern):
32163360
tests.addTest(doctest.DocTestSuite(doctest))
32173361
tests.addTest(doctest.DocTestSuite())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :mod:`doctest` output comparison for exceptions with notes.

0 commit comments

Comments
 (0)