##// END OF EJS Templates
Merge pull request #1768 from minrk/parallelmagics...
Fernando Perez -
r7060:a1360828 merge
parent child Browse files
Show More
@@ -0,0 +1,342 b''
1 # -*- coding: utf-8 -*-
2 """Test Parallel magics
3
4 Authors:
5
6 * Min RK
7 """
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 #-------------------------------------------------------------------------------
16 # Imports
17 #-------------------------------------------------------------------------------
18
19 import sys
20 import time
21
22 import zmq
23 from nose import SkipTest
24
25 from IPython.testing import decorators as dec
26 from IPython.testing.ipunittest import ParametricTestCase
27
28 from IPython import parallel as pmod
29 from IPython.parallel import error
30 from IPython.parallel import AsyncResult
31 from IPython.parallel.util import interactive
32
33 from IPython.parallel.tests import add_engines
34
35 from .clienttest import ClusterTestCase, capture_output, generate_output
36
37 def setup():
38 add_engines(3, total=True)
39
40 class TestParallelMagics(ClusterTestCase, ParametricTestCase):
41
42 def test_px_blocking(self):
43 ip = get_ipython()
44 v = self.client[-1:]
45 v.activate()
46 v.block=True
47
48 ip.magic('px a=5')
49 self.assertEquals(v['a'], [5])
50 ip.magic('px a=10')
51 self.assertEquals(v['a'], [10])
52 # just 'print a' works ~99% of the time, but this ensures that
53 # the stdout message has arrived when the result is finished:
54 with capture_output() as io:
55 ip.magic(
56 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
57 )
58 out = io.stdout
59 self.assertTrue('[stdout:' in out, out)
60 self.assertTrue(out.rstrip().endswith('10'))
61 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
62
63 def test_cellpx_block_args(self):
64 """%%px --[no]block flags work"""
65 ip = get_ipython()
66 v = self.client[-1:]
67 v.activate()
68 v.block=False
69
70 for block in (True, False):
71 v.block = block
72
73 with capture_output() as io:
74 ip.run_cell_magic("px", "", "1")
75 if block:
76 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
77 else:
78 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
79
80 with capture_output() as io:
81 ip.run_cell_magic("px", "--block", "1")
82 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
83
84 with capture_output() as io:
85 ip.run_cell_magic("px", "--noblock", "1")
86 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
87
88 def test_cellpx_groupby_engine(self):
89 """%%px --group-outputs=engine"""
90 ip = get_ipython()
91 v = self.client[:]
92 v.block = True
93 v.activate()
94
95 v['generate_output'] = generate_output
96
97 with capture_output() as io:
98 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
99
100 lines = io.stdout.strip().splitlines()[1:]
101 expected = [
102 ('[stdout:', '] stdout'),
103 'stdout2',
104 'IPython.core.display.HTML',
105 'IPython.core.display.Math',
106 ('] Out[', 'IPython.core.display.Math')
107 ] * len(v)
108
109 self.assertEquals(len(lines), len(expected), io.stdout)
110 for line,expect in zip(lines, expected):
111 if isinstance(expect, str):
112 expect = [expect]
113 for ex in expect:
114 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
115
116 expected = [
117 ('[stderr:', '] stderr'),
118 'stderr2',
119 ] * len(v)
120
121 lines = io.stderr.strip().splitlines()
122 self.assertEquals(len(lines), len(expected), io.stderr)
123 for line,expect in zip(lines, expected):
124 if isinstance(expect, str):
125 expect = [expect]
126 for ex in expect:
127 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
128
129
130 def test_cellpx_groupby_order(self):
131 """%%px --group-outputs=order"""
132 ip = get_ipython()
133 v = self.client[:]
134 v.block = True
135 v.activate()
136
137 v['generate_output'] = generate_output
138
139 with capture_output() as io:
140 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
141
142 lines = io.stdout.strip().splitlines()[1:]
143 expected = []
144 expected.extend([
145 ('[stdout:', '] stdout'),
146 'stdout2',
147 ] * len(v))
148 expected.extend([
149 'IPython.core.display.HTML',
150 ] * len(v))
151 expected.extend([
152 'IPython.core.display.Math',
153 ] * len(v))
154 expected.extend([
155 ('] Out[', 'IPython.core.display.Math')
156 ] * len(v))
157
158 self.assertEquals(len(lines), len(expected), io.stdout)
159 for line,expect in zip(lines, expected):
160 if isinstance(expect, str):
161 expect = [expect]
162 for ex in expect:
163 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
164
165 expected = [
166 ('[stderr:', '] stderr'),
167 'stderr2',
168 ] * len(v)
169
170 lines = io.stderr.strip().splitlines()
171 self.assertEquals(len(lines), len(expected), io.stderr)
172 for line,expect in zip(lines, expected):
173 if isinstance(expect, str):
174 expect = [expect]
175 for ex in expect:
176 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
177
178 def test_cellpx_groupby_atype(self):
179 """%%px --group-outputs=type"""
180 ip = get_ipython()
181 v = self.client[:]
182 v.block = True
183 v.activate()
184
185 v['generate_output'] = generate_output
186
187 with capture_output() as io:
188 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
189
190 lines = io.stdout.strip().splitlines()[1:]
191
192 expected = []
193 expected.extend([
194 ('[stdout:', '] stdout'),
195 'stdout2',
196 ] * len(v))
197 expected.extend([
198 'IPython.core.display.HTML',
199 'IPython.core.display.Math',
200 ] * len(v))
201 expected.extend([
202 ('] Out[', 'IPython.core.display.Math')
203 ] * len(v))
204
205 self.assertEquals(len(lines), len(expected), io.stdout)
206 for line,expect in zip(lines, expected):
207 if isinstance(expect, str):
208 expect = [expect]
209 for ex in expect:
210 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
211
212 expected = [
213 ('[stderr:', '] stderr'),
214 'stderr2',
215 ] * len(v)
216
217 lines = io.stderr.strip().splitlines()
218 self.assertEquals(len(lines), len(expected), io.stderr)
219 for line,expect in zip(lines, expected):
220 if isinstance(expect, str):
221 expect = [expect]
222 for ex in expect:
223 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
224
225
226 def test_px_nonblocking(self):
227 ip = get_ipython()
228 v = self.client[-1:]
229 v.activate()
230 v.block=False
231
232 ip.magic('px a=5')
233 self.assertEquals(v['a'], [5])
234 ip.magic('px a=10')
235 self.assertEquals(v['a'], [10])
236 with capture_output() as io:
237 ar = ip.magic('px print (a)')
238 self.assertTrue(isinstance(ar, AsyncResult))
239 self.assertTrue('Async' in io.stdout)
240 self.assertFalse('[stdout:' in io.stdout)
241 ar = ip.magic('px 1/0')
242 self.assertRaisesRemote(ZeroDivisionError, ar.get)
243
244 def test_autopx_blocking(self):
245 ip = get_ipython()
246 v = self.client[-1]
247 v.activate()
248 v.block=True
249
250 with capture_output() as io:
251 ip.magic('autopx')
252 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
253 ip.run_cell('b*=2')
254 ip.run_cell('print (b)')
255 ip.run_cell('b')
256 ip.run_cell("b/c")
257 ip.magic('autopx')
258
259 output = io.stdout.strip()
260
261 self.assertTrue(output.startswith('%autopx enabled'), output)
262 self.assertTrue(output.endswith('%autopx disabled'), output)
263 self.assertTrue('RemoteError: ZeroDivisionError' in output, output)
264 self.assertTrue('] Out[' in output, output)
265 self.assertTrue(': 24690' in output, output)
266 ar = v.get_result(-1)
267 self.assertEquals(v['a'], 5)
268 self.assertEquals(v['b'], 24690)
269 self.assertRaisesRemote(ZeroDivisionError, ar.get)
270
271 def test_autopx_nonblocking(self):
272 ip = get_ipython()
273 v = self.client[-1]
274 v.activate()
275 v.block=False
276
277 with capture_output() as io:
278 ip.magic('autopx')
279 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
280 ip.run_cell('print (b)')
281 ip.run_cell('import time; time.sleep(0.1)')
282 ip.run_cell("b/c")
283 ip.run_cell('b*=2')
284 ip.magic('autopx')
285
286 output = io.stdout.strip()
287
288 self.assertTrue(output.startswith('%autopx enabled'))
289 self.assertTrue(output.endswith('%autopx disabled'))
290 self.assertFalse('ZeroDivisionError' in output)
291 ar = v.get_result(-2)
292 self.assertRaisesRemote(ZeroDivisionError, ar.get)
293 # prevent TaskAborted on pulls, due to ZeroDivisionError
294 time.sleep(0.5)
295 self.assertEquals(v['a'], 5)
296 # b*=2 will not fire, due to abort
297 self.assertEquals(v['b'], 10)
298
299 def test_result(self):
300 ip = get_ipython()
301 v = self.client[-1]
302 v.activate()
303 data = dict(a=111,b=222)
304 v.push(data, block=True)
305
306 ip.magic('px a')
307 ip.magic('px b')
308 for idx, name in [
309 ('', 'b'),
310 ('-1', 'b'),
311 ('2', 'b'),
312 ('1', 'a'),
313 ('-2', 'a'),
314 ]:
315 with capture_output() as io:
316 ip.magic('result ' + idx)
317 output = io.stdout.strip()
318 msg = "expected %s output to include %s, but got: %s" % \
319 ('%result '+idx, str(data[name]), output)
320 self.assertTrue(str(data[name]) in output, msg)
321
322 @dec.skipif_not_matplotlib
323 def test_px_pylab(self):
324 """%pylab works on engines"""
325 ip = get_ipython()
326 v = self.client[-1]
327 v.block = True
328 v.activate()
329
330 with capture_output() as io:
331 ip.magic("px %pylab inline")
332
333 self.assertTrue("Welcome to pylab" in io.stdout, io.stdout)
334 self.assertTrue("backend_inline" in io.stdout, io.stdout)
335
336 with capture_output() as io:
337 ip.magic("px plot(rand(100))")
338
339 self.assertTrue('] Out[' in io.stdout, io.stdout)
340 self.assertTrue('matplotlib.lines' in io.stdout, io.stdout)
341
342
@@ -0,0 +1,228 b''
1 {
2 "metadata": {
3 "name": "Parallel Magics"
4 },
5 "nbformat": 3,
6 "worksheets": [
7 {
8 "cells": [
9 {
10 "cell_type": "heading",
11 "level": 1,
12 "source": [
13 "Using Parallel Magics"
14 ]
15 },
16 {
17 "cell_type": "markdown",
18 "source": [
19 "IPython has a few magics for working with your engines.",
20 "",
21 "This assumes you have started an IPython cluster, either with the notebook interface,",
22 "or the `ipcluster/controller/engine` commands."
23 ]
24 },
25 {
26 "cell_type": "code",
27 "collapsed": false,
28 "input": [
29 "from IPython import parallel",
30 "rc = parallel.Client()",
31 "dv = rc[:]",
32 "dv.block = True",
33 "dv"
34 ],
35 "language": "python",
36 "outputs": []
37 },
38 {
39 "cell_type": "markdown",
40 "source": [
41 "The parallel magics come from the `parallelmagics` IPython extension.",
42 "The magics are set to work with a particular View object,",
43 "so to activate them, you call the `activate()` method on a particular view:"
44 ]
45 },
46 {
47 "cell_type": "code",
48 "collapsed": true,
49 "input": [
50 "dv.activate()"
51 ],
52 "language": "python",
53 "outputs": []
54 },
55 {
56 "cell_type": "markdown",
57 "source": [
58 "Now we can execute code remotely with `%px`:"
59 ]
60 },
61 {
62 "cell_type": "code",
63 "collapsed": false,
64 "input": [
65 "%px a=5"
66 ],
67 "language": "python",
68 "outputs": []
69 },
70 {
71 "cell_type": "code",
72 "collapsed": false,
73 "input": [
74 "%px print a"
75 ],
76 "language": "python",
77 "outputs": []
78 },
79 {
80 "cell_type": "code",
81 "collapsed": false,
82 "input": [
83 "%px a"
84 ],
85 "language": "python",
86 "outputs": []
87 },
88 {
89 "cell_type": "markdown",
90 "source": [
91 "You don't have to wait for results:"
92 ]
93 },
94 {
95 "cell_type": "code",
96 "collapsed": true,
97 "input": [
98 "dv.block = False"
99 ],
100 "language": "python",
101 "outputs": []
102 },
103 {
104 "cell_type": "code",
105 "collapsed": false,
106 "input": [
107 "%px import time",
108 "%px time.sleep(5)",
109 "%px time.time()"
110 ],
111 "language": "python",
112 "outputs": []
113 },
114 {
115 "cell_type": "markdown",
116 "source": [
117 "But you will notice that this didn't output the result of the last command.",
118 "For this, we have `%result`, which displays the output of the latest request:"
119 ]
120 },
121 {
122 "cell_type": "code",
123 "collapsed": false,
124 "input": [
125 "%result"
126 ],
127 "language": "python",
128 "outputs": []
129 },
130 {
131 "cell_type": "markdown",
132 "source": [
133 "Remember, an IPython engine is IPython, so you can do magics remotely as well!"
134 ]
135 },
136 {
137 "cell_type": "code",
138 "collapsed": false,
139 "input": [
140 "dv.block = True",
141 "%px %pylab inline"
142 ],
143 "language": "python",
144 "outputs": []
145 },
146 {
147 "cell_type": "markdown",
148 "source": [
149 "`%%px` can also be used as a cell magic, for submitting whole blocks.",
150 "This one acceps `--block` and `--noblock` flags to specify",
151 "the blocking behavior, though the default is unchanged.",
152 ""
153 ]
154 },
155 {
156 "cell_type": "code",
157 "collapsed": true,
158 "input": [
159 "dv.scatter('id', dv.targets, flatten=True)",
160 "dv['stride'] = len(dv)"
161 ],
162 "language": "python",
163 "outputs": []
164 },
165 {
166 "cell_type": "code",
167 "collapsed": false,
168 "input": [
169 "%%px --noblock",
170 "x = linspace(0,pi,1000)",
171 "for n in range(id,12, stride):",
172 " print n",
173 " plt.plot(x,sin(n*x))",
174 "plt.title(\"Plot %i\" % id)"
175 ],
176 "language": "python",
177 "outputs": []
178 },
179 {
180 "cell_type": "code",
181 "collapsed": false,
182 "input": [
183 "%result"
184 ],
185 "language": "python",
186 "outputs": []
187 },
188 {
189 "cell_type": "markdown",
190 "source": [
191 "It also lets you choose some amount of the grouping of the outputs with `--group-outputs`:",
192 "",
193 "The choices are:",
194 "",
195 "* `engine` - all of an engine's output is collected together",
196 "* `type` - where stdout of each engine is grouped, etc. (the default)",
197 "* `order` - same as `type`, but individual displaypub outputs are interleaved.",
198 " That is, it will output the first plot from each engine, then the second from each,",
199 " etc."
200 ]
201 },
202 {
203 "cell_type": "code",
204 "collapsed": false,
205 "input": [
206 "%%px --group-outputs=engine",
207 "x = linspace(0,pi,1000)",
208 "for n in range(id,12, stride):",
209 " print n",
210 " plt.plot(x,sin(n*x))",
211 "plt.title(\"Plot %i\" % id)"
212 ],
213 "language": "python",
214 "outputs": []
215 },
216 {
217 "cell_type": "code",
218 "collapsed": true,
219 "input": [
220 ""
221 ],
222 "language": "python",
223 "outputs": []
224 }
225 ]
226 }
227 ]
228 } No newline at end of file
@@ -542,7 +542,7 b' class Magics(object):'
542 542 argv = arg_split(arg_str, posix, strict)
543 543 # Do regular option processing
544 544 try:
545 opts,args = getopt(argv,opt_str,*long_opts)
545 opts,args = getopt(argv, opt_str, long_opts)
546 546 except GetoptError,e:
547 547 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
548 548 " ".join(long_opts)))
@@ -69,6 +69,15 b' def test_magic_parse_options():'
69 69 expected = path
70 70 nt.assert_equals(opts['f'], expected)
71 71
72 def test_magic_parse_long_options():
73 """Magic.parse_options can handle --foo=bar long options"""
74 ip = get_ipython()
75 m = DummyMagics(ip)
76 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
77 nt.assert_true('foo' in opts)
78 nt.assert_true('bar' in opts)
79 nt.assert_true(opts['bar'], "bubble")
80
72 81
73 82 @dec.skip_without('sqlite3')
74 83 def doctest_hist_f():
@@ -11,15 +11,15 b' Usage'
11 11
12 12 ``%autopx``
13 13
14 @AUTOPX_DOC@
14 {AUTOPX_DOC}
15 15
16 16 ``%px``
17 17
18 @PX_DOC@
18 {PX_DOC}
19 19
20 20 ``%result``
21 21
22 @RESULT_DOC@
22 {RESULT_DOC}
23 23
24 24 """
25 25
@@ -37,87 +37,172 b' Usage'
37 37 import ast
38 38 import re
39 39
40 from IPython.core.magic import Magics, magics_class, line_magic
40 from IPython.core.error import UsageError
41 from IPython.core.magic import Magics, magics_class, line_magic, cell_magic
41 42 from IPython.testing.skipdoctest import skip_doctest
42 43
43 44 #-----------------------------------------------------------------------------
44 45 # Definitions of magic functions for use with IPython
45 46 #-----------------------------------------------------------------------------
46 47
47 NO_ACTIVE_VIEW = """
48 Use activate() on a DirectView object to activate it for magics.
49 """
48
49 NO_ACTIVE_VIEW = "Use activate() on a DirectView object to use it with magics."
50 50
51 51
52 52 @magics_class
53 53 class ParallelMagics(Magics):
54 54 """A set of magics useful when controlling a parallel IPython cluster.
55 55 """
56
57 def __init__(self, shell):
58 super(ParallelMagics, self).__init__(shell)
59 # A flag showing if autopx is activated or not
60 self.autopx = False
56
57 # A flag showing if autopx is activated or not
58 _autopx = False
59 # the current view used by the magics:
60 active_view = None
61 61
62 62 @skip_doctest
63 63 @line_magic
64 64 def result(self, parameter_s=''):
65 """Print the result of command i on all engines..
65 """Print the result of command i on all engines.
66 66
67 67 To use this a :class:`DirectView` instance must be created
68 68 and then activated by calling its :meth:`activate` method.
69
70 This lets you recall the results of %px computations after
71 asynchronous submission (view.block=False).
69 72
70 73 Then you can do the following::
71 74
72 In [23]: %result
73 Out[23]:
74 <Results List>
75 [0] In [6]: a = 10
76 [1] In [6]: a = 10
77
78 In [22]: %result 6
79 Out[22]:
80 <Results List>
81 [0] In [6]: a = 10
82 [1] In [6]: a = 10
75 In [23]: %px os.getpid()
76 Async parallel execution on engine(s): all
77
78 In [24]: %result
79 [ 8] Out[10]: 60920
80 [ 9] Out[10]: 60921
81 [10] Out[10]: 60922
82 [11] Out[10]: 60923
83 83 """
84
84 85 if self.active_view is None:
85 print NO_ACTIVE_VIEW
86 return
87
86 raise UsageError(NO_ACTIVE_VIEW)
87
88 stride = len(self.active_view)
88 89 try:
89 90 index = int(parameter_s)
90 91 except:
91 index = None
92 result = self.active_view.get_result(index)
93 return result
92 index = -1
93 msg_ids = self.active_view.history[stride * index:(stride * (index + 1)) or None]
94
95 result = self.active_view.get_result(msg_ids)
96
97 result.get()
98 result.display_outputs()
94 99
95 100 @skip_doctest
96 101 @line_magic
97 102 def px(self, parameter_s=''):
98 103 """Executes the given python command in parallel.
99
104
100 105 To use this a :class:`DirectView` instance must be created
101 106 and then activated by calling its :meth:`activate` method.
102 107
103 108 Then you can do the following::
104 109
105 In [24]: %px a = 5
110 In [24]: %px a = os.getpid()
106 111 Parallel execution on engine(s): all
107 Out[24]:
108 <Results List>
109 [0] In [7]: a = 5
110 [1] In [7]: a = 5
112
113 In [25]: %px print a
114 [stdout:0] 1234
115 [stdout:1] 1235
116 [stdout:2] 1236
117 [stdout:3] 1237
111 118 """
119 return self.parallel_execute(parameter_s)
120
121 def parallel_execute(self, cell, block=None, groupby='type'):
122 """implementation used by %px and %%parallel"""
112 123
113 124 if self.active_view is None:
114 print NO_ACTIVE_VIEW
115 return
116 print "Parallel execution on engine(s): %s" % self.active_view.targets
117 result = self.active_view.execute(parameter_s, block=False)
118 if self.active_view.block:
125 raise UsageError(NO_ACTIVE_VIEW)
126
127 # defaults:
128 block = self.active_view.block if block is None else block
129
130 base = "Parallel" if block else "Async parallel"
131 print base + " execution on engine(s): %s" % self.active_view.targets
132
133 result = self.active_view.execute(cell, silent=False, block=False)
134 if block:
119 135 result.get()
120 self._maybe_display_output(result)
136 result.display_outputs(groupby)
137 else:
138 # return AsyncResult only on non-blocking submission
139 return result
140
141 @skip_doctest
142 @cell_magic('px')
143 def cell_px(self, line='', cell=None):
144 """Executes the given python command in parallel.
145
146 Cell magic usage:
147
148 %%px [-o] [-e] [--group-options=type|engine|order] [--[no]block]
149
150 Options (%%px cell magic only):
151
152 -o: collate outputs in oder (same as group-outputs=order)
153
154 -e: group outputs by engine (same as group-outputs=engine)
155
156 --group-outputs=type [default behavior]:
157 each output type (stdout, stderr, displaypub) for all engines
158 displayed together.
159
160 --group-outputs=order:
161 The same as 'type', but individual displaypub outputs (e.g. plots)
162 will be interleaved, so it will display all of the first plots,
163 then all of the second plots, etc.
164
165 --group-outputs=engine:
166 All of an engine's output is displayed before moving on to the next.
167
168 --[no]block:
169 Whether or not to block for the execution to complete
170 (and display the results). If unspecified, the active view's
171
172
173 To use this a :class:`DirectView` instance must be created
174 and then activated by calling its :meth:`activate` method.
175
176 Then you can do the following::
177
178 In [24]: %%parallel --noblock a = os.getpid()
179 Async parallel execution on engine(s): all
180
181 In [25]: %px print a
182 [stdout:0] 1234
183 [stdout:1] 1235
184 [stdout:2] 1236
185 [stdout:3] 1237
186 """
187
188 block = None
189 groupby = 'type'
190 # as a cell magic, we accept args
191 opts, _ = self.parse_options(line, 'oe', 'group-outputs=', 'block', 'noblock')
192
193 if 'group-outputs' in opts:
194 groupby = opts['group-outputs']
195 elif 'o' in opts:
196 groupby = 'order'
197 elif 'e' in opts:
198 groupby = 'engine'
199
200 if 'block' in opts:
201 block = True
202 elif 'noblock' in opts:
203 block = False
204
205 return self.parallel_execute(cell, block=block, groupby=groupby)
121 206
122 207 @skip_doctest
123 208 @line_magic
@@ -149,7 +234,7 b' class ParallelMagics(Magics):'
149 234 In [27]: %autopx
150 235 %autopx disabled
151 236 """
152 if self.autopx:
237 if self._autopx:
153 238 self._disable_autopx()
154 239 else:
155 240 self._enable_autopx()
@@ -159,50 +244,23 b' class ParallelMagics(Magics):'
159 244 pxrun_cell.
160 245 """
161 246 if self.active_view is None:
162 print NO_ACTIVE_VIEW
163 return
247 raise UsageError(NO_ACTIVE_VIEW)
164 248
165 # override run_cell and run_code
249 # override run_cell
166 250 self._original_run_cell = self.shell.run_cell
167 251 self.shell.run_cell = self.pxrun_cell
168 self._original_run_code = self.shell.run_code
169 self.shell.run_code = self.pxrun_code
170 252
171 self.autopx = True
253 self._autopx = True
172 254 print "%autopx enabled"
173 255
174 256 def _disable_autopx(self):
175 257 """Disable %autopx by restoring the original InteractiveShell.run_cell.
176 258 """
177 if self.autopx:
259 if self._autopx:
178 260 self.shell.run_cell = self._original_run_cell
179 self.shell.run_code = self._original_run_code
180 self.autopx = False
261 self._autopx = False
181 262 print "%autopx disabled"
182 263
183 def _maybe_display_output(self, result):
184 """Maybe display the output of a parallel result.
185
186 If self.active_view.block is True, wait for the result
187 and display the result. Otherwise, this is a noop.
188 """
189 if isinstance(result.stdout, basestring):
190 # single result
191 stdouts = [result.stdout.rstrip()]
192 else:
193 stdouts = [s.rstrip() for s in result.stdout]
194
195 targets = self.active_view.targets
196 if isinstance(targets, int):
197 targets = [targets]
198 elif targets == 'all':
199 targets = self.active_view.client.ids
200
201 if any(stdouts):
202 for eid,stdout in zip(targets, stdouts):
203 print '[stdout:%i]'%eid, stdout
204
205
206 264 def pxrun_cell(self, raw_cell, store_history=False, silent=False):
207 265 """drop-in replacement for InteractiveShell.run_cell.
208 266
@@ -263,47 +321,16 b' class ParallelMagics(Magics):'
263 321 self.shell.showtraceback()
264 322 return True
265 323 else:
266 self._maybe_display_output(result)
267 return False
268
269 def pxrun_code(self, code_obj):
270 """drop-in replacement for InteractiveShell.run_code.
271
272 This executes code remotely, instead of in the local namespace.
273
274 See InteractiveShell.run_code for details.
275 """
276 ipself = self.shell
277 # check code object for the autopx magic
278 if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names \
279 and any( [ isinstance(c, basestring) and 'autopx' in c
280 for c in code_obj.co_consts ]):
281 self._disable_autopx()
282 return False
283 else:
284 try:
285 result = self.active_view.execute(code_obj, block=False)
286 except:
287 ipself.showtraceback()
288 return True
289 else:
290 if self.active_view.block:
291 try:
292 result.get()
293 except:
294 self.shell.showtraceback()
295 return True
296 else:
297 self._maybe_display_output(result)
324 with ipself.builtin_trap:
325 result.display_outputs()
298 326 return False
299 327
300 328
301 __doc__ = __doc__.replace('@AUTOPX_DOC@',
302 " " + ParallelMagics.autopx.__doc__)
303 __doc__ = __doc__.replace('@PX_DOC@',
304 " " + ParallelMagics.px.__doc__)
305 __doc__ = __doc__.replace('@RESULT_DOC@',
306 " " + ParallelMagics.result.__doc__)
329 __doc__ = __doc__.format(
330 AUTOPX_DOC = ' '*8 + ParallelMagics.autopx.__doc__,
331 PX_DOC = ' '*8 + ParallelMagics.px.__doc__,
332 RESULT_DOC = ' '*8 + ParallelMagics.result.__doc__
333 )
307 334
308 335 _loaded = False
309 336
@@ -21,7 +21,7 b' from datetime import datetime'
21 21
22 22 from zmq import MessageTracker
23 23
24 from IPython.core.display import clear_output
24 from IPython.core.display import clear_output, display
25 25 from IPython.external.decorator import decorator
26 26 from IPython.parallel import error
27 27
@@ -377,6 +377,140 b' class AsyncResult(object):'
377 377 sys.stdout.flush()
378 378 print
379 379 print "done"
380
381 def _republish_displaypub(self, content, eid):
382 """republish individual displaypub content dicts"""
383 try:
384 ip = get_ipython()
385 except NameError:
386 # displaypub is meaningless outside IPython
387 return
388 md = content['metadata'] or {}
389 md['engine'] = eid
390 ip.display_pub.publish(content['source'], content['data'], md)
391
392
393 def _display_single_result(self):
394
395 print self.stdout
396 print >> sys.stderr, self.stderr
397
398 try:
399 get_ipython()
400 except NameError:
401 # displaypub is meaningless outside IPython
402 return
403
404 for output in self.outputs:
405 self._republish_displaypub(output, self.engine_id)
406
407 if self.pyout is not None:
408 display(self.get())
409
410 @check_ready
411 def display_outputs(self, groupby="type"):
412 """republish the outputs of the computation
413
414 Parameters
415 ----------
416
417 groupby : str [default: type]
418 if 'type':
419 Group outputs by type (show all stdout, then all stderr, etc.):
420
421 [stdout:1] foo
422 [stdout:2] foo
423 [stderr:1] bar
424 [stderr:2] bar
425 if 'engine':
426 Display outputs for each engine before moving on to the next:
427
428 [stdout:1] foo
429 [stderr:1] bar
430 [stdout:2] foo
431 [stderr:2] bar
432
433 if 'order':
434 Like 'type', but further collate individual displaypub
435 outputs. This is meant for cases of each command producing
436 several plots, and you would like to see all of the first
437 plots together, then all of the second plots, and so on.
438 """
439 # flush iopub, just in case
440 self._client._flush_iopub(self._client._iopub_socket)
441 if self._single_result:
442 self._display_single_result()
443 return
444
445 stdouts = [s.rstrip() for s in self.stdout]
446 stderrs = [s.rstrip() for s in self.stderr]
447 pyouts = [p for p in self.pyout]
448 output_lists = self.outputs
449 results = self.get()
450
451 targets = self.engine_id
452
453 if groupby == "engine":
454 for eid,stdout,stderr,outputs,r,pyout in zip(
455 targets, stdouts, stderrs, output_lists, results, pyouts
456 ):
457 if stdout:
458 print '[stdout:%i]' % eid, stdout
459 if stderr:
460 print >> sys.stderr, '[stderr:%i]' % eid, stderr
461
462 try:
463 get_ipython()
464 except NameError:
465 # displaypub is meaningless outside IPython
466 return
467
468 for output in outputs:
469 self._republish_displaypub(output, eid)
470
471 if pyout is not None:
472 display(r)
473
474 elif groupby in ('type', 'order'):
475 # republish stdout:
476 if any(stdouts):
477 for eid,stdout in zip(targets, stdouts):
478 print '[stdout:%i]' % eid, stdout
479
480 # republish stderr:
481 if any(stderrs):
482 for eid,stderr in zip(targets, stderrs):
483 print >> sys.stderr, '[stderr:%i]' % eid, stderr
484
485 try:
486 get_ipython()
487 except NameError:
488 # displaypub is meaningless outside IPython
489 return
490
491 if groupby == 'order':
492 output_dict = dict((eid, outputs) for eid,outputs in zip(targets, output_lists))
493 N = max(len(outputs) for outputs in output_lists)
494 for i in range(N):
495 for eid in targets:
496 outputs = output_dict[eid]
497 if len(outputs) >= N:
498 self._republish_displaypub(outputs[i], eid)
499 else:
500 # republish displaypub output
501 for eid,outputs in zip(targets, output_lists):
502 for output in outputs:
503 self._republish_displaypub(output, eid)
504
505 # finally, add pyout:
506 for eid,r,pyout in zip(targets, results, pyouts):
507 if pyout is not None:
508 display(r)
509
510 else:
511 raise ValueError("groupby must be one of 'type', 'engine', 'collate', not %r" % groupby)
512
513
380 514
381 515
382 516 class AsyncMapResult(AsyncResult):
@@ -33,6 +33,7 b' import zmq'
33 33 from IPython.config.configurable import MultipleInstanceError
34 34 from IPython.core.application import BaseIPythonApplication
35 35
36 from IPython.utils.coloransi import TermColors
36 37 from IPython.utils.jsonutil import rekey
37 38 from IPython.utils.localinterfaces import LOCAL_IPS
38 39 from IPython.utils.path import get_ipython_dir
@@ -90,13 +91,39 b' class ExecuteReply(object):'
90 91 return self.metadata[key]
91 92
92 93 def __repr__(self):
93 pyout = self.metadata['pyout'] or {}
94 text_out = pyout.get('data', {}).get('text/plain', '')
94 pyout = self.metadata['pyout'] or {'data':{}}
95 text_out = pyout['data'].get('text/plain', '')
95 96 if len(text_out) > 32:
96 97 text_out = text_out[:29] + '...'
97 98
98 99 return "<ExecuteReply[%i]: %s>" % (self.execution_count, text_out)
99 100
101 def _repr_pretty_(self, p, cycle):
102 pyout = self.metadata['pyout'] or {'data':{}}
103 text_out = pyout['data'].get('text/plain', '')
104
105 if not text_out:
106 return
107
108 try:
109 ip = get_ipython()
110 except NameError:
111 colors = "NoColor"
112 else:
113 colors = ip.colors
114
115 if colors == "NoColor":
116 out = normal = ""
117 else:
118 out = TermColors.Red
119 normal = TermColors.Normal
120
121 p.text(
122 u'[%i] ' % self.metadata['engine_id'] +
123 out + u'Out[%i]: ' % self.execution_count +
124 normal + text_out
125 )
126
100 127 def _repr_html_(self):
101 128 pyout = self.metadata['pyout'] or {'data':{}}
102 129 return pyout['data'].get("text/html")
@@ -15,6 +15,7 b' Authors:'
15 15 import sys
16 16 import tempfile
17 17 import time
18 from StringIO import StringIO
18 19
19 20 from nose import SkipTest
20 21
@@ -59,6 +60,28 b' def raiser(eclass):'
59 60 """raise an exception"""
60 61 raise eclass()
61 62
63 def generate_output():
64 """function for testing output
65
66 publishes two outputs of each type, and returns
67 a rich displayable object.
68 """
69
70 import sys
71 from IPython.core.display import display, HTML, Math
72
73 print "stdout"
74 print >> sys.stderr, "stderr"
75
76 display(HTML("<b>HTML</b>"))
77
78 print "stdout2"
79 print >> sys.stderr, "stderr2"
80
81 display(Math(r"\alpha=\beta"))
82
83 return Math("42")
84
62 85 # test decorator for skipping tests when libraries are unavailable
63 86 def skip_without(*names):
64 87 """skip a test if some names are not importable"""
@@ -73,6 +96,41 b' def skip_without(*names):'
73 96 return f(*args, **kwargs)
74 97 return skip_without_names
75 98
99 #-------------------------------------------------------------------------------
100 # Classes
101 #-------------------------------------------------------------------------------
102
103 class CapturedIO(object):
104 """Simple object for containing captured stdout/err StringIO objects"""
105
106 def __init__(self, stdout, stderr):
107 self.stdout_io = stdout
108 self.stderr_io = stderr
109
110 @property
111 def stdout(self):
112 return self.stdout_io.getvalue()
113
114 @property
115 def stderr(self):
116 return self.stderr_io.getvalue()
117
118
119 class capture_output(object):
120 """context manager for capturing stdout/err"""
121
122 def __enter__(self):
123 self.sys_stdout = sys.stdout
124 self.sys_stderr = sys.stderr
125 stdout = sys.stdout = StringIO()
126 stderr = sys.stderr = StringIO()
127 return CapturedIO(stdout, stderr)
128
129 def __exit__(self, exc_type, exc_value, traceback):
130 sys.stdout = self.sys_stdout
131 sys.stderr = self.sys_stderr
132
133
76 134 class ClusterTestCase(BaseZMQTestCase):
77 135
78 136 def add_engines(self, n=1, block=True):
@@ -117,6 +175,17 b' class ClusterTestCase(BaseZMQTestCase):'
117 175 else:
118 176 self.fail("should have raised a RemoteError")
119 177
178 def _wait_for(self, f, timeout=10):
179 """wait for a condition"""
180 tic = time.time()
181 while time.time() <= tic + timeout:
182 if f():
183 return
184 time.sleep(0.1)
185 self.client.spin()
186 if not f():
187 print "Warning: Awaited condition never arrived"
188
120 189 def setUp(self):
121 190 BaseZMQTestCase.setUp(self)
122 191 self.client = self.connect_client()
@@ -366,118 +366,6 b' class TestView(ClusterTestCase, ParametricTestCase):'
366 366
367 367 self.assertEquals(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
368 368
369 # parallel magic tests
370
371 def test_magic_px_blocking(self):
372 ip = get_ipython()
373 v = self.client[-1]
374 v.activate()
375 v.block=True
376
377 ip.magic('px a=5')
378 self.assertEquals(v['a'], 5)
379 ip.magic('px a=10')
380 self.assertEquals(v['a'], 10)
381 sio = StringIO()
382 savestdout = sys.stdout
383 sys.stdout = sio
384 # just 'print a' worst ~99% of the time, but this ensures that
385 # the stdout message has arrived when the result is finished:
386 ip.magic('px import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)')
387 sys.stdout = savestdout
388 buf = sio.getvalue()
389 self.assertTrue('[stdout:' in buf, buf)
390 self.assertTrue(buf.rstrip().endswith('10'))
391 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
392
393 def test_magic_px_nonblocking(self):
394 ip = get_ipython()
395 v = self.client[-1]
396 v.activate()
397 v.block=False
398
399 ip.magic('px a=5')
400 self.assertEquals(v['a'], 5)
401 ip.magic('px a=10')
402 self.assertEquals(v['a'], 10)
403 sio = StringIO()
404 savestdout = sys.stdout
405 sys.stdout = sio
406 ip.magic('px print a')
407 sys.stdout = savestdout
408 buf = sio.getvalue()
409 self.assertFalse('[stdout:%i]'%v.targets in buf)
410 ip.magic('px 1/0')
411 ar = v.get_result(-1)
412 self.assertRaisesRemote(ZeroDivisionError, ar.get)
413
414 def test_magic_autopx_blocking(self):
415 ip = get_ipython()
416 v = self.client[-1]
417 v.activate()
418 v.block=True
419
420 sio = StringIO()
421 savestdout = sys.stdout
422 sys.stdout = sio
423 ip.magic('autopx')
424 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
425 ip.run_cell('b*=2')
426 ip.run_cell('print (b)')
427 ip.run_cell("b/c")
428 ip.magic('autopx')
429 sys.stdout = savestdout
430 output = sio.getvalue().strip()
431 self.assertTrue(output.startswith('%autopx enabled'))
432 self.assertTrue(output.endswith('%autopx disabled'))
433 self.assertTrue('RemoteError: ZeroDivisionError' in output)
434 ar = v.get_result(-1)
435 self.assertEquals(v['a'], 5)
436 self.assertEquals(v['b'], 20)
437 self.assertRaisesRemote(ZeroDivisionError, ar.get)
438
439 def test_magic_autopx_nonblocking(self):
440 ip = get_ipython()
441 v = self.client[-1]
442 v.activate()
443 v.block=False
444
445 sio = StringIO()
446 savestdout = sys.stdout
447 sys.stdout = sio
448 ip.magic('autopx')
449 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
450 ip.run_cell('print (b)')
451 ip.run_cell('import time; time.sleep(0.1)')
452 ip.run_cell("b/c")
453 ip.run_cell('b*=2')
454 ip.magic('autopx')
455 sys.stdout = savestdout
456 output = sio.getvalue().strip()
457 self.assertTrue(output.startswith('%autopx enabled'))
458 self.assertTrue(output.endswith('%autopx disabled'))
459 self.assertFalse('ZeroDivisionError' in output)
460 ar = v.get_result(-2)
461 self.assertRaisesRemote(ZeroDivisionError, ar.get)
462 # prevent TaskAborted on pulls, due to ZeroDivisionError
463 time.sleep(0.5)
464 self.assertEquals(v['a'], 5)
465 # b*=2 will not fire, due to abort
466 self.assertEquals(v['b'], 10)
467
468 def test_magic_result(self):
469 ip = get_ipython()
470 v = self.client[-1]
471 v.activate()
472 v['a'] = 111
473 ra = v['a']
474
475 ar = ip.magic('result')
476 self.assertEquals(ar.msg_ids, [v.history[-1]])
477 self.assertEquals(ar.get(), 111)
478 ar = ip.magic('result -2')
479 self.assertEquals(ar.msg_ids, [v.history[-2]])
480
481 369 def test_unicode_execute(self):
482 370 """test executing unicode strings"""
483 371 v = self.client[-1]
@@ -575,16 +463,6 b' class TestView(ClusterTestCase, ParametricTestCase):'
575 463
576 464
577 465 # begin execute tests
578 def _wait_for(self, f, timeout=10):
579 tic = time.time()
580 while time.time() <= tic + timeout:
581 if f():
582 return
583 time.sleep(0.1)
584 self.client.spin()
585 if not f():
586 print "Warning: Awaited condition never arrived"
587
588 466
589 467 def test_execute_reply(self):
590 468 e0 = self.client[self.client.ids[0]]
@@ -31,12 +31,15 b' class ZMQDisplayHook(object):'
31 31
32 32
33 33 def _encode_binary(format_dict):
34 encoded = format_dict.copy()
34 35 pngdata = format_dict.get('image/png')
35 if pngdata is not None:
36 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
36 if isinstance(pngdata, bytes):
37 encoded['image/png'] = encodestring(pngdata).decode('ascii')
37 38 jpegdata = format_dict.get('image/jpeg')
38 if jpegdata is not None:
39 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
39 if isinstance(jpegdata, bytes):
40 encoded['image/jpeg'] = encodestring(jpegdata).decode('ascii')
41
42 return encoded
40 43
41 44
42 45 class ZMQShellDisplayHook(DisplayHook):
@@ -61,8 +64,7 b' class ZMQShellDisplayHook(DisplayHook):'
61 64 self.msg['content']['execution_count'] = self.prompt_count
62 65
63 66 def write_format_data(self, format_dict):
64 _encode_binary(format_dict)
65 self.msg['content']['data'] = format_dict
67 self.msg['content']['data'] = _encode_binary(format_dict)
66 68
67 69 def finish_displayhook(self):
68 70 """Finish up all displayhook activities."""
@@ -382,6 +382,8 b' class Kernel(Configurable):'
382 382 # runlines. We'll need to clean up this logic later.
383 383 if shell._reply_content is not None:
384 384 reply_content.update(shell._reply_content)
385 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
386 reply_content['engine_info'] = e_info
385 387 # reset after use
386 388 shell._reply_content = None
387 389
@@ -77,8 +77,7 b' class ZMQDisplayPublisher(DisplayPublisher):'
77 77 self._validate_data(source, data, metadata)
78 78 content = {}
79 79 content['source'] = source
80 _encode_binary(data)
81 content['data'] = data
80 content['data'] = _encode_binary(data)
82 81 content['metadata'] = metadata
83 82 self.session.send(
84 83 self.pub_socket, u'display_data', json_clean(content),
@@ -120,21 +120,19 b' using our :func:`psum` function:'
120 120
121 121 In [1]: from IPython.parallel import Client
122 122
123 In [2]: %load_ext parallel_magic
124
125 123 In [3]: c = Client(profile='mpi')
126 124
127 125 In [4]: view = c[:]
128 126
129 In [5]: view.activate()
127 In [5]: view.activate() # enabe magics
130 128
131 129 # run the contents of the file on each engine:
132 130 In [6]: view.run('psum.py')
133 131
134 In [6]: px a = np.random.rand(100)
132 In [6]: %px a = np.random.rand(100)
135 133 Parallel execution on engines: [0,1,2,3]
136 134
137 In [8]: px s = psum(a)
135 In [8]: %px s = psum(a)
138 136 Parallel execution on engines: [0,1,2,3]
139 137
140 138 In [9]: view['s']
@@ -389,11 +389,11 b' Parallel magic commands'
389 389 -----------------------
390 390
391 391 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``)
392 that make it more pleasant to execute Python commands on the engines
393 interactively. These are simply shortcuts to :meth:`execute` and
394 :meth:`get_result` of the :class:`DirectView`. The ``%px`` magic executes a single
395 Python command on the engines specified by the :attr:`targets` attribute of the
396 :class:`DirectView` instance:
392 that make it a bit more pleasant to execute Python commands on the engines interactively.
393 These are simply shortcuts to :meth:`.DirectView.execute`
394 and :meth:`.AsyncResult.display_outputs` methods repsectively.
395 The ``%px`` magic executes a single Python command on the engines
396 specified by the :attr:`targets` attribute of the :class:`DirectView` instance:
397 397
398 398 .. sourcecode:: ipython
399 399
@@ -413,43 +413,127 b' Python command on the engines specified by the :attr:`targets` attribute of the'
413 413 In [27]: %px a = numpy.random.rand(2,2)
414 414 Parallel execution on engines: [0, 1, 2, 3]
415 415
416 In [28]: %px ev = numpy.linalg.eigvals(a)
416 In [28]: %px numpy.linalg.eigvals(a)
417 417 Parallel execution on engines: [0, 1, 2, 3]
418 [0] Out[68]: array([ 0.77120707, -0.19448286])
419 [1] Out[68]: array([ 1.10815921, 0.05110369])
420 [2] Out[68]: array([ 0.74625527, -0.37475081])
421 [3] Out[68]: array([ 0.72931905, 0.07159743])
422
423 In [29]: %px print 'hi'
424 Parallel execution on engine(s): [0, 1, 2, 3]
425 [stdout:0] hi
426 [stdout:1] hi
427 [stdout:2] hi
428 [stdout:3] hi
429
430
431 Since engines are IPython as well, you can even run magics remotely:
432
433 .. sourcecode:: ipython
434
435 In [28]: %px %pylab inline
436 Parallel execution on engine(s): [0, 1, 2, 3]
437 [stdout:0]
438 Welcome to pylab, a matplotlib-based Python environment...
439 For more information, type 'help(pylab)'.
440 [stdout:1]
441 Welcome to pylab, a matplotlib-based Python environment...
442 For more information, type 'help(pylab)'.
443 [stdout:2]
444 Welcome to pylab, a matplotlib-based Python environment...
445 For more information, type 'help(pylab)'.
446 [stdout:3]
447 Welcome to pylab, a matplotlib-based Python environment...
448 For more information, type 'help(pylab)'.
449
450 And once in pylab mode with the inline backend,
451 you can make plots and they will be displayed in your frontend
452 if it suports the inline figures (e.g. notebook or qtconsole):
453
454 .. sourcecode:: ipython
455
456 In [40]: %px plot(rand(100))
457 Parallel execution on engine(s): [0, 1, 2, 3]
458 <plot0>
459 <plot1>
460 <plot2>
461 <plot3>
462 [0] Out[79]: [<matplotlib.lines.Line2D at 0x10a6286d0>]
463 [1] Out[79]: [<matplotlib.lines.Line2D at 0x10b9476d0>]
464 [2] Out[79]: [<matplotlib.lines.Line2D at 0x110652750>]
465 [3] Out[79]: [<matplotlib.lines.Line2D at 0x10c6566d0>]
418 466
419 In [28]: dv['ev']
420 Out[28]: [ array([ 1.09522024, -0.09645227]),
421 ....: array([ 1.21435496, -0.35546712]),
422 ....: array([ 0.72180653, 0.07133042]),
423 ....: array([ 1.46384341, 1.04353244e-04])
424 ....: ]
425 467
426 The ``%result`` magic gets the most recent result, or takes an argument
427 specifying the index of the result to be requested. It is simply a shortcut to the
428 :meth:`get_result` method:
468 ``%%px`` Cell Magic
469 *******************
470
471 `%%px` can also be used as a Cell Magic, which accepts ``--[no]block`` flags,
472 and a ``--group-outputs`` argument, which adjust how the outputs of multiple
473 engines are presented.
474
475 .. seealso::
476
477 :meth:`.AsyncResult.display_outputs` for the grouping options.
429 478
430 479 .. sourcecode:: ipython
480
481 In [50]: %%px --block --group-outputs=engine
482 ....: import numpy as np
483 ....: A = np.random.random((2,2))
484 ....: ev = numpy.linalg.eigvals(A)
485 ....: print ev
486 ....: ev.max()
487 ....:
488 Parallel execution on engine(s): [0, 1, 2, 3]
489 [stdout:0] [ 0.60640442 0.95919621]
490 [0] Out[73]: 0.9591962130899806
491 [stdout:1] [ 0.38501813 1.29430871]
492 [1] Out[73]: 1.2943087091452372
493 [stdout:2] [-0.85925141 0.9387692 ]
494 [2] Out[73]: 0.93876920456230284
495 [stdout:3] [ 0.37998269 1.24218246]
496 [3] Out[73]: 1.2421824618493817
497
498 ``%result`` Magic
499 *****************
500
501 If you are using ``%px`` in non-blocking mode, you won't get output.
502 You can use ``%result`` to display the outputs of the latest command,
503 just as is done when ``%px`` is blocking:
504
505 .. sourcecode:: ipython
506
507 In [39]: dv.block = False
431 508
432 In [29]: dv.apply_async(lambda : ev)
509 In [40]: %px print 'hi'
510 Async parallel execution on engine(s): [0, 1, 2, 3]
433 511
434 In [30]: %result
435 Out[30]: [ [ 1.28167017 0.14197338],
436 ....: [-0.14093616 1.27877273],
437 ....: [-0.37023573 1.06779409],
438 ....: [ 0.83664764 -0.25602658] ]
512 In [41]: %result
513 [stdout:0] hi
514 [stdout:1] hi
515 [stdout:2] hi
516 [stdout:3] hi
517
518 ``%result`` simply calls :meth:`.AsyncResult.display_outputs` on the most recent request.
519 You can pass integers as indices if you want a result other than the latest,
520 e.g. ``%result -2``, or ``%result 0`` for the first.
521
522
523 ``%autopx``
524 ***********
439 525
440 526 The ``%autopx`` magic switches to a mode where everything you type is executed
441 on the engines given by the :attr:`targets` attribute:
527 on the engines until you do ``%autopx`` again.
442 528
443 529 .. sourcecode:: ipython
444 530
445 In [30]: dv.block=False
531 In [30]: dv.block=True
446 532
447 533 In [31]: %autopx
448 Auto Parallel Enabled
449 Type %autopx to disable
534 %autopx enabled
450 535
451 536 In [32]: max_evals = []
452 <IPython.parallel.AsyncResult object at 0x17b8a70>
453 537
454 538 In [33]: for i in range(100):
455 539 ....: a = numpy.random.rand(10,10)
@@ -457,22 +541,15 b' on the engines given by the :attr:`targets` attribute:'
457 541 ....: evals = numpy.linalg.eigvals(a)
458 542 ....: max_evals.append(evals[0].real)
459 543 ....:
460 ....:
461 <IPython.parallel.AsyncResult object at 0x17af8f0>
462
463 In [34]: %autopx
464 Auto Parallel Disabled
465 544
466 In [35]: dv.block=True
467
468 In [36]: px ans= "Average max eigenvalue is: %f"%(sum(max_evals)/len(max_evals))
469 Parallel execution on engines: [0, 1, 2, 3]
545 In [34]: print "Average max eigenvalue is: %f" % (sum(max_evals)/len(max_evals))
546 [stdout:0] Average max eigenvalue is: 10.193101
547 [stdout:1] Average max eigenvalue is: 10.064508
548 [stdout:2] Average max eigenvalue is: 10.055724
549 [stdout:3] Average max eigenvalue is: 10.086876
470 550
471 In [37]: dv['ans']
472 Out[37]: [ 'Average max eigenvalue is: 10.1387247332',
473 ....: 'Average max eigenvalue is: 10.2076902286',
474 ....: 'Average max eigenvalue is: 10.1891484655',
475 ....: 'Average max eigenvalue is: 10.1158837784',]
551 In [35]: %autopx
552 Auto Parallel Disabled
476 553
477 554
478 555 Moving Python objects around
General Comments 0
You need to be logged in to leave comments. Login now