##// END OF EJS Templates
add config file inheritance to kernelapp...
MinRK -
Show More
@@ -1,421 +1,422 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
23
24 # System library imports
24 # System library imports
25 from IPython.external.qt import QtGui
25 from IPython.external.qt import QtGui
26 from pygments.styles import get_all_styles
26 from pygments.styles import get_all_styles
27
27
28 # Local imports
28 # Local imports
29 from IPython.config.application import boolean_flag
29 from IPython.config.application import boolean_flag
30 from IPython.core.application import BaseIPythonApplication
30 from IPython.core.application import BaseIPythonApplication
31 from IPython.core.profiledir import ProfileDir
31 from IPython.core.profiledir import ProfileDir
32 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
32 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
33 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
33 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
34 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
34 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
35 from IPython.frontend.qt.console import styles
35 from IPython.frontend.qt.console import styles
36 from IPython.frontend.qt.kernelmanager import QtKernelManager
36 from IPython.frontend.qt.kernelmanager import QtKernelManager
37 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
38 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
38 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
39 )
39 )
40 from IPython.zmq.ipkernel import (
40 from IPython.zmq.ipkernel import (
41 flags as ipkernel_flags,
41 flags as ipkernel_flags,
42 aliases as ipkernel_aliases,
42 aliases as ipkernel_aliases,
43 IPKernelApp
43 IPKernelApp
44 )
44 )
45 from IPython.zmq.session import Session
45 from IPython.zmq.session import Session
46 from IPython.zmq.zmqshell import ZMQInteractiveShell
46 from IPython.zmq.zmqshell import ZMQInteractiveShell
47
47
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Network Constants
50 # Network Constants
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
53 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Classes
56 # Classes
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 class MainWindow(QtGui.QMainWindow):
59 class MainWindow(QtGui.QMainWindow):
60
60
61 #---------------------------------------------------------------------------
61 #---------------------------------------------------------------------------
62 # 'object' interface
62 # 'object' interface
63 #---------------------------------------------------------------------------
63 #---------------------------------------------------------------------------
64
64
65 def __init__(self, app, frontend, existing=False, may_close=True,
65 def __init__(self, app, frontend, existing=False, may_close=True,
66 confirm_exit=True):
66 confirm_exit=True):
67 """ Create a MainWindow for the specified FrontendWidget.
67 """ Create a MainWindow for the specified FrontendWidget.
68
68
69 The app is passed as an argument to allow for different
69 The app is passed as an argument to allow for different
70 closing behavior depending on whether we are the Kernel's parent.
70 closing behavior depending on whether we are the Kernel's parent.
71
71
72 If existing is True, then this Console does not own the Kernel.
72 If existing is True, then this Console does not own the Kernel.
73
73
74 If may_close is True, then this Console is permitted to close the kernel
74 If may_close is True, then this Console is permitted to close the kernel
75 """
75 """
76 super(MainWindow, self).__init__()
76 super(MainWindow, self).__init__()
77 self._app = app
77 self._app = app
78 self._frontend = frontend
78 self._frontend = frontend
79 self._existing = existing
79 self._existing = existing
80 if existing:
80 if existing:
81 self._may_close = may_close
81 self._may_close = may_close
82 else:
82 else:
83 self._may_close = True
83 self._may_close = True
84 self._frontend.exit_requested.connect(self.close)
84 self._frontend.exit_requested.connect(self.close)
85 self._confirm_exit = confirm_exit
85 self._confirm_exit = confirm_exit
86 self.setCentralWidget(frontend)
86 self.setCentralWidget(frontend)
87
87
88 #---------------------------------------------------------------------------
88 #---------------------------------------------------------------------------
89 # QWidget interface
89 # QWidget interface
90 #---------------------------------------------------------------------------
90 #---------------------------------------------------------------------------
91
91
92 def closeEvent(self, event):
92 def closeEvent(self, event):
93 """ Close the window and the kernel (if necessary).
93 """ Close the window and the kernel (if necessary).
94
94
95 This will prompt the user if they are finished with the kernel, and if
95 This will prompt the user if they are finished with the kernel, and if
96 so, closes the kernel cleanly. Alternatively, if the exit magic is used,
96 so, closes the kernel cleanly. Alternatively, if the exit magic is used,
97 it closes without prompt.
97 it closes without prompt.
98 """
98 """
99 keepkernel = None #Use the prompt by default
99 keepkernel = None #Use the prompt by default
100 if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic
100 if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic
101 keepkernel = self._frontend._keep_kernel_on_exit
101 keepkernel = self._frontend._keep_kernel_on_exit
102
102
103 kernel_manager = self._frontend.kernel_manager
103 kernel_manager = self._frontend.kernel_manager
104
104
105 if keepkernel is None and not self._confirm_exit:
105 if keepkernel is None and not self._confirm_exit:
106 # don't prompt, just terminate the kernel if we own it
106 # don't prompt, just terminate the kernel if we own it
107 # or leave it alone if we don't
107 # or leave it alone if we don't
108 keepkernel = not self._existing
108 keepkernel = not self._existing
109
109
110 if keepkernel is None: #show prompt
110 if keepkernel is None: #show prompt
111 if kernel_manager and kernel_manager.channels_running:
111 if kernel_manager and kernel_manager.channels_running:
112 title = self.window().windowTitle()
112 title = self.window().windowTitle()
113 cancel = QtGui.QMessageBox.Cancel
113 cancel = QtGui.QMessageBox.Cancel
114 okay = QtGui.QMessageBox.Ok
114 okay = QtGui.QMessageBox.Ok
115 if self._may_close:
115 if self._may_close:
116 msg = "You are closing this Console window."
116 msg = "You are closing this Console window."
117 info = "Would you like to quit the Kernel and all attached Consoles as well?"
117 info = "Would you like to quit the Kernel and all attached Consoles as well?"
118 justthis = QtGui.QPushButton("&No, just this Console", self)
118 justthis = QtGui.QPushButton("&No, just this Console", self)
119 justthis.setShortcut('N')
119 justthis.setShortcut('N')
120 closeall = QtGui.QPushButton("&Yes, quit everything", self)
120 closeall = QtGui.QPushButton("&Yes, quit everything", self)
121 closeall.setShortcut('Y')
121 closeall.setShortcut('Y')
122 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
122 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
123 title, msg)
123 title, msg)
124 box.setInformativeText(info)
124 box.setInformativeText(info)
125 box.addButton(cancel)
125 box.addButton(cancel)
126 box.addButton(justthis, QtGui.QMessageBox.NoRole)
126 box.addButton(justthis, QtGui.QMessageBox.NoRole)
127 box.addButton(closeall, QtGui.QMessageBox.YesRole)
127 box.addButton(closeall, QtGui.QMessageBox.YesRole)
128 box.setDefaultButton(closeall)
128 box.setDefaultButton(closeall)
129 box.setEscapeButton(cancel)
129 box.setEscapeButton(cancel)
130 reply = box.exec_()
130 reply = box.exec_()
131 if reply == 1: # close All
131 if reply == 1: # close All
132 kernel_manager.shutdown_kernel()
132 kernel_manager.shutdown_kernel()
133 #kernel_manager.stop_channels()
133 #kernel_manager.stop_channels()
134 event.accept()
134 event.accept()
135 elif reply == 0: # close Console
135 elif reply == 0: # close Console
136 if not self._existing:
136 if not self._existing:
137 # Have kernel: don't quit, just close the window
137 # Have kernel: don't quit, just close the window
138 self._app.setQuitOnLastWindowClosed(False)
138 self._app.setQuitOnLastWindowClosed(False)
139 self.deleteLater()
139 self.deleteLater()
140 event.accept()
140 event.accept()
141 else:
141 else:
142 event.ignore()
142 event.ignore()
143 else:
143 else:
144 reply = QtGui.QMessageBox.question(self, title,
144 reply = QtGui.QMessageBox.question(self, title,
145 "Are you sure you want to close this Console?"+
145 "Are you sure you want to close this Console?"+
146 "\nThe Kernel and other Consoles will remain active.",
146 "\nThe Kernel and other Consoles will remain active.",
147 okay|cancel,
147 okay|cancel,
148 defaultButton=okay
148 defaultButton=okay
149 )
149 )
150 if reply == okay:
150 if reply == okay:
151 event.accept()
151 event.accept()
152 else:
152 else:
153 event.ignore()
153 event.ignore()
154 elif keepkernel: #close console but leave kernel running (no prompt)
154 elif keepkernel: #close console but leave kernel running (no prompt)
155 if kernel_manager and kernel_manager.channels_running:
155 if kernel_manager and kernel_manager.channels_running:
156 if not self._existing:
156 if not self._existing:
157 # I have the kernel: don't quit, just close the window
157 # I have the kernel: don't quit, just close the window
158 self._app.setQuitOnLastWindowClosed(False)
158 self._app.setQuitOnLastWindowClosed(False)
159 event.accept()
159 event.accept()
160 else: #close console and kernel (no prompt)
160 else: #close console and kernel (no prompt)
161 if kernel_manager and kernel_manager.channels_running:
161 if kernel_manager and kernel_manager.channels_running:
162 kernel_manager.shutdown_kernel()
162 kernel_manager.shutdown_kernel()
163 event.accept()
163 event.accept()
164
164
165 #-----------------------------------------------------------------------------
165 #-----------------------------------------------------------------------------
166 # Aliases and Flags
166 # Aliases and Flags
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168
168
169 flags = dict(ipkernel_flags)
169 flags = dict(ipkernel_flags)
170
170
171 flags.update({
171 flags.update({
172 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
172 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
173 "Connect to an existing kernel."),
173 "Connect to an existing kernel."),
174 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
174 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
175 "Use a pure Python kernel instead of an IPython kernel."),
175 "Use a pure Python kernel instead of an IPython kernel."),
176 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
176 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
177 "Disable rich text support."),
177 "Disable rich text support."),
178 })
178 })
179 flags.update(boolean_flag(
179 flags.update(boolean_flag(
180 'gui-completion', 'ConsoleWidget.gui_completion',
180 'gui-completion', 'ConsoleWidget.gui_completion',
181 "use a GUI widget for tab completion",
181 "use a GUI widget for tab completion",
182 "use plaintext output for completion"
182 "use plaintext output for completion"
183 ))
183 ))
184 flags.update(boolean_flag(
184 flags.update(boolean_flag(
185 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
185 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
186 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
186 """Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
187 to force a direct exit without any confirmation.
187 to force a direct exit without any confirmation.
188 """,
188 """,
189 """Don't prompt the user when exiting. This will terminate the kernel
189 """Don't prompt the user when exiting. This will terminate the kernel
190 if it is owned by the frontend, and leave it alive if it is external.
190 if it is owned by the frontend, and leave it alive if it is external.
191 """
191 """
192 ))
192 ))
193 # the flags that are specific to the frontend
193 # the flags that are specific to the frontend
194 # these must be scrubbed before being passed to the kernel,
194 # these must be scrubbed before being passed to the kernel,
195 # or it will raise an error on unrecognized flags
195 # or it will raise an error on unrecognized flags
196 qt_flags = ['existing', 'pure', 'plain', 'gui-completion', 'no-gui-completion',
196 qt_flags = ['existing', 'pure', 'plain', 'gui-completion', 'no-gui-completion',
197 'confirm-exit', 'no-confirm-exit']
197 'confirm-exit', 'no-confirm-exit']
198
198
199 aliases = dict(ipkernel_aliases)
199 aliases = dict(ipkernel_aliases)
200
200
201 aliases.update(dict(
201 aliases.update(dict(
202 hb = 'IPythonQtConsoleApp.hb_port',
202 hb = 'IPythonQtConsoleApp.hb_port',
203 shell = 'IPythonQtConsoleApp.shell_port',
203 shell = 'IPythonQtConsoleApp.shell_port',
204 iopub = 'IPythonQtConsoleApp.iopub_port',
204 iopub = 'IPythonQtConsoleApp.iopub_port',
205 stdin = 'IPythonQtConsoleApp.stdin_port',
205 stdin = 'IPythonQtConsoleApp.stdin_port',
206 ip = 'IPythonQtConsoleApp.ip',
206 ip = 'IPythonQtConsoleApp.ip',
207
207
208 plain = 'IPythonQtConsoleApp.plain',
208 plain = 'IPythonQtConsoleApp.plain',
209 pure = 'IPythonQtConsoleApp.pure',
209 pure = 'IPythonQtConsoleApp.pure',
210 gui_completion = 'ConsoleWidget.gui_completion',
210 gui_completion = 'ConsoleWidget.gui_completion',
211 style = 'IPythonWidget.syntax_style',
211 style = 'IPythonWidget.syntax_style',
212 stylesheet = 'IPythonQtConsoleApp.stylesheet',
212 stylesheet = 'IPythonQtConsoleApp.stylesheet',
213 colors = 'ZMQInteractiveShell.colors',
213 colors = 'ZMQInteractiveShell.colors',
214
214
215 editor = 'IPythonWidget.editor',
215 editor = 'IPythonWidget.editor',
216 ))
216 ))
217
217
218 #-----------------------------------------------------------------------------
218 #-----------------------------------------------------------------------------
219 # IPythonQtConsole
219 # IPythonQtConsole
220 #-----------------------------------------------------------------------------
220 #-----------------------------------------------------------------------------
221 class IPythonQtConsoleApp(BaseIPythonApplication):
221 class IPythonQtConsoleApp(BaseIPythonApplication):
222 name = 'ipython-qtconsole'
222 name = 'ipython-qtconsole'
223 default_config_file_name='ipython_config.py'
223 default_config_file_name='ipython_config.py'
224
224
225 description = """
225 description = """
226 The IPython QtConsole.
226 The IPython QtConsole.
227
227
228 This launches a Console-style application using Qt. It is not a full
228 This launches a Console-style application using Qt. It is not a full
229 console, in that launched terminal subprocesses will not.
229 console, in that launched terminal subprocesses will not.
230
230
231 The QtConsole supports various extra features beyond the
231 The QtConsole supports various extra features beyond the
232
232
233 """
233 """
234
234
235 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
235 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
236 flags = Dict(flags)
236 flags = Dict(flags)
237 aliases = Dict(aliases)
237 aliases = Dict(aliases)
238
238
239 kernel_argv = List(Unicode)
239 kernel_argv = List(Unicode)
240
240
241 # connection info:
241 # connection info:
242 ip = Unicode(LOCALHOST, config=True,
242 ip = Unicode(LOCALHOST, config=True,
243 help="""Set the kernel\'s IP address [default localhost].
243 help="""Set the kernel\'s IP address [default localhost].
244 If the IP address is something other than localhost, then
244 If the IP address is something other than localhost, then
245 Consoles on other machines will be able to connect
245 Consoles on other machines will be able to connect
246 to the Kernel, so be careful!"""
246 to the Kernel, so be careful!"""
247 )
247 )
248 hb_port = Int(0, config=True,
248 hb_port = Int(0, config=True,
249 help="set the heartbeat port [default: random]")
249 help="set the heartbeat port [default: random]")
250 shell_port = Int(0, config=True,
250 shell_port = Int(0, config=True,
251 help="set the shell (XREP) port [default: random]")
251 help="set the shell (XREP) port [default: random]")
252 iopub_port = Int(0, config=True,
252 iopub_port = Int(0, config=True,
253 help="set the iopub (PUB) port [default: random]")
253 help="set the iopub (PUB) port [default: random]")
254 stdin_port = Int(0, config=True,
254 stdin_port = Int(0, config=True,
255 help="set the stdin (XREQ) port [default: random]")
255 help="set the stdin (XREQ) port [default: random]")
256
256
257 existing = CBool(False, config=True,
257 existing = CBool(False, config=True,
258 help="Whether to connect to an already running Kernel.")
258 help="Whether to connect to an already running Kernel.")
259
259
260 stylesheet = Unicode('', config=True,
260 stylesheet = Unicode('', config=True,
261 help="path to a custom CSS stylesheet")
261 help="path to a custom CSS stylesheet")
262
262
263 pure = CBool(False, config=True,
263 pure = CBool(False, config=True,
264 help="Use a pure Python kernel instead of an IPython kernel.")
264 help="Use a pure Python kernel instead of an IPython kernel.")
265 plain = CBool(False, config=True,
265 plain = CBool(False, config=True,
266 help="Use a plaintext widget instead of rich text (plain can't print/save).")
266 help="Use a plaintext widget instead of rich text (plain can't print/save).")
267
267
268 def _pure_changed(self, name, old, new):
268 def _pure_changed(self, name, old, new):
269 kind = 'plain' if self.plain else 'rich'
269 kind = 'plain' if self.plain else 'rich'
270 self.config.ConsoleWidget.kind = kind
270 self.config.ConsoleWidget.kind = kind
271 if self.pure:
271 if self.pure:
272 self.widget_factory = FrontendWidget
272 self.widget_factory = FrontendWidget
273 elif self.plain:
273 elif self.plain:
274 self.widget_factory = IPythonWidget
274 self.widget_factory = IPythonWidget
275 else:
275 else:
276 self.widget_factory = RichIPythonWidget
276 self.widget_factory = RichIPythonWidget
277
277
278 _plain_changed = _pure_changed
278 _plain_changed = _pure_changed
279
279
280 confirm_exit = CBool(True, config=True,
280 confirm_exit = CBool(True, config=True,
281 help="""
281 help="""
282 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
282 Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
283 to force a direct exit without any confirmation.""",
283 to force a direct exit without any confirmation.""",
284 )
284 )
285
285
286 # the factory for creating a widget
286 # the factory for creating a widget
287 widget_factory = Any(RichIPythonWidget)
287 widget_factory = Any(RichIPythonWidget)
288
288
289 def parse_command_line(self, argv=None):
289 def parse_command_line(self, argv=None):
290 super(IPythonQtConsoleApp, self).parse_command_line(argv)
290 super(IPythonQtConsoleApp, self).parse_command_line(argv)
291 if argv is None:
291 if argv is None:
292 argv = sys.argv[1:]
292 argv = sys.argv[1:]
293
293
294 self.kernel_argv = list(argv) # copy
294 self.kernel_argv = list(argv) # copy
295
295 # kernel should inherit default config file from frontend
296 self.kernel_argv.append("KernelApp.parent_appname='%s'"%self.name)
296 # scrub frontend-specific flags
297 # scrub frontend-specific flags
297 for a in argv:
298 for a in argv:
298 if a.startswith('--') and a[2:] in qt_flags:
299 if a.startswith('--') and a[2:] in qt_flags:
299 self.kernel_argv.remove(a)
300 self.kernel_argv.remove(a)
300
301
301 def init_kernel_manager(self):
302 def init_kernel_manager(self):
302 # Don't let Qt or ZMQ swallow KeyboardInterupts.
303 # Don't let Qt or ZMQ swallow KeyboardInterupts.
303 signal.signal(signal.SIGINT, signal.SIG_DFL)
304 signal.signal(signal.SIGINT, signal.SIG_DFL)
304
305
305 # Create a KernelManager and start a kernel.
306 # Create a KernelManager and start a kernel.
306 self.kernel_manager = QtKernelManager(
307 self.kernel_manager = QtKernelManager(
307 shell_address=(self.ip, self.shell_port),
308 shell_address=(self.ip, self.shell_port),
308 sub_address=(self.ip, self.iopub_port),
309 sub_address=(self.ip, self.iopub_port),
309 stdin_address=(self.ip, self.stdin_port),
310 stdin_address=(self.ip, self.stdin_port),
310 hb_address=(self.ip, self.hb_port),
311 hb_address=(self.ip, self.hb_port),
311 config=self.config
312 config=self.config
312 )
313 )
313 # start the kernel
314 # start the kernel
314 if not self.existing:
315 if not self.existing:
315 kwargs = dict(ip=self.ip, ipython=not self.pure)
316 kwargs = dict(ip=self.ip, ipython=not self.pure)
316 kwargs['extra_arguments'] = self.kernel_argv
317 kwargs['extra_arguments'] = self.kernel_argv
317 self.kernel_manager.start_kernel(**kwargs)
318 self.kernel_manager.start_kernel(**kwargs)
318 self.kernel_manager.start_channels()
319 self.kernel_manager.start_channels()
319
320
320
321
321 def init_qt_elements(self):
322 def init_qt_elements(self):
322 # Create the widget.
323 # Create the widget.
323 self.app = QtGui.QApplication([])
324 self.app = QtGui.QApplication([])
324 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
325 local_kernel = (not self.existing) or self.ip in LOCAL_IPS
325 self.widget = self.widget_factory(config=self.config,
326 self.widget = self.widget_factory(config=self.config,
326 local_kernel=local_kernel)
327 local_kernel=local_kernel)
327 self.widget.kernel_manager = self.kernel_manager
328 self.widget.kernel_manager = self.kernel_manager
328 self.window = MainWindow(self.app, self.widget, self.existing,
329 self.window = MainWindow(self.app, self.widget, self.existing,
329 may_close=local_kernel,
330 may_close=local_kernel,
330 confirm_exit=self.confirm_exit)
331 confirm_exit=self.confirm_exit)
331 self.window.setWindowTitle('Python' if self.pure else 'IPython')
332 self.window.setWindowTitle('Python' if self.pure else 'IPython')
332
333
333 def init_colors(self):
334 def init_colors(self):
334 """Configure the coloring of the widget"""
335 """Configure the coloring of the widget"""
335 # Note: This will be dramatically simplified when colors
336 # Note: This will be dramatically simplified when colors
336 # are removed from the backend.
337 # are removed from the backend.
337
338
338 if self.pure:
339 if self.pure:
339 # only IPythonWidget supports styling
340 # only IPythonWidget supports styling
340 return
341 return
341
342
342 # parse the colors arg down to current known labels
343 # parse the colors arg down to current known labels
343 try:
344 try:
344 colors = self.config.ZMQInteractiveShell.colors
345 colors = self.config.ZMQInteractiveShell.colors
345 except AttributeError:
346 except AttributeError:
346 colors = None
347 colors = None
347 try:
348 try:
348 style = self.config.IPythonWidget.colors
349 style = self.config.IPythonWidget.colors
349 except AttributeError:
350 except AttributeError:
350 style = None
351 style = None
351
352
352 # find the value for colors:
353 # find the value for colors:
353 if colors:
354 if colors:
354 colors=colors.lower()
355 colors=colors.lower()
355 if colors in ('lightbg', 'light'):
356 if colors in ('lightbg', 'light'):
356 colors='lightbg'
357 colors='lightbg'
357 elif colors in ('dark', 'linux'):
358 elif colors in ('dark', 'linux'):
358 colors='linux'
359 colors='linux'
359 else:
360 else:
360 colors='nocolor'
361 colors='nocolor'
361 elif style:
362 elif style:
362 if style=='bw':
363 if style=='bw':
363 colors='nocolor'
364 colors='nocolor'
364 elif styles.dark_style(style):
365 elif styles.dark_style(style):
365 colors='linux'
366 colors='linux'
366 else:
367 else:
367 colors='lightbg'
368 colors='lightbg'
368 else:
369 else:
369 colors=None
370 colors=None
370
371
371 # Configure the style.
372 # Configure the style.
372 widget = self.widget
373 widget = self.widget
373 if style:
374 if style:
374 widget.style_sheet = styles.sheet_from_template(style, colors)
375 widget.style_sheet = styles.sheet_from_template(style, colors)
375 widget.syntax_style = style
376 widget.syntax_style = style
376 widget._syntax_style_changed()
377 widget._syntax_style_changed()
377 widget._style_sheet_changed()
378 widget._style_sheet_changed()
378 elif colors:
379 elif colors:
379 # use a default style
380 # use a default style
380 widget.set_default_style(colors=colors)
381 widget.set_default_style(colors=colors)
381 else:
382 else:
382 # this is redundant for now, but allows the widget's
383 # this is redundant for now, but allows the widget's
383 # defaults to change
384 # defaults to change
384 widget.set_default_style()
385 widget.set_default_style()
385
386
386 if self.stylesheet:
387 if self.stylesheet:
387 # we got an expicit stylesheet
388 # we got an expicit stylesheet
388 if os.path.isfile(self.stylesheet):
389 if os.path.isfile(self.stylesheet):
389 with open(self.stylesheet) as f:
390 with open(self.stylesheet) as f:
390 sheet = f.read()
391 sheet = f.read()
391 widget.style_sheet = sheet
392 widget.style_sheet = sheet
392 widget._style_sheet_changed()
393 widget._style_sheet_changed()
393 else:
394 else:
394 raise IOError("Stylesheet %r not found."%self.stylesheet)
395 raise IOError("Stylesheet %r not found."%self.stylesheet)
395
396
396 def initialize(self, argv=None):
397 def initialize(self, argv=None):
397 super(IPythonQtConsoleApp, self).initialize(argv)
398 super(IPythonQtConsoleApp, self).initialize(argv)
398 self.init_kernel_manager()
399 self.init_kernel_manager()
399 self.init_qt_elements()
400 self.init_qt_elements()
400 self.init_colors()
401 self.init_colors()
401
402
402 def start(self):
403 def start(self):
403
404
404 # draw the window
405 # draw the window
405 self.window.show()
406 self.window.show()
406
407
407 # Start the application main loop.
408 # Start the application main loop.
408 self.app.exec_()
409 self.app.exec_()
409
410
410 #-----------------------------------------------------------------------------
411 #-----------------------------------------------------------------------------
411 # Main entry point
412 # Main entry point
412 #-----------------------------------------------------------------------------
413 #-----------------------------------------------------------------------------
413
414
414 def main():
415 def main():
415 app = IPythonQtConsoleApp()
416 app = IPythonQtConsoleApp()
416 app.initialize()
417 app.initialize()
417 app.start()
418 app.start()
418
419
419
420
420 if __name__ == '__main__':
421 if __name__ == '__main__':
421 main()
422 main()
@@ -1,216 +1,226 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """An Application for launching a kernel
2 """An Application for launching a kernel
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * MinRK
6 * MinRK
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING.txt, distributed as part of this software.
12 # the file COPYING.txt, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Standard library imports.
19 # Standard library imports.
20 import os
20 import os
21 import sys
21 import sys
22
22
23 # System library imports.
23 # System library imports.
24 import zmq
24 import zmq
25
25
26 # IPython imports.
26 # IPython imports.
27 from IPython.core.ultratb import FormattedTB
27 from IPython.core.ultratb import FormattedTB
28 from IPython.core.application import (
28 from IPython.core.application import (
29 BaseIPythonApplication, base_flags, base_aliases
29 BaseIPythonApplication, base_flags, base_aliases
30 )
30 )
31 from IPython.utils import io
31 from IPython.utils import io
32 from IPython.utils.localinterfaces import LOCALHOST
32 from IPython.utils.localinterfaces import LOCALHOST
33 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
33 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
34 DottedObjectName)
34 DottedObjectName)
35 from IPython.utils.importstring import import_item
35 from IPython.utils.importstring import import_item
36 # local imports
36 # local imports
37 from IPython.zmq.heartbeat import Heartbeat
37 from IPython.zmq.heartbeat import Heartbeat
38 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
38 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
39 from IPython.zmq.session import Session
39 from IPython.zmq.session import Session
40
40
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Flags and Aliases
43 # Flags and Aliases
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 kernel_aliases = dict(base_aliases)
46 kernel_aliases = dict(base_aliases)
47 kernel_aliases.update({
47 kernel_aliases.update({
48 'ip' : 'KernelApp.ip',
48 'ip' : 'KernelApp.ip',
49 'hb' : 'KernelApp.hb_port',
49 'hb' : 'KernelApp.hb_port',
50 'shell' : 'KernelApp.shell_port',
50 'shell' : 'KernelApp.shell_port',
51 'iopub' : 'KernelApp.iopub_port',
51 'iopub' : 'KernelApp.iopub_port',
52 'stdin' : 'KernelApp.stdin_port',
52 'stdin' : 'KernelApp.stdin_port',
53 'parent': 'KernelApp.parent',
53 'parent': 'KernelApp.parent',
54 })
54 })
55 if sys.platform.startswith('win'):
55 if sys.platform.startswith('win'):
56 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
56 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
57
57
58 kernel_flags = dict(base_flags)
58 kernel_flags = dict(base_flags)
59 kernel_flags.update({
59 kernel_flags.update({
60 'no-stdout' : (
60 'no-stdout' : (
61 {'KernelApp' : {'no_stdout' : True}},
61 {'KernelApp' : {'no_stdout' : True}},
62 "redirect stdout to the null device"),
62 "redirect stdout to the null device"),
63 'no-stderr' : (
63 'no-stderr' : (
64 {'KernelApp' : {'no_stderr' : True}},
64 {'KernelApp' : {'no_stderr' : True}},
65 "redirect stderr to the null device"),
65 "redirect stderr to the null device"),
66 })
66 })
67
67
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # Application class for starting a Kernel
70 # Application class for starting a Kernel
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73 class KernelApp(BaseIPythonApplication):
73 class KernelApp(BaseIPythonApplication):
74 name='pykernel'
74 name='pykernel'
75 aliases = Dict(kernel_aliases)
75 aliases = Dict(kernel_aliases)
76 flags = Dict(kernel_flags)
76 flags = Dict(kernel_flags)
77 classes = [Session]
77 classes = [Session]
78 # the kernel class, as an importstring
78 # the kernel class, as an importstring
79 kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel')
79 kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel')
80 kernel = Any()
80 kernel = Any()
81 poller = Any() # don't restrict this even though current pollers are all Threads
81 poller = Any() # don't restrict this even though current pollers are all Threads
82 heartbeat = Instance(Heartbeat)
82 heartbeat = Instance(Heartbeat)
83 session = Instance('IPython.zmq.session.Session')
83 session = Instance('IPython.zmq.session.Session')
84 ports = Dict()
84 ports = Dict()
85
85
86 # inherit config file name from parent:
87 parent_appname = Unicode(config=True)
88 def _parent_appname_changed(self, name, old, new):
89 if self.config_file_specified:
90 # it was manually specified, ignore
91 return
92 self.config_file_name = new.replace('-','_') + u'_config.py'
93 # don't let this count as specifying the config file
94 self.config_file_specified = False
95
86 # connection info:
96 # connection info:
87 ip = Unicode(LOCALHOST, config=True,
97 ip = Unicode(LOCALHOST, config=True,
88 help="Set the IP or interface on which the kernel will listen.")
98 help="Set the IP or interface on which the kernel will listen.")
89 hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
99 hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
90 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
100 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
91 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
101 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
92 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
102 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
93
103
94 # streams, etc.
104 # streams, etc.
95 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
105 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
96 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
106 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
97 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
107 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
98 config=True, help="The importstring for the OutStream factory")
108 config=True, help="The importstring for the OutStream factory")
99 displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook',
109 displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook',
100 config=True, help="The importstring for the DisplayHook factory")
110 config=True, help="The importstring for the DisplayHook factory")
101
111
102 # polling
112 # polling
103 parent = Int(0, config=True,
113 parent = Int(0, config=True,
104 help="""kill this process if its parent dies. On Windows, the argument
114 help="""kill this process if its parent dies. On Windows, the argument
105 specifies the HANDLE of the parent process, otherwise it is simply boolean.
115 specifies the HANDLE of the parent process, otherwise it is simply boolean.
106 """)
116 """)
107 interrupt = Int(0, config=True,
117 interrupt = Int(0, config=True,
108 help="""ONLY USED ON WINDOWS
118 help="""ONLY USED ON WINDOWS
109 Interrupt this process when the parent is signalled.
119 Interrupt this process when the parent is signalled.
110 """)
120 """)
111
121
112 def init_crash_handler(self):
122 def init_crash_handler(self):
113 # Install minimal exception handling
123 # Install minimal exception handling
114 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
124 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
115 ostream=sys.__stdout__)
125 ostream=sys.__stdout__)
116
126
117 def init_poller(self):
127 def init_poller(self):
118 if sys.platform == 'win32':
128 if sys.platform == 'win32':
119 if self.interrupt or self.parent:
129 if self.interrupt or self.parent:
120 self.poller = ParentPollerWindows(self.interrupt, self.parent)
130 self.poller = ParentPollerWindows(self.interrupt, self.parent)
121 elif self.parent:
131 elif self.parent:
122 self.poller = ParentPollerUnix()
132 self.poller = ParentPollerUnix()
123
133
124 def _bind_socket(self, s, port):
134 def _bind_socket(self, s, port):
125 iface = 'tcp://%s' % self.ip
135 iface = 'tcp://%s' % self.ip
126 if port <= 0:
136 if port <= 0:
127 port = s.bind_to_random_port(iface)
137 port = s.bind_to_random_port(iface)
128 else:
138 else:
129 s.bind(iface + ':%i'%port)
139 s.bind(iface + ':%i'%port)
130 return port
140 return port
131
141
132 def init_sockets(self):
142 def init_sockets(self):
133 # Create a context, a session, and the kernel sockets.
143 # Create a context, a session, and the kernel sockets.
134 io.raw_print("Starting the kernel at pid:", os.getpid())
144 io.raw_print("Starting the kernel at pid:", os.getpid())
135 context = zmq.Context.instance()
145 context = zmq.Context.instance()
136 # Uncomment this to try closing the context.
146 # Uncomment this to try closing the context.
137 # atexit.register(context.term)
147 # atexit.register(context.term)
138
148
139 self.shell_socket = context.socket(zmq.XREP)
149 self.shell_socket = context.socket(zmq.XREP)
140 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
150 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
141 self.log.debug("shell XREP Channel on port: %i"%self.shell_port)
151 self.log.debug("shell XREP Channel on port: %i"%self.shell_port)
142
152
143 self.iopub_socket = context.socket(zmq.PUB)
153 self.iopub_socket = context.socket(zmq.PUB)
144 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
154 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
145 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
155 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
146
156
147 self.stdin_socket = context.socket(zmq.XREQ)
157 self.stdin_socket = context.socket(zmq.XREQ)
148 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
158 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
149 self.log.debug("stdin XREQ Channel on port: %i"%self.stdin_port)
159 self.log.debug("stdin XREQ Channel on port: %i"%self.stdin_port)
150
160
151 self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
161 self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
152 self.hb_port = self.heartbeat.port
162 self.hb_port = self.heartbeat.port
153 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
163 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
154
164
155 # Helper to make it easier to connect to an existing kernel, until we have
165 # Helper to make it easier to connect to an existing kernel, until we have
156 # single-port connection negotiation fully implemented.
166 # single-port connection negotiation fully implemented.
157 self.log.info("To connect another client to this kernel, use:")
167 self.log.info("To connect another client to this kernel, use:")
158 self.log.info("--external shell={0} iopub={1} stdin={2} hb={3}".format(
168 self.log.info("--external shell={0} iopub={1} stdin={2} hb={3}".format(
159 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port))
169 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port))
160
170
161
171
162 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
172 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
163 stdin=self.stdin_port, hb=self.hb_port)
173 stdin=self.stdin_port, hb=self.hb_port)
164
174
165 def init_session(self):
175 def init_session(self):
166 """create our session object"""
176 """create our session object"""
167 self.session = Session(config=self.config, username=u'kernel')
177 self.session = Session(config=self.config, username=u'kernel')
168
178
169 def init_blackhole(self):
179 def init_blackhole(self):
170 """redirects stdout/stderr to devnull if necessary"""
180 """redirects stdout/stderr to devnull if necessary"""
171 if self.no_stdout or self.no_stderr:
181 if self.no_stdout or self.no_stderr:
172 blackhole = file(os.devnull, 'w')
182 blackhole = file(os.devnull, 'w')
173 if self.no_stdout:
183 if self.no_stdout:
174 sys.stdout = sys.__stdout__ = blackhole
184 sys.stdout = sys.__stdout__ = blackhole
175 if self.no_stderr:
185 if self.no_stderr:
176 sys.stderr = sys.__stderr__ = blackhole
186 sys.stderr = sys.__stderr__ = blackhole
177
187
178 def init_io(self):
188 def init_io(self):
179 """Redirect input streams and set a display hook."""
189 """Redirect input streams and set a display hook."""
180 if self.outstream_class:
190 if self.outstream_class:
181 outstream_factory = import_item(str(self.outstream_class))
191 outstream_factory = import_item(str(self.outstream_class))
182 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
192 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
183 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
193 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
184 if self.displayhook_class:
194 if self.displayhook_class:
185 displayhook_factory = import_item(str(self.displayhook_class))
195 displayhook_factory = import_item(str(self.displayhook_class))
186 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
196 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
187
197
188 def init_kernel(self):
198 def init_kernel(self):
189 """Create the Kernel object itself"""
199 """Create the Kernel object itself"""
190 kernel_factory = import_item(str(self.kernel_class))
200 kernel_factory = import_item(str(self.kernel_class))
191 self.kernel = kernel_factory(config=self.config, session=self.session,
201 self.kernel = kernel_factory(config=self.config, session=self.session,
192 shell_socket=self.shell_socket,
202 shell_socket=self.shell_socket,
193 iopub_socket=self.iopub_socket,
203 iopub_socket=self.iopub_socket,
194 stdin_socket=self.stdin_socket,
204 stdin_socket=self.stdin_socket,
195 log=self.log
205 log=self.log
196 )
206 )
197 self.kernel.record_ports(self.ports)
207 self.kernel.record_ports(self.ports)
198
208
199 def initialize(self, argv=None):
209 def initialize(self, argv=None):
200 super(KernelApp, self).initialize(argv)
210 super(KernelApp, self).initialize(argv)
201 self.init_blackhole()
211 self.init_blackhole()
202 self.init_session()
212 self.init_session()
203 self.init_poller()
213 self.init_poller()
204 self.init_sockets()
214 self.init_sockets()
205 self.init_io()
215 self.init_io()
206 self.init_kernel()
216 self.init_kernel()
207
217
208 def start(self):
218 def start(self):
209 self.heartbeat.start()
219 self.heartbeat.start()
210 if self.poller is not None:
220 if self.poller is not None:
211 self.poller.start()
221 self.poller.start()
212 try:
222 try:
213 self.kernel.start()
223 self.kernel.start()
214 except KeyboardInterrupt:
224 except KeyboardInterrupt:
215 pass
225 pass
216
226
General Comments 0
You need to be logged in to leave comments. Login now