debugger.py
147 lines
| 5.2 KiB
| text/x-python
|
PythonLexer
Jonathan Slenders
|
r25342 | import asyncio | ||
Thomas Kluyver
|
r23318 | import signal | ||
import sys | ||||
Thomas Kluyver
|
r22391 | from IPython.core.debugger import Pdb | ||
from IPython.core.completer import IPCompleter | ||||
from .ptutils import IPythonPTCompleter | ||||
Thomas Kluyver
|
r23371 | from .shortcuts import suspend_to_bg, cursor_in_leading_ws | ||
Thomas Kluyver
|
r22391 | |||
Thomas Kluyver
|
r23371 | from prompt_toolkit.enums import DEFAULT_BUFFER | ||
Jonathan Slenders
|
r24376 | from prompt_toolkit.filters import (Condition, has_focus, has_selection, | ||
vi_insert_mode, emacs_insert_mode) | ||||
from prompt_toolkit.key_binding import KeyBindings | ||||
Thomas Kluyver
|
r23371 | from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline | ||
Jonathan Slenders
|
r24376 | from pygments.token import Token | ||
from prompt_toolkit.shortcuts.prompt import PromptSession | ||||
Thomas Kluyver
|
r22391 | from prompt_toolkit.enums import EditingMode | ||
Jonathan Slenders
|
r24376 | from prompt_toolkit.formatted_text import PygmentsTokens | ||
tillahoffmann
|
r22874 | |||
Matthias Bussonnier
|
r25279 | from prompt_toolkit import __version__ as ptk_version | ||
PTK3 = ptk_version.startswith('3.') | ||||
Thomas Kluyver
|
r22391 | |||
class TerminalPdb(Pdb): | ||||
Terry Davis
|
r25174 | """Standalone IPython debugger.""" | ||
Thomas Kluyver
|
r22391 | def __init__(self, *args, **kwargs): | ||
Pdb.__init__(self, *args, **kwargs) | ||||
self._ptcomp = None | ||||
self.pt_init() | ||||
def pt_init(self): | ||||
Jonathan Slenders
|
r24376 | def get_prompt_tokens(): | ||
Thomas Kluyver
|
r22391 | return [(Token.Prompt, self.prompt)] | ||
if self._ptcomp is None: | ||||
compl = IPCompleter(shell=self.shell, | ||||
namespace={}, | ||||
global_namespace={}, | ||||
parent=self.shell, | ||||
) | ||||
Jonathan Slenders
|
r24376 | self._ptcomp = IPythonPTCompleter(compl) | ||
Thomas Kluyver
|
r22391 | |||
Jonathan Slenders
|
r24376 | kb = KeyBindings() | ||
supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP')) | ||||
kb.add('c-z', filter=supports_suspend)(suspend_to_bg) | ||||
Thomas Kluyver
|
r23318 | |||
Thomas Kluyver
|
r23371 | if self.shell.display_completions == 'readlinelike': | ||
Jonathan Slenders
|
r24376 | kb.add('tab', filter=(has_focus(DEFAULT_BUFFER) | ||
& ~has_selection | ||||
& vi_insert_mode | emacs_insert_mode | ||||
& ~cursor_in_leading_ws | ||||
))(display_completions_like_readline) | ||||
Matthias Bussonnier
|
r25279 | options = dict( | ||
message=(lambda: PygmentsTokens(get_prompt_tokens())), | ||||
editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()), | ||||
key_bindings=kb, | ||||
history=self.shell.debugger_history, | ||||
completer=self._ptcomp, | ||||
enable_history_search=True, | ||||
mouse_support=self.shell.mouse_support, | ||||
complete_style=self.shell.pt_complete_style, | ||||
style=self.shell.style, | ||||
color_depth=self.shell.color_depth, | ||||
Thomas Kluyver
|
r22391 | ) | ||
Matthias Bussonnier
|
r25279 | if not PTK3: | ||
Matthias Bussonnier
|
r25325 | options['inputhook'] = self.shell.inputhook | ||
Jonathan Slenders
|
r25342 | self.pt_loop = asyncio.new_event_loop() | ||
Matthias Bussonnier
|
r25279 | self.pt_app = PromptSession(**options) | ||
Thomas Kluyver
|
r22391 | def cmdloop(self, intro=None): | ||
"""Repeatedly issue a prompt, accept input, parse an initial prefix | ||||
off the received input, and dispatch to action methods, passing them | ||||
the remainder of the line as argument. | ||||
override the same methods from cmd.Cmd to provide prompt toolkit replacement. | ||||
""" | ||||
if not self.use_rawinput: | ||||
raise ValueError('Sorry ipdb does not support use_rawinput=False') | ||||
Jonathan Slenders
|
r25342 | # In order to make sure that asyncio code written in the | ||
# interactive shell doesn't interfere with the prompt, we run the | ||||
# prompt in a different event loop. | ||||
# If we don't do this, people could spawn coroutine with a | ||||
# while/true inside which will freeze the prompt. | ||||
try: | ||||
old_loop = asyncio.get_event_loop() | ||||
except RuntimeError: | ||||
# This happens when the user used `asyncio.run()`. | ||||
old_loop = None | ||||
Thomas Kluyver
|
r22391 | self.preloop() | ||
try: | ||||
if intro is not None: | ||||
self.intro = intro | ||||
if self.intro: | ||||
self.stdout.write(str(self.intro)+"\n") | ||||
stop = None | ||||
while not stop: | ||||
if self.cmdqueue: | ||||
line = self.cmdqueue.pop(0) | ||||
else: | ||||
self._ptcomp.ipy_completer.namespace = self.curframe_locals | ||||
self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals | ||||
Jonathan Slenders
|
r25342 | |||
asyncio.set_event_loop(self.pt_loop) | ||||
Thomas Kluyver
|
r22391 | try: | ||
Jonathan Slenders
|
r25342 | line = self.pt_app.prompt() | ||
Thomas Kluyver
|
r22391 | except EOFError: | ||
line = 'EOF' | ||||
Jonathan Slenders
|
r25342 | finally: | ||
# Restore the original event loop. | ||||
asyncio.set_event_loop(old_loop) | ||||
Thomas Kluyver
|
r22391 | line = self.precmd(line) | ||
stop = self.onecmd(line) | ||||
stop = self.postcmd(stop, line) | ||||
self.postloop() | ||||
except Exception: | ||||
raise | ||||
Matthias Bussonnier
|
r22724 | |||
tillahoffmann
|
r22874 | |||
def set_trace(frame=None): | ||||
""" | ||||
Start debugging from `frame`. | ||||
If frame is not specified, debugging starts from caller's frame. | ||||
""" | ||||
TerminalPdb().set_trace(frame or sys._getframe().f_back) | ||||
Matthias Bussonnier
|
r22724 | |||
mbyt
|
r22858 | |||
if __name__ == '__main__': | ||||
import pdb | ||||
mbyt
|
r22879 | # IPython.core.debugger.Pdb.trace_dispatch shall not catch | ||
mbyt
|
r22901 | # bdb.BdbQuit. When started through __main__ and an exception | ||
mbyt
|
r22902 | # happened after hitting "c", this is needed in order to | ||
mbyt
|
r22879 | # be able to quit the debugging session (see #9950). | ||
old_trace_dispatch = pdb.Pdb.trace_dispatch | ||||
mbyt
|
r22858 | pdb.Pdb = TerminalPdb | ||
mbyt
|
r22879 | pdb.Pdb.trace_dispatch = old_trace_dispatch | ||
mbyt
|
r22858 | pdb.main() | ||