##// END OF EJS Templates
add ssh tunnel support to qtconsole
MinRK -
Show More
@@ -1,446 +1,483 b''
1 """ A minimal application using the Qt console-style IPython frontend.
1 """ A minimal application using the Qt console-style IPython frontend.
2
2
3 This is not a complete console app, as subprocess will not be able to receive
3 This is not a complete console app, as subprocess will not be able to receive
4 input, there is no real readline support, among other limitations.
4 input, there is no real readline support, among other limitations.
5
5
6 Authors:
6 Authors:
7
7
8 * Evan Patterson
8 * Evan Patterson
9 * Min RK
9 * Min RK
10 * Erik Tollerud
10 * Erik Tollerud
11 * Fernando Perez
11 * Fernando Perez
12
12
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib imports
19 # stdlib imports
20 import os
20 import os
21 import signal
21 import signal
22 import sys
22 import sys
23 from getpass import getpass
23
24
24 # System library imports
25 # System library imports
25 from IPython.external.qt import QtGui
26 from IPython.external.qt import QtGui
26 from pygments.styles import get_all_styles
27 from pygments.styles import get_all_styles
27
28
29 # from IPython.external.ssh import tunnel
28 # Local imports
30 # Local imports
29 from IPython.config.application import boolean_flag
31 from IPython.config.application import boolean_flag
30 from IPython.core.application import BaseIPythonApplication
32 from IPython.core.application import BaseIPythonApplication
31 from IPython.core.profiledir import ProfileDir
33 from IPython.core.profiledir import ProfileDir
32 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
34 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
33 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
35 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
34 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
36 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
35 from IPython.frontend.qt.console import styles
37 from IPython.frontend.qt.console import styles
36 from IPython.frontend.qt.kernelmanager import QtKernelManager
38 from IPython.frontend.qt.kernelmanager import QtKernelManager
39 from IPython.parallel.util import select_random_ports
37 from IPython.utils.traitlets import (
40 from IPython.utils.traitlets import (
38 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
41 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
39 )
42 )
40 from IPython.zmq.ipkernel import (
43 from IPython.zmq.ipkernel import (
41 flags as ipkernel_flags,
44 flags as ipkernel_flags,
42 aliases as ipkernel_aliases,
45 aliases as ipkernel_aliases,
43 IPKernelApp
46 IPKernelApp
44 )
47 )
45 from IPython.zmq.session import Session
48 from IPython.zmq.session import Session
46 from IPython.zmq.zmqshell import ZMQInteractiveShell
49 from IPython.zmq.zmqshell import ZMQInteractiveShell
47
50
48
51
49 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
50 # Network Constants
53 # Network Constants
51 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
52
55
53 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
56 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
54
57
55 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
56 # Globals
59 # Globals
57 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
58
61
59 _examples = """
62 _examples = """
60 ipython qtconsole # start the qtconsole
63 ipython qtconsole # start the qtconsole
61 ipython qtconsole --pylab=inline # start with pylab in inline plotting mode
64 ipython qtconsole --pylab=inline # start with pylab in inline plotting mode
62 """
65 """
63
66
64 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
65 # Classes
68 # Classes
66 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
67
70
68 class MainWindow(QtGui.QMainWindow):
71 class MainWindow(QtGui.QMainWindow):
69
72
70 #---------------------------------------------------------------------------
73 #---------------------------------------------------------------------------
71 # 'object' interface
74 # 'object' interface
72 #---------------------------------------------------------------------------
75 #---------------------------------------------------------------------------
73
76
74 def __init__(self, app, frontend, existing=False, may_close=True,
77 def __init__(self, app, frontend, existing=False, may_close=True,
75 confirm_exit=True):
78 confirm_exit=True):
76 """ Create a MainWindow for the specified FrontendWidget.
79 """ Create a MainWindow for the specified FrontendWidget.
77
80
78 The app is passed as an argument to allow for different
81 The app is passed as an argument to allow for different
79 closing behavior depending on whether we are the Kernel's parent.
82 closing behavior depending on whether we are the Kernel's parent.
80
83
81 If existing is True, then this Console does not own the Kernel.
84 If existing is True, then this Console does not own the Kernel.
82
85
83 If may_close is True, then this Console is permitted to close the kernel
86 If may_close is True, then this Console is permitted to close the kernel
84 """
87 """
85 super(MainWindow, self).__init__()
88 super(MainWindow, self).__init__()
86 self._app = app
89 self._app = app
87 self._frontend = frontend
90 self._frontend = frontend
88 self._existing = existing
91 self._existing = existing
89 if existing:
92 if existing:
90 self._may_close = may_close
93 self._may_close = may_close
91 else:
94 else:
92 self._may_close = True
95 self._may_close = True
93 self._frontend.exit_requested.connect(self.close)
96 self._frontend.exit_requested.connect(self.close)
94 self._confirm_exit = confirm_exit
97 self._confirm_exit = confirm_exit
95 self.setCentralWidget(frontend)
98 self.setCentralWidget(frontend)
96
99
97 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
98 # QWidget interface
101 # QWidget interface
99 #---------------------------------------------------------------------------
102 #---------------------------------------------------------------------------
100
103
101 def closeEvent(self, event):
104 def closeEvent(self, event):
102 """ Close the window and the kernel (if necessary).
105 """ Close the window and the kernel (if necessary).
103
106
104 This will prompt the user if they are finished with the kernel, and if
107 This will prompt the user if they are finished with the kernel, and if
105 so, closes the kernel cleanly. Alternatively, if the exit magic is used,
108 so, closes the kernel cleanly. Alternatively, if the exit magic is used,
106 it closes without prompt.
109 it closes without prompt.
107 """
110 """
108 keepkernel = None #Use the prompt by default
111 keepkernel = None #Use the prompt by default
109 if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic
112 if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic
110 keepkernel = self._frontend._keep_kernel_on_exit
113 keepkernel = self._frontend._keep_kernel_on_exit
111
114
112 kernel_manager = self._frontend.kernel_manager
115 kernel_manager = self._frontend.kernel_manager
113
116
114 if keepkernel is None and not self._confirm_exit:
117 if keepkernel is None and not self._confirm_exit:
115 # don't prompt, just terminate the kernel if we own it
118 # don't prompt, just terminate the kernel if we own it
116 # or leave it alone if we don't
119 # or leave it alone if we don't
117 keepkernel = not self._existing
120 keepkernel = not self._existing
118
121
119 if keepkernel is None: #show prompt
122 if keepkernel is None: #show prompt
120 if kernel_manager and kernel_manager.channels_running:
123 if kernel_manager and kernel_manager.channels_running:
121 title = self.window().windowTitle()
124 title = self.window().windowTitle()
122 cancel = QtGui.QMessageBox.Cancel
125 cancel = QtGui.QMessageBox.Cancel
123 okay = QtGui.QMessageBox.Ok
126 okay = QtGui.QMessageBox.Ok
124 if self._may_close:
127 if self._may_close:
125 msg = "You are closing this Console window."
128 msg = "You are closing this Console window."
126 info = "Would you like to quit the Kernel and all attached Consoles as well?"
129 info = "Would you like to quit the Kernel and all attached Consoles as well?"
127 justthis = QtGui.QPushButton("&No, just this Console", self)
130 justthis = QtGui.QPushButton("&No, just this Console", self)
128 justthis.setShortcut('N')
131 justthis.setShortcut('N')
129 closeall = QtGui.QPushButton("&Yes, quit everything", self)
132 closeall = QtGui.QPushButton("&Yes, quit everything", self)
130 closeall.setShortcut('Y')
133 closeall.setShortcut('Y')
131 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
134 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
132 title, msg)
135 title, msg)
133 box.setInformativeText(info)
136 box.setInformativeText(info)
134 box.addButton(cancel)
137 box.addButton(cancel)
135 box.addButton(justthis, QtGui.QMessageBox.NoRole)
138 box.addButton(justthis, QtGui.QMessageBox.NoRole)
136 box.addButton(closeall, QtGui.QMessageBox.YesRole)
139 box.addButton(closeall, QtGui.QMessageBox.YesRole)
137 box.setDefaultButton(closeall)
140 box.setDefaultButton(closeall)
138 box.setEscapeButton(cancel)
141 box.setEscapeButton(cancel)
139 reply = box.exec_()
142 reply = box.exec_()
140 if reply == 1: # close All
143 if reply == 1: # close All
141 kernel_manager.shutdown_kernel()
144 kernel_manager.shutdown_kernel()
142 #kernel_manager.stop_channels()
145 #kernel_manager.stop_channels()
143 event.accept()
146 event.accept()
144 elif reply == 0: # close Console
147 elif reply == 0: # close Console
145 if not self._existing:
148 if not self._existing:
146 # Have kernel: don't quit, just close the window
149 # Have kernel: don't quit, just close the window
147 self._app.setQuitOnLastWindowClosed(False)
150 self._app.setQuitOnLastWindowClosed(False)
148 self.deleteLater()
151 self.deleteLater()
149 event.accept()
152 event.accept()
150 else:
153 else:
151 event.ignore()
154 event.ignore()
152 else:
155 else:
153 reply = QtGui.QMessageBox.question(self, title,
156 reply = QtGui.QMessageBox.question(self, title,
154 "Are you sure you want to close this Console?"+
157 "Are you sure you want to close this Console?"+
155 "\nThe Kernel and other Consoles will remain active.",
158 "\nThe Kernel and other Consoles will remain active.",
156 okay|cancel,
159 okay|cancel,
157 defaultButton=okay
160 defaultButton=okay
158 )
161 )
159 if reply == okay:
162 if reply == okay:
160 event.accept()
163 event.accept()
161 else:
164 else:
162 event.ignore()
165 event.ignore()
163 elif keepkernel: #close console but leave kernel running (no prompt)
166 elif keepkernel: #close console but leave kernel running (no prompt)
164 if kernel_manager and kernel_manager.channels_running:
167 if kernel_manager and kernel_manager.channels_running:
165 if not self._existing:
168 if not self._existing:
166 # I have the kernel: don't quit, just close the window
169 # I have the kernel: don't quit, just close the window
167 self._app.setQuitOnLastWindowClosed(False)
170 self._app.setQuitOnLastWindowClosed(False)
168 event.accept()
171 event.accept()
169 else: #close console and kernel (no prompt)
172 else: #close console and kernel (no prompt)
170 if kernel_manager and kernel_manager.channels_running:
173 if kernel_manager and kernel_manager.channels_running:
171 kernel_manager.shutdown_kernel()
174 kernel_manager.shutdown_kernel()
172 event.accept()
175 event.accept()
173
176
174 #-----------------------------------------------------------------------------
177 #-----------------------------------------------------------------------------
175 # Aliases and Flags
178 # Aliases and Flags
176 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
177
180
178 flags = dict(ipkernel_flags)
181 flags = dict(ipkernel_flags)
179 qt_flags = {
182 qt_flags = {
180 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
183 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
181 "Connect to an existing kernel."),
184 "Connect to an existing kernel."),
182 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
185 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
183 "Use a pure Python kernel instead of an IPython kernel."),
186 "Use a pure Python kernel instead of an IPython kernel."),
184 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
187 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
185 "Disable rich text support."),
188 "Disable rich text support."),
186 }
189 }
187 qt_flags.update(boolean_flag(
190 qt_flags.update(boolean_flag(
188 'gui-completion', 'ConsoleWidget.gui_completion',
191 'gui-completion', 'ConsoleWidget.gui_completion',
189 "use a GUI widget for tab completion",
192 "use a GUI widget for tab completion",
190 "use plaintext output for completion"
193 "use plaintext output for completion"
191 ))
194 ))
192 qt_flags.update(boolean_flag(
195 qt_flags.update(boolean_flag(
193 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
196 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
194 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
197 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
195 to force a direct exit without any confirmation.
198 to force a direct exit without any confirmation.
196 """,
199 """,
197 """Don't prompt the user when exiting. This will terminate the kernel
200 """Don't prompt the user when exiting. This will terminate the kernel
198 if it is owned by the frontend, and leave it alive if it is external.
201 if it is owned by the frontend, and leave it alive if it is external.
199 """
202 """
200 ))
203 ))
201 flags.update(qt_flags)
204 flags.update(qt_flags)
202 # the flags that are specific to the frontend
205 # the flags that are specific to the frontend
203 # these must be scrubbed before being passed to the kernel,
206 # these must be scrubbed before being passed to the kernel,
204 # or it will raise an error on unrecognized flags
207 # or it will raise an error on unrecognized flags
205 qt_flags = qt_flags.keys()
208 qt_flags = qt_flags.keys()
206
209
207 aliases = dict(ipkernel_aliases)
210 aliases = dict(ipkernel_aliases)
208
211
209 qt_aliases = dict(
212 qt_aliases = dict(
210 hb = 'IPythonQtConsoleApp.hb_port',
213 hb = 'IPythonQtConsoleApp.hb_port',
211 shell = 'IPythonQtConsoleApp.shell_port',
214 shell = 'IPythonQtConsoleApp.shell_port',
212 iopub = 'IPythonQtConsoleApp.iopub_port',
215 iopub = 'IPythonQtConsoleApp.iopub_port',
213 stdin = 'IPythonQtConsoleApp.stdin_port',
216 stdin = 'IPythonQtConsoleApp.stdin_port',
214 ip = 'IPythonQtConsoleApp.ip',
217 ip = 'IPythonQtConsoleApp.ip',
215
218
216 style = 'IPythonWidget.syntax_style',
219 style = 'IPythonWidget.syntax_style',
217 stylesheet = 'IPythonQtConsoleApp.stylesheet',
220 stylesheet = 'IPythonQtConsoleApp.stylesheet',
218 colors = 'ZMQInteractiveShell.colors',
221 colors = 'ZMQInteractiveShell.colors',
219
222
220 editor = 'IPythonWidget.editor',
223 editor = 'IPythonWidget.editor',
221 paging = 'ConsoleWidget.paging',
224 paging = 'ConsoleWidget.paging',
225 ssh = 'IPythonQtConsoleApp.sshserver',
222 )
226 )
223 aliases.update(qt_aliases)
227 aliases.update(qt_aliases)
224 # also scrub aliases from the frontend
228 # also scrub aliases from the frontend
225 qt_flags.extend(qt_aliases.keys())
229 qt_flags.extend(qt_aliases.keys())
226
230
227
231
228 #-----------------------------------------------------------------------------
232 #-----------------------------------------------------------------------------
229 # IPythonQtConsole
233 # IPythonQtConsole
230 #-----------------------------------------------------------------------------
234 #-----------------------------------------------------------------------------
231
235
232
236
233 class IPythonQtConsoleApp(BaseIPythonApplication):
237 class IPythonQtConsoleApp(BaseIPythonApplication):
234 name = 'ipython-qtconsole'
238 name = 'ipython-qtconsole'
235 default_config_file_name='ipython_config.py'
239 default_config_file_name='ipython_config.py'
236
240
237 description = """
241 description = """
238 The IPython QtConsole.
242 The IPython QtConsole.
239
243
240 This launches a Console-style application using Qt. It is not a full
244 This launches a Console-style application using Qt. It is not a full
241 console, in that launched terminal subprocesses will not be able to accept
245 console, in that launched terminal subprocesses will not be able to accept
242 input.
246 input.
243
247
244 The QtConsole supports various extra features beyond the Terminal IPython
248 The QtConsole supports various extra features beyond the Terminal IPython
245 shell, such as inline plotting with matplotlib, via:
249 shell, such as inline plotting with matplotlib, via:
246
250
247 ipython qtconsole --pylab=inline
251 ipython qtconsole --pylab=inline
248
252
249 as well as saving your session as HTML, and printing the output.
253 as well as saving your session as HTML, and printing the output.
250
254
251 """
255 """
252 examples = _examples
256 examples = _examples
253
257
254 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
258 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
255 flags = Dict(flags)
259 flags = Dict(flags)
256 aliases = Dict(aliases)
260 aliases = Dict(aliases)
257
261
258 kernel_argv = List(Unicode)
262 kernel_argv = List(Unicode)
259
263
260 # create requested profiles by default, if they don't exist:
264 # create requested profiles by default, if they don't exist:
261 auto_create = CBool(True)
265 auto_create = CBool(True)
262 # connection info:
266 # connection info:
263 ip = Unicode(LOCALHOST, config=True,
267 ip = Unicode(LOCALHOST, config=True,
264 help="""Set the kernel\'s IP address [default localhost].
268 help="""Set the kernel\'s IP address [default localhost].
265 If the IP address is something other than localhost, then
269 If the IP address is something other than localhost, then
266 Consoles on other machines will be able to connect
270 Consoles on other machines will be able to connect
267 to the Kernel, so be careful!"""
271 to the Kernel, so be careful!"""
268 )
272 )
273
274 sshserver = Unicode('', config=True,
275 help="""The SSH server to use to connect to the kernel.""")
276 sshkey = Unicode('', config=True,
277 help="""Path to the ssh key to use for logging in to the ssh server.""")
278
269 hb_port = Int(0, config=True,
279 hb_port = Int(0, config=True,
270 help="set the heartbeat port [default: random]")
280 help="set the heartbeat port [default: random]")
271 shell_port = Int(0, config=True,
281 shell_port = Int(0, config=True,
272 help="set the shell (XREP) port [default: random]")
282 help="set the shell (XREP) port [default: random]")
273 iopub_port = Int(0, config=True,
283 iopub_port = Int(0, config=True,
274 help="set the iopub (PUB) port [default: random]")
284 help="set the iopub (PUB) port [default: random]")
275 stdin_port = Int(0, config=True,
285 stdin_port = Int(0, config=True,
276 help="set the stdin (XREQ) port [default: random]")
286 help="set the stdin (XREQ) port [default: random]")
277
287
278 existing = CBool(False, config=True,
288 existing = CBool(False, config=True,
279 help="Whether to connect to an already running Kernel.")
289 help="Whether to connect to an already running Kernel.")
280
290
281 stylesheet = Unicode('', config=True,
291 stylesheet = Unicode('', config=True,
282 help="path to a custom CSS stylesheet")
292 help="path to a custom CSS stylesheet")
283
293
284 pure = CBool(False, config=True,
294 pure = CBool(False, config=True,
285 help="Use a pure Python kernel instead of an IPython kernel.")
295 help="Use a pure Python kernel instead of an IPython kernel.")
286 plain = CBool(False, config=True,
296 plain = CBool(False, config=True,
287 help="Use a plaintext widget instead of rich text (plain can't print/save).")
297 help="Use a plaintext widget instead of rich text (plain can't print/save).")
288
298
289 def _pure_changed(self, name, old, new):
299 def _pure_changed(self, name, old, new):
290 kind = 'plain' if self.plain else 'rich'
300 kind = 'plain' if self.plain else 'rich'
291 self.config.ConsoleWidget.kind = kind
301 self.config.ConsoleWidget.kind = kind
292 if self.pure:
302 if self.pure:
293 self.widget_factory = FrontendWidget
303 self.widget_factory = FrontendWidget
294 elif self.plain:
304 elif self.plain:
295 self.widget_factory = IPythonWidget
305 self.widget_factory = IPythonWidget
296 else:
306 else:
297 self.widget_factory = RichIPythonWidget
307 self.widget_factory = RichIPythonWidget
298
308
299 _plain_changed = _pure_changed
309 _plain_changed = _pure_changed
300
310
301 confirm_exit = CBool(True, config=True,
311 confirm_exit = CBool(True, config=True,
302 help="""
312 help="""
303 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
313 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
304 to force a direct exit without any confirmation.""",
314 to force a direct exit without any confirmation.""",
305 )
315 )
306
316
307 # the factory for creating a widget
317 # the factory for creating a widget
308 widget_factory = Any(RichIPythonWidget)
318 widget_factory = Any(RichIPythonWidget)
309
319
310 def parse_command_line(self, argv=None):
320 def parse_command_line(self, argv=None):
311 super(IPythonQtConsoleApp, self).parse_command_line(argv)
321 super(IPythonQtConsoleApp, self).parse_command_line(argv)
312 if argv is None:
322 if argv is None:
313 argv = sys.argv[1:]
323 argv = sys.argv[1:]
314
324
315 self.kernel_argv = list(argv) # copy
325 self.kernel_argv = list(argv) # copy
316 # kernel should inherit default config file from frontend
326 # kernel should inherit default config file from frontend
317 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
327 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
318 # scrub frontend-specific flags
328 # scrub frontend-specific flags
319 for a in argv:
329 for a in argv:
320
330
321 if a.startswith('-'):
331 if a.startswith('-'):
322 key = a.lstrip('-').split('=')[0]
332 key = a.lstrip('-').split('=')[0]
323 if key in qt_flags:
333 if key in qt_flags:
324 self.kernel_argv.remove(a)
334 self.kernel_argv.remove(a)
325
335
336 def init_ssh(self):
337 # import here, to prevent circular import
338 from IPython.external.ssh import tunnel
339 if not self.sshserver and not self.sshkey:
340 return
341
342 if self.sshkey and not self.sshserver:
343 self.sshserver = self.ip
344 self.ip=LOCALHOST
345
346 lports = select_random_ports(4)
347 rports = self.shell_port, self.iopub_port, self.stdin_port, self.hb_port
348 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = lports
349
350 remote_ip = self.ip
351 self.ip = LOCALHOST
352 self.log.info("Forwarding connections to %s via %s"%(remote_ip, self.sshserver))
353
354 if tunnel.try_passwordless_ssh(self.sshserver, self.sshkey):
355 password=False
356 else:
357 password = getpass("SSH Password for %s: "%self.sshserver)
358
359 for lp,rp in zip(lports, rports):
360 tunnel.ssh_tunnel(lp, rp, self.sshserver, remote_ip, self.sshkey, password)
361
326 def init_kernel_manager(self):
362 def init_kernel_manager(self):
327 # Don't let Qt or ZMQ swallow KeyboardInterupts.
363 # Don't let Qt or ZMQ swallow KeyboardInterupts.
328 signal.signal(signal.SIGINT, signal.SIG_DFL)
364 signal.signal(signal.SIGINT, signal.SIG_DFL)
329
365
330 # Create a KernelManager and start a kernel.
366 # Create a KernelManager and start a kernel.
331 self.kernel_manager = QtKernelManager(
367 self.kernel_manager = QtKernelManager(
332 shell_address=(self.ip, self.shell_port),
368 shell_address=(self.ip, self.shell_port),
333 sub_address=(self.ip, self.iopub_port),
369 sub_address=(self.ip, self.iopub_port),
334 stdin_address=(self.ip, self.stdin_port),
370 stdin_address=(self.ip, self.stdin_port),
335 hb_address=(self.ip, self.hb_port),
371 hb_address=(self.ip, self.hb_port),
336 config=self.config
372 config=self.config
337 )
373 )
338 # start the kernel
374 # start the kernel
339 if not self.existing:
375 if not self.existing:
340 kwargs = dict(ip=self.ip, ipython=not self.pure)
376 kwargs = dict(ip=self.ip, ipython=not self.pure)
341 kwargs['extra_arguments'] = self.kernel_argv
377 kwargs['extra_arguments'] = self.kernel_argv
342 self.kernel_manager.start_kernel(**kwargs)
378 self.kernel_manager.start_kernel(**kwargs)
343 self.kernel_manager.start_channels()
379 self.kernel_manager.start_channels()
344
380
345
381
346 def init_qt_elements(self):
382 def init_qt_elements(self):
347 # Create the widget.
383 # Create the widget.
348 self.app = QtGui.QApplication([])
384 self.app = QtGui.QApplication([])
349 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
385 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
350 self.widget = self.widget_factory(config=self.config,
386 self.widget = self.widget_factory(config=self.config,
351 local_kernel=local_kernel)
387 local_kernel=local_kernel)
352 self.widget.kernel_manager = self.kernel_manager
388 self.widget.kernel_manager = self.kernel_manager
353 self.window = MainWindow(self.app, self.widget, self.existing,
389 self.window = MainWindow(self.app, self.widget, self.existing,
354 may_close=local_kernel,
390 may_close=local_kernel,
355 confirm_exit=self.confirm_exit)
391 confirm_exit=self.confirm_exit)
356 self.window.setWindowTitle('Python' if self.pure else 'IPython')
392 self.window.setWindowTitle('Python' if self.pure else 'IPython')
357
393
358 def init_colors(self):
394 def init_colors(self):
359 """Configure the coloring of the widget"""
395 """Configure the coloring of the widget"""
360 # Note: This will be dramatically simplified when colors
396 # Note: This will be dramatically simplified when colors
361 # are removed from the backend.
397 # are removed from the backend.
362
398
363 if self.pure:
399 if self.pure:
364 # only IPythonWidget supports styling
400 # only IPythonWidget supports styling
365 return
401 return
366
402
367 # parse the colors arg down to current known labels
403 # parse the colors arg down to current known labels
368 try:
404 try:
369 colors = self.config.ZMQInteractiveShell.colors
405 colors = self.config.ZMQInteractiveShell.colors
370 except AttributeError:
406 except AttributeError:
371 colors = None
407 colors = None
372 try:
408 try:
373 style = self.config.IPythonWidget.colors
409 style = self.config.IPythonWidget.colors
374 except AttributeError:
410 except AttributeError:
375 style = None
411 style = None
376
412
377 # find the value for colors:
413 # find the value for colors:
378 if colors:
414 if colors:
379 colors=colors.lower()
415 colors=colors.lower()
380 if colors in ('lightbg', 'light'):
416 if colors in ('lightbg', 'light'):
381 colors='lightbg'
417 colors='lightbg'
382 elif colors in ('dark', 'linux'):
418 elif colors in ('dark', 'linux'):
383 colors='linux'
419 colors='linux'
384 else:
420 else:
385 colors='nocolor'
421 colors='nocolor'
386 elif style:
422 elif style:
387 if style=='bw':
423 if style=='bw':
388 colors='nocolor'
424 colors='nocolor'
389 elif styles.dark_style(style):
425 elif styles.dark_style(style):
390 colors='linux'
426 colors='linux'
391 else:
427 else:
392 colors='lightbg'
428 colors='lightbg'
393 else:
429 else:
394 colors=None
430 colors=None
395
431
396 # Configure the style.
432 # Configure the style.
397 widget = self.widget
433 widget = self.widget
398 if style:
434 if style:
399 widget.style_sheet = styles.sheet_from_template(style, colors)
435 widget.style_sheet = styles.sheet_from_template(style, colors)
400 widget.syntax_style = style
436 widget.syntax_style = style
401 widget._syntax_style_changed()
437 widget._syntax_style_changed()
402 widget._style_sheet_changed()
438 widget._style_sheet_changed()
403 elif colors:
439 elif colors:
404 # use a default style
440 # use a default style
405 widget.set_default_style(colors=colors)
441 widget.set_default_style(colors=colors)
406 else:
442 else:
407 # this is redundant for now, but allows the widget's
443 # this is redundant for now, but allows the widget's
408 # defaults to change
444 # defaults to change
409 widget.set_default_style()
445 widget.set_default_style()
410
446
411 if self.stylesheet:
447 if self.stylesheet:
412 # we got an expicit stylesheet
448 # we got an expicit stylesheet
413 if os.path.isfile(self.stylesheet):
449 if os.path.isfile(self.stylesheet):
414 with open(self.stylesheet) as f:
450 with open(self.stylesheet) as f:
415 sheet = f.read()
451 sheet = f.read()
416 widget.style_sheet = sheet
452 widget.style_sheet = sheet
417 widget._style_sheet_changed()
453 widget._style_sheet_changed()
418 else:
454 else:
419 raise IOError("Stylesheet %r not found."%self.stylesheet)
455 raise IOError("Stylesheet %r not found."%self.stylesheet)
420
456
421 def initialize(self, argv=None):
457 def initialize(self, argv=None):
422 super(IPythonQtConsoleApp, self).initialize(argv)
458 super(IPythonQtConsoleApp, self).initialize(argv)
459 self.init_ssh()
423 self.init_kernel_manager()
460 self.init_kernel_manager()
424 self.init_qt_elements()
461 self.init_qt_elements()
425 self.init_colors()
462 self.init_colors()
426
463
427 def start(self):
464 def start(self):
428
465
429 # draw the window
466 # draw the window
430 self.window.show()
467 self.window.show()
431
468
432 # Start the application main loop.
469 # Start the application main loop.
433 self.app.exec_()
470 self.app.exec_()
434
471
435 #-----------------------------------------------------------------------------
472 #-----------------------------------------------------------------------------
436 # Main entry point
473 # Main entry point
437 #-----------------------------------------------------------------------------
474 #-----------------------------------------------------------------------------
438
475
439 def main():
476 def main():
440 app = IPythonQtConsoleApp()
477 app = IPythonQtConsoleApp()
441 app.initialize()
478 app.initialize()
442 app.start()
479 app.start()
443
480
444
481
445 if __name__ == '__main__':
482 if __name__ == '__main__':
446 main()
483 main()
General Comments 0
You need to be logged in to leave comments. Login now