diff --git a/IPython/config/profile/ipython_config_cluster.py b/IPython/config/profile/ipython_config_cluster.py
index 3273396..fd795a4 100644
--- a/IPython/config/profile/ipython_config_cluster.py
+++ b/IPython/config/profile/ipython_config_cluster.py
@@ -14,4 +14,11 @@ from IPython.kernel.client import *
if hasattr(c.Global, 'exec_lines'):
c.Global.exec_lines.append(lines)
else:
- c.Global.exec_lines = [lines]
\ No newline at end of file
+ c.Global.exec_lines = [lines]
+
+# Load the parallelmagic extension to enable %result, %px, %autopx magics.
+if hasattr(c.Global, 'extensions'):
+ c.Global.extensions.append('parallelmagic')
+else:
+ c.Global.extensions = ['parallelmagic']
+
diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py
index ac59cae..8ddbcf7 100644
--- a/IPython/core/builtin_trap.py
+++ b/IPython/core/builtin_trap.py
@@ -86,6 +86,7 @@ class BuiltinTrap(Component):
"""Store ipython references in the __builtin__ namespace."""
self.add_builtin('exit', Quitter(self.shell, 'exit'))
self.add_builtin('quit', Quitter(self.shell, 'quit'))
+ self.add_builtin('get_ipython', self.shell.get_ipython)
# Recursive reload function
try:
diff --git a/IPython/extensions/cluster_magic.py b/IPython/extensions/cluster_magic.py
deleted file mode 100644
index fb8fa37..0000000
--- a/IPython/extensions/cluster_magic.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-
-"""Magic command interface for interactive parallel work."""
-
-#-----------------------------------------------------------------------------
-# Copyright (C) 2008-2009 The IPython Development Team
-#
-# Distributed under the terms of the BSD License. The full license is in
-# the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# Imports
-#-----------------------------------------------------------------------------
-
-from IPython.core.component import Component
-from IPython.utils.traitlets import Bool, Any
-from IPython.utils.autoattr import auto_attr
-
-
-#-------------------------------------------------------------------------------
-# Definitions of magic functions for use with IPython
-#-------------------------------------------------------------------------------
-
-NO_ACTIVE_MULTIENGINE_CLIENT = """
-Error: No Controller is activated
-Use activate() on a MultiEngineClient object to activate it for magics.
-"""
-
-
-class ParalleMagicComponent(Component):
-
- active_multiengine_client = Any()
- verbose = Bool(False, config=True)
-
- def __init__(self, parent, name=None, config=None):
- super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
- self._define_magics()
-
- # Access other components like this rather than by a regular attribute.
- # This won't lookup the InteractiveShell object until it is used and
- # then it is cached. This is both efficient and couples this class
- # more loosely to InteractiveShell.
- @auto_attr
- def shell(self):
- return Component.get_instances(
- root=self.root,
- klass='IPython.core.iplib.InteractiveShell')[0]
-
- def _define_magics(self):
- self.shell.define_magic('result', self.magic_result)
- self.shell.define_magic('px', self.magic_px)
- self.shell.define_magic('autopx', self.magix_autopx)
-
- def magic_result(self, ipself, parameter_s=''):
- """Print the result of command i on all engines of the active controller.
-
- To activate a controller in IPython, first create it and then call
- the activate() method.
-
- Then you can do the following:
-
- >>> result # Print the latest result
- Printing result...
- [127.0.0.1:0] In [1]: b = 10
- [127.0.0.1:1] In [1]: b = 10
-
- >>> result 0 # Print result 0
- In [14]: result 0
- Printing result...
- [127.0.0.1:0] In [0]: a = 5
- [127.0.0.1:1] In [0]: a = 5
- """
- if self.active_multiengine_client is None:
- print NO_ACTIVE_MULTIENGINE_CLIENT
- return
-
- try:
- index = int(parameter_s)
- except:
- index = None
- result = self.active_multiengine_client.get_result(index)
- return result
-
- # def magic_px(self,parameter_s=''):
- # """Executes the given python command on the active IPython Controller.
- #
- # To activate a Controller in IPython, first create it and then call
- # the activate() method.
- #
- # Then you can do the following:
- #
- # >>> %px a = 5 # Runs a = 5 on all nodes
- # """
- #
- # try:
- # activeController = __IPYTHON__.activeController
- # except AttributeError:
- # print NO_ACTIVE_CONTROLLER
- # else:
- # print "Parallel execution on engines: %s" % activeController.targets
- # result = activeController.execute(parameter_s)
- # return result
- #
- # def pxrunsource(self, source, filename="", symbol="single"):
- #
- # try:
- # code = self.compile(source, filename, symbol)
- # except (OverflowError, SyntaxError, ValueError):
- # # Case 1
- # self.showsyntaxerror(filename)
- # return None
- #
- # if code is None:
- # # Case 2
- # return True
- #
- # # Case 3
- # # Because autopx is enabled, we now call executeAll or disable autopx if
- # # %autopx or autopx has been called
- # if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
- # _disable_autopx(self)
- # return False
- # else:
- # try:
- # result = self.activeController.execute(source)
- # except:
- # self.showtraceback()
- # else:
- # print result.__repr__()
- # return False
- #
- # def magic_autopx(self, parameter_s=''):
- # """Toggles auto parallel mode for the active IPython Controller.
- #
- # To activate a Controller in IPython, first create it and then call
- # the activate() method.
- #
- # Then you can do the following:
- #
- # >>> %autopx # Now all commands are executed in parallel
- # Auto Parallel Enabled
- # Type %autopx to disable
- # ...
- # >>> %autopx # Now all commands are locally executed
- # Auto Parallel Disabled
- # """
- #
- # if hasattr(self, 'autopx'):
- # if self.autopx == True:
- # _disable_autopx(self)
- # else:
- # _enable_autopx(self)
- # else:
- # _enable_autopx(self)
- #
- # def _enable_autopx(self):
- # """Enable %autopx mode by saving the original runsource and installing
- # pxrunsource.
- # """
- # try:
- # activeController = __IPYTHON__.activeController
- # except AttributeError:
- # print "No active RemoteController found, use RemoteController.activate()."
- # else:
- # self._original_runsource = self.runsource
- # self.runsource = new.instancemethod(pxrunsource, self, self.__class__)
- # self.autopx = True
- # print "Auto Parallel Enabled\nType %autopx to disable"
- #
- # def _disable_autopx(self):
- # """Disable %autopx by restoring the original runsource."""
- # if hasattr(self, 'autopx'):
- # if self.autopx == True:
- # self.runsource = self._original_runsource
- # self.autopx = False
- # print "Auto Parallel Disabled"
-
-
-_loaded = False
-
-def load_ipython_extension(ip):
- """Load the extension in IPython as a hook."""
- global _loaded
- if not _loaded:
- prd = ParalleMagicComponent(ip, name='parallel_magic')
- _loaded = True
-
diff --git a/IPython/extensions/parallelmagic.py b/IPython/extensions/parallelmagic.py
new file mode 100644
index 0000000..f72b3b6
--- /dev/null
+++ b/IPython/extensions/parallelmagic.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""Magic command interface for interactive parallel work."""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import new
+
+from IPython.core.component import Component
+from IPython.utils.traitlets import Bool, Any
+from IPython.utils.autoattr import auto_attr
+
+#-----------------------------------------------------------------------------
+# Definitions of magic functions for use with IPython
+#-----------------------------------------------------------------------------
+
+
+NO_ACTIVE_MULTIENGINE_CLIENT = """
+Use activate() on a MultiEngineClient object to activate it for magics.
+"""
+
+
+class ParalleMagicComponent(Component):
+ """A component to manage the %result, %px and %autopx magics."""
+
+ active_multiengine_client = Any()
+ verbose = Bool(False, config=True)
+
+ def __init__(self, parent, name=None, config=None):
+ super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
+ self._define_magics()
+ # A flag showing if autopx is activated or not
+ self.autopx = False
+
+ # Access other components like this rather than by a regular attribute.
+ # This won't lookup the InteractiveShell object until it is used and
+ # then it is cached. This is both efficient and couples this class
+ # more loosely to InteractiveShell.
+ @auto_attr
+ def shell(self):
+ return Component.get_instances(
+ root=self.root,
+ klass='IPython.core.iplib.InteractiveShell')[0]
+
+ def _define_magics(self):
+ """Define the magic functions."""
+ self.shell.define_magic('result', self.magic_result)
+ self.shell.define_magic('px', self.magic_px)
+ self.shell.define_magic('autopx', self.magic_autopx)
+
+ def magic_result(self, ipself, parameter_s=''):
+ """Print the result of command i on all engines..
+
+ To use this a :class:`MultiEngineClient` instance must be created
+ and then activated by calling its :meth:`activate` method.
+
+ Then you can do the following::
+
+ In [23]: %result
+ Out[23]:
+
+ [0] In [6]: a = 10
+ [1] In [6]: a = 10
+
+ In [22]: %result 6
+ Out[22]:
+
+ [0] In [6]: a = 10
+ [1] In [6]: a = 10
+ """
+ if self.active_multiengine_client is None:
+ print NO_ACTIVE_MULTIENGINE_CLIENT
+ return
+
+ try:
+ index = int(parameter_s)
+ except:
+ index = None
+ result = self.active_multiengine_client.get_result(index)
+ return result
+
+ def magic_px(self, ipself, parameter_s=''):
+ """Executes the given python command in parallel.
+
+ To use this a :class:`MultiEngineClient` instance must be created
+ and then activated by calling its :meth:`activate` method.
+
+ Then you can do the following::
+
+ In [24]: %px a = 5
+ Parallel execution on engines: all
+ Out[24]:
+
+ [0] In [7]: a = 5
+ [1] In [7]: a = 5
+ """
+
+ if self.active_multiengine_client is None:
+ print NO_ACTIVE_MULTIENGINE_CLIENT
+ return
+ print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
+ result = self.active_multiengine_client.execute(parameter_s)
+ return result
+
+ def magic_autopx(self, ipself, parameter_s=''):
+ """Toggles auto parallel mode.
+
+ To use this a :class:`MultiEngineClient` instance must be created
+ and then activated by calling its :meth:`activate` method. Once this
+ is called, all commands typed at the command line are send to
+ the engines to be executed in parallel. To control which engine
+ are used, set the ``targets`` attributed of the multiengine client
+ before entering ``%autopx`` mode.
+
+ Then you can do the following::
+
+ In [25]: %autopx
+ %autopx to enabled
+
+ In [26]: a = 10
+
+ [0] In [8]: a = 10
+ [1] In [8]: a = 10
+
+
+ In [27]: %autopx
+ %autopx disabled
+ """
+ if self.autopx:
+ self._disable_autopx()
+ else:
+ self._enable_autopx()
+
+ def _enable_autopx(self):
+ """Enable %autopx mode by saving the original runsource and installing
+ pxrunsource.
+ """
+ if self.active_multiengine_client is None:
+ print NO_ACTIVE_MULTIENGINE_CLIENT
+ return
+
+ self._original_runsource = self.shell.runsource
+ self.shell.runsource = new.instancemethod(
+ self.pxrunsource, self.shell, self.shell.__class__
+ )
+ self.autopx = True
+ print "%autopx enabled"
+
+ def _disable_autopx(self):
+ """Disable %autopx by restoring the original InteractiveShell.runsource."""
+ if self.autopx:
+ self.shell.runsource = self._original_runsource
+ self.autopx = False
+ print "%autopx disabled"
+
+ def pxrunsource(self, ipself, source, filename="", symbol="single"):
+ """A parallel replacement for InteractiveShell.runsource."""
+
+ try:
+ code = ipself.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ ipself.showsyntaxerror(filename)
+ return None
+
+ if code is None:
+ # Case 2
+ return True
+
+ # Case 3
+ # Because autopx is enabled, we now call executeAll or disable autopx if
+ # %autopx or autopx has been called
+ if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
+ self._disable_autopx()
+ return False
+ else:
+ try:
+ result = self.active_multiengine_client.execute(source)
+ except:
+ ipself.showtraceback()
+ else:
+ print result.__repr__()
+ return False
+
+
+_loaded = False
+
+
+def load_ipython_extension(ip):
+ """Load the extension in IPython."""
+ global _loaded
+ if not _loaded:
+ prd = ParalleMagicComponent(ip, name='parallel_magic')
+ _loaded = True
+
diff --git a/IPython/kernel/multiengineclient.py b/IPython/kernel/multiengineclient.py
index 0f3b406..256c174 100644
--- a/IPython/kernel/multiengineclient.py
+++ b/IPython/kernel/multiengineclient.py
@@ -263,9 +263,13 @@ class InteractiveMultiEngineClient(object):
"""
try:
- __IPYTHON__.activeController = self
+ # This is injected into __builtins__.
+ ip = get_ipython()
except NameError:
- print "The IPython Controller magics only work within IPython."
+ print "The IPython parallel magics (%result, %px, %autopx) only work within IPython."
+ else:
+ pmagic = ip.get_component('parallel_magic')
+ pmagic.active_multiengine_client = self
def __setitem__(self, key, value):
"""Add a dictionary interface for pushing/pulling.