##// END OF EJS Templates
update parallel %autopx magics to reflect recent changes in run_cell, run_code
MinRK -
Show More
@@ -1,290 +1,294 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Magic command interface for interactive parallel work."""
4 """Magic command interface for interactive parallel work."""
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import ast
17 import ast
18 import re
18 import re
19
19
20 from IPython.core.plugin import Plugin
20 from IPython.core.plugin import Plugin
21 from IPython.utils.traitlets import Bool, Any, Instance
21 from IPython.utils.traitlets import Bool, Any, Instance
22 from IPython.testing import decorators as testdec
22 from IPython.testing import decorators as testdec
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Definitions of magic functions for use with IPython
25 # Definitions of magic functions for use with IPython
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 NO_ACTIVE_VIEW = """
29 NO_ACTIVE_VIEW = """
30 Use activate() on a DirectView object to activate it for magics.
30 Use activate() on a DirectView object to activate it for magics.
31 """
31 """
32
32
33
33
34 class ParalleMagic(Plugin):
34 class ParalleMagic(Plugin):
35 """A component to manage the %result, %px and %autopx magics."""
35 """A component to manage the %result, %px and %autopx magics."""
36
36
37 active_view = Instance('IPython.parallel.client.view.DirectView')
37 active_view = Instance('IPython.parallel.client.view.DirectView')
38 verbose = Bool(False, config=True)
38 verbose = Bool(False, config=True)
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
40
40
41 def __init__(self, shell=None, config=None):
41 def __init__(self, shell=None, config=None):
42 super(ParalleMagic, self).__init__(shell=shell, config=config)
42 super(ParalleMagic, self).__init__(shell=shell, config=config)
43 self._define_magics()
43 self._define_magics()
44 # A flag showing if autopx is activated or not
44 # A flag showing if autopx is activated or not
45 self.autopx = False
45 self.autopx = False
46
46
47 def _define_magics(self):
47 def _define_magics(self):
48 """Define the magic functions."""
48 """Define the magic functions."""
49 self.shell.define_magic('result', self.magic_result)
49 self.shell.define_magic('result', self.magic_result)
50 self.shell.define_magic('px', self.magic_px)
50 self.shell.define_magic('px', self.magic_px)
51 self.shell.define_magic('autopx', self.magic_autopx)
51 self.shell.define_magic('autopx', self.magic_autopx)
52
52
53 @testdec.skip_doctest
53 @testdec.skip_doctest
54 def magic_result(self, ipself, parameter_s=''):
54 def magic_result(self, ipself, parameter_s=''):
55 """Print the result of command i on all engines..
55 """Print the result of command i on all engines..
56
56
57 To use this a :class:`DirectView` instance must be created
57 To use this a :class:`DirectView` instance must be created
58 and then activated by calling its :meth:`activate` method.
58 and then activated by calling its :meth:`activate` method.
59
59
60 Then you can do the following::
60 Then you can do the following::
61
61
62 In [23]: %result
62 In [23]: %result
63 Out[23]:
63 Out[23]:
64 <Results List>
64 <Results List>
65 [0] In [6]: a = 10
65 [0] In [6]: a = 10
66 [1] In [6]: a = 10
66 [1] In [6]: a = 10
67
67
68 In [22]: %result 6
68 In [22]: %result 6
69 Out[22]:
69 Out[22]:
70 <Results List>
70 <Results List>
71 [0] In [6]: a = 10
71 [0] In [6]: a = 10
72 [1] In [6]: a = 10
72 [1] In [6]: a = 10
73 """
73 """
74 if self.active_view is None:
74 if self.active_view is None:
75 print NO_ACTIVE_VIEW
75 print NO_ACTIVE_VIEW
76 return
76 return
77
77
78 try:
78 try:
79 index = int(parameter_s)
79 index = int(parameter_s)
80 except:
80 except:
81 index = None
81 index = None
82 result = self.active_view.get_result(index)
82 result = self.active_view.get_result(index)
83 return result
83 return result
84
84
85 @testdec.skip_doctest
85 @testdec.skip_doctest
86 def magic_px(self, ipself, parameter_s=''):
86 def magic_px(self, ipself, parameter_s=''):
87 """Executes the given python command in parallel.
87 """Executes the given python command in parallel.
88
88
89 To use this a :class:`DirectView` instance must be created
89 To use this a :class:`DirectView` instance must be created
90 and then activated by calling its :meth:`activate` method.
90 and then activated by calling its :meth:`activate` method.
91
91
92 Then you can do the following::
92 Then you can do the following::
93
93
94 In [24]: %px a = 5
94 In [24]: %px a = 5
95 Parallel execution on engines: all
95 Parallel execution on engines: all
96 Out[24]:
96 Out[24]:
97 <Results List>
97 <Results List>
98 [0] In [7]: a = 5
98 [0] In [7]: a = 5
99 [1] In [7]: a = 5
99 [1] In [7]: a = 5
100 """
100 """
101
101
102 if self.active_view is None:
102 if self.active_view is None:
103 print NO_ACTIVE_VIEW
103 print NO_ACTIVE_VIEW
104 return
104 return
105 print "Parallel execution on engines: %s" % self.active_view.targets
105 print "Parallel execution on engines: %s" % self.active_view.targets
106 result = self.active_view.execute(parameter_s, block=False)
106 result = self.active_view.execute(parameter_s, block=False)
107 if self.active_view.block:
107 if self.active_view.block:
108 result.get()
108 result.get()
109 self._maybe_display_output(result)
109 self._maybe_display_output(result)
110
110
111 @testdec.skip_doctest
111 @testdec.skip_doctest
112 def magic_autopx(self, ipself, parameter_s=''):
112 def magic_autopx(self, ipself, parameter_s=''):
113 """Toggles auto parallel mode.
113 """Toggles auto parallel mode.
114
114
115 To use this a :class:`DirectView` instance must be created
115 To use this a :class:`DirectView` instance must be created
116 and then activated by calling its :meth:`activate` method. Once this
116 and then activated by calling its :meth:`activate` method. Once this
117 is called, all commands typed at the command line are send to
117 is called, all commands typed at the command line are send to
118 the engines to be executed in parallel. To control which engine
118 the engines to be executed in parallel. To control which engine
119 are used, set the ``targets`` attributed of the multiengine client
119 are used, set the ``targets`` attributed of the multiengine client
120 before entering ``%autopx`` mode.
120 before entering ``%autopx`` mode.
121
121
122 Then you can do the following::
122 Then you can do the following::
123
123
124 In [25]: %autopx
124 In [25]: %autopx
125 %autopx to enabled
125 %autopx to enabled
126
126
127 In [26]: a = 10
127 In [26]: a = 10
128 Parallel execution on engines: [0,1,2,3]
128 Parallel execution on engines: [0,1,2,3]
129 In [27]: print a
129 In [27]: print a
130 Parallel execution on engines: [0,1,2,3]
130 Parallel execution on engines: [0,1,2,3]
131 [stdout:0] 10
131 [stdout:0] 10
132 [stdout:1] 10
132 [stdout:1] 10
133 [stdout:2] 10
133 [stdout:2] 10
134 [stdout:3] 10
134 [stdout:3] 10
135
135
136
136
137 In [27]: %autopx
137 In [27]: %autopx
138 %autopx disabled
138 %autopx disabled
139 """
139 """
140 if self.autopx:
140 if self.autopx:
141 self._disable_autopx()
141 self._disable_autopx()
142 else:
142 else:
143 self._enable_autopx()
143 self._enable_autopx()
144
144
145 def _enable_autopx(self):
145 def _enable_autopx(self):
146 """Enable %autopx mode by saving the original run_cell and installing
146 """Enable %autopx mode by saving the original run_cell and installing
147 pxrun_cell.
147 pxrun_cell.
148 """
148 """
149 if self.active_view is None:
149 if self.active_view is None:
150 print NO_ACTIVE_VIEW
150 print NO_ACTIVE_VIEW
151 return
151 return
152
152
153 # override run_cell and run_code
153 # override run_cell and run_code
154 self._original_run_cell = self.shell.run_cell
154 self._original_run_cell = self.shell.run_cell
155 self.shell.run_cell = self.pxrun_cell
155 self.shell.run_cell = self.pxrun_cell
156 self._original_run_code = self.shell.run_code
156 self._original_run_code = self.shell.run_code
157 self.shell.run_code = self.pxrun_code
157 self.shell.run_code = self.pxrun_code
158
158
159 self.autopx = True
159 self.autopx = True
160 print "%autopx enabled"
160 print "%autopx enabled"
161
161
162 def _disable_autopx(self):
162 def _disable_autopx(self):
163 """Disable %autopx by restoring the original InteractiveShell.run_cell.
163 """Disable %autopx by restoring the original InteractiveShell.run_cell.
164 """
164 """
165 if self.autopx:
165 if self.autopx:
166 self.shell.run_cell = self._original_run_cell
166 self.shell.run_cell = self._original_run_cell
167 self.shell.run_code = self._original_run_code
167 self.shell.run_code = self._original_run_code
168 self.autopx = False
168 self.autopx = False
169 print "%autopx disabled"
169 print "%autopx disabled"
170
170
171 def _maybe_display_output(self, result):
171 def _maybe_display_output(self, result):
172 """Maybe display the output of a parallel result.
172 """Maybe display the output of a parallel result.
173
173
174 If self.active_view.block is True, wait for the result
174 If self.active_view.block is True, wait for the result
175 and display the result. Otherwise, this is a noop.
175 and display the result. Otherwise, this is a noop.
176 """
176 """
177 targets = self.active_view.targets
177 targets = self.active_view.targets
178 if isinstance(targets, int):
178 if isinstance(targets, int):
179 targets = [targets]
179 targets = [targets]
180 if targets == 'all':
180 if targets == 'all':
181 targets = self.active_view.client.ids
181 targets = self.active_view.client.ids
182 stdout = [s.rstrip() for s in result.stdout]
182 stdout = [s.rstrip() for s in result.stdout]
183 if any(stdout):
183 if any(stdout):
184 for i,eid in enumerate(targets):
184 for i,eid in enumerate(targets):
185 print '[stdout:%i]'%eid, stdout[i]
185 print '[stdout:%i]'%eid, stdout[i]
186
186
187
187
188 def pxrun_cell(self, cell, store_history=True):
188 def pxrun_cell(self, raw_cell, store_history=True):
189 """drop-in replacement for InteractiveShell.run_cell.
189 """drop-in replacement for InteractiveShell.run_cell.
190
190
191 This executes code remotely, instead of in the local namespace.
191 This executes code remotely, instead of in the local namespace.
192
192
193 See InteractiveShell.run_cell for details.
193 See InteractiveShell.run_cell for details.
194 """
194 """
195
196 if (not raw_cell) or raw_cell.isspace():
197 return
198
195 ipself = self.shell
199 ipself = self.shell
196 raw_cell = cell
200
197 with ipself.builtin_trap:
201 with ipself.builtin_trap:
198 cell = ipself.prefilter_manager.prefilter_lines(cell)
202 cell = ipself.prefilter_manager.prefilter_lines(raw_cell)
199
203
200 # Store raw and processed history
204 # Store raw and processed history
201 if store_history:
205 if store_history:
202 ipself.history_manager.store_inputs(ipself.execution_count,
206 ipself.history_manager.store_inputs(ipself.execution_count,
203 cell, raw_cell)
207 cell, raw_cell)
204
208
205 # ipself.logger.log(cell, raw_cell)
209 # ipself.logger.log(cell, raw_cell)
206
210
207 cell_name = ipself.compile.cache(cell, ipself.execution_count)
211 cell_name = ipself.compile.cache(cell, ipself.execution_count)
208
212
209 try:
213 try:
210 code_ast = ast.parse(cell, filename=cell_name)
214 code_ast = ast.parse(cell, filename=cell_name)
211 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
215 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
212 # Case 1
216 # Case 1
213 ipself.showsyntaxerror()
217 ipself.showsyntaxerror()
214 ipself.execution_count += 1
218 ipself.execution_count += 1
215 return None
219 return None
216 except NameError:
220 except NameError:
217 # ignore name errors, because we don't know the remote keys
221 # ignore name errors, because we don't know the remote keys
218 pass
222 pass
219
223
220 if store_history:
224 if store_history:
221 # Write output to the database. Does nothing unless
225 # Write output to the database. Does nothing unless
222 # history output logging is enabled.
226 # history output logging is enabled.
223 ipself.history_manager.store_output(ipself.execution_count)
227 ipself.history_manager.store_output(ipself.execution_count)
224 # Each cell is a *single* input, regardless of how many lines it has
228 # Each cell is a *single* input, regardless of how many lines it has
225 ipself.execution_count += 1
229 ipself.execution_count += 1
226
230
227 if re.search(r'get_ipython\(\)\.magic\(u?"%?autopx', cell):
231 if re.search(r'get_ipython\(\)\.magic\(u?"%?autopx', cell):
228 self._disable_autopx()
232 self._disable_autopx()
229 return False
233 return False
230 else:
234 else:
231 try:
235 try:
232 result = self.active_view.execute(cell, block=False)
236 result = self.active_view.execute(cell, block=False)
233 except:
237 except:
234 ipself.showtraceback()
238 ipself.showtraceback()
235 return True
239 return True
236 else:
240 else:
237 if self.active_view.block:
241 if self.active_view.block:
238 try:
242 try:
239 result.get()
243 result.get()
240 except:
244 except:
241 self.shell.showtraceback()
245 self.shell.showtraceback()
242 return True
246 return True
243 else:
247 else:
244 self._maybe_display_output(result)
248 self._maybe_display_output(result)
245 return False
249 return False
246
250
247 def pxrun_code(self, code_obj, post_execute=True):
251 def pxrun_code(self, code_obj):
248 """drop-in replacement for InteractiveShell.run_code.
252 """drop-in replacement for InteractiveShell.run_code.
249
253
250 This executes code remotely, instead of in the local namespace.
254 This executes code remotely, instead of in the local namespace.
251
255
252 See InteractiveShell.run_code for details.
256 See InteractiveShell.run_code for details.
253 """
257 """
254 ipself = self.shell
258 ipself = self.shell
255 # check code object for the autopx magic
259 # check code object for the autopx magic
256 if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names and \
260 if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names and \
257 any( [ isinstance(c, basestring) and 'autopx' in c for c in code_obj.co_consts ]):
261 any( [ isinstance(c, basestring) and 'autopx' in c for c in code_obj.co_consts ]):
258 self._disable_autopx()
262 self._disable_autopx()
259 return False
263 return False
260 else:
264 else:
261 try:
265 try:
262 result = self.active_view.execute(code_obj, block=False)
266 result = self.active_view.execute(code_obj, block=False)
263 except:
267 except:
264 ipself.showtraceback()
268 ipself.showtraceback()
265 return True
269 return True
266 else:
270 else:
267 if self.active_view.block:
271 if self.active_view.block:
268 try:
272 try:
269 result.get()
273 result.get()
270 except:
274 except:
271 self.shell.showtraceback()
275 self.shell.showtraceback()
272 return True
276 return True
273 else:
277 else:
274 self._maybe_display_output(result)
278 self._maybe_display_output(result)
275 return False
279 return False
276
280
277
281
278
282
279
283
280 _loaded = False
284 _loaded = False
281
285
282
286
283 def load_ipython_extension(ip):
287 def load_ipython_extension(ip):
284 """Load the extension in IPython."""
288 """Load the extension in IPython."""
285 global _loaded
289 global _loaded
286 if not _loaded:
290 if not _loaded:
287 plugin = ParalleMagic(shell=ip, config=ip.config)
291 plugin = ParalleMagic(shell=ip, config=ip.config)
288 ip.plugin_manager.register_plugin('parallelmagic', plugin)
292 ip.plugin_manager.register_plugin('parallelmagic', plugin)
289 _loaded = True
293 _loaded = True
290
294
General Comments 0
You need to be logged in to leave comments. Login now