##// END OF EJS Templates
aesthetics pass on AsyncResult.display_outputs...
MinRK -
Show More
@@ -15,13 +15,15 b' Authors:'
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 from __future__ import print_function
19
18 20 import sys
19 21 import time
20 22 from datetime import datetime
21 23
22 24 from zmq import MessageTracker
23 25
24 from IPython.core.display import clear_output, display
26 from IPython.core.display import clear_output, display, display_pretty
25 27 from IPython.external.decorator import decorator
26 28 from IPython.parallel import error
27 29
@@ -38,6 +40,9 b' def _total_seconds(td):'
38 40 # Python 2.6
39 41 return 1e-6 * (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6)
40 42
43 def _raw_text(s):
44 display_pretty(s, raw=True)
45
41 46 #-----------------------------------------------------------------------------
42 47 # Classes
43 48 #-----------------------------------------------------------------------------
@@ -373,10 +378,10 b' class AsyncResult(object):'
373 378 while not self.ready() and (timeout is None or time.time() - tic <= timeout):
374 379 self.wait(interval)
375 380 clear_output()
376 print "%4i/%i tasks finished after %4i s" % (self.progress, N, self.elapsed),
381 print("%4i/%i tasks finished after %4i s" % (self.progress, N, self.elapsed), end="")
377 382 sys.stdout.flush()
378 print
379 print "done"
383 print()
384 print("done")
380 385
381 386 def _republish_displaypub(self, content, eid):
382 387 """republish individual displaypub content dicts"""
@@ -388,20 +393,31 b' class AsyncResult(object):'
388 393 md = content['metadata'] or {}
389 394 md['engine'] = eid
390 395 ip.display_pub.publish(content['source'], content['data'], md)
396
397 def _display_stream(self, text, prefix='', file=None):
398 if not text:
399 # nothing to display
400 return
401 if file is None:
402 file = sys.stdout
403 end = '' if text.endswith('\n') else '\n'
391 404
405 multiline = text.count('\n') > int(text.endswith('\n'))
406 if prefix and multiline and not text.startswith('\n'):
407 prefix = prefix + '\n'
408 print("%s%s" % (prefix, text), file=file, end=end)
392 409
410
393 411 def _display_single_result(self):
394 if self.stdout:
395 print self.stdout
396 if self.stderr:
397 print >> sys.stderr, self.stderr
412 self._display_stream(self.stdout)
413 self._display_stream(self.stderr, file=sys.stderr)
398 414
399 415 try:
400 416 get_ipython()
401 417 except NameError:
402 418 # displaypub is meaningless outside IPython
403 419 return
404
420
405 421 for output in self.outputs:
406 422 self._republish_displaypub(output, self.engine_id)
407 423
@@ -443,9 +459,9 b' class AsyncResult(object):'
443 459 self._display_single_result()
444 460 return
445 461
446 stdouts = [s.rstrip() for s in self.stdout]
447 stderrs = [s.rstrip() for s in self.stderr]
448 pyouts = [p for p in self.pyout]
462 stdouts = self.stdout
463 stderrs = self.stderr
464 pyouts = self.pyout
449 465 output_lists = self.outputs
450 466 results = self.get()
451 467
@@ -455,10 +471,8 b' class AsyncResult(object):'
455 471 for eid,stdout,stderr,outputs,r,pyout in zip(
456 472 targets, stdouts, stderrs, output_lists, results, pyouts
457 473 ):
458 if stdout:
459 print '[stdout:%i]' % eid, stdout
460 if stderr:
461 print >> sys.stderr, '[stderr:%i]' % eid, stderr
474 self._display_stream(stdout, '[stdout:%i] ' % eid)
475 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
462 476
463 477 try:
464 478 get_ipython()
@@ -466,6 +480,9 b' class AsyncResult(object):'
466 480 # displaypub is meaningless outside IPython
467 481 return
468 482
483 if outputs or pyout is not None:
484 _raw_text('[output:%i]' % eid)
485
469 486 for output in outputs:
470 487 self._republish_displaypub(output, eid)
471 488
@@ -474,14 +491,12 b' class AsyncResult(object):'
474 491
475 492 elif groupby in ('type', 'order'):
476 493 # republish stdout:
477 if any(stdouts):
478 for eid,stdout in zip(targets, stdouts):
479 print '[stdout:%i]' % eid, stdout
494 for eid,stdout in zip(targets, stdouts):
495 self._display_stream(stdout, '[stdout:%i] ' % eid)
480 496
481 497 # republish stderr:
482 if any(stderrs):
483 for eid,stderr in zip(targets, stderrs):
484 print >> sys.stderr, '[stderr:%i]' % eid, stderr
498 for eid,stderr in zip(targets, stderrs):
499 self._display_stream(stderr, '[stderr:%i] ' % eid, file=sys.stderr)
485 500
486 501 try:
487 502 get_ipython()
@@ -496,10 +511,13 b' class AsyncResult(object):'
496 511 for eid in targets:
497 512 outputs = output_dict[eid]
498 513 if len(outputs) >= N:
514 _raw_text('[output:%i]' % eid)
499 515 self._republish_displaypub(outputs[i], eid)
500 516 else:
501 517 # republish displaypub output
502 518 for eid,outputs in zip(targets, output_lists):
519 if outputs:
520 _raw_text('[output:%i]' % eid)
503 521 for output in outputs:
504 522 self._republish_displaypub(output, eid)
505 523
@@ -118,10 +118,14 b' class ExecuteReply(object):'
118 118 out = TermColors.Red
119 119 normal = TermColors.Normal
120 120
121 if '\n' in text_out and not text_out.startswith('\n'):
122 # add newline for multiline reprs
123 text_out = '\n' + text_out
124
121 125 p.text(
122 u'[%i] ' % self.metadata['engine_id'] +
123 out + u'Out[%i]: ' % self.execution_count +
124 normal + text_out
126 out + u'Out[%i:%i]: ' % (
127 self.metadata['engine_id'], self.execution_count
128 ) + normal + text_out
125 129 )
126 130
127 131 def _repr_html_(self):
@@ -212,7 +212,7 b' class AsyncResultTest(ClusterTestCase):'
212 212 with capture_output() as io:
213 213 ar.display_outputs()
214 214 self.assertEquals(io.stderr, '')
215 self.assertTrue('5555' in io.stdout)
215 self.assertEquals('5555\n', io.stdout)
216 216
217 217 ar = v.execute("a=5")
218 218 ar.get(5)
@@ -232,6 +232,7 b' class AsyncResultTest(ClusterTestCase):'
232 232 ar.display_outputs()
233 233 self.assertEquals(io.stderr, '')
234 234 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
235 self.assertFalse('\n\n' in io.stdout, io.stdout)
235 236 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
236 237
237 238 ar = v.execute("a=5")
@@ -252,6 +253,7 b' class AsyncResultTest(ClusterTestCase):'
252 253 ar.display_outputs('engine')
253 254 self.assertEquals(io.stderr, '')
254 255 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
256 self.assertFalse('\n\n' in io.stdout, io.stdout)
255 257 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
256 258
257 259 ar = v.execute("a=5")
@@ -16,6 +16,7 b' Authors:'
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18
19 import re
19 20 import sys
20 21 import time
21 22
@@ -57,9 +58,26 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
57 58 )
58 59 out = io.stdout
59 60 self.assertTrue('[stdout:' in out, out)
61 self.assertFalse('\n\n' in out)
60 62 self.assertTrue(out.rstrip().endswith('10'))
61 63 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
62 64
65 def _check_generated_stderr(self, stderr, n):
66 expected = [
67 r'\[stderr:\d+\]',
68 '^stderr$',
69 '^stderr2$',
70 ] * n
71
72 self.assertFalse('\n\n' in stderr, stderr)
73 lines = stderr.splitlines()
74 self.assertEquals(len(lines), len(expected), stderr)
75 for line,expect in zip(lines, expected):
76 if isinstance(expect, str):
77 expect = [expect]
78 for ex in expect:
79 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
80
63 81 def test_cellpx_block_args(self):
64 82 """%%px --[no]block flags work"""
65 83 ip = get_ipython()
@@ -97,13 +115,16 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
97 115 with capture_output() as io:
98 116 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
99 117
100 lines = io.stdout.strip().splitlines()[1:]
118 self.assertFalse('\n\n' in io.stdout)
119 lines = io.stdout.splitlines()[1:]
101 120 expected = [
102 ('[stdout:', '] stdout'),
121 r'\[stdout:\d+\]',
122 'stdout',
103 123 'stdout2',
104 'IPython.core.display.HTML',
105 'IPython.core.display.Math',
106 ('] Out[', 'IPython.core.display.Math')
124 r'\[output:\d+\]',
125 r'IPython\.core\.display\.HTML',
126 r'IPython\.core\.display\.Math',
127 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
107 128 ] * len(v)
108 129
109 130 self.assertEquals(len(lines), len(expected), io.stdout)
@@ -111,20 +132,9 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
111 132 if isinstance(expect, str):
112 133 expect = [expect]
113 134 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)
135 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
120 136
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))
137 self._check_generated_stderr(io.stderr, len(v))
128 138
129 139
130 140 def test_cellpx_groupby_order(self):
@@ -139,20 +149,24 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
139 149 with capture_output() as io:
140 150 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
141 151
142 lines = io.stdout.strip().splitlines()[1:]
152 self.assertFalse('\n\n' in io.stdout)
153 lines = io.stdout.splitlines()[1:]
143 154 expected = []
144 155 expected.extend([
145 ('[stdout:', '] stdout'),
156 r'\[stdout:\d+\]',
157 'stdout',
146 158 'stdout2',
147 159 ] * len(v))
148 160 expected.extend([
161 r'\[output:\d+\]',
149 162 'IPython.core.display.HTML',
150 163 ] * len(v))
151 164 expected.extend([
165 r'\[output:\d+\]',
152 166 'IPython.core.display.Math',
153 167 ] * len(v))
154 168 expected.extend([
155 ('] Out[', 'IPython.core.display.Math')
169 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
156 170 ] * len(v))
157 171
158 172 self.assertEquals(len(lines), len(expected), io.stdout)
@@ -160,22 +174,11 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
160 174 if isinstance(expect, str):
161 175 expect = [expect]
162 176 for ex in expect:
163 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
177 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
164 178
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))
179 self._check_generated_stderr(io.stderr, len(v))
177 180
178 def test_cellpx_groupby_atype(self):
181 def test_cellpx_groupby_type(self):
179 182 """%%px --group-outputs=type"""
180 183 ip = get_ipython()
181 184 v = self.client[:]
@@ -187,19 +190,22 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
187 190 with capture_output() as io:
188 191 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
189 192
190 lines = io.stdout.strip().splitlines()[1:]
193 self.assertFalse('\n\n' in io.stdout)
194 lines = io.stdout.splitlines()[1:]
191 195
192 196 expected = []
193 197 expected.extend([
194 ('[stdout:', '] stdout'),
198 r'\[stdout:\d+\]',
199 'stdout',
195 200 'stdout2',
196 201 ] * len(v))
197 202 expected.extend([
198 'IPython.core.display.HTML',
199 'IPython.core.display.Math',
203 r'\[output:\d+\]',
204 r'IPython\.core\.display\.HTML',
205 r'IPython\.core\.display\.Math',
200 206 ] * len(v))
201 207 expected.extend([
202 ('] Out[', 'IPython.core.display.Math')
208 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
203 209 ] * len(v))
204 210
205 211 self.assertEquals(len(lines), len(expected), io.stdout)
@@ -207,20 +213,9 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
207 213 if isinstance(expect, str):
208 214 expect = [expect]
209 215 for ex in expect:
210 self.assertTrue(ex in line, "Expected %r in %r" % (ex, line))
216 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
211 217
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))
218 self._check_generated_stderr(io.stderr, len(v))
224 219
225 220
226 221 def test_px_nonblocking(self):
@@ -238,6 +233,8 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
238 233 self.assertTrue(isinstance(ar, AsyncResult))
239 234 self.assertTrue('Async' in io.stdout)
240 235 self.assertFalse('[stdout:' in io.stdout)
236 self.assertFalse('\n\n' in io.stdout)
237
241 238 ar = ip.magic('px 1/0')
242 239 self.assertRaisesRemote(ZeroDivisionError, ar.get)
243 240
@@ -256,12 +253,12 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
256 253 ip.run_cell("b/c")
257 254 ip.magic('autopx')
258 255
259 output = io.stdout.strip()
256 output = io.stdout
260 257
261 258 self.assertTrue(output.startswith('%autopx enabled'), output)
262 self.assertTrue(output.endswith('%autopx disabled'), output)
259 self.assertTrue(output.rstrip().endswith('%autopx disabled'), output)
263 260 self.assertTrue('RemoteError: ZeroDivisionError' in output, output)
264 self.assertTrue('] Out[' in output, output)
261 self.assertTrue('\nOut[' in output, output)
265 262 self.assertTrue(': 24690' in output, output)
266 263 ar = v.get_result(-1)
267 264 self.assertEquals(v['a'], 5)
@@ -283,7 +280,7 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
283 280 ip.run_cell('b*=2')
284 281 ip.magic('autopx')
285 282
286 output = io.stdout.strip()
283 output = io.stdout.rstrip()
287 284
288 285 self.assertTrue(output.startswith('%autopx enabled'))
289 286 self.assertTrue(output.endswith('%autopx disabled'))
@@ -314,7 +311,7 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
314 311 ]:
315 312 with capture_output() as io:
316 313 ip.magic('result ' + idx)
317 output = io.stdout.strip()
314 output = io.stdout
318 315 msg = "expected %s output to include %s, but got: %s" % \
319 316 ('%result '+idx, str(data[name]), output)
320 317 self.assertTrue(str(data[name]) in output, msg)
@@ -336,7 +333,7 b' class TestParallelMagics(ClusterTestCase, ParametricTestCase):'
336 333 with capture_output() as io:
337 334 ip.magic("px plot(rand(100))")
338 335
339 self.assertTrue('] Out[' in io.stdout, io.stdout)
336 self.assertTrue('Out[' in io.stdout, io.stdout)
340 337 self.assertTrue('matplotlib.lines' in io.stdout, io.stdout)
341 338
342 339
@@ -86,6 +86,15 b''
86 86 "outputs": []
87 87 },
88 88 {
89 "cell_type": "code",
90 "collapsed": false,
91 "input": [
92 "%px print >> sys.stderr, \"ERROR\""
93 ],
94 "language": "python",
95 "outputs": []
96 },
97 {
89 98 "cell_type": "markdown",
90 99 "source": [
91 100 "You don't have to wait for results:"
@@ -207,6 +216,7 b''
207 216 "x = linspace(0,pi,1000)",
208 217 "for n in range(id,12, stride):",
209 218 " print n",
219 " plt.figure()",
210 220 " plt.plot(x,sin(n*x))",
211 221 "plt.title(\"Plot %i\" % id)"
212 222 ],
@@ -214,10 +224,85 b''
214 224 "outputs": []
215 225 },
216 226 {
227 "cell_type": "markdown",
228 "source": [
229 "When you specify 'order', then individual display outputs (e.g. plots) will be interleaved:"
230 ]
231 },
232 {
233 "cell_type": "code",
234 "collapsed": false,
235 "input": [
236 "%%px --group-outputs=order",
237 "x = linspace(0,pi,1000)",
238 "for n in range(id,12, stride):",
239 " print n",
240 " plt.figure()",
241 " plt.plot(x,sin(n*x))",
242 "plt.title(\"Plot %i\" % id)"
243 ],
244 "language": "python",
245 "outputs": []
246 },
247 {
248 "cell_type": "heading",
249 "level": 2,
250 "source": [
251 "Single-engine views"
252 ]
253 },
254 {
255 "cell_type": "markdown",
256 "source": [
257 "When a DirectView has a single target, the output is a bit simpler (no prefixes on stdout/err, etc.):"
258 ]
259 },
260 {
261 "cell_type": "code",
262 "collapsed": true,
263 "input": [
264 "def generate_output():",
265 " \"\"\"function for testing output",
266 " ",
267 " publishes two outputs of each type, and returns something",
268 " \"\"\"",
269 " ",
270 " import sys,os",
271 " from IPython.core.display import display, HTML, Math",
272 " ",
273 " print \"stdout\"",
274 " print >> sys.stderr, \"stderr\"",
275 " ",
276 " display(HTML(\"<b>HTML</b>\"))",
277 " ",
278 " print \"stdout2\"",
279 " print >> sys.stderr, \"stderr2\"",
280 " ",
281 " display(Math(r\"\\alpha=\\beta\"))",
282 " ",
283 " return os.getpid()",
284 "",
285 "dv['generate_output'] = generate_output"
286 ],
287 "language": "python",
288 "outputs": []
289 },
290 {
217 291 "cell_type": "code",
218 292 "collapsed": true,
219 293 "input": [
220 ""
294 "e0 = rc[-1]",
295 "e0.block = True",
296 "e0.activate()"
297 ],
298 "language": "python",
299 "outputs": []
300 },
301 {
302 "cell_type": "code",
303 "collapsed": false,
304 "input": [
305 "%px generate_output()"
221 306 ],
222 307 "language": "python",
223 308 "outputs": []
General Comments 0
You need to be logged in to leave comments. Login now