##// END OF EJS Templates
Multiple improvements to tab completion....
Multiple improvements to tab completion. I refactored the API quite a bit, to retain readline compatibility but make it more independent of readline. There's still more to do in cleaning up our init_readline() method, but now the completer objects have separate rlcomplete() and complete() methods. The former uses the quirky readline API with a state flag, while the latter is stateless, takes only text information, and is more suitable for GUIs and other frontends to call programatically. Made other minor fixes to ensure the test suite passes in full. While all this code is a bit messy, we're getting in the direction of the APIs we need in the long run.

File last commit:

r2760:afe1263a
r2839:8cff4913
Show More
parallelmagic.py
201 lines | 6.4 KiB | text/x-python | PythonLexer
#!/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.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
#-----------------------------------------------------------------------------
# Definitions of magic functions for use with IPython
#-----------------------------------------------------------------------------
NO_ACTIVE_MULTIENGINE_CLIENT = """
Use activate() on a MultiEngineClient object to activate it for magics.
"""
class ParalleMagic(Plugin):
"""A component to manage the %result, %px and %autopx magics."""
active_multiengine_client = Any()
verbose = Bool(False, config=True)
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
def __init__(self, shell=None, config=None):
super(ParalleMagic, self).__init__(shell=shell, config=config)
self._define_magics()
# A flag showing if autopx is activated or not
self.autopx = False
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)
@testdec.skip_doctest
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]:
<Results List>
[0] In [6]: a = 10
[1] In [6]: a = 10
In [22]: %result 6
Out[22]:
<Results List>
[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
@testdec.skip_doctest
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]:
<Results List>
[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
@testdec.skip_doctest
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
<Results List>
[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="<input>", 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:
plugin = ParalleMagic(shell=ip, config=ip.config)
ip.plugin_manager.register_plugin('parallel_magic', plugin)
_loaded = True