Permalink
Browse files

fix %autopx in scripts by calling run_code for each ast node

Previously, there was no call to override if %autopx was called inside
a single cell (e.g. %run script.ipy). This splits run_ast_nodes, so that
each node gets a separate call to run_code.

reviewed changes:
* remove old use of 'new'
* fix interactiveshell.run_code docstring

Additional change:
automatically load parallelmagic extension on view.activate()
  • Loading branch information...
1 parent db2dba6 commit 31c15b8f73713c934f7b0c64ae6fc602bea7d99c @minrk committed Apr 9, 2011
Showing with 89 additions and 40 deletions.
  1. +23 −12 IPython/core/interactiveshell.py
  2. +61 −23 IPython/extensions/parallelmagic.py
  3. +5 −5 IPython/parallel/client/view.py
View
35 IPython/core/interactiveshell.py
@@ -2211,15 +2211,20 @@ def run_ast_nodes(self, nodelist, cell_name, interactivity='last'):
exec_count = self.execution_count
if to_run_exec:
- mod = ast.Module(to_run_exec)
- self.code_to_run = code = self.compile(mod, cell_name, "exec")
- if self.run_code(code) == 1:
- return
-
+ for i, node in enumerate(to_run_exec):
+ mod = ast.Module([node])
+ self.code_to_run = code = self.compile(mod, cell_name+str(i), "exec")
+ if self.run_code(code) == 1:
+ return 1
+
if to_run_interactive:
- mod = ast.Interactive(to_run_interactive)
- self.code_to_run = code = self.compile(mod, cell_name, "single")
- return self.run_code(code)
+ for i, node in enumerate(to_run_interactive):
+ mod = ast.Interactive([node])
+ self.code_to_run = code = self.compile(mod, cell_name, "single")
+ if self.run_code(code) == 1:
+ return 1
+
+ return 0
# PENDING REMOVAL: this method is slated for deletion, once our new
@@ -2336,11 +2341,17 @@ def run_code(self, code_obj):
When an exception occurs, self.showtraceback() is called to display a
traceback.
- Return value: a flag indicating whether the code to be run completed
- successfully:
+ Parameters
+ ----------
+ code_obj : code object
+ A compiled code object, to be executed
+ post_execute : bool [default: True]
+ whether to call post_execute hooks after this particular execution.
- - 0: successful execution.
- - 1: an error occurred.
+ Returns
+ -------
+ 0 : successful execution.
+ 1 : an error occurred.
"""
# Set our own excepthook in case the user code tries to call it
View
84 IPython/extensions/parallelmagic.py
@@ -15,12 +15,10 @@
#-----------------------------------------------------------------------------
import ast
-import new
import re
from IPython.core.plugin import Plugin
from IPython.utils.traitlets import Bool, Any, Instance
-from IPython.utils.autoattr import auto_attr
from IPython.testing import decorators as testdec
#-----------------------------------------------------------------------------
@@ -146,10 +144,12 @@ def _enable_autopx(self):
print NO_ACTIVE_VIEW
return
+ # override run_cell and run_code
self._original_run_cell = self.shell.run_cell
- self.shell.run_cell = new.instancemethod(
- self.pxrun_cell, self.shell, self.shell.__class__
- )
+ self.shell.run_cell = self.pxrun_cell
+ self._original_run_code = self.shell.run_code
+ self.shell.run_code = self.pxrun_code
+
self.autopx = True
print "%autopx enabled"
@@ -158,14 +158,43 @@ def _disable_autopx(self):
"""
if self.autopx:
self.shell.run_cell = self._original_run_cell
+ self.shell.run_code = self._original_run_code
self.autopx = False
print "%autopx disabled"
- def pxrun_cell(self, ipself, cell, store_history=True):
+ def _maybe_display_output(self, result):
+ """Maybe display the output of a parallel result.
+
+ If self.active_view.block is True, wait for the result
+ and display the result. Otherwise, this is a noop.
+ """
+ if self.active_view.block:
+ try:
+ result.get()
+ except:
+ self.shell.showtraceback()
+ return True
+ else:
+ targets = self.active_view.targets
+ if isinstance(targets, int):
+ targets = [targets]
+ if targets == 'all':
+ targets = self.active_view.client.ids
+ stdout = [s.rstrip() for s in result.stdout]
+ if any(stdout):
+ for i,eid in enumerate(targets):
+ print '[stdout:%i]'%eid, stdout[i]
+ return False
+
+
+ def pxrun_cell(self, cell, store_history=True):
"""drop-in replacement for InteractiveShell.run_cell.
This executes code remotely, instead of in the local namespace.
+
+ See InteractiveShell.run_cell for details.
"""
+ ipself = self.shell
raw_cell = cell
with ipself.builtin_trap:
cell = ipself.prefilter_manager.prefilter_lines(cell)
@@ -187,6 +216,7 @@ def pxrun_cell(self, ipself, cell, store_history=True):
ipself.execution_count += 1
return None
except NameError:
+ # ignore name errors, because we don't know the remote keys
pass
if store_history:
@@ -195,7 +225,6 @@ def pxrun_cell(self, ipself, cell, store_history=True):
ipself.history_manager.store_output(ipself.execution_count)
# Each cell is a *single* input, regardless of how many lines it has
ipself.execution_count += 1
- print cell
if re.search(r'get_ipython\(\)\.magic\(u?"%?autopx', cell):
self._disable_autopx()
@@ -206,23 +235,32 @@ def pxrun_cell(self, ipself, cell, store_history=True):
except:
ipself.showtraceback()
return False
-
- if self.active_view.block:
- try:
- result.get()
- except:
- ipself.showtraceback()
- else:
- targets = self.active_view.targets
- if isinstance(targets, int):
- targets = [targets]
- if targets == 'all':
- targets = self.active_view.client.ids
- stdout = [s.rstrip() for s in result.stdout]
- if any(stdout):
- for i,eid in enumerate(targets):
- print '[stdout:%i]'%eid, stdout[i]
+ else:
+ return self._maybe_display_output(result)
+
+ def pxrun_code(self, code_obj, post_execute=True):
+ """drop-in replacement for InteractiveShell.run_code.
+
+ This executes code remotely, instead of in the local namespace.
+
+ See InteractiveShell.run_code for details.
+ """
+ ipself = self.shell
+ # check code object for the autopx magic
+ if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names and \
+ any( [ isinstance(c, basestring) and 'autopx' in c for c in code_obj.co_consts ]):
+ self._disable_autopx()
return False
+ else:
+ try:
+ result = self.active_view.execute(code_obj, block=False)
+ except:
+ ipself.showtraceback()
+ return False
+ else:
+ return self._maybe_display_output(result)
+
+
_loaded = False
View
10 IPython/parallel/client/view.py
@@ -765,11 +765,11 @@ def activate(self):
print "The IPython parallel magics (%result, %px, %autopx) only work within IPython."
else:
pmagic = ip.plugin_manager.get_plugin('parallelmagic')
- if pmagic is not None:
- pmagic.active_view = self
- else:
- print "You must first load the parallelmagic extension " \
- "by doing '%load_ext parallelmagic'"
+ if pmagic is None:
+ ip.magic_load_ext('parallelmagic')
+ pmagic = ip.plugin_manager.get_plugin('parallelmagic')
+
+ pmagic.active_view = self
@testdec.skip_doctest

0 comments on commit 31c15b8

Please sign in to comment.