Skip to content
This repository

minor post-execute fixes (#1154) #1155

Merged
merged 3 commits into from over 2 years ago

2 participants

Min RK Fernando Perez
Min RK
Owner

Two changes:

  1. Don't unregister failing post-exec callbacks automatically. Instead, print a message regarding the failure, pointing to new disable_failing_post_execute trait for skipping failing callbacks.
    • When this flag is False (the default), failing callbacks will continue to be called.
    • When True, behavior is unchanged from previous, where callbacks are only allowed to fail once.
  2. protect flush_figures() post-exec function from user error. Invalid matplotlib data may raise inside print_figure(). flush_figures() is a post-exec function, so user errors should not raise. Instead, call get_ipython().showtraceback() if called from IPython, raising as before otherwise.

closes #1154

added some commits December 14, 2011
Min RK Don't unregister failing post-exec callbacks automatically
Instead, print a message regarding the failure, pointing to new
`disable_failing_post_execute` trait for skipping failing callbacks.

When this flag is False (the default), failing callbacks will continue to be called.
When True, behavior is unchanged from previous, where callbacks are only allowed to fail once.
f972ef8
Min RK protect flush_figures post-exec function from user error
Invalid matplotlib data may raise inside print_figure.  flush_figures()
is a post-exec function, so user errors should not raise.  Instead,
call get_ipython().showtraceback() if called from IPython, raising as before
otherwise.
c98183c
Fernando Perez
Owner

Reviewed together at Berkeley, @minrk is making one tiny fix and then we'll merge.

Fernando Perez fperez merged commit 2c683b7 into from December 14, 2011
Fernando Perez fperez closed this December 14, 2011
Fernando Perez fperez 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.

Dec 14, 2011
Min RK Don't unregister failing post-exec callbacks automatically
Instead, print a message regarding the failure, pointing to new
`disable_failing_post_execute` trait for skipping failing callbacks.

When this flag is False (the default), failing callbacks will continue to be called.
When True, behavior is unchanged from previous, where callbacks are only allowed to fail once.
f972ef8
Min RK protect flush_figures post-exec function from user error
Invalid matplotlib data may raise inside print_figure.  flush_figures()
is a post-exec function, so user errors should not raise.  Instead,
call get_ipython().showtraceback() if called from IPython, raising as before
otherwise.
c98183c
Min RK don't catch potential NameErrors in showtraceback() b319385
This page is out of date. Refresh to see the latest.
18  IPython/core/interactiveshell.py
@@ -261,6 +261,9 @@ class InteractiveShell(SingletonConfigurable, Magic):
261 261
         deep_reload will still be available as dreload().
262 262
         """
263 263
     )
  264
+    disable_failing_post_execute = CBool(False, config=True,
  265
+        help="Don't call post-execute functions that have failed in the past."""
  266
+    )
264 267
     display_formatter = Instance(DisplayFormatter)
265 268
     displayhook_class = Type(DisplayHook)
266 269
     display_pub_class = Type(DisplayPublisher)
@@ -749,7 +752,7 @@ def register_post_execute(self, func):
749 752
         if not callable(func):
750 753
             raise ValueError('argument %s must be callable' % func)
751 754
         self._post_execute[func] = True
752  
-
  755
+    
753 756
     #-------------------------------------------------------------------------
754 757
     # Things related to the "main" module
755 758
     #-------------------------------------------------------------------------
@@ -2426,17 +2429,22 @@ def run_cell(self, raw_cell, store_history=False):
2426 2429
 
2427 2430
                     # Execute any registered post-execution functions.
2428 2431
                     for func, status in self._post_execute.iteritems():
2429  
-                        if not status:
  2432
+                        if self.disable_failing_post_execute and not status:
2430 2433
                             continue
2431 2434
                         try:
2432 2435
                             func()
2433 2436
                         except KeyboardInterrupt:
2434 2437
                             print >> io.stderr, "\nKeyboardInterrupt"
2435 2438
                         except Exception:
2436  
-                            print >> io.stderr, "Disabling failed post-execution function: %s" % func
2437  
-                            self.showtraceback()
2438  
-                            # Deactivate failing function
  2439
+                            # register as failing:
2439 2440
                             self._post_execute[func] = False
  2441
+                            self.showtraceback()
  2442
+                            print >> io.stderr, '\n'.join([
  2443
+                                "post-execution function %r produced an error." % func,
  2444
+                                "If this problem persists, you can disable failing post-exec functions with:",
  2445
+                                "",
  2446
+                                "    get_ipython().disable_failing_post_execute = True"
  2447
+                            ])
2440 2448
 
2441 2449
         if store_history:
2442 2450
             # Write output to the database. Does nothing unless
37  IPython/zmq/pylab/backend_inline.py
@@ -140,19 +140,43 @@ def flush_figures():
140 140
 
141 141
     This is meant to be called automatically and will call show() if, during
142 142
     prior code execution, there had been any calls to draw_if_interactive.
  143
+    
  144
+    This function is meant to be used as a post_execute callback in IPython,
  145
+    so user-caused errors are handled with showtraceback() instead of being
  146
+    allowed to raise.  If this function is not called from within IPython,
  147
+    then these exceptions will raise.
143 148
     """
144 149
     if not show._draw_called:
145 150
         return
146 151
     
147 152
     if InlineBackend.instance().close_figures:
148 153
         # ignore the tracking, just draw and close all figures
149  
-        return show(True)
150  
-    
  154
+        try:
  155
+            return show(True)
  156
+        except Exception as e:
  157
+            # safely show traceback if in IPython, else raise
  158
+            try:
  159
+                get_ipython
  160
+            except NameError:
  161
+                raise e
  162
+            else:
  163
+                get_ipython().showtraceback()
  164
+                return
151 165
     try:
152 166
         # exclude any figures that were closed:
153 167
         active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
154 168
         for fig in [ fig for fig in show._to_draw if fig in active ]:
155  
-            send_figure(fig)
  169
+            try:
  170
+                send_figure(fig)
  171
+            except Exception as e:
  172
+                # safely show traceback if in IPython, else raise
  173
+                try:
  174
+                    get_ipython
  175
+                except NameError:
  176
+                    raise e
  177
+                else:
  178
+                    get_ipython().showtraceback()
  179
+                    break
156 180
     finally:
157 181
         # clear flags for next round
158 182
         show._to_draw = []
@@ -162,12 +186,11 @@ def flush_figures():
162 186
 def send_figure(fig):
163 187
     """Draw the current figure and send it as a PNG payload.
164 188
     """
165  
-    # For an empty figure, don't even bother calling figure_to_svg, to avoid
166  
-    # big blank spaces in the qt console
167  
-    if not fig.axes:
168  
-        return
169 189
     fmt = InlineBackend.instance().figure_format
170 190
     data = print_figure(fig, fmt)
  191
+    # print_figure will return None if there's nothing to draw:
  192
+    if data is None:
  193
+        return
171 194
     mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
172 195
     mime = mimetypes[fmt]
173 196
     # flush text streams before sending figures, helps a little with output
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.