From b0c7dbd7fef1883b12eabefed6b5d495844f7b6f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 4 Sep 2023 10:59:07 +0200 Subject: [PATCH 01/11] gh-106670: Fix Pdb handling of chained Exceptions with no stacks. The introduction of chained exception in gh-106676 would sometime lead to File .../Lib/pdb.py", line 298, in setup self.curframe = self.stack[self.curindex][0] ~~~~~~~~~~^^^^^^^^^^^^^^^ IndexError: list index out of range This fixes that by filtering exceptions that that do not have a stack/traceback. Update tests to not use stack-less exceptions when testing another feature, and add an explicit test on how we handle stackless exceptions. --- Lib/pdb.py | 6 ++- Lib/test/test_pdb.py | 90 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 90f26a2eb99848..7d97952c188bf9 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -438,7 +438,7 @@ def _get_tb_and_exceptions(self, tb_or_exc): traceback, current = tb_or_exc.__traceback__, tb_or_exc while current is not None: - if current in _exceptions: + if current in _exceptions or not current.__traceback__: break _exceptions.append(current) if current.__cause__ is not None: @@ -491,6 +491,10 @@ def interaction(self, frame, tb_or_exc): Pdb._previous_sigint_handler = None _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) + if not _chained_exceptions and isinstance(tb_or_exc, BaseException): + raise ValueError( + "A valid traceback must be passed if no exception is being handled" + ) with self._hold_exceptions(_chained_exceptions): if self.setup(frame, tb): # no interaction desired at this time (happens if .pdbrc contains diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 734b5c83cdff7d..a5cbcc48f8f273 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -907,11 +907,18 @@ def test_post_mortem_chained(): def test_post_mortem_cause_no_context(): """Test post mortem traceback debugging of chained exception + >>> def make_ex_with_stack(type_, *content, from_=None): + ... try: + ... raise type_(*content) from from_ + ... except Exception as out: + ... return out + ... + >>> def main(): ... try: ... raise ValueError('Context Not Shown') ... except Exception as e1: - ... raise ValueError("With Cause") from TypeError('The Cause') + ... raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') >>> def test_function(): ... import pdb; @@ -925,6 +932,7 @@ def test_post_mortem_cause_no_context(): >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... 'exceptions', + ... 'exceptions 0', ... 'exceptions 1', ... 'up', ... 'down', @@ -934,20 +942,23 @@ def test_post_mortem_cause_no_context(): ... test_function() ... except ValueError: ... print('Ok.') - > (5)main() - -> raise ValueError("With Cause") from TypeError('The Cause') + > (5)main() + -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') (Pdb) exceptions - 0 TypeError('The Cause') - > 1 ValueError('With Cause') + 0 TypeError('The Cause') + > 1 ValueError('With Cause') + (Pdb) exceptions 0 + > (3)make_ex_with_stack() + -> raise type_(*content) from from_ (Pdb) exceptions 1 - > (5)main() - -> raise ValueError("With Cause") from TypeError('The Cause') + > (5)main() + -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') (Pdb) up - > (5)test_function() + > (5)test_function() -> main() (Pdb) down - > (5)main() - -> raise ValueError("With Cause") from TypeError('The Cause') + > (5)main() + -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') (Pdb) exit""" @@ -1066,6 +1077,65 @@ def test_post_mortem_from_none(): """ +def test_post_mortem_from_no_stack(): + """Test post mortem traceback debugging of chained exception + + especially when one exception has not stack. + + >>> def main(): + ... raise Exception() from Exception() + + + >>> 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.') + > (2)main() + -> raise Exception() from Exception() + (Pdb) exceptions + > 0 Exception() + (Pdb) exit + """ + + +def test_post_mortem_single_no_stack(): + """Test post mortem called when origin exception has not stack + + + >>> def test_function(): + ... import pdb; + ... instance = pdb.Pdb(nosigint=True, readrc=False) + ... import sys + ... sys.last_exc = Exception() + ... # same as pdb.post_mortem(e), but with custom pdb instance. + ... instance.reset() + ... instance.interaction(None, sys.last_exc) + + >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... [] + ... ): + ... try: + ... test_function() + ... except ValueError as e: + ... print(e) + A valid traceback must be passed if no exception is being handled + """ + + def test_post_mortem_complex(): """Test post mortem traceback debugging of chained exception From 3607006c7703393ec1c948b6237a8519793f0603 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 4 Sep 2023 19:08:23 +0200 Subject: [PATCH 02/11] change wording of exception --- Lib/pdb.py | 4 +--- Lib/test/test_pdb.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 7d97952c188bf9..511d20325c5887 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -492,9 +492,7 @@ def interaction(self, frame, tb_or_exc): _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) if not _chained_exceptions and isinstance(tb_or_exc, BaseException): - raise ValueError( - "A valid traceback must be passed if no exception is being handled" - ) + raise ValueError("No exception traceback to inspect") with self._hold_exceptions(_chained_exceptions): if self.setup(frame, tb): # no interaction desired at this time (happens if .pdbrc contains diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index a5cbcc48f8f273..2256a16e2c5a97 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1132,7 +1132,7 @@ def test_post_mortem_single_no_stack(): ... test_function() ... except ValueError as e: ... print(e) - A valid traceback must be passed if no exception is being handled + No exception traceback to inspect """ From fbd394d42e1336e6d96ee90d8235c61e0450cca6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 4 Sep 2023 19:58:46 +0200 Subject: [PATCH 03/11] take comments into account --- Lib/pdb.py | 6 +++++- Lib/test/test_pdb.py | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 511d20325c5887..2099e7edccb247 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -491,7 +491,11 @@ def interaction(self, frame, tb_or_exc): Pdb._previous_sigint_handler = None _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) - if not _chained_exceptions and isinstance(tb_or_exc, BaseException): + if ( + not _chained_exceptions + and isinstance(tb_or_exc, BaseException) + and tb is None + ): raise ValueError("No exception traceback to inspect") with self._hold_exceptions(_chained_exceptions): if self.setup(frame, tb): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 2256a16e2c5a97..3bdc2ca806874f 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -907,7 +907,7 @@ def test_post_mortem_chained(): def test_post_mortem_cause_no_context(): """Test post mortem traceback debugging of chained exception - >>> def make_ex_with_stack(type_, *content, from_=None): + >>> def make_exc_with_stack(type_, *content, from_=None): ... try: ... raise type_(*content) from from_ ... except Exception as out: @@ -918,7 +918,7 @@ def test_post_mortem_cause_no_context(): ... try: ... raise ValueError('Context Not Shown') ... except Exception as e1: - ... raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') + ... raise ValueError("With Cause") from make_exc_with_stack(TypeError,'The Cause') >>> def test_function(): ... import pdb; @@ -943,22 +943,22 @@ def test_post_mortem_cause_no_context(): ... except ValueError: ... print('Ok.') > (5)main() - -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') + -> raise ValueError("With Cause") from make_exc_with_stack(TypeError,'The Cause') (Pdb) exceptions 0 TypeError('The Cause') > 1 ValueError('With Cause') (Pdb) exceptions 0 - > (3)make_ex_with_stack() + > (3)make_exc_with_stack() -> raise type_(*content) from from_ (Pdb) exceptions 1 > (5)main() - -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') + -> raise ValueError("With Cause") from make_exc_with_stack(TypeError,'The Cause') (Pdb) up > (5)test_function() -> main() (Pdb) down > (5)main() - -> raise ValueError("With Cause") from make_ex_with_stack(TypeError,'The Cause') + -> raise ValueError("With Cause") from make_exc_with_stack(TypeError,'The Cause') (Pdb) exit""" From b138ddeeac058ab923700fdf1dc041d36ba3a117 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 09:11:14 +0200 Subject: [PATCH 04/11] Try to handle exceptions without traceback --- Lib/pdb.py | 21 +++++++++++++-------- Lib/test/test_pdb.py | 6 +++++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 2099e7edccb247..88e48d467136de 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -438,7 +438,7 @@ def _get_tb_and_exceptions(self, tb_or_exc): traceback, current = tb_or_exc.__traceback__, tb_or_exc while current is not None: - if current in _exceptions or not current.__traceback__: + if current in _exceptions or not current: break _exceptions.append(current) if current.__cause__ is not None: @@ -491,11 +491,7 @@ def interaction(self, frame, tb_or_exc): Pdb._previous_sigint_handler = None _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) - if ( - not _chained_exceptions - and isinstance(tb_or_exc, BaseException) - and tb is None - ): + if isinstance(tb_or_exc, BaseException) and tb is None: raise ValueError("No exception traceback to inspect") with self._hold_exceptions(_chained_exceptions): if self.setup(frame, tb): @@ -1172,7 +1168,12 @@ def do_exceptions(self, arg): rep = repr(exc) if len(rep) > 80: rep = rep[:77] + "..." - self.message(f"{prompt} {ix:>3} {rep}") + indicator = ( + " -" + if self._chained_exceptions[ix].__traceback__ is None + else f"{ix:>3}" + ) + self.message(f"{prompt} {indicator} {rep}") else: try: number = int(arg) @@ -1180,6 +1181,10 @@ def do_exceptions(self, arg): self.error("Argument must be an integer") return if 0 <= number < len(self._chained_exceptions): + if self._chained_exceptions[number].__traceback__ is None: + self.error("This exception has not traceback, cannot jump to it") + return + self._chained_exception_index = number self.setup(None, self._chained_exceptions[number].__traceback__) self.print_stack_entry(self.stack[self.curindex]) @@ -2019,7 +2024,7 @@ def post_mortem(t=None): if exc is not None: t = exc.__traceback__ - if t is None: + if t is None or (isinstance(t, BaseException) and t.__traceback__ is None): raise ValueError("A valid traceback must be passed if no " "exception is being handled") diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 3bdc2ca806874f..c9184788b18878 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1098,6 +1098,7 @@ def test_post_mortem_from_no_stack(): >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... ["exceptions", + ... "exceptions 0", ... "exit"], ... ): ... try: @@ -1107,7 +1108,10 @@ def test_post_mortem_from_no_stack(): > (2)main() -> raise Exception() from Exception() (Pdb) exceptions - > 0 Exception() + - Exception() + > 1 Exception() + (Pdb) exceptions 0 + *** This exception has not traceback, cannot jump to it (Pdb) exit """ From 7b697f11a36d08f9782d7a37004834c1695e0d33 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 09:29:25 +0200 Subject: [PATCH 05/11] introduce private _post_mortem --- Lib/pdb.py | 9 +++++++++ Lib/test/test_pdb.py | 30 ++++++++---------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 88e48d467136de..3c2f61e0a2e1ba 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -2018,6 +2018,14 @@ def post_mortem(t=None): If `t` is an exception object, the `exceptions` command makes it possible to list and inspect its chained exceptions (if any). """ + return _post_mortem(t, Pdb()) + + +def _post_mortem(t, pdb_instance): + """ + Private version of post_mortem, which allow to pass a pdb instance + for testing purposes. + """ # handling the default if t is None: exc = sys.exception() @@ -2032,6 +2040,7 @@ def post_mortem(t=None): p.reset() p.interaction(None, t) + def pm(): """Enter post-mortem debugging of the traceback found in sys.last_exc.""" post_mortem(sys.last_exc) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index c9184788b18878..e89c5ff1d6f12a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -848,9 +848,7 @@ def test_post_mortem_chained(): ... 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) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... 'exceptions', @@ -926,9 +924,7 @@ def test_post_mortem_cause_no_context(): ... try: ... main() ... except Exception as e: - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, e) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... 'exceptions', @@ -982,9 +978,7 @@ def test_post_mortem_context_of_the_cause(): ... try: ... main() ... except Exception as e: - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, e) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... 'exceptions', @@ -1057,9 +1051,7 @@ def test_post_mortem_from_none(): ... try: ... main() ... except Exception as e: - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, e) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... 'exceptions', @@ -1092,9 +1084,7 @@ def test_post_mortem_from_no_stack(): ... try: ... main() ... except Exception as e: - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, e) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... ["exceptions", @@ -1125,9 +1115,7 @@ def test_post_mortem_single_no_stack(): ... instance = pdb.Pdb(nosigint=True, readrc=False) ... import sys ... sys.last_exc = Exception() - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, sys.last_exc) + ... pdb._post_mortem(sys.last_exc, instance) >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... [] @@ -1136,7 +1124,7 @@ def test_post_mortem_single_no_stack(): ... test_function() ... except ValueError as e: ... print(e) - No exception traceback to inspect + A valid traceback must be passed if no exception is being handled """ @@ -1204,9 +1192,7 @@ def test_post_mortem_complex(): ... try: ... main() ... except Exception as e: - ... # same as pdb.post_mortem(e), but with custom pdb instance. - ... instance.reset() - ... instance.interaction(None, e) + ... pdb._post_mortem(e, instance) >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... ["exceptions", From e47906cc18f2aa41ef5f567e81e54eb47d3edc89 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 00:30:51 -0700 Subject: [PATCH 06/11] Update Lib/pdb.py --- Lib/pdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 88e48d467136de..6e72e2c8c95fde 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -438,7 +438,7 @@ def _get_tb_and_exceptions(self, tb_or_exc): traceback, current = tb_or_exc.__traceback__, tb_or_exc while current is not None: - if current in _exceptions or not current: + if current in _exceptions: break _exceptions.append(current) if current.__cause__ is not None: From 02f5b320eb30eb66ab45a99bcc0fa47b768e131f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 02:27:38 -0700 Subject: [PATCH 07/11] Update Lib/pdb.py Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/pdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 6e72e2c8c95fde..231a13110a99ce 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1182,7 +1182,7 @@ def do_exceptions(self, arg): return if 0 <= number < len(self._chained_exceptions): if self._chained_exceptions[number].__traceback__ is None: - self.error("This exception has not traceback, cannot jump to it") + self.error("This exception does not have a traceback, cannot jump to it") return self._chained_exception_index = number From 087e39ab4b6aa0c90a46148b7d69884683e72d04 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 18:01:58 +0200 Subject: [PATCH 08/11] protect interaction, if an exception is given and has not tb jumpt to the next previous one with tb --- Lib/pdb.py | 9 +++++++-- Lib/test/test_pdb.py | 45 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index 3c2f61e0a2e1ba..bd9eda3998d804 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -491,9 +491,14 @@ def interaction(self, frame, tb_or_exc): Pdb._previous_sigint_handler = None _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) - if isinstance(tb_or_exc, BaseException) and tb is None: - raise ValueError("No exception traceback to inspect") with self._hold_exceptions(_chained_exceptions): + if isinstance(tb_or_exc, BaseException) and tb is None: + for ix, exc in reversed(list(enumerate(_chained_exceptions))): + if exc.__traceback__: + tb = exc.__traceback__ + self._chained_exception_index = ix + break + if self.setup(frame, tb): # no interaction desired at this time (happens if .pdbrc contains # a command like "continue") diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index e89c5ff1d6f12a..bd69e4c4de8d37 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1128,6 +1128,51 @@ def test_post_mortem_single_no_stack(): """ +def test_post_mortem_base_no_stack(): + """Test post mortem called when base exception has not stack + + >>> def test_function(): + ... import pdb; + ... import sys + ... instance = pdb.Pdb(nosigint=True, readrc=False) + ... try: + ... raise ValueError('stack') from TypeError('no-stack') + ... except ValueError as e: + ... sub_exc = e + ... exc = Exception('base-no-stack') + ... exc.__cause__ = sub_exc + ... instance.reset() + ... instance.interaction(None, exc) + + >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... [ + ... "exceptions", + ... "exceptions 0", + ... "exceptions", + ... "exit" + ... ] + ... ): + ... try: + ... test_function() + ... except ValueError as e: + ... print(e) + > (6)test_function() + -> raise ValueError('stack') from TypeError('no-stack') + (Pdb) exceptions + - TypeError('no-stack') + > 1 ValueError('stack') + - Exception('base-no-stack') + (Pdb) exceptions 0 + *** This exception has not traceback, cannot jump to it + (Pdb) exceptions + - TypeError('no-stack') + > 1 ValueError('stack') + - Exception('base-no-stack') + (Pdb) exit + + """ + + def test_post_mortem_complex(): """Test post mortem traceback debugging of chained exception From f90a4533865a81612fc03709b14c77d9a72aa036 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 18:17:29 +0200 Subject: [PATCH 09/11] fix wording --- Lib/test/test_pdb.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index bd69e4c4de8d37..d9d71812980a53 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1072,7 +1072,7 @@ def test_post_mortem_from_none(): def test_post_mortem_from_no_stack(): """Test post mortem traceback debugging of chained exception - especially when one exception has not stack. + especially when one exception has no stack. >>> def main(): ... raise Exception() from Exception() @@ -1101,13 +1101,13 @@ def test_post_mortem_from_no_stack(): - Exception() > 1 Exception() (Pdb) exceptions 0 - *** This exception has not traceback, cannot jump to it + *** This exception does not have a traceback, cannot jump to it (Pdb) exit """ def test_post_mortem_single_no_stack(): - """Test post mortem called when origin exception has not stack + """Test post mortem called when origin exception has no stack >>> def test_function(): @@ -1129,7 +1129,7 @@ def test_post_mortem_single_no_stack(): def test_post_mortem_base_no_stack(): - """Test post mortem called when base exception has not stack + """Test post mortem called when base exception has no stack >>> def test_function(): ... import pdb; @@ -1163,7 +1163,7 @@ def test_post_mortem_base_no_stack(): > 1 ValueError('stack') - Exception('base-no-stack') (Pdb) exceptions 0 - *** This exception has not traceback, cannot jump to it + *** This exception does not have a traceback, cannot jump to it (Pdb) exceptions - TypeError('no-stack') > 1 ValueError('stack') From e7533c97ed88aad85825cf58af3616d901d838f5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Sep 2023 11:02:49 -0700 Subject: [PATCH 10/11] Update Lib/pdb.py --- Lib/pdb.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index ada222c4bd9bba..a1cfc0138c4535 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -2041,9 +2041,8 @@ def _post_mortem(t, pdb_instance): raise ValueError("A valid traceback must be passed if no " "exception is being handled") - p = Pdb() - p.reset() - p.interaction(None, t) + pdb_instance.reset() + pdb_instance.interaction(None, t) def pm(): From 368222cd878c5db8853b87f6fe30552557c81b68 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 6 Sep 2023 10:48:58 +0200 Subject: [PATCH 11/11] remove autoumping to last exception w/o tb --- Lib/pdb.py | 9 ++------- Lib/test/test_pdb.py | 46 -------------------------------------------- 2 files changed, 2 insertions(+), 53 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index a1cfc0138c4535..78e9bd7eb6e334 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -491,14 +491,9 @@ def interaction(self, frame, tb_or_exc): Pdb._previous_sigint_handler = None _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc) + if isinstance(tb_or_exc, BaseException): + assert tb is not None, "main exception must have a traceback" with self._hold_exceptions(_chained_exceptions): - if isinstance(tb_or_exc, BaseException) and tb is None: - for ix, exc in reversed(list(enumerate(_chained_exceptions))): - if exc.__traceback__: - tb = exc.__traceback__ - self._chained_exception_index = ix - break - if self.setup(frame, tb): # no interaction desired at this time (happens if .pdbrc contains # a command like "continue") diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d9d71812980a53..45d2bfe885dbe8 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1127,52 +1127,6 @@ def test_post_mortem_single_no_stack(): A valid traceback must be passed if no exception is being handled """ - -def test_post_mortem_base_no_stack(): - """Test post mortem called when base exception has no stack - - >>> def test_function(): - ... import pdb; - ... import sys - ... instance = pdb.Pdb(nosigint=True, readrc=False) - ... try: - ... raise ValueError('stack') from TypeError('no-stack') - ... except ValueError as e: - ... sub_exc = e - ... exc = Exception('base-no-stack') - ... exc.__cause__ = sub_exc - ... instance.reset() - ... instance.interaction(None, exc) - - >>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - ... [ - ... "exceptions", - ... "exceptions 0", - ... "exceptions", - ... "exit" - ... ] - ... ): - ... try: - ... test_function() - ... except ValueError as e: - ... print(e) - > (6)test_function() - -> raise ValueError('stack') from TypeError('no-stack') - (Pdb) exceptions - - TypeError('no-stack') - > 1 ValueError('stack') - - Exception('base-no-stack') - (Pdb) exceptions 0 - *** This exception does not have a traceback, cannot jump to it - (Pdb) exceptions - - TypeError('no-stack') - > 1 ValueError('stack') - - Exception('base-no-stack') - (Pdb) exit - - """ - - def test_post_mortem_complex(): """Test post mortem traceback debugging of chained exception