Show More
@@ -430,12 +430,6 class ConsoleWidget(QtGui.QWidget): | |||||
430 | """ |
|
430 | """ | |
431 | raise NotImplementedError |
|
431 | raise NotImplementedError | |
432 |
|
432 | |||
433 | def _execute_interrupt(self): |
|
|||
434 | """ Attempts to stop execution. Returns whether this method has an |
|
|||
435 | implementation. |
|
|||
436 | """ |
|
|||
437 | return False |
|
|||
438 |
|
||||
439 | def _prompt_started_hook(self): |
|
433 | def _prompt_started_hook(self): | |
440 | """ Called immediately after a new prompt is displayed. |
|
434 | """ Called immediately after a new prompt is displayed. | |
441 | """ |
|
435 | """ | |
@@ -575,10 +569,7 class ConsoleWidget(QtGui.QWidget): | |||||
575 | intercepted = True |
|
569 | intercepted = True | |
576 |
|
570 | |||
577 | elif ctrl_down: |
|
571 | elif ctrl_down: | |
578 |
if key == QtCore.Qt.Key_ |
|
572 | if key == QtCore.Qt.Key_K: | |
579 | intercepted = self._executing and self._execute_interrupt() |
|
|||
580 |
|
||||
581 | elif key == QtCore.Qt.Key_K: |
|
|||
582 | if self._in_buffer(position): |
|
573 | if self._in_buffer(position): | |
583 | cursor.movePosition(QtGui.QTextCursor.EndOfLine, |
|
574 | cursor.movePosition(QtGui.QTextCursor.EndOfLine, | |
584 | QtGui.QTextCursor.KeepAnchor) |
|
575 | QtGui.QTextCursor.KeepAnchor) |
@@ -72,12 +72,22 class FrontendHighlighter(PygmentsHighlighter): | |||||
72 | class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): |
|
72 | class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): | |
73 | """ A Qt frontend for a generic Python kernel. |
|
73 | """ A Qt frontend for a generic Python kernel. | |
74 | """ |
|
74 | """ | |
|
75 | ||||
|
76 | # An option and corresponding signal for overriding the default kernel | |||
|
77 | # interrupt behavior. | |||
|
78 | custom_interrupt = False | |||
|
79 | custom_interrupt_requested = QtCore.pyqtSignal() | |||
|
80 | ||||
|
81 | # An option and corresponding signal for overriding the default kernel | |||
|
82 | # restart behavior. | |||
|
83 | custom_restart = False | |||
|
84 | custom_restart_requested = QtCore.pyqtSignal() | |||
75 |
|
85 | |||
76 | # Emitted when an 'execute_reply' has been received from the kernel and |
|
86 | # Emitted when an 'execute_reply' has been received from the kernel and | |
77 | # processed by the FrontendWidget. |
|
87 | # processed by the FrontendWidget. | |
78 | executed = QtCore.pyqtSignal(object) |
|
88 | executed = QtCore.pyqtSignal(object) | |
79 |
|
89 | |||
80 |
# Protected class |
|
90 | # Protected class variables. | |
81 | _highlighter_class = FrontendHighlighter |
|
91 | _highlighter_class = FrontendHighlighter | |
82 | _input_splitter_class = InputSplitter |
|
92 | _input_splitter_class = InputSplitter | |
83 |
|
93 | |||
@@ -123,13 +133,6 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): | |||||
123 | """ |
|
133 | """ | |
124 | self.kernel_manager.xreq_channel.execute(source, hidden) |
|
134 | self.kernel_manager.xreq_channel.execute(source, hidden) | |
125 | self._hidden = hidden |
|
135 | self._hidden = hidden | |
126 |
|
||||
127 | def _execute_interrupt(self): |
|
|||
128 | """ Attempts to stop execution. Returns whether this method has an |
|
|||
129 | implementation. |
|
|||
130 | """ |
|
|||
131 | self._interrupt_kernel() |
|
|||
132 | return True |
|
|||
133 |
|
136 | |||
134 | def _prompt_started_hook(self): |
|
137 | def _prompt_started_hook(self): | |
135 | """ Called immediately after a new prompt is displayed. |
|
138 | """ Called immediately after a new prompt is displayed. | |
@@ -163,6 +166,19 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): | |||||
163 | # 'ConsoleWidget' protected interface |
|
166 | # 'ConsoleWidget' protected interface | |
164 | #--------------------------------------------------------------------------- |
|
167 | #--------------------------------------------------------------------------- | |
165 |
|
168 | |||
|
169 | def _event_filter_console_keypress(self, event): | |||
|
170 | """ Reimplemented to allow execution interruption. | |||
|
171 | """ | |||
|
172 | key = event.key() | |||
|
173 | if self._executing and self._control_key_down(event.modifiers()): | |||
|
174 | if key == QtCore.Qt.Key_C: | |||
|
175 | self._kernel_interrupt() | |||
|
176 | return True | |||
|
177 | elif key == QtCore.Qt.Key_Period: | |||
|
178 | self._kernel_restart() | |||
|
179 | return True | |||
|
180 | return super(FrontendWidget, self)._event_filter_console_keypress(event) | |||
|
181 | ||||
166 | def _show_continuation_prompt(self): |
|
182 | def _show_continuation_prompt(self): | |
167 | """ Reimplemented for auto-indentation. |
|
183 | """ Reimplemented for auto-indentation. | |
168 | """ |
|
184 | """ | |
@@ -324,15 +340,36 class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): | |||||
324 | text = str(cursor.selection().toPlainText()) |
|
340 | text = str(cursor.selection().toPlainText()) | |
325 | return self._completion_lexer.get_context(text) |
|
341 | return self._completion_lexer.get_context(text) | |
326 |
|
342 | |||
327 |
def _interrupt |
|
343 | def _kernel_interrupt(self): | |
328 |
""" Attempts to |
|
344 | """ Attempts to interrupt the running kernel. | |
329 | """ |
|
345 | """ | |
330 | if self.kernel_manager.has_kernel: |
|
346 | if self.custom_interrupt: | |
|
347 | self.custom_interrupt_requested.emit() | |||
|
348 | elif self.kernel_manager.has_kernel: | |||
331 | self.kernel_manager.signal_kernel(signal.SIGINT) |
|
349 | self.kernel_manager.signal_kernel(signal.SIGINT) | |
332 | else: |
|
350 | else: | |
333 | self._append_plain_text('Kernel process is either remote or ' |
|
351 | self._append_plain_text('Kernel process is either remote or ' | |
334 | 'unspecified. Cannot interrupt.\n') |
|
352 | 'unspecified. Cannot interrupt.\n') | |
335 |
|
353 | |||
|
354 | def _kernel_restart(self): | |||
|
355 | """ Attempts to restart the running kernel. | |||
|
356 | """ | |||
|
357 | if self.custom_restart: | |||
|
358 | self.custom_restart_requested.emit() | |||
|
359 | elif self.kernel_manager.has_kernel: | |||
|
360 | try: | |||
|
361 | self.kernel_manager.restart_kernel() | |||
|
362 | except RuntimeError: | |||
|
363 | message = 'Kernel started externally. Cannot restart.\n' | |||
|
364 | self._append_plain_text(message) | |||
|
365 | else: | |||
|
366 | self._stopped_channels() | |||
|
367 | self._append_plain_text('Kernel restarting...\n') | |||
|
368 | self._show_interpreter_prompt() | |||
|
369 | else: | |||
|
370 | self._append_plain_text('Kernel process is either remote or ' | |||
|
371 | 'unspecified. Cannot restart.\n') | |||
|
372 | ||||
336 | def _process_execute_abort(self, msg): |
|
373 | def _process_execute_abort(self, msg): | |
337 | """ Process a reply for an aborted execution request. |
|
374 | """ Process a reply for an aborted execution request. | |
338 | """ |
|
375 | """ |
@@ -1,5 +1,3 | |||||
1 | import os |
|
|||
2 |
|
||||
3 |
|
|
1 | # System library imports | |
4 | from PyQt4 import QtCore, QtGui |
|
2 | from PyQt4 import QtCore, QtGui | |
5 |
|
3 |
@@ -482,6 +482,7 class KernelManager(HasTraits): | |||||
482 | rep_channel_class = Type(RepSocketChannel) |
|
482 | rep_channel_class = Type(RepSocketChannel) | |
483 |
|
483 | |||
484 | # Protected traits. |
|
484 | # Protected traits. | |
|
485 | _launch_args = Any | |||
485 | _xreq_channel = Any |
|
486 | _xreq_channel = Any | |
486 | _sub_channel = Any |
|
487 | _sub_channel = Any | |
487 | _rep_channel = Any |
|
488 | _rep_channel = Any | |
@@ -523,7 +524,7 class KernelManager(HasTraits): | |||||
523 | # Kernel process management methods: |
|
524 | # Kernel process management methods: | |
524 | #-------------------------------------------------------------------------- |
|
525 | #-------------------------------------------------------------------------- | |
525 |
|
526 | |||
526 |
def start_kernel(self, |
|
527 | def start_kernel(self, **kw): | |
527 | """Starts a kernel process and configures the manager to use it. |
|
528 | """Starts a kernel process and configures the manager to use it. | |
528 |
|
529 | |||
529 | If random ports (port=0) are being used, this method must be called |
|
530 | If random ports (port=0) are being used, this method must be called | |
@@ -540,7 +541,8 class KernelManager(HasTraits): | |||||
540 | "Make sure that the '*_address' attributes are " |
|
541 | "Make sure that the '*_address' attributes are " | |
541 | "configured properly.") |
|
542 | "configured properly.") | |
542 |
|
543 | |||
543 | if ipython: |
|
544 | self._launch_args = kw.copy() | |
|
545 | if kw.pop('ipython', True): | |||
544 | from ipkernel import launch_kernel as launch |
|
546 | from ipkernel import launch_kernel as launch | |
545 | else: |
|
547 | else: | |
546 | from pykernel import launch_kernel as launch |
|
548 | from pykernel import launch_kernel as launch | |
@@ -550,6 +552,19 class KernelManager(HasTraits): | |||||
550 | self.sub_address = (LOCALHOST, pub) |
|
552 | self.sub_address = (LOCALHOST, pub) | |
551 | self.rep_address = (LOCALHOST, req) |
|
553 | self.rep_address = (LOCALHOST, req) | |
552 |
|
554 | |||
|
555 | def restart_kernel(self): | |||
|
556 | """Restarts a kernel with the same arguments that were used to launch | |||
|
557 | it. If the old kernel was launched with random ports, the same ports | |||
|
558 | will be used for the new kernel. | |||
|
559 | """ | |||
|
560 | if self._launch_args is None: | |||
|
561 | raise RuntimeError("Cannot restart the kernel. " | |||
|
562 | "No previous call to 'start_kernel'.") | |||
|
563 | else: | |||
|
564 | if self.has_kernel: | |||
|
565 | self.kill_kernel() | |||
|
566 | self.start_kernel(*self._launch_args) | |||
|
567 | ||||
553 | @property |
|
568 | @property | |
554 | def has_kernel(self): |
|
569 | def has_kernel(self): | |
555 | """Returns whether a kernel process has been specified for the kernel |
|
570 | """Returns whether a kernel process has been specified for the kernel |
General Comments 0
You need to be logged in to leave comments.
Login now