From a3074b8cf3fbb20482732a5602c20cf7bac0a215 2024-04-02 11:14:58 From: M Bussonnier Date: 2024-04-02 11:14:58 Subject: [PATCH] Cache debugger skip frame predicate (#14386) I'm not 100% sure this is correct as technically the value of __debugger_skip__ could change in the current frame while we are stepping into it, but that is likely super rare, and the slowdown that this create is problematic. There is still a small overhead for me, but this should make the experience much better. See https://github.com/spyder-ide/spyder-kernels/pull/458, https://github.com/ipython/ipython/issues/13972, https://github.com/spyder-ide/spyder/issues/20571, https://github.com/ipython/ipython/issues/14382 --- diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index d7ace4c..fde44f3 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Pdb debugger class. @@ -101,17 +100,25 @@ All the changes since then are under the same license as IPython. # #***************************************************************************** +from __future__ import annotations + import inspect import linecache -import sys -import re import os +import re +import sys +from contextlib import contextmanager +from functools import lru_cache 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 +from IPython.utils import PyColorize, coloransi, py3compat + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + # otherwise circular import + from IPython.core.interactiveshell import InteractiveShell # skip module docstests __skip_doctest__ = True @@ -191,6 +198,8 @@ class Pdb(OldPdb): """ + shell: InteractiveShell + if CHAIN_EXCEPTIONS: MAX_CHAINED_EXCEPTION_DEPTH = 999 @@ -471,24 +480,11 @@ class Pdb(OldPdb): return line - def new_do_frame(self, arg): - OldPdb.do_frame(self, arg) - def new_do_quit(self, arg): - - if hasattr(self, 'old_all_completions'): - self.shell.Completer.all_completions = self.old_all_completions - return OldPdb.do_quit(self, arg) do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit) - def new_do_restart(self, arg): - """Restart command. In the context of ipython this is exactly the same - thing as 'quit'.""" - self.msg("Restart doesn't make sense here. Using 'quit' instead.") - return self.do_quit(arg) - def print_stack_trace(self, context=None): Colors = self.color_scheme_table.active_colors ColorsNormal = Colors.Normal @@ -941,11 +937,14 @@ class Pdb(OldPdb): Utility to tell us whether we are in a decorator internal and should stop. """ - # if we are disabled don't skip if not self._predicates["debuggerskip"]: return False + return self._cachable_skip(frame) + + @lru_cache + def _cachable_skip(self, frame): # if frame is tagged, skip by default. if DEBUGGERSKIP in frame.f_code.co_varnames: return True