gh-110721: Use the traceback module for PyErr_Display() and fallback to the C implementation (#110702)

This commit is contained in:
Pablo Galindo Salgado 2023-10-12 16:52:14 +02:00 committed by GitHub
parent 8c6c14b91b
commit e7331365b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 146 additions and 837 deletions

View file

@ -963,7 +963,9 @@ class CPythonTracebackLegacyErrorCaretTests(
Same set of tests as above but with Python's legacy internal traceback printing.
"""
class TracebackFormatTests(unittest.TestCase):
class TracebackFormatMixin:
DEBUG_RANGES = True
def some_exception(self):
raise KeyError('blah')
@ -1137,6 +1139,8 @@ class TracebackFormatTests(unittest.TestCase):
)
expected = (tb_line + result_g).splitlines()
actual = stderr_g.getvalue().splitlines()
if not self.DEBUG_RANGES:
expected = [line for line in expected if not set(line.strip()) == {"^"}]
self.assertEqual(actual, expected)
# Check 2 different repetitive sections
@ -1173,6 +1177,8 @@ class TracebackFormatTests(unittest.TestCase):
)
expected = (result_h + result_g).splitlines()
actual = stderr_h.getvalue().splitlines()
if not self.DEBUG_RANGES:
expected = [line for line in expected if not set(line.strip()) == {"^"}]
self.assertEqual(actual, expected)
# Check the boundary conditions. First, test just below the cutoff.
@ -1199,11 +1205,13 @@ class TracebackFormatTests(unittest.TestCase):
)
tb_line = (
'Traceback (most recent call last):\n'
f' File "{__file__}", line {lineno_g+77}, in _check_recursive_traceback_display\n'
f' File "{__file__}", line {lineno_g+81}, in _check_recursive_traceback_display\n'
' g(traceback._RECURSIVE_CUTOFF)\n'
)
expected = (tb_line + result_g).splitlines()
actual = stderr_g.getvalue().splitlines()
if not self.DEBUG_RANGES:
expected = [line for line in expected if not set(line.strip()) == {"^"}]
self.assertEqual(actual, expected)
# Second, test just above the cutoff.
@ -1231,24 +1239,24 @@ class TracebackFormatTests(unittest.TestCase):
)
tb_line = (
'Traceback (most recent call last):\n'
f' File "{__file__}", line {lineno_g+108}, in _check_recursive_traceback_display\n'
f' File "{__file__}", line {lineno_g+114}, in _check_recursive_traceback_display\n'
' g(traceback._RECURSIVE_CUTOFF + 1)\n'
)
expected = (tb_line + result_g).splitlines()
actual = stderr_g.getvalue().splitlines()
if not self.DEBUG_RANGES:
expected = [line for line in expected if not set(line.strip()) == {"^"}]
self.assertEqual(actual, expected)
@requires_debug_ranges()
def test_recursive_traceback_python(self):
self._check_recursive_traceback_display(traceback.print_exc)
@cpython_only
@requires_debug_ranges()
def test_recursive_traceback_cpython_internal(self):
from _testcapi import exception_print
def render_exc():
exception_print(sys.exception())
self._check_recursive_traceback_display(render_exc)
def test_recursive_traceback(self):
if self.DEBUG_RANGES:
self._check_recursive_traceback_display(traceback.print_exc)
else:
from _testcapi import exception_print
def render_exc():
exception_print(sys.exception())
self._check_recursive_traceback_display(render_exc)
def test_format_stack(self):
def fmt():
@ -1321,7 +1329,8 @@ class TracebackFormatTests(unittest.TestCase):
def test_print_exception_bad_type_capi(self):
from _testcapi import exception_print
with captured_output("stderr") as stderr:
exception_print(42)
with support.catch_unraisable_exception():
exception_print(42)
self.assertEqual(
stderr.getvalue(),
('TypeError: print_exception(): '
@ -1345,6 +1354,24 @@ context_message = (
boundaries = re.compile(
'(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
class TestTracebackFormat(unittest.TestCase, TracebackFormatMixin):
pass
@cpython_only
class TestFallbackTracebackFormat(unittest.TestCase, TracebackFormatMixin):
DEBUG_RANGES = False
def setUp(self) -> None:
self.original_unraisable_hook = sys.unraisablehook
sys.unraisablehook = lambda *args: None
self.original_hook = traceback._print_exception_bltin
traceback._print_exception_bltin = lambda *args: 1/0
return super().setUp()
def tearDown(self) -> None:
traceback._print_exception_bltin = self.original_hook
sys.unraisablehook = self.original_unraisable_hook
return super().tearDown()
class BaseExceptionReportingTests:
def get_exception(self, exception_or_callable):