aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/core/debugger.py
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2023-09-30 10:27:28 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2023-09-30 10:47:10 +0300
commit5a6373c9d09bbfb7094f9992a4531477bb97829e (patch)
treeebea8fd55fee858876743312cdf789a1f01487b5 /contrib/python/ipython/py3/IPython/core/debugger.py
parent15f3c7493474de25a6b23296878bb8f49470d2e6 (diff)
downloadydb-5a6373c9d09bbfb7094f9992a4531477bb97829e.tar.gz
Update contrib/python/ipython/py3 to 8.15.0
Diffstat (limited to 'contrib/python/ipython/py3/IPython/core/debugger.py')
-rw-r--r--contrib/python/ipython/py3/IPython/core/debugger.py118
1 files changed, 114 insertions, 4 deletions
diff --git a/contrib/python/ipython/py3/IPython/core/debugger.py b/contrib/python/ipython/py3/IPython/core/debugger.py
index c8082e34e7..30be9fc0d1 100644
--- a/contrib/python/ipython/py3/IPython/core/debugger.py
+++ b/contrib/python/ipython/py3/IPython/core/debugger.py
@@ -108,6 +108,7 @@ import re
import os
from IPython import get_ipython
+from contextlib import contextmanager
from IPython.utils import PyColorize
from IPython.utils import coloransi, py3compat
from IPython.core.excolors import exception_colors
@@ -127,6 +128,11 @@ from pdb import Pdb as OldPdb
DEBUGGERSKIP = "__debuggerskip__"
+# this has been implemented in Pdb in Python 3.13 (https://github.com/python/cpython/pull/106676
+# on lower python versions, we backported the feature.
+CHAIN_EXCEPTIONS = sys.version_info < (3, 13)
+
+
def make_arrow(pad):
"""generate the leading arrow in front of traceback or debugger"""
if pad >= 2:
@@ -185,6 +191,9 @@ class Pdb(OldPdb):
"""
+ if CHAIN_EXCEPTIONS:
+ MAX_CHAINED_EXCEPTION_DEPTH = 999
+
default_predicates = {
"tbhide": True,
"readonly": False,
@@ -281,6 +290,10 @@ class Pdb(OldPdb):
# list of predicates we use to skip frames
self._predicates = self.default_predicates
+ if CHAIN_EXCEPTIONS:
+ self._chained_exceptions = tuple()
+ self._chained_exception_index = 0
+
#
def set_colors(self, scheme):
"""Shorthand access to the color table scheme selector method."""
@@ -330,9 +343,106 @@ class Pdb(OldPdb):
ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
return ip_hide
- def interaction(self, frame, traceback):
+ if CHAIN_EXCEPTIONS:
+
+ def _get_tb_and_exceptions(self, tb_or_exc):
+ """
+ Given a tracecack or an exception, return a tuple of chained exceptions
+ and current traceback to inspect.
+ This will deal with selecting the right ``__cause__`` or ``__context__``
+ as well as handling cycles, and return a flattened list of exceptions we
+ can jump to with do_exceptions.
+ """
+ _exceptions = []
+ if isinstance(tb_or_exc, BaseException):
+ traceback, current = tb_or_exc.__traceback__, tb_or_exc
+
+ while current is not None:
+ if current in _exceptions:
+ break
+ _exceptions.append(current)
+ if current.__cause__ is not None:
+ current = current.__cause__
+ elif (
+ current.__context__ is not None
+ and not current.__suppress_context__
+ ):
+ current = current.__context__
+
+ if len(_exceptions) >= self.MAX_CHAINED_EXCEPTION_DEPTH:
+ self.message(
+ f"More than {self.MAX_CHAINED_EXCEPTION_DEPTH}"
+ " chained exceptions found, not all exceptions"
+ "will be browsable with `exceptions`."
+ )
+ break
+ else:
+ traceback = tb_or_exc
+ return tuple(reversed(_exceptions)), traceback
+
+ @contextmanager
+ def _hold_exceptions(self, exceptions):
+ """
+ Context manager to ensure proper cleaning of exceptions references
+ When given a chained exception instead of a traceback,
+ pdb may hold references to many objects which may leak memory.
+ We use this context manager to make sure everything is properly cleaned
+ """
+ try:
+ self._chained_exceptions = exceptions
+ self._chained_exception_index = len(exceptions) - 1
+ yield
+ finally:
+ # we can't put those in forget as otherwise they would
+ # be cleared on exception change
+ self._chained_exceptions = tuple()
+ self._chained_exception_index = 0
+
+ def do_exceptions(self, arg):
+ """exceptions [number]
+ List or change current exception in an exception chain.
+ Without arguments, list all the current exception in the exception
+ chain. Exceptions will be numbered, with the current exception indicated
+ with an arrow.
+ If given an integer as argument, switch to the exception at that index.
+ """
+ if not self._chained_exceptions:
+ self.message(
+ "Did not find chained exceptions. To move between"
+ " exceptions, pdb/post_mortem must be given an exception"
+ " object rather than a traceback."
+ )
+ return
+ if not arg:
+ for ix, exc in enumerate(self._chained_exceptions):
+ prompt = ">" if ix == self._chained_exception_index else " "
+ rep = repr(exc)
+ if len(rep) > 80:
+ rep = rep[:77] + "..."
+ self.message(f"{prompt} {ix:>3} {rep}")
+ else:
+ try:
+ number = int(arg)
+ except ValueError:
+ self.error("Argument must be an integer")
+ return
+ if 0 <= number < len(self._chained_exceptions):
+ self._chained_exception_index = number
+ self.setup(None, self._chained_exceptions[number].__traceback__)
+ self.print_stack_entry(self.stack[self.curindex])
+ else:
+ self.error("No exception with that number")
+
+ def interaction(self, frame, tb_or_exc):
try:
- OldPdb.interaction(self, frame, traceback)
+ if CHAIN_EXCEPTIONS:
+ # this context manager is part of interaction in 3.13
+ _chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc)
+ with self._hold_exceptions(_chained_exceptions):
+ OldPdb.interaction(self, frame, tb)
+ else:
+ OldPdb.interaction(self, frame, traceback)
+
except KeyboardInterrupt:
self.stdout.write("\n" + self.shell.get_exception_only())
@@ -640,7 +750,7 @@ class Pdb(OldPdb):
"""
self.lastcmd = 'list'
last = None
- if arg:
+ if arg and arg != ".":
try:
x = eval(arg, {}, {})
if type(x) == type(()):
@@ -655,7 +765,7 @@ class Pdb(OldPdb):
except:
print('*** Error in argument:', repr(arg), file=self.stdout)
return
- elif self.lineno is None:
+ elif self.lineno is None or arg == ".":
first = max(1, self.curframe.f_lineno - 5)
else:
first = self.lineno + 1