##// END OF EJS Templates
Merge pull request #13485 from cansarigol/master...
Matthias Bussonnier -
r27545:dd3bed29 merge
parent child Browse files
Show More
@@ -1,165 +1,167 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 else:
72 self.debugger_history = self.shell.debugger_history
71
73
72 options = dict(
74 options = dict(
73 message=(lambda: PygmentsTokens(get_prompt_tokens())),
75 message=(lambda: PygmentsTokens(get_prompt_tokens())),
74 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
76 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
75 key_bindings=create_ipython_shortcuts(self.shell),
77 key_bindings=create_ipython_shortcuts(self.shell),
76 history=self.debugger_history,
78 history=self.debugger_history,
77 completer=self._ptcomp,
79 completer=self._ptcomp,
78 enable_history_search=True,
80 enable_history_search=True,
79 mouse_support=self.shell.mouse_support,
81 mouse_support=self.shell.mouse_support,
80 complete_style=self.shell.pt_complete_style,
82 complete_style=self.shell.pt_complete_style,
81 style=getattr(self.shell, "style", None),
83 style=getattr(self.shell, "style", None),
82 color_depth=self.shell.color_depth,
84 color_depth=self.shell.color_depth,
83 )
85 )
84
86
85 if not PTK3:
87 if not PTK3:
86 options['inputhook'] = self.shell.inputhook
88 options['inputhook'] = self.shell.inputhook
87 options.update(pt_session_options)
89 options.update(pt_session_options)
88 self.pt_loop = asyncio.new_event_loop()
90 self.pt_loop = asyncio.new_event_loop()
89 self.pt_app = PromptSession(**options)
91 self.pt_app = PromptSession(**options)
90
92
91 def cmdloop(self, intro=None):
93 def cmdloop(self, intro=None):
92 """Repeatedly issue a prompt, accept input, parse an initial prefix
94 """Repeatedly issue a prompt, accept input, parse an initial prefix
93 off the received input, and dispatch to action methods, passing them
95 off the received input, and dispatch to action methods, passing them
94 the remainder of the line as argument.
96 the remainder of the line as argument.
95
97
96 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
98 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
97 """
99 """
98 if not self.use_rawinput:
100 if not self.use_rawinput:
99 raise ValueError('Sorry ipdb does not support use_rawinput=False')
101 raise ValueError('Sorry ipdb does not support use_rawinput=False')
100
102
101 # In order to make sure that prompt, which uses asyncio doesn't
103 # 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
104 # 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
105 # 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
106 # within an event loop). This new thread won't have any event loop
105 # running, and here we run our prompt-loop.
107 # running, and here we run our prompt-loop.
106 self.preloop()
108 self.preloop()
107
109
108 try:
110 try:
109 if intro is not None:
111 if intro is not None:
110 self.intro = intro
112 self.intro = intro
111 if self.intro:
113 if self.intro:
112 print(self.intro, file=self.stdout)
114 print(self.intro, file=self.stdout)
113 stop = None
115 stop = None
114 while not stop:
116 while not stop:
115 if self.cmdqueue:
117 if self.cmdqueue:
116 line = self.cmdqueue.pop(0)
118 line = self.cmdqueue.pop(0)
117 else:
119 else:
118 self._ptcomp.ipy_completer.namespace = self.curframe_locals
120 self._ptcomp.ipy_completer.namespace = self.curframe_locals
119 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
121 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
120
122
121 # Run the prompt in a different thread.
123 # Run the prompt in a different thread.
122 try:
124 try:
123 line = self.thread_executor.submit(self.pt_app.prompt).result()
125 line = self.thread_executor.submit(self.pt_app.prompt).result()
124 except EOFError:
126 except EOFError:
125 line = "EOF"
127 line = "EOF"
126
128
127 line = self.precmd(line)
129 line = self.precmd(line)
128 stop = self.onecmd(line)
130 stop = self.onecmd(line)
129 stop = self.postcmd(stop, line)
131 stop = self.postcmd(stop, line)
130 self.postloop()
132 self.postloop()
131 except Exception:
133 except Exception:
132 raise
134 raise
133
135
134 def do_interact(self, arg):
136 def do_interact(self, arg):
135 ipshell = embed.InteractiveShellEmbed(
137 ipshell = embed.InteractiveShellEmbed(
136 config=self.shell.config,
138 config=self.shell.config,
137 banner1="*interactive*",
139 banner1="*interactive*",
138 exit_msg="*exiting interactive console...*",
140 exit_msg="*exiting interactive console...*",
139 )
141 )
140 global_ns = self.curframe.f_globals
142 global_ns = self.curframe.f_globals
141 ipshell(
143 ipshell(
142 module=sys.modules.get(global_ns["__name__"], None),
144 module=sys.modules.get(global_ns["__name__"], None),
143 local_ns=self.curframe_locals,
145 local_ns=self.curframe_locals,
144 )
146 )
145
147
146
148
147 def set_trace(frame=None):
149 def set_trace(frame=None):
148 """
150 """
149 Start debugging from `frame`.
151 Start debugging from `frame`.
150
152
151 If frame is not specified, debugging starts from caller's frame.
153 If frame is not specified, debugging starts from caller's frame.
152 """
154 """
153 TerminalPdb().set_trace(frame or sys._getframe().f_back)
155 TerminalPdb().set_trace(frame or sys._getframe().f_back)
154
156
155
157
156 if __name__ == '__main__':
158 if __name__ == '__main__':
157 import pdb
159 import pdb
158 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
160 # IPython.core.debugger.Pdb.trace_dispatch shall not catch
159 # bdb.BdbQuit. When started through __main__ and an exception
161 # bdb.BdbQuit. When started through __main__ and an exception
160 # happened after hitting "c", this is needed in order to
162 # happened after hitting "c", this is needed in order to
161 # be able to quit the debugging session (see #9950).
163 # be able to quit the debugging session (see #9950).
162 old_trace_dispatch = pdb.Pdb.trace_dispatch
164 old_trace_dispatch = pdb.Pdb.trace_dispatch
163 pdb.Pdb = TerminalPdb # type: ignore
165 pdb.Pdb = TerminalPdb # type: ignore
164 pdb.Pdb.trace_dispatch = old_trace_dispatch # type: ignore
166 pdb.Pdb.trace_dispatch = old_trace_dispatch # type: ignore
165 pdb.main()
167 pdb.main()
General Comments 0
You need to be logged in to leave comments. Login now