##// END OF EJS Templates
Parallel magics (%result, %px, %autopx) are fixed....
Brian Granger -
Show More
@@ -0,0 +1,205 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3
4 """Magic command interface for interactive parallel work."""
5
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 import new
18
19 from IPython.core.component import Component
20 from IPython.utils.traitlets import Bool, Any
21 from IPython.utils.autoattr import auto_attr
22
23 #-----------------------------------------------------------------------------
24 # Definitions of magic functions for use with IPython
25 #-----------------------------------------------------------------------------
26
27
28 NO_ACTIVE_MULTIENGINE_CLIENT = """
29 Use activate() on a MultiEngineClient object to activate it for magics.
30 """
31
32
33 class ParalleMagicComponent(Component):
34 """A component to manage the %result, %px and %autopx magics."""
35
36 active_multiengine_client = Any()
37 verbose = Bool(False, config=True)
38
39 def __init__(self, parent, name=None, config=None):
40 super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
41 self._define_magics()
42 # A flag showing if autopx is activated or not
43 self.autopx = False
44
45 # Access other components like this rather than by a regular attribute.
46 # This won't lookup the InteractiveShell object until it is used and
47 # then it is cached. This is both efficient and couples this class
48 # more loosely to InteractiveShell.
49 @auto_attr
50 def shell(self):
51 return Component.get_instances(
52 root=self.root,
53 klass='IPython.core.iplib.InteractiveShell')[0]
54
55 def _define_magics(self):
56 """Define the magic functions."""
57 self.shell.define_magic('result', self.magic_result)
58 self.shell.define_magic('px', self.magic_px)
59 self.shell.define_magic('autopx', self.magic_autopx)
60
61 def magic_result(self, ipself, parameter_s=''):
62 """Print the result of command i on all engines..
63
64 To use this a :class:`MultiEngineClient` instance must be created
65 and then activated by calling its :meth:`activate` method.
66
67 Then you can do the following::
68
69 In [23]: %result
70 Out[23]:
71 <Results List>
72 [0] In [6]: a = 10
73 [1] In [6]: a = 10
74
75 In [22]: %result 6
76 Out[22]:
77 <Results List>
78 [0] In [6]: a = 10
79 [1] In [6]: a = 10
80 """
81 if self.active_multiengine_client is None:
82 print NO_ACTIVE_MULTIENGINE_CLIENT
83 return
84
85 try:
86 index = int(parameter_s)
87 except:
88 index = None
89 result = self.active_multiengine_client.get_result(index)
90 return result
91
92 def magic_px(self, ipself, parameter_s=''):
93 """Executes the given python command in parallel.
94
95 To use this a :class:`MultiEngineClient` instance must be created
96 and then activated by calling its :meth:`activate` method.
97
98 Then you can do the following::
99
100 In [24]: %px a = 5
101 Parallel execution on engines: all
102 Out[24]:
103 <Results List>
104 [0] In [7]: a = 5
105 [1] In [7]: a = 5
106 """
107
108 if self.active_multiengine_client is None:
109 print NO_ACTIVE_MULTIENGINE_CLIENT
110 return
111 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
112 result = self.active_multiengine_client.execute(parameter_s)
113 return result
114
115 def magic_autopx(self, ipself, parameter_s=''):
116 """Toggles auto parallel mode.
117
118 To use this a :class:`MultiEngineClient` instance must be created
119 and then activated by calling its :meth:`activate` method. Once this
120 is called, all commands typed at the command line are send to
121 the engines to be executed in parallel. To control which engine
122 are used, set the ``targets`` attributed of the multiengine client
123 before entering ``%autopx`` mode.
124
125 Then you can do the following::
126
127 In [25]: %autopx
128 %autopx to enabled
129
130 In [26]: a = 10
131 <Results List>
132 [0] In [8]: a = 10
133 [1] In [8]: a = 10
134
135
136 In [27]: %autopx
137 %autopx disabled
138 """
139 if self.autopx:
140 self._disable_autopx()
141 else:
142 self._enable_autopx()
143
144 def _enable_autopx(self):
145 """Enable %autopx mode by saving the original runsource and installing
146 pxrunsource.
147 """
148 if self.active_multiengine_client is None:
149 print NO_ACTIVE_MULTIENGINE_CLIENT
150 return
151
152 self._original_runsource = self.shell.runsource
153 self.shell.runsource = new.instancemethod(
154 self.pxrunsource, self.shell, self.shell.__class__
155 )
156 self.autopx = True
157 print "%autopx enabled"
158
159 def _disable_autopx(self):
160 """Disable %autopx by restoring the original InteractiveShell.runsource."""
161 if self.autopx:
162 self.shell.runsource = self._original_runsource
163 self.autopx = False
164 print "%autopx disabled"
165
166 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
167 """A parallel replacement for InteractiveShell.runsource."""
168
169 try:
170 code = ipself.compile(source, filename, symbol)
171 except (OverflowError, SyntaxError, ValueError):
172 # Case 1
173 ipself.showsyntaxerror(filename)
174 return None
175
176 if code is None:
177 # Case 2
178 return True
179
180 # Case 3
181 # Because autopx is enabled, we now call executeAll or disable autopx if
182 # %autopx or autopx has been called
183 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
184 self._disable_autopx()
185 return False
186 else:
187 try:
188 result = self.active_multiengine_client.execute(source)
189 except:
190 ipself.showtraceback()
191 else:
192 print result.__repr__()
193 return False
194
195
196 _loaded = False
197
198
199 def load_ipython_extension(ip):
200 """Load the extension in IPython."""
201 global _loaded
202 if not _loaded:
203 prd = ParalleMagicComponent(ip, name='parallel_magic')
204 _loaded = True
205
@@ -14,4 +14,11 b' from IPython.kernel.client import *'
14 if hasattr(c.Global, 'exec_lines'):
14 if hasattr(c.Global, 'exec_lines'):
15 c.Global.exec_lines.append(lines)
15 c.Global.exec_lines.append(lines)
16 else:
16 else:
17 c.Global.exec_lines = [lines] No newline at end of file
17 c.Global.exec_lines = [lines]
18
19 # Load the parallelmagic extension to enable %result, %px, %autopx magics.
20 if hasattr(c.Global, 'extensions'):
21 c.Global.extensions.append('parallelmagic')
22 else:
23 c.Global.extensions = ['parallelmagic']
24
@@ -86,6 +86,7 b' class BuiltinTrap(Component):'
86 """Store ipython references in the __builtin__ namespace."""
86 """Store ipython references in the __builtin__ namespace."""
87 self.add_builtin('exit', Quitter(self.shell, 'exit'))
87 self.add_builtin('exit', Quitter(self.shell, 'exit'))
88 self.add_builtin('quit', Quitter(self.shell, 'quit'))
88 self.add_builtin('quit', Quitter(self.shell, 'quit'))
89 self.add_builtin('get_ipython', self.shell.get_ipython)
89
90
90 # Recursive reload function
91 # Recursive reload function
91 try:
92 try:
@@ -263,9 +263,13 b' class InteractiveMultiEngineClient(object):'
263 """
263 """
264
264
265 try:
265 try:
266 __IPYTHON__.activeController = self
266 # This is injected into __builtins__.
267 ip = get_ipython()
267 except NameError:
268 except NameError:
268 print "The IPython Controller magics only work within IPython."
269 print "The IPython parallel magics (%result, %px, %autopx) only work within IPython."
270 else:
271 pmagic = ip.get_component('parallel_magic')
272 pmagic.active_multiengine_client = self
269
273
270 def __setitem__(self, key, value):
274 def __setitem__(self, key, value):
271 """Add a dictionary interface for pushing/pulling.
275 """Add a dictionary interface for pushing/pulling.
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now