##// END OF EJS Templates
put qtconsole forground when launching
Matthias BUSSONNIER -
Show More
@@ -1,352 +1,353 b''
1 1 """ A minimal application using the Qt console-style IPython frontend.
2 2
3 3 This is not a complete console app, as subprocess will not be able to receive
4 4 input, there is no real readline support, among other limitations.
5 5
6 6 Authors:
7 7
8 8 * Evan Patterson
9 9 * Min RK
10 10 * Erik Tollerud
11 11 * Fernando Perez
12 12 * Bussonnier Matthias
13 13 * Thomas Kluyver
14 14 * Paul Ivanov
15 15
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # stdlib imports
23 23 import json
24 24 import os
25 25 import signal
26 26 import sys
27 27 import uuid
28 28
29 29 # System library imports
30 30 from IPython.external.qt import QtCore, QtGui
31 31
32 32 # Local imports
33 33 from IPython.config.application import boolean_flag, catch_config_error
34 34 from IPython.core.application import BaseIPythonApplication
35 35 from IPython.core.profiledir import ProfileDir
36 36 from IPython.lib.kernel import tunnel_to_kernel, find_connection_file
37 37 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
38 38 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
39 39 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
40 40 from IPython.frontend.qt.console import styles
41 41 from IPython.frontend.qt.console.mainwindow import MainWindow
42 42 from IPython.frontend.qt.kernelmanager import QtKernelManager
43 43 from IPython.utils.path import filefind
44 44 from IPython.utils.py3compat import str_to_bytes
45 45 from IPython.utils.traitlets import (
46 46 Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any
47 47 )
48 48 from IPython.zmq.ipkernel import IPKernelApp
49 49 from IPython.zmq.session import Session, default_secure
50 50 from IPython.zmq.zmqshell import ZMQInteractiveShell
51 51
52 52 from IPython.frontend.consoleapp import (
53 53 IPythonConsoleApp, app_aliases, app_flags, flags, aliases
54 54 )
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Network Constants
58 58 #-----------------------------------------------------------------------------
59 59
60 60 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Globals
64 64 #-----------------------------------------------------------------------------
65 65
66 66 _examples = """
67 67 ipython qtconsole # start the qtconsole
68 68 ipython qtconsole --pylab=inline # start with pylab in inline plotting mode
69 69 """
70 70
71 71 #-----------------------------------------------------------------------------
72 72 # Aliases and Flags
73 73 #-----------------------------------------------------------------------------
74 74
75 75 # start with copy of flags
76 76 flags = dict(flags)
77 77 qt_flags = {
78 78 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
79 79 "Use a pure Python kernel instead of an IPython kernel."),
80 80 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
81 81 "Disable rich text support."),
82 82 }
83 83 qt_flags.update(boolean_flag(
84 84 'gui-completion', 'ConsoleWidget.gui_completion',
85 85 "use a GUI widget for tab completion",
86 86 "use plaintext output for completion"
87 87 ))
88 88 # and app_flags from the Console Mixin
89 89 qt_flags.update(app_flags)
90 90 # add frontend flags to the full set
91 91 flags.update(qt_flags)
92 92
93 93 # start with copy of front&backend aliases list
94 94 aliases = dict(aliases)
95 95 qt_aliases = dict(
96 96
97 97 style = 'IPythonWidget.syntax_style',
98 98 stylesheet = 'IPythonQtConsoleApp.stylesheet',
99 99 colors = 'ZMQInteractiveShell.colors',
100 100
101 101 editor = 'IPythonWidget.editor',
102 102 paging = 'ConsoleWidget.paging',
103 103 )
104 104 # and app_aliases from the Console Mixin
105 105 qt_aliases.update(app_aliases)
106 106 # add frontend aliases to the full set
107 107 aliases.update(qt_aliases)
108 108
109 109 # get flags&aliases into sets, and remove a couple that
110 110 # shouldn't be scrubbed from backend flags:
111 111 qt_aliases = set(qt_aliases.keys())
112 112 qt_aliases.remove('colors')
113 113 qt_flags = set(qt_flags.keys())
114 114
115 115 #-----------------------------------------------------------------------------
116 116 # Classes
117 117 #-----------------------------------------------------------------------------
118 118
119 119 #-----------------------------------------------------------------------------
120 120 # IPythonQtConsole
121 121 #-----------------------------------------------------------------------------
122 122
123 123
124 124 class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):
125 125 name = 'ipython-qtconsole'
126 126
127 127 description = """
128 128 The IPython QtConsole.
129 129
130 130 This launches a Console-style application using Qt. It is not a full
131 131 console, in that launched terminal subprocesses will not be able to accept
132 132 input.
133 133
134 134 The QtConsole supports various extra features beyond the Terminal IPython
135 135 shell, such as inline plotting with matplotlib, via:
136 136
137 137 ipython qtconsole --pylab=inline
138 138
139 139 as well as saving your session as HTML, and printing the output.
140 140
141 141 """
142 142 examples = _examples
143 143
144 144 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
145 145 flags = Dict(flags)
146 146 aliases = Dict(aliases)
147 147 frontend_flags = Any(qt_flags)
148 148 frontend_aliases = Any(qt_aliases)
149 149 kernel_manager_class = QtKernelManager
150 150
151 151 stylesheet = Unicode('', config=True,
152 152 help="path to a custom CSS stylesheet")
153 153
154 154 plain = CBool(False, config=True,
155 155 help="Use a plaintext widget instead of rich text (plain can't print/save).")
156 156
157 157 def _pure_changed(self, name, old, new):
158 158 kind = 'plain' if self.plain else 'rich'
159 159 self.config.ConsoleWidget.kind = kind
160 160 if self.pure:
161 161 self.widget_factory = FrontendWidget
162 162 elif self.plain:
163 163 self.widget_factory = IPythonWidget
164 164 else:
165 165 self.widget_factory = RichIPythonWidget
166 166
167 167 _plain_changed = _pure_changed
168 168
169 169 # the factory for creating a widget
170 170 widget_factory = Any(RichIPythonWidget)
171 171
172 172 def parse_command_line(self, argv=None):
173 173 super(IPythonQtConsoleApp, self).parse_command_line(argv)
174 174 self.build_kernel_argv(argv)
175 175
176 176
177 177 def new_frontend_master(self):
178 178 """ Create and return new frontend attached to new kernel, launched on localhost.
179 179 """
180 180 ip = self.ip if self.ip in LOCAL_IPS else LOCALHOST
181 181 kernel_manager = QtKernelManager(
182 182 ip=ip,
183 183 connection_file=self._new_connection_file(),
184 184 config=self.config,
185 185 )
186 186 # start the kernel
187 187 kwargs = dict(ipython=not self.pure)
188 188 kwargs['extra_arguments'] = self.kernel_argv
189 189 kernel_manager.start_kernel(**kwargs)
190 190 kernel_manager.start_channels()
191 191 widget = self.widget_factory(config=self.config,
192 192 local_kernel=True)
193 193 widget.kernel_manager = kernel_manager
194 194 widget._existing = False
195 195 widget._may_close = True
196 196 widget._confirm_exit = self.confirm_exit
197 197 return widget
198 198
199 199 def new_frontend_slave(self, current_widget):
200 200 """Create and return a new frontend attached to an existing kernel.
201 201
202 202 Parameters
203 203 ----------
204 204 current_widget : IPythonWidget
205 205 The IPythonWidget whose kernel this frontend is to share
206 206 """
207 207 kernel_manager = QtKernelManager(
208 208 connection_file=current_widget.kernel_manager.connection_file,
209 209 config = self.config,
210 210 )
211 211 kernel_manager.load_connection_file()
212 212 kernel_manager.start_channels()
213 213 widget = self.widget_factory(config=self.config,
214 214 local_kernel=False)
215 215 widget._existing = True
216 216 widget._may_close = False
217 217 widget._confirm_exit = False
218 218 widget.kernel_manager = kernel_manager
219 219 return widget
220 220
221 221 def init_qt_elements(self):
222 222 # Create the widget.
223 223 self.app = QtGui.QApplication([])
224 224
225 225 base_path = os.path.abspath(os.path.dirname(__file__))
226 226 icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg')
227 227 self.app.icon = QtGui.QIcon(icon_path)
228 228 QtGui.QApplication.setWindowIcon(self.app.icon)
229 229
230 230 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
231 231 self.widget = self.widget_factory(config=self.config,
232 232 local_kernel=local_kernel)
233 233 self.widget._existing = self.existing
234 234 self.widget._may_close = not self.existing
235 235 self.widget._confirm_exit = self.confirm_exit
236 236
237 237 self.widget.kernel_manager = self.kernel_manager
238 238 self.window = MainWindow(self.app,
239 239 confirm_exit=self.confirm_exit,
240 240 new_frontend_factory=self.new_frontend_master,
241 241 slave_frontend_factory=self.new_frontend_slave,
242 242 )
243 243 self.window.log = self.log
244 244 self.window.add_tab_with_frontend(self.widget)
245 245 self.window.init_menu_bar()
246 246
247 247 self.window.setWindowTitle('Python' if self.pure else 'IPython')
248 248
249 249 def init_colors(self):
250 250 """Configure the coloring of the widget"""
251 251 # Note: This will be dramatically simplified when colors
252 252 # are removed from the backend.
253 253
254 254 if self.pure:
255 255 # only IPythonWidget supports styling
256 256 return
257 257
258 258 # parse the colors arg down to current known labels
259 259 try:
260 260 colors = self.config.ZMQInteractiveShell.colors
261 261 except AttributeError:
262 262 colors = None
263 263 try:
264 264 style = self.config.IPythonWidget.syntax_style
265 265 except AttributeError:
266 266 style = None
267 267
268 268 # find the value for colors:
269 269 if colors:
270 270 colors=colors.lower()
271 271 if colors in ('lightbg', 'light'):
272 272 colors='lightbg'
273 273 elif colors in ('dark', 'linux'):
274 274 colors='linux'
275 275 else:
276 276 colors='nocolor'
277 277 elif style:
278 278 if style=='bw':
279 279 colors='nocolor'
280 280 elif styles.dark_style(style):
281 281 colors='linux'
282 282 else:
283 283 colors='lightbg'
284 284 else:
285 285 colors=None
286 286
287 287 # Configure the style.
288 288 widget = self.widget
289 289 if style:
290 290 widget.style_sheet = styles.sheet_from_template(style, colors)
291 291 widget.syntax_style = style
292 292 widget._syntax_style_changed()
293 293 widget._style_sheet_changed()
294 294 elif colors:
295 295 # use a default style
296 296 widget.set_default_style(colors=colors)
297 297 else:
298 298 # this is redundant for now, but allows the widget's
299 299 # defaults to change
300 300 widget.set_default_style()
301 301
302 302 if self.stylesheet:
303 303 # we got an expicit stylesheet
304 304 if os.path.isfile(self.stylesheet):
305 305 with open(self.stylesheet) as f:
306 306 sheet = f.read()
307 307 widget.style_sheet = sheet
308 308 widget._style_sheet_changed()
309 309 else:
310 310 raise IOError("Stylesheet %r not found."%self.stylesheet)
311 311
312 312 def init_signal(self):
313 313 """allow clean shutdown on sigint"""
314 314 signal.signal(signal.SIGINT, lambda sig, frame: self.exit(-2))
315 315 # need a timer, so that QApplication doesn't block until a real
316 316 # Qt event fires (can require mouse movement)
317 317 # timer trick from http://stackoverflow.com/q/4938723/938949
318 318 timer = QtCore.QTimer()
319 319 # Let the interpreter run each 200 ms:
320 320 timer.timeout.connect(lambda: None)
321 321 timer.start(200)
322 322 # hold onto ref, so the timer doesn't get cleaned up
323 323 self._sigint_timer = timer
324 324
325 325 @catch_config_error
326 326 def initialize(self, argv=None):
327 327 super(IPythonQtConsoleApp, self).initialize(argv)
328 328 IPythonConsoleApp.initialize(self,argv)
329 329 self.init_qt_elements()
330 330 self.init_colors()
331 331 self.init_signal()
332 332
333 333 def start(self):
334 334
335 335 # draw the window
336 336 self.window.show()
337 self.window.raise_()
337 338
338 339 # Start the application main loop.
339 340 self.app.exec_()
340 341
341 342 #-----------------------------------------------------------------------------
342 343 # Main entry point
343 344 #-----------------------------------------------------------------------------
344 345
345 346 def main():
346 347 app = IPythonQtConsoleApp()
347 348 app.initialize()
348 349 app.start()
349 350
350 351
351 352 if __name__ == '__main__':
352 353 main()
General Comments 0
You need to be logged in to leave comments. Login now