Skip to content

Commit

Permalink
fix %autopx in scripts by calling run_code for each ast node
Browse files Browse the repository at this point in the history
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
minrk committed Apr 11, 2011
1 parent db2dba6 commit 31c15b8
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 40 deletions.
35 changes: 23 additions & 12 deletions IPython/core/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
84 changes: 61 additions & 23 deletions IPython/extensions/parallelmagic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

#-----------------------------------------------------------------------------
Expand Down Expand Up @@ -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"

Expand All @@ -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)
Expand All @@ -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:
Expand All @@ -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()
Expand All @@ -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
Expand Down
10 changes: 5 additions & 5 deletions IPython/parallel/client/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 31c15b8

Please sign in to comment.