Skip to content
This repository

Don't assume history requests succeed in qtconsole #745

Merged
merged 3 commits into from over 2 years ago

2 participants

Min RK Evan Patterson
Min RK
Owner

If there was an error in user startup code, the history request will be aborted. It is generally not acceptable in frontends to assume that requests succeed. This assumption is made all over our frontend code, and should be be fixed. For now, this handles a known issue of the qtconsole crashing hard when invalid input is given to startup code (e.g. ipython qtconsole -c "DNE").

If the history request was aborted (this means a different request raised an error, causing the queue to be flushed), it will be tried again, exactly once, after waiting for the abort flush.

added some commits August 02, 2011
Min RK make ConsoleWidget LoggingConfigurable
This adds the attribute Widget.log, which is hooked up to the
running application's logger.
b13dbdb
Min RK Don't assume history request succeeded
errors in startup can cause the history request to be aborted.  There could be any of
a number of reasons the history request should fail, and the frontend should *never*
assume that the status is 'ok'.
24d3b02
Min RK retry aborted history requests in qtconsole fc67794
Evan Patterson
Collaborator

Thanks for the fix, Min. I noticed this crash recently myself.

That said, this approach makes me a little leery. The Qt console (and no doubt other frontends as well) makes many different requests: for execution, history, tab completion, object info, etc. It seems painful to have check status and possibly retry the request under all these differences circumstances. I wonder if it possible to abstract at least some of this away, e.g. by having BaseFrontendMixin handle the retries automatically.

This is all somewhat vague. I will think about this some more and see if I can produce anything more substantial.

Evan Patterson
Collaborator

OK, I have an implementation plan for more robust error handling. Since this will involve some refactoring, I think it's worth merging this now as an interim fix.

Min RK minrk merged commit 17494a1 into from September 09, 2011
Min RK minrk closed this September 09, 2011
Brian E. Granger ellisonbg referenced this pull request from a commit January 10, 2012
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 1 author.

Aug 29, 2011
Min RK make ConsoleWidget LoggingConfigurable
This adds the attribute Widget.log, which is hooked up to the
running application's logger.
b13dbdb
Min RK Don't assume history request succeeded
errors in startup can cause the history request to be aborted.  There could be any of
a number of reasons the history request should fail, and the frontend should *never*
assume that the status is 'ok'.
24d3b02
Min RK retry aborted history requests in qtconsole fc67794
This page is out of date. Refresh to see the latest.
6  IPython/frontend/qt/console/console_widget.py
@@ -16,7 +16,7 @@
16 16
 from IPython.external.qt import QtCore, QtGui
17 17
 
18 18
 # Local imports
19  
-from IPython.config.configurable import Configurable
  19
+from IPython.config.configurable import LoggingConfigurable
20 20
 from IPython.frontend.qt.rich_text import HtmlExporter
21 21
 from IPython.frontend.qt.util import MetaQObjectHasTraits, get_font
22 22
 from IPython.utils.text import columnize
@@ -39,7 +39,7 @@ def is_letter_or_number(char):
39 39
 # Classes
40 40
 #-----------------------------------------------------------------------------
41 41
 
42  
-class ConsoleWidget(Configurable, QtGui.QWidget):
  42
+class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):
43 43
     """ An abstract base class for console-type widgets. This class has 
44 44
         functionality for:
45 45
 
@@ -170,7 +170,7 @@ def __init__(self, parent=None, **kw):
170 170
             The parent for this widget.
171 171
         """
172 172
         QtGui.QWidget.__init__(self, parent)
173  
-        Configurable.__init__(self, **kw)
  173
+        LoggingConfigurable.__init__(self, **kw)
174 174
 
175 175
         # Create the layout and underlying text widget.
176 176
         layout = QtGui.QStackedLayout(self)
22  IPython/frontend/qt/console/ipython_widget.py
@@ -12,6 +12,7 @@
12 12
 import re
13 13
 from subprocess import Popen
14 14
 import sys
  15
+import time
15 16
 from textwrap import dedent
16 17
 
17 18
 # System library imports
@@ -104,6 +105,7 @@ class IPythonWidget(FrontendWidget):
104 105
     _payload_source_exit = zmq_shell_source + '.ask_exit'
105 106
     _payload_source_next_input = zmq_shell_source + '.set_next_input'
106 107
     _payload_source_page = 'IPython.zmq.page.page'
  108
+    _retrying_history_request = False
107 109
 
108 110
     #---------------------------------------------------------------------------
109 111
     # 'object' interface
@@ -174,7 +176,25 @@ def _handle_history_reply(self, msg):
174 176
         """ Implemented to handle history tail replies, which are only supported
175 177
             by the IPython kernel.
176 178
         """
177  
-        history_items = msg['content']['history']
  179
+        content = msg['content']
  180
+        if 'history' not in content:
  181
+            self.log.error("History request failed: %r"%content)
  182
+            if content.get('status', '') == 'aborted' and \
  183
+                                            not self._retrying_history_request:
  184
+                # a *different* action caused this request to be aborted, so
  185
+                # we should try again.
  186
+                self.log.error("Retrying aborted history request")
  187
+                # prevent multiple retries of aborted requests:
  188
+                self._retrying_history_request = True
  189
+                # wait out the kernel's queue flush, which is currently timed at 0.1s
  190
+                time.sleep(0.25)
  191
+                self.kernel_manager.shell_channel.history(hist_access_type='tail',n=1000)
  192
+            else:
  193
+                self._retrying_history_request = False
  194
+            return
  195
+        # reset retry flag
  196
+        self._retrying_history_request = False
  197
+        history_items = content['history']
178 198
         items = [ line.rstrip() for _, _, line in history_items ]
179 199
         self._set_history(items)
180 200
 
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.