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 | argv = arg_split(arg_str, posix, strict) |
|
542 | argv = arg_split(arg_str, posix, strict) | |
543 | # Do regular option processing |
|
543 | # Do regular option processing | |
544 | try: |
|
544 | try: | |
545 |
opts,args = getopt(argv,opt_str, |
|
545 | opts,args = getopt(argv, opt_str, long_opts) | |
546 | except GetoptError,e: |
|
546 | except GetoptError,e: | |
547 | raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, |
|
547 | raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, | |
548 | " ".join(long_opts))) |
|
548 | " ".join(long_opts))) |
@@ -69,6 +69,15 b' def test_magic_parse_options():' | |||||
69 | expected = path |
|
69 | expected = path | |
70 | nt.assert_equals(opts['f'], expected) |
|
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 | @dec.skip_without('sqlite3') |
|
82 | @dec.skip_without('sqlite3') | |
74 | def doctest_hist_f(): |
|
83 | def doctest_hist_f(): |
@@ -11,15 +11,15 b' Usage' | |||||
11 |
|
11 | |||
12 | ``%autopx`` |
|
12 | ``%autopx`` | |
13 |
|
13 | |||
14 |
|
|
14 | {AUTOPX_DOC} | |
15 |
|
15 | |||
16 | ``%px`` |
|
16 | ``%px`` | |
17 |
|
17 | |||
18 |
|
|
18 | {PX_DOC} | |
19 |
|
19 | |||
20 | ``%result`` |
|
20 | ``%result`` | |
21 |
|
21 | |||
22 |
|
|
22 | {RESULT_DOC} | |
23 |
|
23 | |||
24 | """ |
|
24 | """ | |
25 |
|
25 | |||
@@ -37,16 +37,16 b' Usage' | |||||
37 | import ast |
|
37 | import ast | |
38 | import re |
|
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 | from IPython.testing.skipdoctest import skip_doctest |
|
42 | from IPython.testing.skipdoctest import skip_doctest | |
42 |
|
43 | |||
43 | #----------------------------------------------------------------------------- |
|
44 | #----------------------------------------------------------------------------- | |
44 | # Definitions of magic functions for use with IPython |
|
45 | # Definitions of magic functions for use with IPython | |
45 | #----------------------------------------------------------------------------- |
|
46 | #----------------------------------------------------------------------------- | |
46 |
|
47 | |||
47 | NO_ACTIVE_VIEW = """ |
|
48 | ||
48 |
Use activate() on a DirectView object to |
|
49 | NO_ACTIVE_VIEW = "Use activate() on a DirectView object to use it with magics." | |
49 | """ |
|
|||
50 |
|
50 | |||
51 |
|
51 | |||
52 | @magics_class |
|
52 | @magics_class | |
@@ -54,43 +54,48 b' class ParallelMagics(Magics):' | |||||
54 | """A set of magics useful when controlling a parallel IPython cluster. |
|
54 | """A set of magics useful when controlling a parallel IPython cluster. | |
55 | """ |
|
55 | """ | |
56 |
|
56 | |||
57 | def __init__(self, shell): |
|
|||
58 | super(ParallelMagics, self).__init__(shell) |
|
|||
59 |
|
|
57 | # A flag showing if autopx is activated or not | |
60 |
|
|
58 | _autopx = False | |
|
59 | # the current view used by the magics: | |||
|
60 | active_view = None | |||
61 |
|
61 | |||
62 | @skip_doctest |
|
62 | @skip_doctest | |
63 | @line_magic |
|
63 | @line_magic | |
64 | def result(self, parameter_s=''): |
|
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 | To use this a :class:`DirectView` instance must be created |
|
67 | To use this a :class:`DirectView` instance must be created | |
68 | and then activated by calling its :meth:`activate` method. |
|
68 | and then activated by calling its :meth:`activate` method. | |
69 |
|
69 | |||
|
70 | This lets you recall the results of %px computations after | |||
|
71 | asynchronous submission (view.block=False). | |||
|
72 | ||||
70 | Then you can do the following:: |
|
73 | Then you can do the following:: | |
71 |
|
74 | |||
72 |
In [23]: % |
|
75 | In [23]: %px os.getpid() | |
73 | Out[23]: |
|
76 | Async parallel execution on engine(s): all | |
74 | <Results List> |
|
77 | ||
75 |
|
|
78 | In [24]: %result | |
76 |
[ |
|
79 | [ 8] Out[10]: 60920 | |
77 |
|
80 | [ 9] Out[10]: 60921 | ||
78 | In [22]: %result 6 |
|
81 | [10] Out[10]: 60922 | |
79 |
|
|
82 | [11] Out[10]: 60923 | |
80 | <Results List> |
|
|||
81 | [0] In [6]: a = 10 |
|
|||
82 | [1] In [6]: a = 10 |
|
|||
83 | """ |
|
83 | """ | |
|
84 | ||||
84 | if self.active_view is None: |
|
85 | if self.active_view is None: | |
85 |
|
|
86 | raise UsageError(NO_ACTIVE_VIEW) | |
86 | return |
|
|||
87 |
|
87 | |||
|
88 | stride = len(self.active_view) | |||
88 | try: |
|
89 | try: | |
89 | index = int(parameter_s) |
|
90 | index = int(parameter_s) | |
90 | except: |
|
91 | except: | |
91 |
index = |
|
92 | index = -1 | |
92 | result = self.active_view.get_result(index) |
|
93 | msg_ids = self.active_view.history[stride * index:(stride * (index + 1)) or None] | |
93 | return result |
|
94 | ||
|
95 | result = self.active_view.get_result(msg_ids) | |||
|
96 | ||||
|
97 | result.get() | |||
|
98 | result.display_outputs() | |||
94 |
|
99 | |||
95 | @skip_doctest |
|
100 | @skip_doctest | |
96 | @line_magic |
|
101 | @line_magic | |
@@ -102,22 +107,102 b' class ParallelMagics(Magics):' | |||||
102 |
|
107 | |||
103 | Then you can do the following:: |
|
108 | Then you can do the following:: | |
104 |
|
109 | |||
105 |
In [24]: %px a = |
|
110 | In [24]: %px a = os.getpid() | |
106 | Parallel execution on engine(s): all |
|
111 | Parallel execution on engine(s): all | |
107 |
|
|
112 | ||
108 | <Results List> |
|
113 | In [25]: %px print a | |
109 | [0] In [7]: a = 5 |
|
114 | [stdout:0] 1234 | |
110 |
[ |
|
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 | if self.active_view is None: |
|
124 | if self.active_view is None: | |
114 |
|
|
125 | raise UsageError(NO_ACTIVE_VIEW) | |
115 |
|
|
126 | ||
116 | print "Parallel execution on engine(s): %s" % self.active_view.targets |
|
127 | # defaults: | |
117 | result = self.active_view.execute(parameter_s, block=False) |
|
128 | block = self.active_view.block if block is None else block | |
118 | if self.active_view.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 | result.get() |
|
135 | result.get() | |
120 |
|
|
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 | @skip_doctest |
|
207 | @skip_doctest | |
123 | @line_magic |
|
208 | @line_magic | |
@@ -149,7 +234,7 b' class ParallelMagics(Magics):' | |||||
149 | In [27]: %autopx |
|
234 | In [27]: %autopx | |
150 | %autopx disabled |
|
235 | %autopx disabled | |
151 | """ |
|
236 | """ | |
152 | if self.autopx: |
|
237 | if self._autopx: | |
153 | self._disable_autopx() |
|
238 | self._disable_autopx() | |
154 | else: |
|
239 | else: | |
155 | self._enable_autopx() |
|
240 | self._enable_autopx() | |
@@ -159,50 +244,23 b' class ParallelMagics(Magics):' | |||||
159 | pxrun_cell. |
|
244 | pxrun_cell. | |
160 | """ |
|
245 | """ | |
161 | if self.active_view is None: |
|
246 | if self.active_view is None: | |
162 |
|
|
247 | raise UsageError(NO_ACTIVE_VIEW) | |
163 | return |
|
|||
164 |
|
248 | |||
165 |
# override run_cell |
|
249 | # override run_cell | |
166 | self._original_run_cell = self.shell.run_cell |
|
250 | self._original_run_cell = self.shell.run_cell | |
167 | self.shell.run_cell = self.pxrun_cell |
|
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 | print "%autopx enabled" |
|
254 | print "%autopx enabled" | |
173 |
|
255 | |||
174 | def _disable_autopx(self): |
|
256 | def _disable_autopx(self): | |
175 | """Disable %autopx by restoring the original InteractiveShell.run_cell. |
|
257 | """Disable %autopx by restoring the original InteractiveShell.run_cell. | |
176 | """ |
|
258 | """ | |
177 | if self.autopx: |
|
259 | if self._autopx: | |
178 | self.shell.run_cell = self._original_run_cell |
|
260 | self.shell.run_cell = self._original_run_cell | |
179 | self.shell.run_code = self._original_run_code |
|
261 | self._autopx = False | |
180 | self.autopx = False |
|
|||
181 | print "%autopx disabled" |
|
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 | def pxrun_cell(self, raw_cell, store_history=False, silent=False): |
|
264 | def pxrun_cell(self, raw_cell, store_history=False, silent=False): | |
207 | """drop-in replacement for InteractiveShell.run_cell. |
|
265 | """drop-in replacement for InteractiveShell.run_cell. | |
208 |
|
266 | |||
@@ -263,47 +321,16 b' class ParallelMagics(Magics):' | |||||
263 | self.shell.showtraceback() |
|
321 | self.shell.showtraceback() | |
264 | return True |
|
322 | return True | |
265 | else: |
|
323 | else: | |
266 |
self. |
|
324 | with ipself.builtin_trap: | |
267 | return False |
|
325 | result.display_outputs() | |
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) |
|
|||
298 | return False |
|
326 | return False | |
299 |
|
327 | |||
300 |
|
328 | |||
301 |
__doc__ = __doc__. |
|
329 | __doc__ = __doc__.format( | |
302 |
|
|
330 | AUTOPX_DOC = ' '*8 + ParallelMagics.autopx.__doc__, | |
303 | __doc__ = __doc__.replace('@PX_DOC@', |
|
331 | PX_DOC = ' '*8 + ParallelMagics.px.__doc__, | |
304 |
|
|
332 | RESULT_DOC = ' '*8 + ParallelMagics.result.__doc__ | |
305 | __doc__ = __doc__.replace('@RESULT_DOC@', |
|
333 | ) | |
306 | " " + ParallelMagics.result.__doc__) |
|
|||
307 |
|
334 | |||
308 | _loaded = False |
|
335 | _loaded = False | |
309 |
|
336 |
@@ -21,7 +21,7 b' from datetime import datetime' | |||||
21 |
|
21 | |||
22 | from zmq import MessageTracker |
|
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 | from IPython.external.decorator import decorator |
|
25 | from IPython.external.decorator import decorator | |
26 | from IPython.parallel import error |
|
26 | from IPython.parallel import error | |
27 |
|
27 | |||
@@ -378,6 +378,140 b' class AsyncResult(object):' | |||||
378 |
|
378 | |||
379 | print "done" |
|
379 | print "done" | |
380 |
|
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 | ||||
|
514 | ||||
381 |
|
515 | |||
382 | class AsyncMapResult(AsyncResult): |
|
516 | class AsyncMapResult(AsyncResult): | |
383 | """Class for representing results of non-blocking gathers. |
|
517 | """Class for representing results of non-blocking gathers. |
@@ -33,6 +33,7 b' import zmq' | |||||
33 | from IPython.config.configurable import MultipleInstanceError |
|
33 | from IPython.config.configurable import MultipleInstanceError | |
34 | from IPython.core.application import BaseIPythonApplication |
|
34 | from IPython.core.application import BaseIPythonApplication | |
35 |
|
35 | |||
|
36 | from IPython.utils.coloransi import TermColors | |||
36 | from IPython.utils.jsonutil import rekey |
|
37 | from IPython.utils.jsonutil import rekey | |
37 | from IPython.utils.localinterfaces import LOCAL_IPS |
|
38 | from IPython.utils.localinterfaces import LOCAL_IPS | |
38 | from IPython.utils.path import get_ipython_dir |
|
39 | from IPython.utils.path import get_ipython_dir | |
@@ -90,13 +91,39 b' class ExecuteReply(object):' | |||||
90 | return self.metadata[key] |
|
91 | return self.metadata[key] | |
91 |
|
92 | |||
92 | def __repr__(self): |
|
93 | def __repr__(self): | |
93 | pyout = self.metadata['pyout'] or {} |
|
94 | pyout = self.metadata['pyout'] or {'data':{}} | |
94 |
text_out = pyout |
|
95 | text_out = pyout['data'].get('text/plain', '') | |
95 | if len(text_out) > 32: |
|
96 | if len(text_out) > 32: | |
96 | text_out = text_out[:29] + '...' |
|
97 | text_out = text_out[:29] + '...' | |
97 |
|
98 | |||
98 | return "<ExecuteReply[%i]: %s>" % (self.execution_count, text_out) |
|
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 | def _repr_html_(self): |
|
127 | def _repr_html_(self): | |
101 | pyout = self.metadata['pyout'] or {'data':{}} |
|
128 | pyout = self.metadata['pyout'] or {'data':{}} | |
102 | return pyout['data'].get("text/html") |
|
129 | return pyout['data'].get("text/html") |
@@ -15,6 +15,7 b' Authors:' | |||||
15 | import sys |
|
15 | import sys | |
16 | import tempfile |
|
16 | import tempfile | |
17 | import time |
|
17 | import time | |
|
18 | from StringIO import StringIO | |||
18 |
|
19 | |||
19 | from nose import SkipTest |
|
20 | from nose import SkipTest | |
20 |
|
21 | |||
@@ -59,6 +60,28 b' def raiser(eclass):' | |||||
59 | """raise an exception""" |
|
60 | """raise an exception""" | |
60 | raise eclass() |
|
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 | # test decorator for skipping tests when libraries are unavailable |
|
85 | # test decorator for skipping tests when libraries are unavailable | |
63 | def skip_without(*names): |
|
86 | def skip_without(*names): | |
64 | """skip a test if some names are not importable""" |
|
87 | """skip a test if some names are not importable""" | |
@@ -73,6 +96,41 b' def skip_without(*names):' | |||||
73 | return f(*args, **kwargs) |
|
96 | return f(*args, **kwargs) | |
74 | return skip_without_names |
|
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 | class ClusterTestCase(BaseZMQTestCase): |
|
134 | class ClusterTestCase(BaseZMQTestCase): | |
77 |
|
135 | |||
78 | def add_engines(self, n=1, block=True): |
|
136 | def add_engines(self, n=1, block=True): | |
@@ -117,6 +175,17 b' class ClusterTestCase(BaseZMQTestCase):' | |||||
117 | else: |
|
175 | else: | |
118 | self.fail("should have raised a RemoteError") |
|
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 | def setUp(self): |
|
189 | def setUp(self): | |
121 | BaseZMQTestCase.setUp(self) |
|
190 | BaseZMQTestCase.setUp(self) | |
122 | self.client = self.connect_client() |
|
191 | self.client = self.connect_client() |
@@ -366,118 +366,6 b' class TestView(ClusterTestCase, ParametricTestCase):' | |||||
366 |
|
366 | |||
367 | self.assertEquals(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split()) |
|
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 | def test_unicode_execute(self): |
|
369 | def test_unicode_execute(self): | |
482 | """test executing unicode strings""" |
|
370 | """test executing unicode strings""" | |
483 | v = self.client[-1] |
|
371 | v = self.client[-1] | |
@@ -575,16 +463,6 b' class TestView(ClusterTestCase, ParametricTestCase):' | |||||
575 |
|
463 | |||
576 |
|
464 | |||
577 | # begin execute tests |
|
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 | def test_execute_reply(self): |
|
467 | def test_execute_reply(self): | |
590 | e0 = self.client[self.client.ids[0]] |
|
468 | e0 = self.client[self.client.ids[0]] |
@@ -31,12 +31,15 b' class ZMQDisplayHook(object):' | |||||
31 |
|
31 | |||
32 |
|
32 | |||
33 | def _encode_binary(format_dict): |
|
33 | def _encode_binary(format_dict): | |
|
34 | encoded = format_dict.copy() | |||
34 | pngdata = format_dict.get('image/png') |
|
35 | pngdata = format_dict.get('image/png') | |
35 | if pngdata is not None: |
|
36 | if isinstance(pngdata, bytes): | |
36 |
|
|
37 | encoded['image/png'] = encodestring(pngdata).decode('ascii') | |
37 | jpegdata = format_dict.get('image/jpeg') |
|
38 | jpegdata = format_dict.get('image/jpeg') | |
38 | if jpegdata is not None: |
|
39 | if isinstance(jpegdata, bytes): | |
39 |
|
|
40 | encoded['image/jpeg'] = encodestring(jpegdata).decode('ascii') | |
|
41 | ||||
|
42 | return encoded | |||
40 |
|
43 | |||
41 |
|
44 | |||
42 | class ZMQShellDisplayHook(DisplayHook): |
|
45 | class ZMQShellDisplayHook(DisplayHook): | |
@@ -61,8 +64,7 b' class ZMQShellDisplayHook(DisplayHook):' | |||||
61 | self.msg['content']['execution_count'] = self.prompt_count |
|
64 | self.msg['content']['execution_count'] = self.prompt_count | |
62 |
|
65 | |||
63 | def write_format_data(self, format_dict): |
|
66 | def write_format_data(self, format_dict): | |
64 | _encode_binary(format_dict) |
|
67 | self.msg['content']['data'] = _encode_binary(format_dict) | |
65 | self.msg['content']['data'] = format_dict |
|
|||
66 |
|
68 | |||
67 | def finish_displayhook(self): |
|
69 | def finish_displayhook(self): | |
68 | """Finish up all displayhook activities.""" |
|
70 | """Finish up all displayhook activities.""" |
@@ -382,6 +382,8 b' class Kernel(Configurable):' | |||||
382 | # runlines. We'll need to clean up this logic later. |
|
382 | # runlines. We'll need to clean up this logic later. | |
383 | if shell._reply_content is not None: |
|
383 | if shell._reply_content is not None: | |
384 | reply_content.update(shell._reply_content) |
|
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 | # reset after use |
|
387 | # reset after use | |
386 | shell._reply_content = None |
|
388 | shell._reply_content = None | |
387 |
|
389 |
@@ -77,8 +77,7 b' class ZMQDisplayPublisher(DisplayPublisher):' | |||||
77 | self._validate_data(source, data, metadata) |
|
77 | self._validate_data(source, data, metadata) | |
78 | content = {} |
|
78 | content = {} | |
79 | content['source'] = source |
|
79 | content['source'] = source | |
80 | _encode_binary(data) |
|
80 | content['data'] = _encode_binary(data) | |
81 | content['data'] = data |
|
|||
82 | content['metadata'] = metadata |
|
81 | content['metadata'] = metadata | |
83 | self.session.send( |
|
82 | self.session.send( | |
84 | self.pub_socket, u'display_data', json_clean(content), |
|
83 | self.pub_socket, u'display_data', json_clean(content), |
@@ -120,21 +120,19 b' using our :func:`psum` function:' | |||||
120 |
|
120 | |||
121 | In [1]: from IPython.parallel import Client |
|
121 | In [1]: from IPython.parallel import Client | |
122 |
|
122 | |||
123 | In [2]: %load_ext parallel_magic |
|
|||
124 |
|
||||
125 | In [3]: c = Client(profile='mpi') |
|
123 | In [3]: c = Client(profile='mpi') | |
126 |
|
124 | |||
127 | In [4]: view = c[:] |
|
125 | In [4]: view = c[:] | |
128 |
|
126 | |||
129 | In [5]: view.activate() |
|
127 | In [5]: view.activate() # enabe magics | |
130 |
|
128 | |||
131 | # run the contents of the file on each engine: |
|
129 | # run the contents of the file on each engine: | |
132 | In [6]: view.run('psum.py') |
|
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 | Parallel execution on engines: [0,1,2,3] |
|
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 | Parallel execution on engines: [0,1,2,3] |
|
136 | Parallel execution on engines: [0,1,2,3] | |
139 |
|
137 | |||
140 | In [9]: view['s'] |
|
138 | In [9]: view['s'] |
@@ -389,11 +389,11 b' Parallel magic commands' | |||||
389 | ----------------------- |
|
389 | ----------------------- | |
390 |
|
390 | |||
391 | We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``) |
|
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 |
|
392 | that make it a bit more pleasant to execute Python commands on the engines interactively. | |
393 |
|
|
393 | These are simply shortcuts to :meth:`.DirectView.execute` | |
394 | :meth:`get_result` of the :class:`DirectView`. The ``%px`` magic executes a single |
|
394 | and :meth:`.AsyncResult.display_outputs` methods repsectively. | |
395 | Python command on the engines specified by the :attr:`targets` attribute of the |
|
395 | The ``%px`` magic executes a single Python command on the engines | |
396 | :class:`DirectView` instance: |
|
396 | specified by the :attr:`targets` attribute of the :class:`DirectView` instance: | |
397 |
|
397 | |||
398 | .. sourcecode:: ipython |
|
398 | .. sourcecode:: ipython | |
399 |
|
399 | |||
@@ -413,43 +413,127 b' Python command on the engines specified by the :attr:`targets` attribute of the' | |||||
413 | In [27]: %px a = numpy.random.rand(2,2) |
|
413 | In [27]: %px a = numpy.random.rand(2,2) | |
414 | Parallel execution on engines: [0, 1, 2, 3] |
|
414 | Parallel execution on engines: [0, 1, 2, 3] | |
415 |
|
415 | |||
416 |
In [28]: %px |
|
416 | In [28]: %px numpy.linalg.eigvals(a) | |
417 | Parallel execution on engines: [0, 1, 2, 3] |
|
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]) | |||
418 |
|
422 | |||
419 | In [28]: dv['ev'] |
|
423 | In [29]: %px print 'hi' | |
420 | Out[28]: [ array([ 1.09522024, -0.09645227]), |
|
424 | Parallel execution on engine(s): [0, 1, 2, 3] | |
421 | ....: array([ 1.21435496, -0.35546712]), |
|
425 | [stdout:0] hi | |
422 | ....: array([ 0.72180653, 0.07133042]), |
|
426 | [stdout:1] hi | |
423 | ....: array([ 1.46384341, 1.04353244e-04]) |
|
427 | [stdout:2] hi | |
424 | ....: ] |
|
428 | [stdout:3] hi | |
425 |
|
429 | |||
426 | The ``%result`` magic gets the most recent result, or takes an argument |
|
430 | ||
427 | specifying the index of the result to be requested. It is simply a shortcut to the |
|
431 | Since engines are IPython as well, you can even run magics remotely: | |
428 | :meth:`get_result` method: |
|
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): | |||
429 |
|
453 | |||
430 | .. sourcecode:: ipython |
|
454 | .. sourcecode:: ipython | |
431 |
|
455 | |||
432 | In [29]: dv.apply_async(lambda : ev) |
|
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>] | |||
|
466 | ||||
|
467 | ||||
|
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. | |||
433 |
|
474 | |||
434 | In [30]: %result |
|
475 | .. seealso:: | |
435 | Out[30]: [ [ 1.28167017 0.14197338], |
|
476 | ||
436 | ....: [-0.14093616 1.27877273], |
|
477 | :meth:`.AsyncResult.display_outputs` for the grouping options. | |
437 | ....: [-0.37023573 1.06779409], |
|
478 | ||
438 | ....: [ 0.83664764 -0.25602658] ] |
|
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 | |||
|
508 | ||||
|
509 | In [40]: %px print 'hi' | |||
|
510 | Async parallel execution on engine(s): [0, 1, 2, 3] | |||
|
511 | ||||
|
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 | The ``%autopx`` magic switches to a mode where everything you type is executed |
|
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 | .. sourcecode:: ipython |
|
529 | .. sourcecode:: ipython | |
444 |
|
530 | |||
445 |
In [30]: dv.block= |
|
531 | In [30]: dv.block=True | |
446 |
|
532 | |||
447 | In [31]: %autopx |
|
533 | In [31]: %autopx | |
448 |
|
|
534 | %autopx enabled | |
449 | Type %autopx to disable |
|
|||
450 |
|
535 | |||
451 | In [32]: max_evals = [] |
|
536 | In [32]: max_evals = [] | |
452 | <IPython.parallel.AsyncResult object at 0x17b8a70> |
|
|||
453 |
|
537 | |||
454 | In [33]: for i in range(100): |
|
538 | In [33]: for i in range(100): | |
455 | ....: a = numpy.random.rand(10,10) |
|
539 | ....: a = numpy.random.rand(10,10) | |
@@ -457,22 +541,15 b' on the engines given by the :attr:`targets` attribute:' | |||||
457 | ....: evals = numpy.linalg.eigvals(a) |
|
541 | ....: evals = numpy.linalg.eigvals(a) | |
458 | ....: max_evals.append(evals[0].real) |
|
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 |
|
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 | |||
467 |
|
550 | |||
468 | In [36]: px ans= "Average max eigenvalue is: %f"%(sum(max_evals)/len(max_evals)) |
|
551 | In [35]: %autopx | |
469 | Parallel execution on engines: [0, 1, 2, 3] |
|
552 | Auto Parallel Disabled | |
470 |
|
||||
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',] |
|
|||
476 |
|
553 | |||
477 |
|
554 | |||
478 | Moving Python objects around |
|
555 | Moving Python objects around |
General Comments 0
You need to be logged in to leave comments.
Login now