##// END OF EJS Templates
Updated display_banner help message...
Helen ST -
Show More
@@ -1,384 +1,384 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
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 14 # stdlib imports
15 15 import os
16 16 import signal
17 17 import sys
18 18
19 19 # If run on Windows, install an exception hook which pops up a
20 20 # message box. Pythonw.exe hides the console, so without this
21 21 # the application silently fails to load.
22 22 #
23 23 # We always install this handler, because the expectation is for
24 24 # qtconsole to bring up a GUI even if called from the console.
25 25 # The old handler is called, so the exception is printed as well.
26 26 # If desired, check for pythonw with an additional condition
27 27 # (sys.executable.lower().find('pythonw.exe') >= 0).
28 28 if os.name == 'nt':
29 29 old_excepthook = sys.excepthook
30 30
31 31 # Exclude this from our autogenerated API docs.
32 32 undoc = lambda func: func
33 33
34 34 @undoc
35 35 def gui_excepthook(exctype, value, tb):
36 36 try:
37 37 import ctypes, traceback
38 38 MB_ICONERROR = 0x00000010
39 39 title = u'Error starting IPython QtConsole'
40 40 msg = u''.join(traceback.format_exception(exctype, value, tb))
41 41 ctypes.windll.user32.MessageBoxW(0, msg, title, MB_ICONERROR)
42 42 finally:
43 43 # Also call the old exception hook to let it do
44 44 # its thing too.
45 45 old_excepthook(exctype, value, tb)
46 46
47 47 sys.excepthook = gui_excepthook
48 48
49 49 # System library imports
50 50 from IPython.external.qt import QtCore, QtGui
51 51
52 52 # Local imports
53 53 from IPython.config.application import boolean_flag
54 54 from IPython.config.application import catch_config_error
55 55 from IPython.core.application import BaseIPythonApplication
56 56 from IPython.qt.console.ipython_widget import IPythonWidget
57 57 from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
58 58 from IPython.qt.console import styles
59 59 from IPython.qt.console.mainwindow import MainWindow
60 60 from IPython.qt.client import QtKernelClient
61 61 from IPython.qt.manager import QtKernelManager
62 62 from IPython.utils.traitlets import (
63 63 Dict, Unicode, CBool, Any
64 64 )
65 65
66 66 from IPython.consoleapp import (
67 67 IPythonConsoleApp, app_aliases, app_flags, flags, aliases
68 68 )
69 69
70 70 #-----------------------------------------------------------------------------
71 71 # Network Constants
72 72 #-----------------------------------------------------------------------------
73 73
74 74 from IPython.utils.localinterfaces import is_local_ip
75 75
76 76 #-----------------------------------------------------------------------------
77 77 # Globals
78 78 #-----------------------------------------------------------------------------
79 79
80 80 _examples = """
81 81 ipython qtconsole # start the qtconsole
82 82 ipython qtconsole --matplotlib=inline # start with matplotlib inline plotting mode
83 83 """
84 84
85 85 #-----------------------------------------------------------------------------
86 86 # Aliases and Flags
87 87 #-----------------------------------------------------------------------------
88 88
89 89 # start with copy of flags
90 90 flags = dict(flags)
91 91 qt_flags = {
92 92 'plain' : ({'IPythonQtConsoleApp' : {'plain' : True}},
93 93 "Disable rich text support."),
94 94 }
95 95 qt_flags.update(boolean_flag(
96 96 'banner', 'IPythonQtConsoleApp.display_banner',
97 97 "Display a banner upon starting the QtConsole.",
98 98 "Don't display a banner upon starting the QtConsole."
99 99 ))
100 100
101 101 # and app_flags from the Console Mixin
102 102 qt_flags.update(app_flags)
103 103 # add frontend flags to the full set
104 104 flags.update(qt_flags)
105 105
106 106 # start with copy of front&backend aliases list
107 107 aliases = dict(aliases)
108 108 qt_aliases = dict(
109 109 style = 'IPythonWidget.syntax_style',
110 110 stylesheet = 'IPythonQtConsoleApp.stylesheet',
111 111 colors = 'ZMQInteractiveShell.colors',
112 112
113 113 editor = 'IPythonWidget.editor',
114 114 paging = 'ConsoleWidget.paging',
115 115 )
116 116 # and app_aliases from the Console Mixin
117 117 qt_aliases.update(app_aliases)
118 118 qt_aliases.update({'gui-completion':'ConsoleWidget.gui_completion'})
119 119 # add frontend aliases to the full set
120 120 aliases.update(qt_aliases)
121 121
122 122 # get flags&aliases into sets, and remove a couple that
123 123 # shouldn't be scrubbed from backend flags:
124 124 qt_aliases = set(qt_aliases.keys())
125 125 qt_aliases.remove('colors')
126 126 qt_flags = set(qt_flags.keys())
127 127
128 128 #-----------------------------------------------------------------------------
129 129 # Classes
130 130 #-----------------------------------------------------------------------------
131 131
132 132 #-----------------------------------------------------------------------------
133 133 # IPythonQtConsole
134 134 #-----------------------------------------------------------------------------
135 135
136 136
137 137 class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):
138 138 name = 'ipython-qtconsole'
139 139
140 140 description = """
141 141 The IPython QtConsole.
142 142
143 143 This launches a Console-style application using Qt. It is not a full
144 144 console, in that launched terminal subprocesses will not be able to accept
145 145 input.
146 146
147 147 The QtConsole supports various extra features beyond the Terminal IPython
148 148 shell, such as inline plotting with matplotlib, via:
149 149
150 150 ipython qtconsole --matplotlib=inline
151 151
152 152 as well as saving your session as HTML, and printing the output.
153 153
154 154 """
155 155 examples = _examples
156 156
157 157 classes = [IPythonWidget] + IPythonConsoleApp.classes
158 158 flags = Dict(flags)
159 159 aliases = Dict(aliases)
160 160 frontend_flags = Any(qt_flags)
161 161 frontend_aliases = Any(qt_aliases)
162 162 kernel_client_class = QtKernelClient
163 163 kernel_manager_class = QtKernelManager
164 164
165 165 stylesheet = Unicode('', config=True,
166 166 help="path to a custom CSS stylesheet")
167 167
168 168 hide_menubar = CBool(False, config=True,
169 169 help="Start the console window with the menu bar hidden.")
170 170
171 171 maximize = CBool(False, config=True,
172 172 help="Start the console window maximized.")
173 173
174 174 plain = CBool(False, config=True,
175 175 help="Use a plaintext widget instead of rich text (plain can't print/save).")
176 176
177 177 display_banner = CBool(True, config=True,
178 help="Whether to display a banner upon starting IPython."
178 help="Whether to display a banner upon starting the QtConsole."
179 179 )
180 180
181 181 def _plain_changed(self, name, old, new):
182 182 kind = 'plain' if new else 'rich'
183 183 self.config.ConsoleWidget.kind = kind
184 184 if new:
185 185 self.widget_factory = IPythonWidget
186 186 else:
187 187 self.widget_factory = RichIPythonWidget
188 188
189 189 # the factory for creating a widget
190 190 widget_factory = Any(RichIPythonWidget)
191 191
192 192 def parse_command_line(self, argv=None):
193 193 super(IPythonQtConsoleApp, self).parse_command_line(argv)
194 194 self.build_kernel_argv(argv)
195 195
196 196
197 197 def new_frontend_master(self):
198 198 """ Create and return new frontend attached to new kernel, launched on localhost.
199 199 """
200 200 kernel_manager = self.kernel_manager_class(
201 201 connection_file=self._new_connection_file(),
202 202 parent=self,
203 203 autorestart=True,
204 204 )
205 205 # start the kernel
206 206 kwargs = {}
207 207 # FIXME: remove special treatment of IPython kernels
208 208 if self.kernel_manager.ipython_kernel:
209 209 kwargs['extra_arguments'] = self.kernel_argv
210 210 kernel_manager.start_kernel(**kwargs)
211 211 kernel_manager.client_factory = self.kernel_client_class
212 212 kernel_client = kernel_manager.client()
213 213 kernel_client.start_channels(shell=True, iopub=True)
214 214 widget = self.widget_factory(config=self.config,
215 215 local_kernel=True)
216 216 self.init_colors(widget)
217 217 widget.kernel_manager = kernel_manager
218 218 widget.kernel_client = kernel_client
219 219 widget._existing = False
220 220 widget._may_close = True
221 221 widget._confirm_exit = self.confirm_exit
222 222 return widget
223 223
224 224 def new_frontend_slave(self, current_widget):
225 225 """Create and return a new frontend attached to an existing kernel.
226 226
227 227 Parameters
228 228 ----------
229 229 current_widget : IPythonWidget
230 230 The IPythonWidget whose kernel this frontend is to share
231 231 """
232 232 kernel_client = self.kernel_client_class(
233 233 connection_file=current_widget.kernel_client.connection_file,
234 234 config = self.config,
235 235 )
236 236 kernel_client.load_connection_file()
237 237 kernel_client.start_channels()
238 238 widget = self.widget_factory(config=self.config,
239 239 local_kernel=False)
240 240 self.init_colors(widget)
241 241 widget._existing = True
242 242 widget._may_close = False
243 243 widget._confirm_exit = False
244 244 widget.kernel_client = kernel_client
245 245 widget.kernel_manager = current_widget.kernel_manager
246 246 return widget
247 247
248 248 def init_qt_app(self):
249 249 # separate from qt_elements, because it must run first
250 250 self.app = QtGui.QApplication([])
251 251
252 252 def init_qt_elements(self):
253 253 # Create the widget.
254 254
255 255 base_path = os.path.abspath(os.path.dirname(__file__))
256 256 icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg')
257 257 self.app.icon = QtGui.QIcon(icon_path)
258 258 QtGui.QApplication.setWindowIcon(self.app.icon)
259 259
260 260 ip = self.ip
261 261 local_kernel = (not self.existing) or is_local_ip(ip)
262 262 self.widget = self.widget_factory(config=self.config,
263 263 local_kernel=local_kernel)
264 264 self.init_colors(self.widget)
265 265 self.widget._existing = self.existing
266 266 self.widget._may_close = not self.existing
267 267 self.widget._confirm_exit = self.confirm_exit
268 268 self.widget._display_banner = self.display_banner
269 269
270 270 self.widget.kernel_manager = self.kernel_manager
271 271 self.widget.kernel_client = self.kernel_client
272 272 self.window = MainWindow(self.app,
273 273 confirm_exit=self.confirm_exit,
274 274 new_frontend_factory=self.new_frontend_master,
275 275 slave_frontend_factory=self.new_frontend_slave,
276 276 )
277 277 self.window.log = self.log
278 278 self.window.add_tab_with_frontend(self.widget)
279 279 self.window.init_magic_helper()
280 280 self.window.init_menu_bar()
281 281
282 282 # Ignore on OSX, where there is always a menu bar
283 283 if sys.platform != 'darwin' and self.hide_menubar:
284 284 self.window.menuBar().setVisible(False)
285 285
286 286 self.window.setWindowTitle('IPython')
287 287
288 288 def init_colors(self, widget):
289 289 """Configure the coloring of the widget"""
290 290 # Note: This will be dramatically simplified when colors
291 291 # are removed from the backend.
292 292
293 293 # parse the colors arg down to current known labels
294 294 cfg = self.config
295 295 colors = cfg.ZMQInteractiveShell.colors if 'ZMQInteractiveShell.colors' in cfg else None
296 296 style = cfg.IPythonWidget.syntax_style if 'IPythonWidget.syntax_style' in cfg else None
297 297 sheet = cfg.IPythonWidget.style_sheet if 'IPythonWidget.style_sheet' in cfg else None
298 298
299 299 # find the value for colors:
300 300 if colors:
301 301 colors=colors.lower()
302 302 if colors in ('lightbg', 'light'):
303 303 colors='lightbg'
304 304 elif colors in ('dark', 'linux'):
305 305 colors='linux'
306 306 else:
307 307 colors='nocolor'
308 308 elif style:
309 309 if style=='bw':
310 310 colors='nocolor'
311 311 elif styles.dark_style(style):
312 312 colors='linux'
313 313 else:
314 314 colors='lightbg'
315 315 else:
316 316 colors=None
317 317
318 318 # Configure the style
319 319 if style:
320 320 widget.style_sheet = styles.sheet_from_template(style, colors)
321 321 widget.syntax_style = style
322 322 widget._syntax_style_changed()
323 323 widget._style_sheet_changed()
324 324 elif colors:
325 325 # use a default dark/light/bw style
326 326 widget.set_default_style(colors=colors)
327 327
328 328 if self.stylesheet:
329 329 # we got an explicit stylesheet
330 330 if os.path.isfile(self.stylesheet):
331 331 with open(self.stylesheet) as f:
332 332 sheet = f.read()
333 333 else:
334 334 raise IOError("Stylesheet %r not found." % self.stylesheet)
335 335 if sheet:
336 336 widget.style_sheet = sheet
337 337 widget._style_sheet_changed()
338 338
339 339
340 340 def init_signal(self):
341 341 """allow clean shutdown on sigint"""
342 342 signal.signal(signal.SIGINT, lambda sig, frame: self.exit(-2))
343 343 # need a timer, so that QApplication doesn't block until a real
344 344 # Qt event fires (can require mouse movement)
345 345 # timer trick from http://stackoverflow.com/q/4938723/938949
346 346 timer = QtCore.QTimer()
347 347 # Let the interpreter run each 200 ms:
348 348 timer.timeout.connect(lambda: None)
349 349 timer.start(200)
350 350 # hold onto ref, so the timer doesn't get cleaned up
351 351 self._sigint_timer = timer
352 352
353 353 @catch_config_error
354 354 def initialize(self, argv=None):
355 355 self.init_qt_app()
356 356 super(IPythonQtConsoleApp, self).initialize(argv)
357 357 IPythonConsoleApp.initialize(self,argv)
358 358 self.init_qt_elements()
359 359 self.init_signal()
360 360
361 361 def start(self):
362 362
363 363 # draw the window
364 364 if self.maximize:
365 365 self.window.showMaximized()
366 366 else:
367 367 self.window.show()
368 368 self.window.raise_()
369 369
370 370 # Start the application main loop.
371 371 self.app.exec_()
372 372
373 373 #-----------------------------------------------------------------------------
374 374 # Main entry point
375 375 #-----------------------------------------------------------------------------
376 376
377 377 def main():
378 378 app = IPythonQtConsoleApp()
379 379 app.initialize()
380 380 app.start()
381 381
382 382
383 383 if __name__ == '__main__':
384 384 main()
General Comments 0
You need to be logged in to leave comments. Login now