##// END OF EJS Templates
Merge pull request #12148 from meeseeksmachine/auto-backport-of-pr-12141-on-7.x...
Matthias Bussonnier -
r25547:58860c13 merge
parent child Browse files
Show More
@@ -1,136 +1,141 b''
1 import asyncio
1 import asyncio
2 import signal
2 import signal
3 import sys
3 import sys
4 import threading
4
5
5 from IPython.core.debugger import Pdb
6 from IPython.core.debugger import Pdb
6
7
7 from IPython.core.completer import IPCompleter
8 from IPython.core.completer import IPCompleter
8 from .ptutils import IPythonPTCompleter
9 from .ptutils import IPythonPTCompleter
9 from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws
10 from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws
10
11
11 from prompt_toolkit.enums import DEFAULT_BUFFER
12 from prompt_toolkit.enums import DEFAULT_BUFFER
12 from prompt_toolkit.filters import (Condition, has_focus, has_selection,
13 from prompt_toolkit.filters import (Condition, has_focus, has_selection,
13 vi_insert_mode, emacs_insert_mode)
14 vi_insert_mode, emacs_insert_mode)
14 from prompt_toolkit.key_binding import KeyBindings
15 from prompt_toolkit.key_binding import KeyBindings
15 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
16 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
16 from pygments.token import Token
17 from pygments.token import Token
17 from prompt_toolkit.shortcuts.prompt import PromptSession
18 from prompt_toolkit.shortcuts.prompt import PromptSession
18 from prompt_toolkit.enums import EditingMode
19 from prompt_toolkit.enums import EditingMode
19 from prompt_toolkit.formatted_text import PygmentsTokens
20 from prompt_toolkit.formatted_text import PygmentsTokens
20
21
21 from prompt_toolkit import __version__ as ptk_version
22 from prompt_toolkit import __version__ as ptk_version
22 PTK3 = ptk_version.startswith('3.')
23 PTK3 = ptk_version.startswith('3.')
23
24
24
25
25 class TerminalPdb(Pdb):
26 class TerminalPdb(Pdb):
26 """Standalone IPython debugger."""
27 """Standalone IPython debugger."""
27
28
28 def __init__(self, *args, **kwargs):
29 def __init__(self, *args, **kwargs):
29 Pdb.__init__(self, *args, **kwargs)
30 Pdb.__init__(self, *args, **kwargs)
30 self._ptcomp = None
31 self._ptcomp = None
31 self.pt_init()
32 self.pt_init()
32
33
33 def pt_init(self):
34 def pt_init(self):
34 def get_prompt_tokens():
35 def get_prompt_tokens():
35 return [(Token.Prompt, self.prompt)]
36 return [(Token.Prompt, self.prompt)]
36
37
37 if self._ptcomp is None:
38 if self._ptcomp is None:
38 compl = IPCompleter(shell=self.shell,
39 compl = IPCompleter(shell=self.shell,
39 namespace={},
40 namespace={},
40 global_namespace={},
41 global_namespace={},
41 parent=self.shell,
42 parent=self.shell,
42 )
43 )
43 self._ptcomp = IPythonPTCompleter(compl)
44 self._ptcomp = IPythonPTCompleter(compl)
44
45
45 options = dict(
46 options = dict(
46 message=(lambda: PygmentsTokens(get_prompt_tokens())),
47 message=(lambda: PygmentsTokens(get_prompt_tokens())),
47 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
48 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
48 key_bindings=create_ipython_shortcuts(self.shell),
49 key_bindings=create_ipython_shortcuts(self.shell),
49 history=self.shell.debugger_history,
50 history=self.shell.debugger_history,
50 completer=self._ptcomp,
51 completer=self._ptcomp,
51 enable_history_search=True,
52 enable_history_search=True,
52 mouse_support=self.shell.mouse_support,
53 mouse_support=self.shell.mouse_support,
53 complete_style=self.shell.pt_complete_style,
54 complete_style=self.shell.pt_complete_style,
54 style=self.shell.style,
55 style=self.shell.style,
55 color_depth=self.shell.color_depth,
56 color_depth=self.shell.color_depth,
56 )
57 )
57
58
58 if not PTK3:
59 if not PTK3:
59 options['inputhook'] = self.shell.inputhook
60 options['inputhook'] = self.shell.inputhook
60 self.pt_loop = asyncio.new_event_loop()
61 self.pt_loop = asyncio.new_event_loop()
61 self.pt_app = PromptSession(**options)
62 self.pt_app = PromptSession(**options)
62
63
63 def cmdloop(self, intro=None):
64 def cmdloop(self, intro=None):
64 """Repeatedly issue a prompt, accept input, parse an initial prefix
65 """Repeatedly issue a prompt, accept input, parse an initial prefix
65 off the received input, and dispatch to action methods, passing them
66 off the received input, and dispatch to action methods, passing them
66 the remainder of the line as argument.
67 the remainder of the line as argument.
67
68
68 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
69 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
69 """
70 """
70 if not self.use_rawinput:
71 if not self.use_rawinput:
71 raise ValueError('Sorry ipdb does not support use_rawinput=False')
72 raise ValueError('Sorry ipdb does not support use_rawinput=False')
72
73
73 # In order to make sure that asyncio code written in the
74 # In order to make sure that prompt, which uses asyncio doesn't
74 # interactive shell doesn't interfere with the prompt, we run the
75 # interfere with applications in which it's used, we always run the
75 # prompt in a different event loop.
76 # prompt itself in a different thread (we can't start an event loop
76 # If we don't do this, people could spawn coroutine with a
77 # within an event loop). This new thread won't have any event loop
77 # while/true inside which will freeze the prompt.
78 # running, and here we run our prompt-loop.
78
79 try:
80 old_loop = asyncio.get_event_loop()
81 except RuntimeError:
82 # This happens when the user used `asyncio.run()`.
83 old_loop = None
84
85
79
86 self.preloop()
80 self.preloop()
87
81
88 try:
82 try:
89 if intro is not None:
83 if intro is not None:
90 self.intro = intro
84 self.intro = intro
91 if self.intro:
85 if self.intro:
92 self.stdout.write(str(self.intro)+"\n")
86 self.stdout.write(str(self.intro)+"\n")
93 stop = None
87 stop = None
94 while not stop:
88 while not stop:
95 if self.cmdqueue:
89 if self.cmdqueue:
96 line = self.cmdqueue.pop(0)
90 line = self.cmdqueue.pop(0)
97 else:
91 else:
98 self._ptcomp.ipy_completer.namespace = self.curframe_locals
92 self._ptcomp.ipy_completer.namespace = self.curframe_locals
99 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
93 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
100
94
101 asyncio.set_event_loop(self.pt_loop)
95 # Run the prompt in a different thread.
96 line = ''
97 keyboard_interrupt = False
98
99 def in_thread():
100 nonlocal line, keyboard_interrupt
102 try:
101 try:
103 line = self.pt_app.prompt()
102 line = self.pt_app.prompt()
104 except EOFError:
103 except EOFError:
105 line = 'EOF'
104 line = 'EOF'
106 finally:
105 except KeyboardInterrupt:
107 # Restore the original event loop.
106 keyboard_interrupt = True
108 asyncio.set_event_loop(old_loop)
107
108 th = threading.Thread(target=in_thread)
109 th.start()
110 th.join()
111
112 if keyboard_interrupt:
113 raise KeyboardInterrupt
109
114
110 line = self.precmd(line)
115 line = self.precmd(line)
111 stop = self.onecmd(line)
116 stop = self.onecmd(line)
112 stop = self.postcmd(stop, line)
117 stop = self.postcmd(stop, line)
113 self.postloop()
118 self.postloop()
114 except Exception:
119 except Exception:
115 raise
120 raise
116
121
117
122
118 def set_trace(frame=None):
123 def set_trace(frame=None):
119 """
124 """
120 Start debugging from `frame`.
125 Start debugging from `frame`.
121
126
122 If frame is not specified, debugging starts from caller's frame.
127 If frame is not specified, debugging starts from caller's frame.
123 """
128 """
124 TerminalPdb().set_trace(frame or sys._getframe().f_back)
129 TerminalPdb().set_trace(frame or sys._getframe().f_back)
125
130
126
131
127 if __name__ == '__main__':
132 if __name__ == '__main__':
128 import pdb
133 import pdb
129 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
134 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
130 # bdb.BdbQuit. When started through __main__ and an exception
135 # bdb.BdbQuit. When started through __main__ and an exception
131 # happened after hitting "c", this is needed in order to
136 # happened after hitting "c", this is needed in order to
132 # be able to quit the debugging session (see #9950).
137 # be able to quit the debugging session (see #9950).
133 old_trace_dispatch = pdb.Pdb.trace_dispatch
138 old_trace_dispatch = pdb.Pdb.trace_dispatch
134 pdb.Pdb = TerminalPdb
139 pdb.Pdb = TerminalPdb
135 pdb.Pdb.trace_dispatch = old_trace_dispatch
140 pdb.Pdb.trace_dispatch = old_trace_dispatch
136 pdb.main()
141 pdb.main()
General Comments 0
You need to be logged in to leave comments. Login now