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 | 14 | if hasattr(c.Global, 'exec_lines'): |
|
15 | 15 | c.Global.exec_lines.append(lines) |
|
16 | 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 | 86 | """Store ipython references in the __builtin__ namespace.""" |
|
87 | 87 | self.add_builtin('exit', Quitter(self.shell, 'exit')) |
|
88 | 88 | self.add_builtin('quit', Quitter(self.shell, 'quit')) |
|
89 | self.add_builtin('get_ipython', self.shell.get_ipython) | |
|
89 | 90 | |
|
90 | 91 | # Recursive reload function |
|
91 | 92 | try: |
@@ -263,9 +263,13 b' class InteractiveMultiEngineClient(object):' | |||
|
263 | 263 | """ |
|
264 | 264 | |
|
265 | 265 | try: |
|
266 | __IPYTHON__.activeController = self | |
|
266 | # This is injected into __builtins__. | |
|
267 | ip = get_ipython() | |
|
267 | 268 | except NameError: |
|
268 |
print "The 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 | 274 | def __setitem__(self, key, value): |
|
271 | 275 | """Add a dictionary interface for pushing/pulling. |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now