From 31c15b8f73713c934f7b0c64ae6fc602bea7d99c 2011-04-11 18:27:28 From: MinRK Date: 2011-04-11 18:27:28 Subject: [PATCH] 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() --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 89fa687..72c4de9 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2211,15 +2211,20 @@ class InteractiveShell(Configurable, Magic): 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 @@ class InteractiveShell(Configurable, Magic): 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 diff --git a/IPython/extensions/parallelmagic.py b/IPython/extensions/parallelmagic.py index ba93762..ea672a1 100755 --- a/IPython/extensions/parallelmagic.py +++ b/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 @@ class ParalleMagic(Plugin): 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 @@ class ParalleMagic(Plugin): """ 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 @@ class ParalleMagic(Plugin): 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 @@ class ParalleMagic(Plugin): 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 @@ class ParalleMagic(Plugin): 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 diff --git a/IPython/parallel/client/view.py b/IPython/parallel/client/view.py index fb6903b..647729d 100644 --- a/IPython/parallel/client/view.py +++ b/IPython/parallel/client/view.py @@ -765,11 +765,11 @@ class DirectView(View): 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