summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_pdb.py
diff options
context:
space:
mode:
authorMatthias Bussonnier <bussonniermatthias@gmail.com>2023-08-28 18:31:03 (GMT)
committerGitHub <noreply@github.com>2023-08-28 18:31:03 (GMT)
commitf75cefd402c4c830228d85ca3442377ebaf09454 (patch)
tree71daf3d2dd8e82dfcd8c89ef31f84067781fe448 /Lib/test/test_pdb.py
parent242bef459bfbd0ec5e45e6d47df2709093cfefa7 (diff)
downloadcpython-f75cefd402c4c830228d85ca3442377ebaf09454.zip
cpython-f75cefd402c4c830228d85ca3442377ebaf09454.tar.gz
cpython-f75cefd402c4c830228d85ca3442377ebaf09454.tar.bz2
gh-106670: Allow Pdb to move between chained exceptions (#106676)
Diffstat (limited to 'Lib/test/test_pdb.py')
-rw-r--r--Lib/test/test_pdb.py343
1 files changed, 343 insertions, 0 deletions
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index a669535..734b5c8 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -826,6 +826,349 @@ def test_convenience_variables():
(Pdb) continue
"""
+
+def test_post_mortem_chained():
+ """Test post mortem traceback debugging of chained exception
+
+ >>> def test_function_2():
+ ... try:
+ ... 1/0
+ ... finally:
+ ... print('Exception!')
+
+ >>> def test_function_reraise():
+ ... try:
+ ... test_function_2()
+ ... except ZeroDivisionError as e:
+ ... raise ZeroDivisionError('reraised') from e
+
+ >>> def test_function():
+ ... import pdb;
+ ... instance = pdb.Pdb(nosigint=True, readrc=False)
+ ... try:
+ ... test_function_reraise()
+ ... except Exception as e:
+ ... # same as pdb.post_mortem(e), but with custom pdb instance.
+ ... instance.reset()
+ ... instance.interaction(None, e)
+
+ >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ ... 'exceptions',
+ ... 'exceptions 0',
+ ... 'up',
+ ... 'down',
+ ... 'exceptions 1',
+ ... 'up',
+ ... 'down',
+ ... 'exceptions -1',
+ ... 'exceptions 3',
+ ... 'up',
+ ... 'exit',
+ ... ]):
+ ... try:
+ ... test_function()
+ ... except ZeroDivisionError:
+ ... print('Correctly reraised.')
+ Exception!
+ > <doctest test.test_pdb.test_post_mortem_chained[1]>(5)test_function_reraise()
+ -> raise ZeroDivisionError('reraised') from e
+ (Pdb) exceptions
+ 0 ZeroDivisionError('division by zero')
+ > 1 ZeroDivisionError('reraised')
+ (Pdb) exceptions 0
+ > <doctest test.test_pdb.test_post_mortem_chained[0]>(3)test_function_2()
+ -> 1/0
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_chained[1]>(3)test_function_reraise()
+ -> test_function_2()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_chained[0]>(3)test_function_2()
+ -> 1/0
+ (Pdb) exceptions 1
+ > <doctest test.test_pdb.test_post_mortem_chained[1]>(5)test_function_reraise()
+ -> raise ZeroDivisionError('reraised') from e
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_chained[2]>(5)test_function()
+ -> test_function_reraise()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_chained[1]>(5)test_function_reraise()
+ -> raise ZeroDivisionError('reraised') from e
+ (Pdb) exceptions -1
+ *** No exception with that number
+ (Pdb) exceptions 3
+ *** No exception with that number
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_chained[2]>(5)test_function()
+ -> test_function_reraise()
+ (Pdb) exit
+ """
+
+
+def test_post_mortem_cause_no_context():
+ """Test post mortem traceback debugging of chained exception
+
+ >>> def main():
+ ... try:
+ ... raise ValueError('Context Not Shown')
+ ... except Exception as e1:
+ ... raise ValueError("With Cause") from TypeError('The Cause')
+
+ >>> def test_function():
+ ... import pdb;
+ ... instance = pdb.Pdb(nosigint=True, readrc=False)
+ ... try:
+ ... main()
+ ... except Exception as e:
+ ... # same as pdb.post_mortem(e), but with custom pdb instance.
+ ... instance.reset()
+ ... instance.interaction(None, e)
+
+ >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ ... 'exceptions',
+ ... 'exceptions 1',
+ ... 'up',
+ ... 'down',
+ ... 'exit',
+ ... ]):
+ ... try:
+ ... test_function()
+ ... except ValueError:
+ ... print('Ok.')
+ > <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
+ -> raise ValueError("With Cause") from TypeError('The Cause')
+ (Pdb) exceptions
+ 0 TypeError('The Cause')
+ > 1 ValueError('With Cause')
+ (Pdb) exceptions 1
+ > <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
+ -> raise ValueError("With Cause") from TypeError('The Cause')
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_cause_no_context[1]>(5)test_function()
+ -> main()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
+ -> raise ValueError("With Cause") from TypeError('The Cause')
+ (Pdb) exit"""
+
+
+def test_post_mortem_context_of_the_cause():
+ """Test post mortem traceback debugging of chained exception
+
+
+ >>> def main():
+ ... try:
+ ... raise TypeError('Context of the cause')
+ ... except Exception as e1:
+ ... try:
+ ... raise ValueError('Root Cause')
+ ... except Exception as e2:
+ ... ex = e2
+ ... raise ValueError("With Cause, and cause has context") from ex
+
+ >>> def test_function():
+ ... import pdb;
+ ... instance = pdb.Pdb(nosigint=True, readrc=False)
+ ... try:
+ ... main()
+ ... except Exception as e:
+ ... # same as pdb.post_mortem(e), but with custom pdb instance.
+ ... instance.reset()
+ ... instance.interaction(None, e)
+
+ >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ ... 'exceptions',
+ ... 'exceptions 2',
+ ... 'up',
+ ... 'down',
+ ... 'exceptions 3',
+ ... 'up',
+ ... 'down',
+ ... 'exceptions 4',
+ ... 'up',
+ ... 'down',
+ ... 'exit',
+ ... ]):
+ ... try:
+ ... test_function()
+ ... except ValueError:
+ ... print('Correctly reraised.')
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[0]>(9)main()
+ -> raise ValueError("With Cause, and cause has context") from ex
+ (Pdb) exceptions
+ 0 TypeError('Context of the cause')
+ 1 ValueError('Root Cause')
+ > 2 ValueError('With Cause, and cause has context')
+ (Pdb) exceptions 2
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[0]>(9)main()
+ -> raise ValueError("With Cause, and cause has context") from ex
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[1]>(5)test_function()
+ -> main()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[0]>(9)main()
+ -> raise ValueError("With Cause, and cause has context") from ex
+ (Pdb) exceptions 3
+ *** No exception with that number
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[1]>(5)test_function()
+ -> main()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[0]>(9)main()
+ -> raise ValueError("With Cause, and cause has context") from ex
+ (Pdb) exceptions 4
+ *** No exception with that number
+ (Pdb) up
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[1]>(5)test_function()
+ -> main()
+ (Pdb) down
+ > <doctest test.test_pdb.test_post_mortem_context_of_the_cause[0]>(9)main()
+ -> raise ValueError("With Cause, and cause has context") from ex
+ (Pdb) exit
+ """
+
+
+def test_post_mortem_from_none():
+ """Test post mortem traceback debugging of chained exception
+
+ In particular that cause from None (which sets __supress_context__ to True)
+ does not show context.
+
+
+ >>> def main():
+ ... try:
+ ... raise TypeError('Context of the cause')
+ ... except Exception as e1:
+ ... raise ValueError("With Cause, and cause has context") from None
+
+ >>> def test_function():
+ ... import pdb;
+ ... instance = pdb.Pdb(nosigint=True, readrc=False)
+ ... try:
+ ... main()
+ ... except Exception as e:
+ ... # same as pdb.post_mortem(e), but with custom pdb instance.
+ ... instance.reset()
+ ... instance.interaction(None, e)
+
+ >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ ... 'exceptions',
+ ... 'exit',
+ ... ]):
+ ... try:
+ ... test_function()
+ ... except ValueError:
+ ... print('Correctly reraised.')
+ > <doctest test.test_pdb.test_post_mortem_from_none[0]>(5)main()
+ -> raise ValueError("With Cause, and cause has context") from None
+ (Pdb) exceptions
+ > 0 ValueError('With Cause, and cause has context')
+ (Pdb) exit
+ """
+
+
+def test_post_mortem_complex():
+ """Test post mortem traceback debugging of chained exception
+
+ Test with simple and complex cycles, exception groups,...
+
+ >>> def make_ex_with_stack(type_, *content, from_=None):
+ ... try:
+ ... raise type_(*content) from from_
+ ... except Exception as out:
+ ... return out
+ ...
+
+ >>> def cycle():
+ ... try:
+ ... raise ValueError("Cycle Leaf")
+ ... except Exception as e:
+ ... raise e from e
+ ...
+
+ >>> def tri_cycle():
+ ... a = make_ex_with_stack(ValueError, "Cycle1")
+ ... b = make_ex_with_stack(ValueError, "Cycle2")
+ ... c = make_ex_with_stack(ValueError, "Cycle3")
+ ...
+ ... a.__cause__ = b
+ ... b.__cause__ = c
+ ...
+ ... raise c from a
+ ...
+
+ >>> def cause():
+ ... try:
+ ... raise ValueError("Cause Leaf")
+ ... except Exception as e:
+ ... raise e
+ ...
+
+ >>> def context(n=10):
+ ... try:
+ ... raise ValueError(f"Context Leaf {n}")
+ ... except Exception as e:
+ ... if n == 0:
+ ... raise ValueError(f"With Context {n}") from e
+ ... else:
+ ... context(n - 1)
+ ...
+
+ >>> def main():
+ ... try:
+ ... cycle()
+ ... except Exception as e1:
+ ... try:
+ ... tri_cycle()
+ ... except Exception as e2:
+ ... ex = e2
+ ... raise ValueError("With Context and With Cause") from ex
+
+
+ >>> def test_function():
+ ... import pdb;
+ ... instance = pdb.Pdb(nosigint=True, readrc=False)
+ ... try:
+ ... main()
+ ... except Exception as e:
+ ... # same as pdb.post_mortem(e), but with custom pdb instance.
+ ... instance.reset()
+ ... instance.interaction(None, e)
+
+ >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
+ ... ["exceptions",
+ ... "exceptions 0",
+ ... "exceptions 1",
+ ... "exceptions 2",
+ ... "exceptions 3",
+ ... "exit"],
+ ... ):
+ ... try:
+ ... test_function()
+ ... except ValueError:
+ ... print('Correctly reraised.')
+ > <doctest test.test_pdb.test_post_mortem_complex[5]>(9)main()
+ -> raise ValueError("With Context and With Cause") from ex
+ (Pdb) exceptions
+ 0 ValueError('Cycle2')
+ 1 ValueError('Cycle1')
+ 2 ValueError('Cycle3')
+ > 3 ValueError('With Context and With Cause')
+ (Pdb) exceptions 0
+ > <doctest test.test_pdb.test_post_mortem_complex[0]>(3)make_ex_with_stack()
+ -> raise type_(*content) from from_
+ (Pdb) exceptions 1
+ > <doctest test.test_pdb.test_post_mortem_complex[0]>(3)make_ex_with_stack()
+ -> raise type_(*content) from from_
+ (Pdb) exceptions 2
+ > <doctest test.test_pdb.test_post_mortem_complex[0]>(3)make_ex_with_stack()
+ -> raise type_(*content) from from_
+ (Pdb) exceptions 3
+ > <doctest test.test_pdb.test_post_mortem_complex[5]>(9)main()
+ -> raise ValueError("With Context and With Cause") from ex
+ (Pdb) exit
+ """
+
+
def test_post_mortem():
"""Test post mortem traceback debugging.