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