mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
bpo-30579: Allow TracebackType creation and tb_next mutation from Python (GH-4793)
Third party projects may wish to hide their own internal machinery in order to present more comprehensible tracebacks to end users (e.g. Jinja2 and Trio both do this). Previously such projects have had to rely on ctypes to do so:fe3dadacdf/jinja2/debug.py (L345)
1e86b1aee8/trio/_core/_multierror.py (L296)
This provides a Python level API for creating and modifying real Traceback objects, allowing tracebacks to be edited at runtime. Patch by Nathaniel Smith.
This commit is contained in:
parent
d327ae6ba1
commit
e46a8af450
4 changed files with 226 additions and 26 deletions
|
@ -228,6 +228,72 @@ class TestTraceback(unittest.TestCase):
|
|||
self.fail("No exception raised")
|
||||
|
||||
|
||||
class TestTracebackType(unittest.TestCase):
|
||||
|
||||
def raiser(self):
|
||||
raise ValueError
|
||||
|
||||
def test_attrs(self):
|
||||
try:
|
||||
self.raiser()
|
||||
except Exception as exc:
|
||||
tb = exc.__traceback__
|
||||
|
||||
self.assertIsInstance(tb.tb_next, types.TracebackType)
|
||||
self.assertIs(tb.tb_frame, sys._getframe())
|
||||
self.assertIsInstance(tb.tb_lasti, int)
|
||||
self.assertIsInstance(tb.tb_lineno, int)
|
||||
|
||||
self.assertIs(tb.tb_next.tb_next, None)
|
||||
|
||||
# Invalid assignments
|
||||
with self.assertRaises(TypeError):
|
||||
del tb.tb_next
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
tb.tb_next = "asdf"
|
||||
|
||||
# Loops
|
||||
with self.assertRaises(ValueError):
|
||||
tb.tb_next = tb
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
tb.tb_next.tb_next = tb
|
||||
|
||||
# Valid assignments
|
||||
tb.tb_next = None
|
||||
self.assertIs(tb.tb_next, None)
|
||||
|
||||
new_tb = get_tb()
|
||||
tb.tb_next = new_tb
|
||||
self.assertIs(tb.tb_next, new_tb)
|
||||
|
||||
def test_constructor(self):
|
||||
other_tb = get_tb()
|
||||
frame = sys._getframe()
|
||||
|
||||
tb = types.TracebackType(other_tb, frame, 1, 2)
|
||||
self.assertEqual(tb.tb_next, other_tb)
|
||||
self.assertEqual(tb.tb_frame, frame)
|
||||
self.assertEqual(tb.tb_lasti, 1)
|
||||
self.assertEqual(tb.tb_lineno, 2)
|
||||
|
||||
tb = types.TracebackType(None, frame, 1, 2)
|
||||
self.assertEqual(tb.tb_next, None)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
types.TracebackType("no", frame, 1, 2)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
types.TracebackType(other_tb, "no", 1, 2)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
types.TracebackType(other_tb, frame, "no", 2)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
types.TracebackType(other_tb, frame, 1, "nuh-uh")
|
||||
|
||||
|
||||
class TestContext(unittest.TestCase):
|
||||
def test_instance_context_instance_raise(self):
|
||||
context = IndexError()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue