##// END OF EJS Templates
ipdb: fix formatting in terminal.debugger
Blazej Michalik -
Show More
@@ -1,155 +1,154 b''
1 import asyncio
1 import asyncio
2 import sys
2 import sys
3 import threading
3 import threading
4
4
5 from IPython.core.debugger import Pdb
5 from IPython.core.debugger import Pdb
6
6
7 from IPython.core.completer import IPCompleter
7 from IPython.core.completer import IPCompleter
8 from .ptutils import IPythonPTCompleter
8 from .ptutils import IPythonPTCompleter
9 from .shortcuts import create_ipython_shortcuts
9 from .shortcuts import create_ipython_shortcuts
10
10
11 from pygments.token import Token
11 from pygments.token import Token
12 from prompt_toolkit.shortcuts.prompt import PromptSession
12 from prompt_toolkit.shortcuts.prompt import PromptSession
13 from prompt_toolkit.enums import EditingMode
13 from prompt_toolkit.enums import EditingMode
14 from prompt_toolkit.formatted_text import PygmentsTokens
14 from prompt_toolkit.formatted_text import PygmentsTokens
15
15
16 from prompt_toolkit import __version__ as ptk_version
16 from prompt_toolkit import __version__ as ptk_version
17 PTK3 = ptk_version.startswith('3.')
17 PTK3 = ptk_version.startswith('3.')
18
18
19
19
20 class TerminalPdb(Pdb):
20 class TerminalPdb(Pdb):
21 """Standalone IPython debugger."""
21 """Standalone IPython debugger."""
22
22
23 def __init__(self, *args, pt_session_options=None, **kwargs):
23 def __init__(self, *args, pt_session_options=None, **kwargs):
24 Pdb.__init__(self, *args, **kwargs)
24 Pdb.__init__(self, *args, **kwargs)
25 self._ptcomp = None
25 self._ptcomp = None
26 self.pt_init(pt_session_options)
26 self.pt_init(pt_session_options)
27
27
28 def pt_init(self, pt_session_options=None):
28 def pt_init(self, pt_session_options=None):
29 """Initialize the prompt session and the prompt loop
29 """Initialize the prompt session and the prompt loop
30 and store them in self.pt_app and self.pt_loop.
30 and store them in self.pt_app and self.pt_loop.
31
31
32 Additional keyword arguments for the PromptSession class
32 Additional keyword arguments for the PromptSession class
33 can be specified in pt_session_options.
33 can be specified in pt_session_options.
34 """
34 """
35 if pt_session_options is None:
35 if pt_session_options is None:
36 pt_session_options = {}
36 pt_session_options = {}
37
37
38 def get_prompt_tokens():
38 def get_prompt_tokens():
39 return [(Token.Prompt, self.prompt)]
39 return [(Token.Prompt, self.prompt)]
40
40
41 if self._ptcomp is None:
41 if self._ptcomp is None:
42 compl = IPCompleter(shell=self.shell,
42 compl = IPCompleter(shell=self.shell,
43 namespace={},
43 namespace={},
44 global_namespace={},
44 global_namespace={},
45 parent=self.shell,
45 parent=self.shell)
46 )
47 # add a completer for all the do_ methods
46 # add a completer for all the do_ methods
48 methods_names = [m[3:] for m in dir(self) if m.startswith("do_")]
47 methods_names = [m[3:] for m in dir(self) if m.startswith("do_")]
49
48
50 def gen_comp(self, text):
49 def gen_comp(self, text):
51 return [m for m in methods_names if m.startswith(text)]
50 return [m for m in methods_names if m.startswith(text)]
52 import types
51 import types
53 newcomp = types.MethodType(gen_comp, compl)
52 newcomp = types.MethodType(gen_comp, compl)
54 compl.custom_matchers.insert(0, newcomp)
53 compl.custom_matchers.insert(0, newcomp)
55 # end add completer.
54 # end add completer.
56
55
57 self._ptcomp = IPythonPTCompleter(compl)
56 self._ptcomp = IPythonPTCompleter(compl)
58
57
59 options = dict(
58 options = dict(
60 message=(lambda: PygmentsTokens(get_prompt_tokens())),
59 message=(lambda: PygmentsTokens(get_prompt_tokens())),
61 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
60 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
62 key_bindings=create_ipython_shortcuts(self.shell),
61 key_bindings=create_ipython_shortcuts(self.shell),
63 history=self.shell.debugger_history,
62 history=self.shell.debugger_history,
64 completer=self._ptcomp,
63 completer=self._ptcomp,
65 enable_history_search=True,
64 enable_history_search=True,
66 mouse_support=self.shell.mouse_support,
65 mouse_support=self.shell.mouse_support,
67 complete_style=self.shell.pt_complete_style,
66 complete_style=self.shell.pt_complete_style,
68 style=self.shell.style,
67 style=self.shell.style,
69 color_depth=self.shell.color_depth,
68 color_depth=self.shell.color_depth,
70 )
69 )
71
70
72 if not PTK3:
71 if not PTK3:
73 options['inputhook'] = self.shell.inputhook
72 options['inputhook'] = self.shell.inputhook
74 options.update(pt_session_options)
73 options.update(pt_session_options)
75 self.pt_loop = asyncio.new_event_loop()
74 self.pt_loop = asyncio.new_event_loop()
76 self.pt_app = PromptSession(**options)
75 self.pt_app = PromptSession(**options)
77
76
78 def cmdloop(self, intro=None):
77 def cmdloop(self, intro=None):
79 """Repeatedly issue a prompt, accept input, parse an initial prefix
78 """Repeatedly issue a prompt, accept input, parse an initial prefix
80 off the received input, and dispatch to action methods, passing them
79 off the received input, and dispatch to action methods, passing them
81 the remainder of the line as argument.
80 the remainder of the line as argument.
82
81
83 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
82 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
84 """
83 """
85 if not self.use_rawinput:
84 if not self.use_rawinput:
86 raise ValueError('Sorry ipdb does not support use_rawinput=False')
85 raise ValueError('Sorry ipdb does not support use_rawinput=False')
87
86
88 # In order to make sure that prompt, which uses asyncio doesn't
87 # In order to make sure that prompt, which uses asyncio doesn't
89 # interfere with applications in which it's used, we always run the
88 # interfere with applications in which it's used, we always run the
90 # prompt itself in a different thread (we can't start an event loop
89 # prompt itself in a different thread (we can't start an event loop
91 # within an event loop). This new thread won't have any event loop
90 # within an event loop). This new thread won't have any event loop
92 # running, and here we run our prompt-loop.
91 # running, and here we run our prompt-loop.
93
92
94 self.preloop()
93 self.preloop()
95
94
96 try:
95 try:
97 if intro is not None:
96 if intro is not None:
98 self.intro = intro
97 self.intro = intro
99 if self.intro:
98 if self.intro:
100 self.stdout.write(str(self.intro)+"\n")
99 self.stdout.write(str(self.intro)+"\n")
101 stop = None
100 stop = None
102 while not stop:
101 while not stop:
103 if self.cmdqueue:
102 if self.cmdqueue:
104 line = self.cmdqueue.pop(0)
103 line = self.cmdqueue.pop(0)
105 else:
104 else:
106 self._ptcomp.ipy_completer.namespace = self.curframe_locals
105 self._ptcomp.ipy_completer.namespace = self.curframe_locals
107 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
106 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
108
107
109 # Run the prompt in a different thread.
108 # Run the prompt in a different thread.
110 line = ''
109 line = ''
111 keyboard_interrupt = False
110 keyboard_interrupt = False
112
111
113 def in_thread():
112 def in_thread():
114 nonlocal line, keyboard_interrupt
113 nonlocal line, keyboard_interrupt
115 try:
114 try:
116 line = self.pt_app.prompt()
115 line = self.pt_app.prompt()
117 except EOFError:
116 except EOFError:
118 line = 'EOF'
117 line = 'EOF'
119 except KeyboardInterrupt:
118 except KeyboardInterrupt:
120 keyboard_interrupt = True
119 keyboard_interrupt = True
121
120
122 th = threading.Thread(target=in_thread)
121 th = threading.Thread(target=in_thread)
123 th.start()
122 th.start()
124 th.join()
123 th.join()
125
124
126 if keyboard_interrupt:
125 if keyboard_interrupt:
127 raise KeyboardInterrupt
126 raise KeyboardInterrupt
128
127
129 line = self.precmd(line)
128 line = self.precmd(line)
130 stop = self.onecmd(line)
129 stop = self.onecmd(line)
131 stop = self.postcmd(stop, line)
130 stop = self.postcmd(stop, line)
132 self.postloop()
131 self.postloop()
133 except Exception:
132 except Exception:
134 raise
133 raise
135
134
136
135
137 def set_trace(frame=None):
136 def set_trace(frame=None):
138 """
137 """
139 Start debugging from `frame`.
138 Start debugging from `frame`.
140
139
141 If frame is not specified, debugging starts from caller's frame.
140 If frame is not specified, debugging starts from caller's frame.
142 """
141 """
143 TerminalPdb().set_trace(frame or sys._getframe().f_back)
142 TerminalPdb().set_trace(frame or sys._getframe().f_back)
144
143
145
144
146 if __name__ == '__main__':
145 if __name__ == '__main__':
147 import pdb
146 import pdb
148 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
147 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
149 # bdb.BdbQuit. When started through __main__ and an exception
148 # bdb.BdbQuit. When started through __main__ and an exception
150 # happened after hitting "c", this is needed in order to
149 # happened after hitting "c", this is needed in order to
151 # be able to quit the debugging session (see #9950).
150 # be able to quit the debugging session (see #9950).
152 old_trace_dispatch = pdb.Pdb.trace_dispatch
151 old_trace_dispatch = pdb.Pdb.trace_dispatch
153 pdb.Pdb = TerminalPdb
152 pdb.Pdb = TerminalPdb
154 pdb.Pdb.trace_dispatch = old_trace_dispatch
153 pdb.Pdb.trace_dispatch = old_trace_dispatch
155 pdb.main()
154 pdb.main()
General Comments 0
You need to be logged in to leave comments. Login now