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 |
|
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