##// END OF EJS Templates
prevent startup print messages from appearing above banner in qtconsole
MinRK -
Show More
@@ -1,645 +1,648
1 1 from __future__ import print_function
2 2
3 3 # Standard library imports
4 4 from collections import namedtuple
5 5 import sys
6 6 import time
7 7
8 8 # System library imports
9 9 from pygments.lexers import PythonLexer
10 10 from IPython.external.qt import QtCore, QtGui
11 11
12 12 # Local imports
13 13 from IPython.core.inputsplitter import InputSplitter, transform_classic_prompt
14 14 from IPython.core.oinspect import call_tip
15 15 from IPython.frontend.qt.base_frontend_mixin import BaseFrontendMixin
16 16 from IPython.utils.traitlets import Bool, Instance, Unicode
17 17 from bracket_matcher import BracketMatcher
18 18 from call_tip_widget import CallTipWidget
19 19 from completion_lexer import CompletionLexer
20 20 from history_console_widget import HistoryConsoleWidget
21 21 from pygments_highlighter import PygmentsHighlighter
22 22
23 23
24 24 class FrontendHighlighter(PygmentsHighlighter):
25 25 """ A PygmentsHighlighter that understands and ignores prompts.
26 26 """
27 27
28 28 def __init__(self, frontend):
29 29 super(FrontendHighlighter, self).__init__(frontend._control.document())
30 30 self._current_offset = 0
31 31 self._frontend = frontend
32 32 self.highlighting_on = False
33 33
34 34 def highlightBlock(self, string):
35 35 """ Highlight a block of text. Reimplemented to highlight selectively.
36 36 """
37 37 if not self.highlighting_on:
38 38 return
39 39
40 40 # The input to this function is a unicode string that may contain
41 41 # paragraph break characters, non-breaking spaces, etc. Here we acquire
42 42 # the string as plain text so we can compare it.
43 43 current_block = self.currentBlock()
44 44 string = self._frontend._get_block_plain_text(current_block)
45 45
46 46 # Decide whether to check for the regular or continuation prompt.
47 47 if current_block.contains(self._frontend._prompt_pos):
48 48 prompt = self._frontend._prompt
49 49 else:
50 50 prompt = self._frontend._continuation_prompt
51 51
52 52 # Only highlight if we can identify a prompt, but make sure not to
53 53 # highlight the prompt.
54 54 if string.startswith(prompt):
55 55 self._current_offset = len(prompt)
56 56 string = string[len(prompt):]
57 57 super(FrontendHighlighter, self).highlightBlock(string)
58 58
59 59 def rehighlightBlock(self, block):
60 60 """ Reimplemented to temporarily enable highlighting if disabled.
61 61 """
62 62 old = self.highlighting_on
63 63 self.highlighting_on = True
64 64 super(FrontendHighlighter, self).rehighlightBlock(block)
65 65 self.highlighting_on = old
66 66
67 67 def setFormat(self, start, count, format):
68 68 """ Reimplemented to highlight selectively.
69 69 """
70 70 start += self._current_offset
71 71 super(FrontendHighlighter, self).setFormat(start, count, format)
72 72
73 73
74 74 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
75 75 """ A Qt frontend for a generic Python kernel.
76 76 """
77 77
78 78 # The text to show when the kernel is (re)started.
79 79 banner = Unicode()
80 80
81 81 # An option and corresponding signal for overriding the default kernel
82 82 # interrupt behavior.
83 83 custom_interrupt = Bool(False)
84 84 custom_interrupt_requested = QtCore.Signal()
85 85
86 86 # An option and corresponding signals for overriding the default kernel
87 87 # restart behavior.
88 88 custom_restart = Bool(False)
89 89 custom_restart_kernel_died = QtCore.Signal(float)
90 90 custom_restart_requested = QtCore.Signal()
91 91
92 92 # Whether to automatically show calltips on open-parentheses.
93 93 enable_calltips = Bool(True, config=True,
94 94 help="Whether to draw information calltips on open-parentheses.")
95 95
96 96 # Emitted when a user visible 'execute_request' has been submitted to the
97 97 # kernel from the FrontendWidget. Contains the code to be executed.
98 98 executing = QtCore.Signal(object)
99 99
100 100 # Emitted when a user-visible 'execute_reply' has been received from the
101 101 # kernel and processed by the FrontendWidget. Contains the response message.
102 102 executed = QtCore.Signal(object)
103 103
104 104 # Emitted when an exit request has been received from the kernel.
105 105 exit_requested = QtCore.Signal(object)
106 106
107 107 # Protected class variables.
108 108 _CallTipRequest = namedtuple('_CallTipRequest', ['id', 'pos'])
109 109 _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos'])
110 110 _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
111 111 _input_splitter_class = InputSplitter
112 112 _local_kernel = False
113 113 _highlighter = Instance(FrontendHighlighter)
114 114
115 115 #---------------------------------------------------------------------------
116 116 # 'object' interface
117 117 #---------------------------------------------------------------------------
118 118
119 119 def __init__(self, *args, **kw):
120 120 super(FrontendWidget, self).__init__(*args, **kw)
121 121
122 122 # FrontendWidget protected variables.
123 123 self._bracket_matcher = BracketMatcher(self._control)
124 124 self._call_tip_widget = CallTipWidget(self._control)
125 125 self._completion_lexer = CompletionLexer(PythonLexer())
126 126 self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None)
127 127 self._hidden = False
128 128 self._highlighter = FrontendHighlighter(self)
129 129 self._input_splitter = self._input_splitter_class(input_mode='cell')
130 130 self._kernel_manager = None
131 131 self._request_info = {}
132 132
133 133 # Configure the ConsoleWidget.
134 134 self.tab_width = 4
135 135 self._set_continuation_prompt('... ')
136 136
137 137 # Configure the CallTipWidget.
138 138 self._call_tip_widget.setFont(self.font)
139 139 self.font_changed.connect(self._call_tip_widget.setFont)
140 140
141 141 # Configure actions.
142 142 action = self._copy_raw_action
143 143 key = QtCore.Qt.CTRL | QtCore.Qt.SHIFT | QtCore.Qt.Key_C
144 144 action.setEnabled(False)
145 145 action.setShortcut(QtGui.QKeySequence(key))
146 146 action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
147 147 action.triggered.connect(self.copy_raw)
148 148 self.copy_available.connect(action.setEnabled)
149 149 self.addAction(action)
150 150
151 151 # Connect signal handlers.
152 152 document = self._control.document()
153 153 document.contentsChange.connect(self._document_contents_change)
154 154
155 155 # Set flag for whether we are connected via localhost.
156 156 self._local_kernel = kw.get('local_kernel',
157 157 FrontendWidget._local_kernel)
158 158
159 159 #---------------------------------------------------------------------------
160 160 # 'ConsoleWidget' public interface
161 161 #---------------------------------------------------------------------------
162 162
163 163 def copy(self):
164 164 """ Copy the currently selected text to the clipboard, removing prompts.
165 165 """
166 166 text = self._control.textCursor().selection().toPlainText()
167 167 if text:
168 168 lines = map(transform_classic_prompt, text.splitlines())
169 169 text = '\n'.join(lines)
170 170 QtGui.QApplication.clipboard().setText(text)
171 171
172 172 #---------------------------------------------------------------------------
173 173 # 'ConsoleWidget' abstract interface
174 174 #---------------------------------------------------------------------------
175 175
176 176 def _is_complete(self, source, interactive):
177 177 """ Returns whether 'source' can be completely processed and a new
178 178 prompt created. When triggered by an Enter/Return key press,
179 179 'interactive' is True; otherwise, it is False.
180 180 """
181 181 complete = self._input_splitter.push(source)
182 182 if interactive:
183 183 complete = not self._input_splitter.push_accepts_more()
184 184 return complete
185 185
186 186 def _execute(self, source, hidden):
187 187 """ Execute 'source'. If 'hidden', do not show any output.
188 188
189 189 See parent class :meth:`execute` docstring for full details.
190 190 """
191 191 msg_id = self.kernel_manager.shell_channel.execute(source, hidden)
192 192 self._request_info['execute'] = self._ExecutionRequest(msg_id, 'user')
193 193 self._hidden = hidden
194 194 if not hidden:
195 195 self.executing.emit(source)
196 196
197 197 def _prompt_started_hook(self):
198 198 """ Called immediately after a new prompt is displayed.
199 199 """
200 200 if not self._reading:
201 201 self._highlighter.highlighting_on = True
202 202
203 203 def _prompt_finished_hook(self):
204 204 """ Called immediately after a prompt is finished, i.e. when some input
205 205 will be processed and a new prompt displayed.
206 206 """
207 207 # Flush all state from the input splitter so the next round of
208 208 # reading input starts with a clean buffer.
209 209 self._input_splitter.reset()
210 210
211 211 if not self._reading:
212 212 self._highlighter.highlighting_on = False
213 213
214 214 def _tab_pressed(self):
215 215 """ Called when the tab key is pressed. Returns whether to continue
216 216 processing the event.
217 217 """
218 218 # Perform tab completion if:
219 219 # 1) The cursor is in the input buffer.
220 220 # 2) There is a non-whitespace character before the cursor.
221 221 text = self._get_input_buffer_cursor_line()
222 222 if text is None:
223 223 return False
224 224 complete = bool(text[:self._get_input_buffer_cursor_column()].strip())
225 225 if complete:
226 226 self._complete()
227 227 return not complete
228 228
229 229 #---------------------------------------------------------------------------
230 230 # 'ConsoleWidget' protected interface
231 231 #---------------------------------------------------------------------------
232 232
233 233 def _context_menu_make(self, pos):
234 234 """ Reimplemented to add an action for raw copy.
235 235 """
236 236 menu = super(FrontendWidget, self)._context_menu_make(pos)
237 237 for before_action in menu.actions():
238 238 if before_action.shortcut().matches(QtGui.QKeySequence.Paste) == \
239 239 QtGui.QKeySequence.ExactMatch:
240 240 menu.insertAction(before_action, self._copy_raw_action)
241 241 break
242 242 return menu
243 243
244 244 def request_interrupt_kernel(self):
245 245 if self._executing:
246 246 self.interrupt_kernel()
247 247
248 248 def request_restart_kernel(self):
249 249 message = 'Are you sure you want to restart the kernel?'
250 250 self.restart_kernel(message, now=False)
251 251
252 252 def _event_filter_console_keypress(self, event):
253 253 """ Reimplemented for execution interruption and smart backspace.
254 254 """
255 255 key = event.key()
256 256 if self._control_key_down(event.modifiers(), include_command=False):
257 257
258 258 if key == QtCore.Qt.Key_C and self._executing:
259 259 self.request_interrupt_kernel()
260 260 return True
261 261
262 262 elif key == QtCore.Qt.Key_Period:
263 263 self.request_restart_kernel()
264 264 return True
265 265
266 266 elif not event.modifiers() & QtCore.Qt.AltModifier:
267 267
268 268 # Smart backspace: remove four characters in one backspace if:
269 269 # 1) everything left of the cursor is whitespace
270 270 # 2) the four characters immediately left of the cursor are spaces
271 271 if key == QtCore.Qt.Key_Backspace:
272 272 col = self._get_input_buffer_cursor_column()
273 273 cursor = self._control.textCursor()
274 274 if col > 3 and not cursor.hasSelection():
275 275 text = self._get_input_buffer_cursor_line()[:col]
276 276 if text.endswith(' ') and not text.strip():
277 277 cursor.movePosition(QtGui.QTextCursor.Left,
278 278 QtGui.QTextCursor.KeepAnchor, 4)
279 279 cursor.removeSelectedText()
280 280 return True
281 281
282 282 return super(FrontendWidget, self)._event_filter_console_keypress(event)
283 283
284 284 def _insert_continuation_prompt(self, cursor):
285 285 """ Reimplemented for auto-indentation.
286 286 """
287 287 super(FrontendWidget, self)._insert_continuation_prompt(cursor)
288 288 cursor.insertText(' ' * self._input_splitter.indent_spaces)
289 289
290 290 #---------------------------------------------------------------------------
291 291 # 'BaseFrontendMixin' abstract interface
292 292 #---------------------------------------------------------------------------
293 293
294 294 def _handle_complete_reply(self, rep):
295 295 """ Handle replies for tab completion.
296 296 """
297 297 self.log.debug("complete: %s", rep.get('content', ''))
298 298 cursor = self._get_cursor()
299 299 info = self._request_info.get('complete')
300 300 if info and info.id == rep['parent_header']['msg_id'] and \
301 301 info.pos == cursor.position():
302 302 text = '.'.join(self._get_context())
303 303 cursor.movePosition(QtGui.QTextCursor.Left, n=len(text))
304 304 self._complete_with_items(cursor, rep['content']['matches'])
305 305
306 306 def _handle_execute_reply(self, msg):
307 307 """ Handles replies for code execution.
308 308 """
309 309 self.log.debug("execute: %s", msg.get('content', ''))
310 310 info = self._request_info.get('execute')
311 311 if info and info.id == msg['parent_header']['msg_id'] and \
312 312 info.kind == 'user' and not self._hidden:
313 313 # Make sure that all output from the SUB channel has been processed
314 314 # before writing a new prompt.
315 315 self.kernel_manager.sub_channel.flush()
316 316
317 317 # Reset the ANSI style information to prevent bad text in stdout
318 318 # from messing up our colors. We're not a true terminal so we're
319 319 # allowed to do this.
320 320 if self.ansi_codes:
321 321 self._ansi_processor.reset_sgr()
322 322
323 323 content = msg['content']
324 324 status = content['status']
325 325 if status == 'ok':
326 326 self._process_execute_ok(msg)
327 327 elif status == 'error':
328 328 self._process_execute_error(msg)
329 329 elif status == 'abort':
330 330 self._process_execute_abort(msg)
331 331
332 332 self._show_interpreter_prompt_for_reply(msg)
333 333 self.executed.emit(msg)
334 334 else:
335 335 super(FrontendWidget, self)._handle_execute_reply(msg)
336 336
337 337 def _handle_input_request(self, msg):
338 338 """ Handle requests for raw_input.
339 339 """
340 340 self.log.debug("input: %s", msg.get('content', ''))
341 341 if self._hidden:
342 342 raise RuntimeError('Request for raw input during hidden execution.')
343 343
344 344 # Make sure that all output from the SUB channel has been processed
345 345 # before entering readline mode.
346 346 self.kernel_manager.sub_channel.flush()
347 347
348 348 def callback(line):
349 349 self.kernel_manager.stdin_channel.input(line)
350 350 self._readline(msg['content']['prompt'], callback=callback)
351 351
352 352 def _handle_kernel_died(self, since_last_heartbeat):
353 353 """ Handle the kernel's death by asking if the user wants to restart.
354 354 """
355 355 self.log.debug("kernel died: %s", since_last_heartbeat)
356 356 if self.custom_restart:
357 357 self.custom_restart_kernel_died.emit(since_last_heartbeat)
358 358 else:
359 359 message = 'The kernel heartbeat has been inactive for %.2f ' \
360 360 'seconds. Do you want to restart the kernel? You may ' \
361 361 'first want to check the network connection.' % \
362 362 since_last_heartbeat
363 363 self.restart_kernel(message, now=True)
364 364
365 365 def _handle_object_info_reply(self, rep):
366 366 """ Handle replies for call tips.
367 367 """
368 368 self.log.debug("oinfo: %s", rep.get('content', ''))
369 369 cursor = self._get_cursor()
370 370 info = self._request_info.get('call_tip')
371 371 if info and info.id == rep['parent_header']['msg_id'] and \
372 372 info.pos == cursor.position():
373 373 # Get the information for a call tip. For now we format the call
374 374 # line as string, later we can pass False to format_call and
375 375 # syntax-highlight it ourselves for nicer formatting in the
376 376 # calltip.
377 377 content = rep['content']
378 378 # if this is from pykernel, 'docstring' will be the only key
379 379 if content.get('ismagic', False):
380 380 # Don't generate a call-tip for magics. Ideally, we should
381 381 # generate a tooltip, but not on ( like we do for actual
382 382 # callables.
383 383 call_info, doc = None, None
384 384 else:
385 385 call_info, doc = call_tip(content, format_call=True)
386 386 if call_info or doc:
387 387 self._call_tip_widget.show_call_info(call_info, doc)
388 388
389 389 def _handle_pyout(self, msg):
390 390 """ Handle display hook output.
391 391 """
392 392 self.log.debug("pyout: %s", msg.get('content', ''))
393 393 if not self._hidden and self._is_from_this_session(msg):
394 394 text = msg['content']['data']
395 395 self._append_plain_text(text + '\n', before_prompt=True)
396 396
397 397 def _handle_stream(self, msg):
398 398 """ Handle stdout, stderr, and stdin.
399 399 """
400 400 self.log.debug("stream: %s", msg.get('content', ''))
401 401 if not self._hidden and self._is_from_this_session(msg):
402 402 # Most consoles treat tabs as being 8 space characters. Convert tabs
403 403 # to spaces so that output looks as expected regardless of this
404 404 # widget's tab width.
405 405 text = msg['content']['data'].expandtabs(8)
406 406
407 407 self._append_plain_text(text, before_prompt=True)
408 408 self._control.moveCursor(QtGui.QTextCursor.End)
409 409
410 410 def _handle_shutdown_reply(self, msg):
411 411 """ Handle shutdown signal, only if from other console.
412 412 """
413 413 self.log.debug("shutdown: %s", msg.get('content', ''))
414 414 if not self._hidden and not self._is_from_this_session(msg):
415 415 if self._local_kernel:
416 416 if not msg['content']['restart']:
417 417 self.exit_requested.emit(self)
418 418 else:
419 419 # we just got notified of a restart!
420 420 time.sleep(0.25) # wait 1/4 sec to reset
421 421 # lest the request for a new prompt
422 422 # goes to the old kernel
423 423 self.reset()
424 424 else: # remote kernel, prompt on Kernel shutdown/reset
425 425 title = self.window().windowTitle()
426 426 if not msg['content']['restart']:
427 427 reply = QtGui.QMessageBox.question(self, title,
428 428 "Kernel has been shutdown permanently. "
429 429 "Close the Console?",
430 430 QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
431 431 if reply == QtGui.QMessageBox.Yes:
432 432 self.exit_requested.emit(self)
433 433 else:
434 434 reply = QtGui.QMessageBox.question(self, title,
435 435 "Kernel has been reset. Clear the Console?",
436 436 QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
437 437 if reply == QtGui.QMessageBox.Yes:
438 438 time.sleep(0.25) # wait 1/4 sec to reset
439 439 # lest the request for a new prompt
440 440 # goes to the old kernel
441 441 self.reset()
442 442
443 443 def _started_channels(self):
444 444 """ Called when the KernelManager channels have started listening or
445 445 when the frontend is assigned an already listening KernelManager.
446 446 """
447 447 self.reset()
448 448
449 449 #---------------------------------------------------------------------------
450 450 # 'FrontendWidget' public interface
451 451 #---------------------------------------------------------------------------
452 452
453 453 def copy_raw(self):
454 454 """ Copy the currently selected text to the clipboard without attempting
455 455 to remove prompts or otherwise alter the text.
456 456 """
457 457 self._control.copy()
458 458
459 459 def execute_file(self, path, hidden=False):
460 460 """ Attempts to execute file with 'path'. If 'hidden', no output is
461 461 shown.
462 462 """
463 463 self.execute('execfile(%r)' % path, hidden=hidden)
464 464
465 465 def interrupt_kernel(self):
466 466 """ Attempts to interrupt the running kernel.
467 467 """
468 468 if self.custom_interrupt:
469 469 self.custom_interrupt_requested.emit()
470 470 elif self.kernel_manager.has_kernel:
471 471 self.kernel_manager.interrupt_kernel()
472 472 else:
473 473 self._append_plain_text('Kernel process is either remote or '
474 474 'unspecified. Cannot interrupt.\n')
475 475
476 476 def reset(self):
477 477 """ Resets the widget to its initial state. Similar to ``clear``, but
478 478 also re-writes the banner and aborts execution if necessary.
479 479 """
480 480 if self._executing:
481 481 self._executing = False
482 482 self._request_info['execute'] = None
483 483 self._reading = False
484 484 self._highlighter.highlighting_on = False
485 485
486 486 self._control.clear()
487 487 self._append_plain_text(self.banner)
488 # update output marker for stdout/stderr, so that startup
489 # messages appear after banner:
490 self._append_before_prompt_pos = self._get_cursor().position()
488 491 self._show_interpreter_prompt()
489 492
490 493 def restart_kernel(self, message, now=False):
491 494 """ Attempts to restart the running kernel.
492 495 """
493 496 # FIXME: now should be configurable via a checkbox in the dialog. Right
494 497 # now at least the heartbeat path sets it to True and the manual restart
495 498 # to False. But those should just be the pre-selected states of a
496 499 # checkbox that the user could override if so desired. But I don't know
497 500 # enough Qt to go implementing the checkbox now.
498 501
499 502 if self.custom_restart:
500 503 self.custom_restart_requested.emit()
501 504
502 505 elif self.kernel_manager.has_kernel:
503 506 # Pause the heart beat channel to prevent further warnings.
504 507 self.kernel_manager.hb_channel.pause()
505 508
506 509 # Prompt the user to restart the kernel. Un-pause the heartbeat if
507 510 # they decline. (If they accept, the heartbeat will be un-paused
508 511 # automatically when the kernel is restarted.)
509 512 buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
510 513 result = QtGui.QMessageBox.question(self, 'Restart kernel?',
511 514 message, buttons)
512 515 if result == QtGui.QMessageBox.Yes:
513 516 try:
514 517 self.kernel_manager.restart_kernel(now=now)
515 518 except RuntimeError:
516 519 self._append_plain_text('Kernel started externally. '
517 520 'Cannot restart.\n')
518 521 else:
519 522 self.reset()
520 523 else:
521 524 self.kernel_manager.hb_channel.unpause()
522 525
523 526 else:
524 527 self._append_plain_text('Kernel process is either remote or '
525 528 'unspecified. Cannot restart.\n')
526 529
527 530 #---------------------------------------------------------------------------
528 531 # 'FrontendWidget' protected interface
529 532 #---------------------------------------------------------------------------
530 533
531 534 def _call_tip(self):
532 535 """ Shows a call tip, if appropriate, at the current cursor location.
533 536 """
534 537 # Decide if it makes sense to show a call tip
535 538 if not self.enable_calltips:
536 539 return False
537 540 cursor = self._get_cursor()
538 541 cursor.movePosition(QtGui.QTextCursor.Left)
539 542 if cursor.document().characterAt(cursor.position()) != '(':
540 543 return False
541 544 context = self._get_context(cursor)
542 545 if not context:
543 546 return False
544 547
545 548 # Send the metadata request to the kernel
546 549 name = '.'.join(context)
547 550 msg_id = self.kernel_manager.shell_channel.object_info(name)
548 551 pos = self._get_cursor().position()
549 552 self._request_info['call_tip'] = self._CallTipRequest(msg_id, pos)
550 553 return True
551 554
552 555 def _complete(self):
553 556 """ Performs completion at the current cursor location.
554 557 """
555 558 context = self._get_context()
556 559 if context:
557 560 # Send the completion request to the kernel
558 561 msg_id = self.kernel_manager.shell_channel.complete(
559 562 '.'.join(context), # text
560 563 self._get_input_buffer_cursor_line(), # line
561 564 self._get_input_buffer_cursor_column(), # cursor_pos
562 565 self.input_buffer) # block
563 566 pos = self._get_cursor().position()
564 567 info = self._CompletionRequest(msg_id, pos)
565 568 self._request_info['complete'] = info
566 569
567 570 def _get_context(self, cursor=None):
568 571 """ Gets the context for the specified cursor (or the current cursor
569 572 if none is specified).
570 573 """
571 574 if cursor is None:
572 575 cursor = self._get_cursor()
573 576 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
574 577 QtGui.QTextCursor.KeepAnchor)
575 578 text = cursor.selection().toPlainText()
576 579 return self._completion_lexer.get_context(text)
577 580
578 581 def _process_execute_abort(self, msg):
579 582 """ Process a reply for an aborted execution request.
580 583 """
581 584 self._append_plain_text("ERROR: execution aborted\n")
582 585
583 586 def _process_execute_error(self, msg):
584 587 """ Process a reply for an execution request that resulted in an error.
585 588 """
586 589 content = msg['content']
587 590 # If a SystemExit is passed along, this means exit() was called - also
588 591 # all the ipython %exit magic syntax of '-k' to be used to keep
589 592 # the kernel running
590 593 if content['ename']=='SystemExit':
591 594 keepkernel = content['evalue']=='-k' or content['evalue']=='True'
592 595 self._keep_kernel_on_exit = keepkernel
593 596 self.exit_requested.emit(self)
594 597 else:
595 598 traceback = ''.join(content['traceback'])
596 599 self._append_plain_text(traceback)
597 600
598 601 def _process_execute_ok(self, msg):
599 602 """ Process a reply for a successful execution equest.
600 603 """
601 604 payload = msg['content']['payload']
602 605 for item in payload:
603 606 if not self._process_execute_payload(item):
604 607 warning = 'Warning: received unknown payload of type %s'
605 608 print(warning % repr(item['source']))
606 609
607 610 def _process_execute_payload(self, item):
608 611 """ Process a single payload item from the list of payload items in an
609 612 execution reply. Returns whether the payload was handled.
610 613 """
611 614 # The basic FrontendWidget doesn't handle payloads, as they are a
612 615 # mechanism for going beyond the standard Python interpreter model.
613 616 return False
614 617
615 618 def _show_interpreter_prompt(self):
616 619 """ Shows a prompt for the interpreter.
617 620 """
618 621 self._show_prompt('>>> ')
619 622
620 623 def _show_interpreter_prompt_for_reply(self, msg):
621 624 """ Shows a prompt for the interpreter given an 'execute_reply' message.
622 625 """
623 626 self._show_interpreter_prompt()
624 627
625 628 #------ Signal handlers ----------------------------------------------------
626 629
627 630 def _document_contents_change(self, position, removed, added):
628 631 """ Called whenever the document's content changes. Display a call tip
629 632 if appropriate.
630 633 """
631 634 # Calculate where the cursor should be *after* the change:
632 635 position += added
633 636
634 637 document = self._control.document()
635 638 if position == self._get_cursor().position():
636 639 self._call_tip()
637 640
638 641 #------ Trait default initializers -----------------------------------------
639 642
640 643 def _banner_default(self):
641 644 """ Returns the standard Python banner.
642 645 """
643 646 banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \
644 647 '"license" for more information.'
645 648 return banner % (sys.version, sys.platform)
General Comments 0
You need to be logged in to leave comments. Login now