##// END OF EJS Templates
clean up imports
Paul Ivanov -
Show More
@@ -1,96 +1,95 b''
1 1 """Tests for input manipulation machinery."""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Imports
5 5 #-----------------------------------------------------------------------------
6 6 import nose.tools as nt
7 7
8 8 from IPython.core.prefilter import AutocallChecker
9 from IPython.testing import decorators as dec
10 9 from IPython.testing.globalipapp import get_ipython
11 10
12 11 #-----------------------------------------------------------------------------
13 12 # Tests
14 13 #-----------------------------------------------------------------------------
15 14 ip = get_ipython()
16 15
17 16 def test_prefilter():
18 17 """Test user input conversions"""
19 18
20 19 # pairs of (raw, expected correct) input
21 20 pairs = [ ('2+2','2+2'),
22 21 ]
23 22
24 23 for raw, correct in pairs:
25 24 nt.assert_equal(ip.prefilter(raw), correct)
26 25
27 26
28 27 def test_autocall_binops():
29 28 """See https://github.com/ipython/ipython/issues/81"""
30 29 ip.magic('autocall 2')
31 30 f = lambda x: x
32 31 ip.user_ns['f'] = f
33 32 try:
34 33 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
35 34 for t in ['f +1', 'f -1']:
36 35 nt.assert_equal(ip.prefilter(t), t)
37 36
38 37 # Run tests again with a more permissive exclude_regexp, which will
39 38 # allow transformation of binary operations ('f -1' -> 'f(-1)').
40 39 pm = ip.prefilter_manager
41 40 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
42 41 config=pm.config)
43 42 try:
44 43 ac.priority = 1
45 44 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
46 45 pm.sort_checkers()
47 46
48 47 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
49 48 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
50 49 finally:
51 50 pm.unregister_checker(ac)
52 51 finally:
53 52 ip.magic('autocall 0')
54 53 del ip.user_ns['f']
55 54
56 55
57 56 def test_issue_114():
58 57 """Check that multiline string literals don't expand as magic
59 58 see http://github.com/ipython/ipython/issues/114"""
60 59
61 60 template = '"""\n%s\n"""'
62 61 # Store the current value of multi_line_specials and turn it off before
63 62 # running test, since it could be true (case in which the test doesn't make
64 63 # sense, as multiline string literals *will* expand as magic in that case).
65 64 msp = ip.prefilter_manager.multi_line_specials
66 65 ip.prefilter_manager.multi_line_specials = False
67 66 try:
68 67 for mgk in ip.magics_manager.lsmagic()['line']:
69 68 raw = template % mgk
70 69 nt.assert_equal(ip.prefilter(raw), raw)
71 70 finally:
72 71 ip.prefilter_manager.multi_line_specials = msp
73 72
74 73
75 74 def test_prefilter_attribute_errors():
76 75 """Capture exceptions thrown by user objects on attribute access.
77 76
78 77 See http://github.com/ipython/ipython/issues/988."""
79 78
80 79 class X(object):
81 80 def __getattr__(self, k):
82 81 raise ValueError('broken object')
83 82 def __call__(self, x):
84 83 return x
85 84
86 85 # Create a callable broken object
87 86 ip.user_ns['x'] = X()
88 87 ip.magic('autocall 2')
89 88 try:
90 89 # Even if x throws an attribute error when looking at its rewrite
91 90 # attribute, we should not crash. So the test here is simply making
92 91 # the prefilter call and not having an exception.
93 92 ip.prefilter('x 1')
94 93 finally:
95 94 del ip.user_ns['x']
96 95 ip.magic('autocall 0')
@@ -1,59 +1,58 b''
1 1 """Tests for kernel utility functions
2 2
3 3 Authors
4 4 -------
5 5 * MinRK
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2011, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Third-party imports
20 20 import nose.tools as nt
21 21
22 22 # Our own imports
23 from IPython.testing import decorators as dec
24 23 from IPython.kernel.launcher import swallow_argv
25 24
26 25 #-----------------------------------------------------------------------------
27 26 # Classes and functions
28 27 #-----------------------------------------------------------------------------
29 28
30 29 def test_swallow_argv():
31 30 tests = [
32 31 # expected , argv , aliases, flags
33 32 (['-a', '5'], ['-a', '5'], None, None),
34 33 (['5'], ['-a', '5'], None, ['a']),
35 34 ([], ['-a', '5'], ['a'], None),
36 35 ([], ['-a', '5'], ['a'], ['a']),
37 36 ([], ['--foo'], None, ['foo']),
38 37 ([], ['--foo'], ['foobar'], []),
39 38 ([], ['--foo', '5'], ['foo'], []),
40 39 ([], ['--foo=5'], ['foo'], []),
41 40 (['--foo=5'], ['--foo=5'], [], ['foo']),
42 41 (['5'], ['--foo', '5'], [], ['foo']),
43 42 (['bar'], ['--foo', '5', 'bar'], ['foo'], ['foo']),
44 43 (['bar'], ['--foo=5', 'bar'], ['foo'], ['foo']),
45 44 (['5','bar'], ['--foo', '5', 'bar'], None, ['foo']),
46 45 (['bar'], ['--foo', '5', 'bar'], ['foo'], None),
47 46 (['bar'], ['--foo=5', 'bar'], ['foo'], None),
48 47 ]
49 48 for expected, argv, aliases, flags in tests:
50 49 stripped = swallow_argv(argv, aliases=aliases, flags=flags)
51 50 message = '\n'.join(['',
52 51 "argv: %r" % argv,
53 52 "aliases: %r" % aliases,
54 53 "flags : %r" % flags,
55 54 "expected : %r" % expected,
56 55 "returned : %r" % stripped,
57 56 ])
58 57 nt.assert_equal(expected, stripped, message)
59 58
@@ -1,128 +1,127 b''
1 1 """
2 2 Module with tests for Strings
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 import os
17 17
18 from IPython.testing import decorators as dec
19 18 from ...tests.base import TestsBase
20 19 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
21 20 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
22 21 )
23 22
24 23
25 24 #-----------------------------------------------------------------------------
26 25 # Class
27 26 #-----------------------------------------------------------------------------
28 27
29 28 class TestStrings(TestsBase):
30 29
31 30 def test_wrap_text(self):
32 31 """wrap_text test"""
33 32 test_text = """
34 33 Tush! never tell me; I take it much unkindly
35 34 That thou, Iago, who hast had my purse
36 35 As if the strings were thine, shouldst know of this.
37 36 """
38 37 for length in [30,5,1]:
39 38 self._confirm_wrap_text(test_text, length)
40 39
41 40
42 41 def _confirm_wrap_text(self, text, length):
43 42 for line in wrap_text(text, length).split('\n'):
44 43 assert len(line) <= length
45 44
46 45
47 46 def test_html2text(self):
48 47 """html2text test"""
49 48 #TODO: More tests
50 49 self.assertEqual(html2text('<name>joe</name>'), 'joe')
51 50
52 51
53 52 def test_add_anchor(self):
54 53 """add_anchor test"""
55 54 #TODO: More tests
56 55 results = add_anchor('<b>Hello World!</b>')
57 56 assert 'Hello World!' in results
58 57 assert 'id="' in results
59 58 assert 'class="anchor-link"' in results
60 59 assert '<b' in results
61 60 assert '</b>' in results
62 61
63 62
64 63 def test_strip_dollars(self):
65 64 """strip_dollars test"""
66 65 tests = [
67 66 ('', ''),
68 67 ('$$', ''),
69 68 ('$H$', 'H'),
70 69 ('$He', 'He'),
71 70 ('H$el', 'H$el'),
72 71 ('Hell$', 'Hell'),
73 72 ('Hello', 'Hello'),
74 73 ('W$o$rld', 'W$o$rld')]
75 74 for test in tests:
76 75 self._try_strip_dollars(test[0], test[1])
77 76
78 77
79 78 def _try_strip_dollars(self, test, result):
80 79 self.assertEqual(strip_dollars(test), result)
81 80
82 81
83 82 def test_strip_files_prefix(self):
84 83 """strip_files_prefix test"""
85 84 tests = [
86 85 ('', ''),
87 86 ('/files', '/files'),
88 87 ('test="/files"', 'test="/files"'),
89 88 ('My files are in `files/`', 'My files are in `files/`'),
90 89 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>')]
91 90 for test in tests:
92 91 self._try_files_prefix(test[0], test[1])
93 92
94 93
95 94 def _try_files_prefix(self, test, result):
96 95 self.assertEqual(strip_files_prefix(test), result)
97 96
98 97
99 98 def test_comment_lines(self):
100 99 """comment_lines test"""
101 100 for line in comment_lines('hello\nworld\n!').split('\n'):
102 101 assert line.startswith('# ')
103 102 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
104 103 assert line.startswith('beep')
105 104
106 105
107 106 def test_get_lines(self):
108 107 """get_lines test"""
109 108 text = "hello\nworld\n!"
110 109 self.assertEqual(get_lines(text, start=1), "world\n!")
111 110 self.assertEqual(get_lines(text, end=2), "hello\nworld")
112 111 self.assertEqual(get_lines(text, start=2, end=5), "!")
113 112 self.assertEqual(get_lines(text, start=-2), "world\n!")
114 113
115 114
116 115 def test_ipython2python(self):
117 116 """ipython2python test"""
118 117 #TODO: More tests
119 118 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
120 119 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
121 120 ignore_spaces=True, ignore_newlines=True)
122 121
123 122 def test_posix_path(self):
124 123 path_list = ['foo', 'bar']
125 124 expected = '/'.join(path_list)
126 125 native = os.path.join(*path_list)
127 126 filtered = posix_path(native)
128 127 self.assertEqual(filtered, expected)
@@ -1,379 +1,374 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test Parallel magics
3 3
4 4 Authors:
5 5
6 6 * Min RK
7 7 """
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18
19 19 import re
20 import sys
21 20 import time
22 21
23 import zmq
24 from nose import SkipTest
25 22
26 23 from IPython.testing import decorators as dec
27 24 from IPython.utils.io import capture_output
28 25
29 26 from IPython import parallel as pmod
30 from IPython.parallel import error
31 27 from IPython.parallel import AsyncResult
32 from IPython.parallel.util import interactive
33 28
34 29 from IPython.parallel.tests import add_engines
35 30
36 31 from .clienttest import ClusterTestCase, generate_output
37 32
38 33 def setup():
39 34 add_engines(3, total=True)
40 35
41 36 class TestParallelMagics(ClusterTestCase):
42 37
43 38 def test_px_blocking(self):
44 39 ip = get_ipython()
45 40 v = self.client[-1:]
46 41 v.activate()
47 42 v.block=True
48 43
49 44 ip.magic('px a=5')
50 45 self.assertEqual(v['a'], [5])
51 46 ip.magic('px a=10')
52 47 self.assertEqual(v['a'], [10])
53 48 # just 'print a' works ~99% of the time, but this ensures that
54 49 # the stdout message has arrived when the result is finished:
55 50 with capture_output() as io:
56 51 ip.magic(
57 52 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
58 53 )
59 54 self.assertIn('[stdout:', io.stdout)
60 55 self.assertNotIn('\n\n', io.stdout)
61 56 assert io.stdout.rstrip().endswith('10')
62 57 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
63 58
64 59 def _check_generated_stderr(self, stderr, n):
65 60 expected = [
66 61 r'\[stderr:\d+\]',
67 62 '^stderr$',
68 63 '^stderr2$',
69 64 ] * n
70 65
71 66 self.assertNotIn('\n\n', stderr)
72 67 lines = stderr.splitlines()
73 68 self.assertEqual(len(lines), len(expected), stderr)
74 69 for line,expect in zip(lines, expected):
75 70 if isinstance(expect, str):
76 71 expect = [expect]
77 72 for ex in expect:
78 73 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
79 74
80 75 def test_cellpx_block_args(self):
81 76 """%%px --[no]block flags work"""
82 77 ip = get_ipython()
83 78 v = self.client[-1:]
84 79 v.activate()
85 80 v.block=False
86 81
87 82 for block in (True, False):
88 83 v.block = block
89 84 ip.magic("pxconfig --verbose")
90 85 with capture_output(display=False) as io:
91 86 ip.run_cell_magic("px", "", "1")
92 87 if block:
93 88 assert io.stdout.startswith("Parallel"), io.stdout
94 89 else:
95 90 assert io.stdout.startswith("Async"), io.stdout
96 91
97 92 with capture_output(display=False) as io:
98 93 ip.run_cell_magic("px", "--block", "1")
99 94 assert io.stdout.startswith("Parallel"), io.stdout
100 95
101 96 with capture_output(display=False) as io:
102 97 ip.run_cell_magic("px", "--noblock", "1")
103 98 assert io.stdout.startswith("Async"), io.stdout
104 99
105 100 def test_cellpx_groupby_engine(self):
106 101 """%%px --group-outputs=engine"""
107 102 ip = get_ipython()
108 103 v = self.client[:]
109 104 v.block = True
110 105 v.activate()
111 106
112 107 v['generate_output'] = generate_output
113 108
114 109 with capture_output(display=False) as io:
115 110 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
116 111
117 112 self.assertNotIn('\n\n', io.stdout)
118 113 lines = io.stdout.splitlines()
119 114 expected = [
120 115 r'\[stdout:\d+\]',
121 116 'stdout',
122 117 'stdout2',
123 118 r'\[output:\d+\]',
124 119 r'IPython\.core\.display\.HTML',
125 120 r'IPython\.core\.display\.Math',
126 121 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
127 122 ] * len(v)
128 123
129 124 self.assertEqual(len(lines), len(expected), io.stdout)
130 125 for line,expect in zip(lines, expected):
131 126 if isinstance(expect, str):
132 127 expect = [expect]
133 128 for ex in expect:
134 129 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
135 130
136 131 self._check_generated_stderr(io.stderr, len(v))
137 132
138 133
139 134 def test_cellpx_groupby_order(self):
140 135 """%%px --group-outputs=order"""
141 136 ip = get_ipython()
142 137 v = self.client[:]
143 138 v.block = True
144 139 v.activate()
145 140
146 141 v['generate_output'] = generate_output
147 142
148 143 with capture_output(display=False) as io:
149 144 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
150 145
151 146 self.assertNotIn('\n\n', io.stdout)
152 147 lines = io.stdout.splitlines()
153 148 expected = []
154 149 expected.extend([
155 150 r'\[stdout:\d+\]',
156 151 'stdout',
157 152 'stdout2',
158 153 ] * len(v))
159 154 expected.extend([
160 155 r'\[output:\d+\]',
161 156 'IPython.core.display.HTML',
162 157 ] * len(v))
163 158 expected.extend([
164 159 r'\[output:\d+\]',
165 160 'IPython.core.display.Math',
166 161 ] * len(v))
167 162 expected.extend([
168 163 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
169 164 ] * len(v))
170 165
171 166 self.assertEqual(len(lines), len(expected), io.stdout)
172 167 for line,expect in zip(lines, expected):
173 168 if isinstance(expect, str):
174 169 expect = [expect]
175 170 for ex in expect:
176 171 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
177 172
178 173 self._check_generated_stderr(io.stderr, len(v))
179 174
180 175 def test_cellpx_groupby_type(self):
181 176 """%%px --group-outputs=type"""
182 177 ip = get_ipython()
183 178 v = self.client[:]
184 179 v.block = True
185 180 v.activate()
186 181
187 182 v['generate_output'] = generate_output
188 183
189 184 with capture_output(display=False) as io:
190 185 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
191 186
192 187 self.assertNotIn('\n\n', io.stdout)
193 188 lines = io.stdout.splitlines()
194 189
195 190 expected = []
196 191 expected.extend([
197 192 r'\[stdout:\d+\]',
198 193 'stdout',
199 194 'stdout2',
200 195 ] * len(v))
201 196 expected.extend([
202 197 r'\[output:\d+\]',
203 198 r'IPython\.core\.display\.HTML',
204 199 r'IPython\.core\.display\.Math',
205 200 ] * len(v))
206 201 expected.extend([
207 202 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
208 203 ] * len(v))
209 204
210 205 self.assertEqual(len(lines), len(expected), io.stdout)
211 206 for line,expect in zip(lines, expected):
212 207 if isinstance(expect, str):
213 208 expect = [expect]
214 209 for ex in expect:
215 210 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
216 211
217 212 self._check_generated_stderr(io.stderr, len(v))
218 213
219 214
220 215 def test_px_nonblocking(self):
221 216 ip = get_ipython()
222 217 v = self.client[-1:]
223 218 v.activate()
224 219 v.block=False
225 220
226 221 ip.magic('px a=5')
227 222 self.assertEqual(v['a'], [5])
228 223 ip.magic('px a=10')
229 224 self.assertEqual(v['a'], [10])
230 225 ip.magic('pxconfig --verbose')
231 226 with capture_output() as io:
232 227 ar = ip.magic('px print (a)')
233 228 self.assertIsInstance(ar, AsyncResult)
234 229 self.assertIn('Async', io.stdout)
235 230 self.assertNotIn('[stdout:', io.stdout)
236 231 self.assertNotIn('\n\n', io.stdout)
237 232
238 233 ar = ip.magic('px 1/0')
239 234 self.assertRaisesRemote(ZeroDivisionError, ar.get)
240 235
241 236 def test_autopx_blocking(self):
242 237 ip = get_ipython()
243 238 v = self.client[-1]
244 239 v.activate()
245 240 v.block=True
246 241
247 242 with capture_output(display=False) as io:
248 243 ip.magic('autopx')
249 244 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
250 245 ip.run_cell('b*=2')
251 246 ip.run_cell('print (b)')
252 247 ip.run_cell('b')
253 248 ip.run_cell("b/c")
254 249 ip.magic('autopx')
255 250
256 251 output = io.stdout
257 252
258 253 assert output.startswith('%autopx enabled'), output
259 254 assert output.rstrip().endswith('%autopx disabled'), output
260 255 self.assertIn('ZeroDivisionError', output)
261 256 self.assertIn('\nOut[', output)
262 257 self.assertIn(': 24690', output)
263 258 ar = v.get_result(-1)
264 259 self.assertEqual(v['a'], 5)
265 260 self.assertEqual(v['b'], 24690)
266 261 self.assertRaisesRemote(ZeroDivisionError, ar.get)
267 262
268 263 def test_autopx_nonblocking(self):
269 264 ip = get_ipython()
270 265 v = self.client[-1]
271 266 v.activate()
272 267 v.block=False
273 268
274 269 with capture_output() as io:
275 270 ip.magic('autopx')
276 271 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
277 272 ip.run_cell('print (b)')
278 273 ip.run_cell('import time; time.sleep(0.1)')
279 274 ip.run_cell("b/c")
280 275 ip.run_cell('b*=2')
281 276 ip.magic('autopx')
282 277
283 278 output = io.stdout.rstrip()
284 279
285 280 assert output.startswith('%autopx enabled'), output
286 281 assert output.endswith('%autopx disabled'), output
287 282 self.assertNotIn('ZeroDivisionError', output)
288 283 ar = v.get_result(-2)
289 284 self.assertRaisesRemote(ZeroDivisionError, ar.get)
290 285 # prevent TaskAborted on pulls, due to ZeroDivisionError
291 286 time.sleep(0.5)
292 287 self.assertEqual(v['a'], 5)
293 288 # b*=2 will not fire, due to abort
294 289 self.assertEqual(v['b'], 10)
295 290
296 291 def test_result(self):
297 292 ip = get_ipython()
298 293 v = self.client[-1]
299 294 v.activate()
300 295 data = dict(a=111,b=222)
301 296 v.push(data, block=True)
302 297
303 298 for name in ('a', 'b'):
304 299 ip.magic('px ' + name)
305 300 with capture_output(display=False) as io:
306 301 ip.magic('pxresult')
307 302 self.assertIn(str(data[name]), io.stdout)
308 303
309 304 @dec.skipif_not_matplotlib
310 305 def test_px_pylab(self):
311 306 """%pylab works on engines"""
312 307 ip = get_ipython()
313 308 v = self.client[-1]
314 309 v.block = True
315 310 v.activate()
316 311
317 312 with capture_output() as io:
318 313 ip.magic("px %pylab inline")
319 314
320 315 self.assertIn("Populating the interactive namespace from numpy and matplotlib", io.stdout)
321 316
322 317 with capture_output(display=False) as io:
323 318 ip.magic("px plot(rand(100))")
324 319 self.assertIn('Out[', io.stdout)
325 320 self.assertIn('matplotlib.lines', io.stdout)
326 321
327 322 def test_pxconfig(self):
328 323 ip = get_ipython()
329 324 rc = self.client
330 325 v = rc.activate(-1, '_tst')
331 326 self.assertEqual(v.targets, rc.ids[-1])
332 327 ip.magic("%pxconfig_tst -t :")
333 328 self.assertEqual(v.targets, rc.ids)
334 329 ip.magic("%pxconfig_tst -t ::2")
335 330 self.assertEqual(v.targets, rc.ids[::2])
336 331 ip.magic("%pxconfig_tst -t 1::2")
337 332 self.assertEqual(v.targets, rc.ids[1::2])
338 333 ip.magic("%pxconfig_tst -t 1")
339 334 self.assertEqual(v.targets, 1)
340 335 ip.magic("%pxconfig_tst --block")
341 336 self.assertEqual(v.block, True)
342 337 ip.magic("%pxconfig_tst --noblock")
343 338 self.assertEqual(v.block, False)
344 339
345 340 def test_cellpx_targets(self):
346 341 """%%px --targets doesn't change defaults"""
347 342 ip = get_ipython()
348 343 rc = self.client
349 344 view = rc.activate(rc.ids)
350 345 self.assertEqual(view.targets, rc.ids)
351 346 ip.magic('pxconfig --verbose')
352 347 for cell in ("pass", "1/0"):
353 348 with capture_output(display=False) as io:
354 349 try:
355 350 ip.run_cell_magic("px", "--targets all", cell)
356 351 except pmod.RemoteError:
357 352 pass
358 353 self.assertIn('engine(s): all', io.stdout)
359 354 self.assertEqual(view.targets, rc.ids)
360 355
361 356
362 357 def test_cellpx_block(self):
363 358 """%%px --block doesn't change default"""
364 359 ip = get_ipython()
365 360 rc = self.client
366 361 view = rc.activate(rc.ids)
367 362 view.block = False
368 363 self.assertEqual(view.targets, rc.ids)
369 364 ip.magic('pxconfig --verbose')
370 365 for cell in ("pass", "1/0"):
371 366 with capture_output(display=False) as io:
372 367 try:
373 368 ip.run_cell_magic("px", "--block", cell)
374 369 except pmod.RemoteError:
375 370 pass
376 371 self.assertNotIn('Async', io.stdout)
377 372 self.assertEqual(view.block, False)
378 373
379 374
@@ -1,811 +1,808 b''
1 1 # -*- coding: utf-8 -*-
2 2 """test View objects
3 3
4 4 Authors:
5 5
6 6 * Min RK
7 7 """
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18
19 19 import base64
20 20 import sys
21 21 import platform
22 22 import time
23 23 from collections import namedtuple
24 24 from tempfile import mktemp
25 from StringIO import StringIO
26 25
27 26 import zmq
28 from nose import SkipTest
29 27 from nose.plugins.attrib import attr
30 28
31 29 from IPython.testing import decorators as dec
32 30 from IPython.utils.io import capture_output
33 31
34 32 from IPython import parallel as pmod
35 33 from IPython.parallel import error
36 34 from IPython.parallel import AsyncResult, AsyncHubResult, AsyncMapResult
37 from IPython.parallel import DirectView
38 35 from IPython.parallel.util import interactive
39 36
40 37 from IPython.parallel.tests import add_engines
41 38
42 39 from .clienttest import ClusterTestCase, crash, wait, skip_without
43 40
44 41 def setup():
45 42 add_engines(3, total=True)
46 43
47 44 point = namedtuple("point", "x y")
48 45
49 46 class TestView(ClusterTestCase):
50 47
51 48 def setUp(self):
52 49 # On Win XP, wait for resource cleanup, else parallel test group fails
53 50 if platform.system() == "Windows" and platform.win32_ver()[0] == "XP":
54 51 # 1 sec fails. 1.5 sec seems ok. Using 2 sec for margin of safety
55 52 time.sleep(2)
56 53 super(TestView, self).setUp()
57 54
58 55 @attr('crash')
59 56 def test_z_crash_mux(self):
60 57 """test graceful handling of engine death (direct)"""
61 58 # self.add_engines(1)
62 59 eid = self.client.ids[-1]
63 60 ar = self.client[eid].apply_async(crash)
64 61 self.assertRaisesRemote(error.EngineError, ar.get, 10)
65 62 eid = ar.engine_id
66 63 tic = time.time()
67 64 while eid in self.client.ids and time.time()-tic < 5:
68 65 time.sleep(.01)
69 66 self.client.spin()
70 67 self.assertFalse(eid in self.client.ids, "Engine should have died")
71 68
72 69 def test_push_pull(self):
73 70 """test pushing and pulling"""
74 71 data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'})
75 72 t = self.client.ids[-1]
76 73 v = self.client[t]
77 74 push = v.push
78 75 pull = v.pull
79 76 v.block=True
80 77 nengines = len(self.client)
81 78 push({'data':data})
82 79 d = pull('data')
83 80 self.assertEqual(d, data)
84 81 self.client[:].push({'data':data})
85 82 d = self.client[:].pull('data', block=True)
86 83 self.assertEqual(d, nengines*[data])
87 84 ar = push({'data':data}, block=False)
88 85 self.assertTrue(isinstance(ar, AsyncResult))
89 86 r = ar.get()
90 87 ar = self.client[:].pull('data', block=False)
91 88 self.assertTrue(isinstance(ar, AsyncResult))
92 89 r = ar.get()
93 90 self.assertEqual(r, nengines*[data])
94 91 self.client[:].push(dict(a=10,b=20))
95 92 r = self.client[:].pull(('a','b'), block=True)
96 93 self.assertEqual(r, nengines*[[10,20]])
97 94
98 95 def test_push_pull_function(self):
99 96 "test pushing and pulling functions"
100 97 def testf(x):
101 98 return 2.0*x
102 99
103 100 t = self.client.ids[-1]
104 101 v = self.client[t]
105 102 v.block=True
106 103 push = v.push
107 104 pull = v.pull
108 105 execute = v.execute
109 106 push({'testf':testf})
110 107 r = pull('testf')
111 108 self.assertEqual(r(1.0), testf(1.0))
112 109 execute('r = testf(10)')
113 110 r = pull('r')
114 111 self.assertEqual(r, testf(10))
115 112 ar = self.client[:].push({'testf':testf}, block=False)
116 113 ar.get()
117 114 ar = self.client[:].pull('testf', block=False)
118 115 rlist = ar.get()
119 116 for r in rlist:
120 117 self.assertEqual(r(1.0), testf(1.0))
121 118 execute("def g(x): return x*x")
122 119 r = pull(('testf','g'))
123 120 self.assertEqual((r[0](10),r[1](10)), (testf(10), 100))
124 121
125 122 def test_push_function_globals(self):
126 123 """test that pushed functions have access to globals"""
127 124 @interactive
128 125 def geta():
129 126 return a
130 127 # self.add_engines(1)
131 128 v = self.client[-1]
132 129 v.block=True
133 130 v['f'] = geta
134 131 self.assertRaisesRemote(NameError, v.execute, 'b=f()')
135 132 v.execute('a=5')
136 133 v.execute('b=f()')
137 134 self.assertEqual(v['b'], 5)
138 135
139 136 def test_push_function_defaults(self):
140 137 """test that pushed functions preserve default args"""
141 138 def echo(a=10):
142 139 return a
143 140 v = self.client[-1]
144 141 v.block=True
145 142 v['f'] = echo
146 143 v.execute('b=f()')
147 144 self.assertEqual(v['b'], 10)
148 145
149 146 def test_get_result(self):
150 147 """test getting results from the Hub."""
151 148 c = pmod.Client(profile='iptest')
152 149 # self.add_engines(1)
153 150 t = c.ids[-1]
154 151 v = c[t]
155 152 v2 = self.client[t]
156 153 ar = v.apply_async(wait, 1)
157 154 # give the monitor time to notice the message
158 155 time.sleep(.25)
159 156 ahr = v2.get_result(ar.msg_ids[0])
160 157 self.assertTrue(isinstance(ahr, AsyncHubResult))
161 158 self.assertEqual(ahr.get(), ar.get())
162 159 ar2 = v2.get_result(ar.msg_ids[0])
163 160 self.assertFalse(isinstance(ar2, AsyncHubResult))
164 161 c.spin()
165 162 c.close()
166 163
167 164 def test_run_newline(self):
168 165 """test that run appends newline to files"""
169 166 tmpfile = mktemp()
170 167 with open(tmpfile, 'w') as f:
171 168 f.write("""def g():
172 169 return 5
173 170 """)
174 171 v = self.client[-1]
175 172 v.run(tmpfile, block=True)
176 173 self.assertEqual(v.apply_sync(lambda f: f(), pmod.Reference('g')), 5)
177 174
178 175 def test_apply_tracked(self):
179 176 """test tracking for apply"""
180 177 # self.add_engines(1)
181 178 t = self.client.ids[-1]
182 179 v = self.client[t]
183 180 v.block=False
184 181 def echo(n=1024*1024, **kwargs):
185 182 with v.temp_flags(**kwargs):
186 183 return v.apply(lambda x: x, 'x'*n)
187 184 ar = echo(1, track=False)
188 185 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
189 186 self.assertTrue(ar.sent)
190 187 ar = echo(track=True)
191 188 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
192 189 self.assertEqual(ar.sent, ar._tracker.done)
193 190 ar._tracker.wait()
194 191 self.assertTrue(ar.sent)
195 192
196 193 def test_push_tracked(self):
197 194 t = self.client.ids[-1]
198 195 ns = dict(x='x'*1024*1024)
199 196 v = self.client[t]
200 197 ar = v.push(ns, block=False, track=False)
201 198 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
202 199 self.assertTrue(ar.sent)
203 200
204 201 ar = v.push(ns, block=False, track=True)
205 202 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
206 203 ar._tracker.wait()
207 204 self.assertEqual(ar.sent, ar._tracker.done)
208 205 self.assertTrue(ar.sent)
209 206 ar.get()
210 207
211 208 def test_scatter_tracked(self):
212 209 t = self.client.ids
213 210 x='x'*1024*1024
214 211 ar = self.client[t].scatter('x', x, block=False, track=False)
215 212 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
216 213 self.assertTrue(ar.sent)
217 214
218 215 ar = self.client[t].scatter('x', x, block=False, track=True)
219 216 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
220 217 self.assertEqual(ar.sent, ar._tracker.done)
221 218 ar._tracker.wait()
222 219 self.assertTrue(ar.sent)
223 220 ar.get()
224 221
225 222 def test_remote_reference(self):
226 223 v = self.client[-1]
227 224 v['a'] = 123
228 225 ra = pmod.Reference('a')
229 226 b = v.apply_sync(lambda x: x, ra)
230 227 self.assertEqual(b, 123)
231 228
232 229
233 230 def test_scatter_gather(self):
234 231 view = self.client[:]
235 232 seq1 = range(16)
236 233 view.scatter('a', seq1)
237 234 seq2 = view.gather('a', block=True)
238 235 self.assertEqual(seq2, seq1)
239 236 self.assertRaisesRemote(NameError, view.gather, 'asdf', block=True)
240 237
241 238 @skip_without('numpy')
242 239 def test_scatter_gather_numpy(self):
243 240 import numpy
244 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
241 from numpy.testing.utils import assert_array_equal
245 242 view = self.client[:]
246 243 a = numpy.arange(64)
247 244 view.scatter('a', a, block=True)
248 245 b = view.gather('a', block=True)
249 246 assert_array_equal(b, a)
250 247
251 248 def test_scatter_gather_lazy(self):
252 249 """scatter/gather with targets='all'"""
253 250 view = self.client.direct_view(targets='all')
254 251 x = range(64)
255 252 view.scatter('x', x)
256 253 gathered = view.gather('x', block=True)
257 254 self.assertEqual(gathered, x)
258 255
259 256
260 257 @dec.known_failure_py3
261 258 @skip_without('numpy')
262 259 def test_push_numpy_nocopy(self):
263 260 import numpy
264 261 view = self.client[:]
265 262 a = numpy.arange(64)
266 263 view['A'] = a
267 264 @interactive
268 265 def check_writeable(x):
269 266 return x.flags.writeable
270 267
271 268 for flag in view.apply_sync(check_writeable, pmod.Reference('A')):
272 269 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
273 270
274 271 view.push(dict(B=a))
275 272 for flag in view.apply_sync(check_writeable, pmod.Reference('B')):
276 273 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
277 274
278 275 @skip_without('numpy')
279 276 def test_apply_numpy(self):
280 277 """view.apply(f, ndarray)"""
281 278 import numpy
282 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
279 from numpy.testing.utils import assert_array_equal
283 280
284 281 A = numpy.random.random((100,100))
285 282 view = self.client[-1]
286 283 for dt in [ 'int32', 'uint8', 'float32', 'float64' ]:
287 284 B = A.astype(dt)
288 285 C = view.apply_sync(lambda x:x, B)
289 286 assert_array_equal(B,C)
290 287
291 288 @skip_without('numpy')
292 289 def test_push_pull_recarray(self):
293 290 """push/pull recarrays"""
294 291 import numpy
295 292 from numpy.testing.utils import assert_array_equal
296 293
297 294 view = self.client[-1]
298 295
299 296 R = numpy.array([
300 297 (1, 'hi', 0.),
301 298 (2**30, 'there', 2.5),
302 299 (-99999, 'world', -12345.6789),
303 300 ], [('n', int), ('s', '|S10'), ('f', float)])
304 301
305 302 view['RR'] = R
306 303 R2 = view['RR']
307 304
308 305 r_dtype, r_shape = view.apply_sync(interactive(lambda : (RR.dtype, RR.shape)))
309 306 self.assertEqual(r_dtype, R.dtype)
310 307 self.assertEqual(r_shape, R.shape)
311 308 self.assertEqual(R2.dtype, R.dtype)
312 309 self.assertEqual(R2.shape, R.shape)
313 310 assert_array_equal(R2, R)
314 311
315 312 @skip_without('pandas')
316 313 def test_push_pull_timeseries(self):
317 314 """push/pull pandas.TimeSeries"""
318 315 import pandas
319 316
320 317 ts = pandas.TimeSeries(range(10))
321 318
322 319 view = self.client[-1]
323 320
324 321 view.push(dict(ts=ts), block=True)
325 322 rts = view['ts']
326 323
327 324 self.assertEqual(type(rts), type(ts))
328 325 self.assertTrue((ts == rts).all())
329 326
330 327 def test_map(self):
331 328 view = self.client[:]
332 329 def f(x):
333 330 return x**2
334 331 data = range(16)
335 332 r = view.map_sync(f, data)
336 333 self.assertEqual(r, map(f, data))
337 334
338 335 def test_map_iterable(self):
339 336 """test map on iterables (direct)"""
340 337 view = self.client[:]
341 338 # 101 is prime, so it won't be evenly distributed
342 339 arr = range(101)
343 340 # ensure it will be an iterator, even in Python 3
344 341 it = iter(arr)
345 342 r = view.map_sync(lambda x: x, it)
346 343 self.assertEqual(r, list(arr))
347 344
348 345 @skip_without('numpy')
349 346 def test_map_numpy(self):
350 347 """test map on numpy arrays (direct)"""
351 348 import numpy
352 349 from numpy.testing.utils import assert_array_equal
353 350
354 351 view = self.client[:]
355 352 # 101 is prime, so it won't be evenly distributed
356 353 arr = numpy.arange(101)
357 354 r = view.map_sync(lambda x: x, arr)
358 355 assert_array_equal(r, arr)
359 356
360 357 def test_scatter_gather_nonblocking(self):
361 358 data = range(16)
362 359 view = self.client[:]
363 360 view.scatter('a', data, block=False)
364 361 ar = view.gather('a', block=False)
365 362 self.assertEqual(ar.get(), data)
366 363
367 364 @skip_without('numpy')
368 365 def test_scatter_gather_numpy_nonblocking(self):
369 366 import numpy
370 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
367 from numpy.testing.utils import assert_array_equal
371 368 a = numpy.arange(64)
372 369 view = self.client[:]
373 370 ar = view.scatter('a', a, block=False)
374 371 self.assertTrue(isinstance(ar, AsyncResult))
375 372 amr = view.gather('a', block=False)
376 373 self.assertTrue(isinstance(amr, AsyncMapResult))
377 374 assert_array_equal(amr.get(), a)
378 375
379 376 def test_execute(self):
380 377 view = self.client[:]
381 378 # self.client.debug=True
382 379 execute = view.execute
383 380 ar = execute('c=30', block=False)
384 381 self.assertTrue(isinstance(ar, AsyncResult))
385 382 ar = execute('d=[0,1,2]', block=False)
386 383 self.client.wait(ar, 1)
387 384 self.assertEqual(len(ar.get()), len(self.client))
388 385 for c in view['c']:
389 386 self.assertEqual(c, 30)
390 387
391 388 def test_abort(self):
392 389 view = self.client[-1]
393 390 ar = view.execute('import time; time.sleep(1)', block=False)
394 391 ar2 = view.apply_async(lambda : 2)
395 392 ar3 = view.apply_async(lambda : 3)
396 393 view.abort(ar2)
397 394 view.abort(ar3.msg_ids)
398 395 self.assertRaises(error.TaskAborted, ar2.get)
399 396 self.assertRaises(error.TaskAborted, ar3.get)
400 397
401 398 def test_abort_all(self):
402 399 """view.abort() aborts all outstanding tasks"""
403 400 view = self.client[-1]
404 401 ars = [ view.apply_async(time.sleep, 0.25) for i in range(10) ]
405 402 view.abort()
406 403 view.wait(timeout=5)
407 404 for ar in ars[5:]:
408 405 self.assertRaises(error.TaskAborted, ar.get)
409 406
410 407 def test_temp_flags(self):
411 408 view = self.client[-1]
412 409 view.block=True
413 410 with view.temp_flags(block=False):
414 411 self.assertFalse(view.block)
415 412 self.assertTrue(view.block)
416 413
417 414 @dec.known_failure_py3
418 415 def test_importer(self):
419 416 view = self.client[-1]
420 417 view.clear(block=True)
421 418 with view.importer:
422 419 import re
423 420
424 421 @interactive
425 422 def findall(pat, s):
426 423 # this globals() step isn't necessary in real code
427 424 # only to prevent a closure in the test
428 425 re = globals()['re']
429 426 return re.findall(pat, s)
430 427
431 428 self.assertEqual(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
432 429
433 430 def test_unicode_execute(self):
434 431 """test executing unicode strings"""
435 432 v = self.client[-1]
436 433 v.block=True
437 434 if sys.version_info[0] >= 3:
438 435 code="a='é'"
439 436 else:
440 437 code=u"a=u'é'"
441 438 v.execute(code)
442 439 self.assertEqual(v['a'], u'é')
443 440
444 441 def test_unicode_apply_result(self):
445 442 """test unicode apply results"""
446 443 v = self.client[-1]
447 444 r = v.apply_sync(lambda : u'é')
448 445 self.assertEqual(r, u'é')
449 446
450 447 def test_unicode_apply_arg(self):
451 448 """test passing unicode arguments to apply"""
452 449 v = self.client[-1]
453 450
454 451 @interactive
455 452 def check_unicode(a, check):
456 453 assert isinstance(a, unicode), "%r is not unicode"%a
457 454 assert isinstance(check, bytes), "%r is not bytes"%check
458 455 assert a.encode('utf8') == check, "%s != %s"%(a,check)
459 456
460 457 for s in [ u'é', u'ßø®∫',u'asdf' ]:
461 458 try:
462 459 v.apply_sync(check_unicode, s, s.encode('utf8'))
463 460 except error.RemoteError as e:
464 461 if e.ename == 'AssertionError':
465 462 self.fail(e.evalue)
466 463 else:
467 464 raise e
468 465
469 466 def test_map_reference(self):
470 467 """view.map(<Reference>, *seqs) should work"""
471 468 v = self.client[:]
472 469 v.scatter('n', self.client.ids, flatten=True)
473 470 v.execute("f = lambda x,y: x*y")
474 471 rf = pmod.Reference('f')
475 472 nlist = list(range(10))
476 473 mlist = nlist[::-1]
477 474 expected = [ m*n for m,n in zip(mlist, nlist) ]
478 475 result = v.map_sync(rf, mlist, nlist)
479 476 self.assertEqual(result, expected)
480 477
481 478 def test_apply_reference(self):
482 479 """view.apply(<Reference>, *args) should work"""
483 480 v = self.client[:]
484 481 v.scatter('n', self.client.ids, flatten=True)
485 482 v.execute("f = lambda x: n*x")
486 483 rf = pmod.Reference('f')
487 484 result = v.apply_sync(rf, 5)
488 485 expected = [ 5*id for id in self.client.ids ]
489 486 self.assertEqual(result, expected)
490 487
491 488 def test_eval_reference(self):
492 489 v = self.client[self.client.ids[0]]
493 490 v['g'] = range(5)
494 491 rg = pmod.Reference('g[0]')
495 492 echo = lambda x:x
496 493 self.assertEqual(v.apply_sync(echo, rg), 0)
497 494
498 495 def test_reference_nameerror(self):
499 496 v = self.client[self.client.ids[0]]
500 497 r = pmod.Reference('elvis_has_left')
501 498 echo = lambda x:x
502 499 self.assertRaisesRemote(NameError, v.apply_sync, echo, r)
503 500
504 501 def test_single_engine_map(self):
505 502 e0 = self.client[self.client.ids[0]]
506 503 r = range(5)
507 504 check = [ -1*i for i in r ]
508 505 result = e0.map_sync(lambda x: -1*x, r)
509 506 self.assertEqual(result, check)
510 507
511 508 def test_len(self):
512 509 """len(view) makes sense"""
513 510 e0 = self.client[self.client.ids[0]]
514 511 self.assertEqual(len(e0), 1)
515 512 v = self.client[:]
516 513 self.assertEqual(len(v), len(self.client.ids))
517 514 v = self.client.direct_view('all')
518 515 self.assertEqual(len(v), len(self.client.ids))
519 516 v = self.client[:2]
520 517 self.assertEqual(len(v), 2)
521 518 v = self.client[:1]
522 519 self.assertEqual(len(v), 1)
523 520 v = self.client.load_balanced_view()
524 521 self.assertEqual(len(v), len(self.client.ids))
525 522
526 523
527 524 # begin execute tests
528 525
529 526 def test_execute_reply(self):
530 527 e0 = self.client[self.client.ids[0]]
531 528 e0.block = True
532 529 ar = e0.execute("5", silent=False)
533 530 er = ar.get()
534 531 self.assertEqual(str(er), "<ExecuteReply[%i]: 5>" % er.execution_count)
535 532 self.assertEqual(er.pyout['data']['text/plain'], '5')
536 533
537 534 def test_execute_reply_rich(self):
538 535 e0 = self.client[self.client.ids[0]]
539 536 e0.block = True
540 537 e0.execute("from IPython.display import Image, HTML")
541 538 ar = e0.execute("Image(data=b'garbage', format='png', width=10)", silent=False)
542 539 er = ar.get()
543 540 b64data = base64.encodestring(b'garbage').decode('ascii')
544 541 self.assertEqual(er._repr_png_(), (b64data, dict(width=10)))
545 542 ar = e0.execute("HTML('<b>bold</b>')", silent=False)
546 543 er = ar.get()
547 544 self.assertEqual(er._repr_html_(), "<b>bold</b>")
548 545
549 546 def test_execute_reply_stdout(self):
550 547 e0 = self.client[self.client.ids[0]]
551 548 e0.block = True
552 549 ar = e0.execute("print (5)", silent=False)
553 550 er = ar.get()
554 551 self.assertEqual(er.stdout.strip(), '5')
555 552
556 553 def test_execute_pyout(self):
557 554 """execute triggers pyout with silent=False"""
558 555 view = self.client[:]
559 556 ar = view.execute("5", silent=False, block=True)
560 557
561 558 expected = [{'text/plain' : '5'}] * len(view)
562 559 mimes = [ out['data'] for out in ar.pyout ]
563 560 self.assertEqual(mimes, expected)
564 561
565 562 def test_execute_silent(self):
566 563 """execute does not trigger pyout with silent=True"""
567 564 view = self.client[:]
568 565 ar = view.execute("5", block=True)
569 566 expected = [None] * len(view)
570 567 self.assertEqual(ar.pyout, expected)
571 568
572 569 def test_execute_magic(self):
573 570 """execute accepts IPython commands"""
574 571 view = self.client[:]
575 572 view.execute("a = 5")
576 573 ar = view.execute("%whos", block=True)
577 574 # this will raise, if that failed
578 575 ar.get(5)
579 576 for stdout in ar.stdout:
580 577 lines = stdout.splitlines()
581 578 self.assertEqual(lines[0].split(), ['Variable', 'Type', 'Data/Info'])
582 579 found = False
583 580 for line in lines[2:]:
584 581 split = line.split()
585 582 if split == ['a', 'int', '5']:
586 583 found = True
587 584 break
588 585 self.assertTrue(found, "whos output wrong: %s" % stdout)
589 586
590 587 def test_execute_displaypub(self):
591 588 """execute tracks display_pub output"""
592 589 view = self.client[:]
593 590 view.execute("from IPython.core.display import *")
594 591 ar = view.execute("[ display(i) for i in range(5) ]", block=True)
595 592
596 593 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
597 594 for outputs in ar.outputs:
598 595 mimes = [ out['data'] for out in outputs ]
599 596 self.assertEqual(mimes, expected)
600 597
601 598 def test_apply_displaypub(self):
602 599 """apply tracks display_pub output"""
603 600 view = self.client[:]
604 601 view.execute("from IPython.core.display import *")
605 602
606 603 @interactive
607 604 def publish():
608 605 [ display(i) for i in range(5) ]
609 606
610 607 ar = view.apply_async(publish)
611 608 ar.get(5)
612 609 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
613 610 for outputs in ar.outputs:
614 611 mimes = [ out['data'] for out in outputs ]
615 612 self.assertEqual(mimes, expected)
616 613
617 614 def test_execute_raises(self):
618 615 """exceptions in execute requests raise appropriately"""
619 616 view = self.client[-1]
620 617 ar = view.execute("1/0")
621 618 self.assertRaisesRemote(ZeroDivisionError, ar.get, 2)
622 619
623 620 def test_remoteerror_render_exception(self):
624 621 """RemoteErrors get nice tracebacks"""
625 622 view = self.client[-1]
626 623 ar = view.execute("1/0")
627 624 ip = get_ipython()
628 625 ip.user_ns['ar'] = ar
629 626 with capture_output() as io:
630 627 ip.run_cell("ar.get(2)")
631 628
632 629 self.assertTrue('ZeroDivisionError' in io.stdout, io.stdout)
633 630
634 631 def test_compositeerror_render_exception(self):
635 632 """CompositeErrors get nice tracebacks"""
636 633 view = self.client[:]
637 634 ar = view.execute("1/0")
638 635 ip = get_ipython()
639 636 ip.user_ns['ar'] = ar
640 637
641 638 with capture_output() as io:
642 639 ip.run_cell("ar.get(2)")
643 640
644 641 count = min(error.CompositeError.tb_limit, len(view))
645 642
646 643 self.assertEqual(io.stdout.count('ZeroDivisionError'), count * 2, io.stdout)
647 644 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
648 645 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
649 646
650 647 def test_compositeerror_truncate(self):
651 648 """Truncate CompositeErrors with many exceptions"""
652 649 view = self.client[:]
653 650 msg_ids = []
654 651 for i in range(10):
655 652 ar = view.execute("1/0")
656 653 msg_ids.extend(ar.msg_ids)
657 654
658 655 ar = self.client.get_result(msg_ids)
659 656 try:
660 657 ar.get()
661 658 except error.CompositeError as _e:
662 659 e = _e
663 660 else:
664 661 self.fail("Should have raised CompositeError")
665 662
666 663 lines = e.render_traceback()
667 664 with capture_output() as io:
668 665 e.print_traceback()
669 666
670 667 self.assertTrue("more exceptions" in lines[-1])
671 668 count = e.tb_limit
672 669
673 670 self.assertEqual(io.stdout.count('ZeroDivisionError'), 2 * count, io.stdout)
674 671 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
675 672 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
676 673
677 674 @dec.skipif_not_matplotlib
678 675 def test_magic_pylab(self):
679 676 """%pylab works on engines"""
680 677 view = self.client[-1]
681 678 ar = view.execute("%pylab inline")
682 679 # at least check if this raised:
683 680 reply = ar.get(5)
684 681 # include imports, in case user config
685 682 ar = view.execute("plot(rand(100))", silent=False)
686 683 reply = ar.get(5)
687 684 self.assertEqual(len(reply.outputs), 1)
688 685 output = reply.outputs[0]
689 686 self.assertTrue("data" in output)
690 687 data = output['data']
691 688 self.assertTrue("image/png" in data)
692 689
693 690 def test_func_default_func(self):
694 691 """interactively defined function as apply func default"""
695 692 def foo():
696 693 return 'foo'
697 694
698 695 def bar(f=foo):
699 696 return f()
700 697
701 698 view = self.client[-1]
702 699 ar = view.apply_async(bar)
703 700 r = ar.get(10)
704 701 self.assertEqual(r, 'foo')
705 702 def test_data_pub_single(self):
706 703 view = self.client[-1]
707 704 ar = view.execute('\n'.join([
708 705 'from IPython.kernel.zmq.datapub import publish_data',
709 706 'for i in range(5):',
710 707 ' publish_data(dict(i=i))'
711 708 ]), block=False)
712 709 self.assertTrue(isinstance(ar.data, dict))
713 710 ar.get(5)
714 711 self.assertEqual(ar.data, dict(i=4))
715 712
716 713 def test_data_pub(self):
717 714 view = self.client[:]
718 715 ar = view.execute('\n'.join([
719 716 'from IPython.kernel.zmq.datapub import publish_data',
720 717 'for i in range(5):',
721 718 ' publish_data(dict(i=i))'
722 719 ]), block=False)
723 720 self.assertTrue(all(isinstance(d, dict) for d in ar.data))
724 721 ar.get(5)
725 722 self.assertEqual(ar.data, [dict(i=4)] * len(ar))
726 723
727 724 def test_can_list_arg(self):
728 725 """args in lists are canned"""
729 726 view = self.client[-1]
730 727 view['a'] = 128
731 728 rA = pmod.Reference('a')
732 729 ar = view.apply_async(lambda x: x, [rA])
733 730 r = ar.get(5)
734 731 self.assertEqual(r, [128])
735 732
736 733 def test_can_dict_arg(self):
737 734 """args in dicts are canned"""
738 735 view = self.client[-1]
739 736 view['a'] = 128
740 737 rA = pmod.Reference('a')
741 738 ar = view.apply_async(lambda x: x, dict(foo=rA))
742 739 r = ar.get(5)
743 740 self.assertEqual(r, dict(foo=128))
744 741
745 742 def test_can_list_kwarg(self):
746 743 """kwargs in lists are canned"""
747 744 view = self.client[-1]
748 745 view['a'] = 128
749 746 rA = pmod.Reference('a')
750 747 ar = view.apply_async(lambda x=5: x, x=[rA])
751 748 r = ar.get(5)
752 749 self.assertEqual(r, [128])
753 750
754 751 def test_can_dict_kwarg(self):
755 752 """kwargs in dicts are canned"""
756 753 view = self.client[-1]
757 754 view['a'] = 128
758 755 rA = pmod.Reference('a')
759 756 ar = view.apply_async(lambda x=5: x, dict(foo=rA))
760 757 r = ar.get(5)
761 758 self.assertEqual(r, dict(foo=128))
762 759
763 760 def test_map_ref(self):
764 761 """view.map works with references"""
765 762 view = self.client[:]
766 763 ranks = sorted(self.client.ids)
767 764 view.scatter('rank', ranks, flatten=True)
768 765 rrank = pmod.Reference('rank')
769 766
770 767 amr = view.map_async(lambda x: x*2, [rrank] * len(view))
771 768 drank = amr.get(5)
772 769 self.assertEqual(drank, [ r*2 for r in ranks ])
773 770
774 771 def test_nested_getitem_setitem(self):
775 772 """get and set with view['a.b']"""
776 773 view = self.client[-1]
777 774 view.execute('\n'.join([
778 775 'class A(object): pass',
779 776 'a = A()',
780 777 'a.b = 128',
781 778 ]), block=True)
782 779 ra = pmod.Reference('a')
783 780
784 781 r = view.apply_sync(lambda x: x.b, ra)
785 782 self.assertEqual(r, 128)
786 783 self.assertEqual(view['a.b'], 128)
787 784
788 785 view['a.b'] = 0
789 786
790 787 r = view.apply_sync(lambda x: x.b, ra)
791 788 self.assertEqual(r, 0)
792 789 self.assertEqual(view['a.b'], 0)
793 790
794 791 def test_return_namedtuple(self):
795 792 def namedtuplify(x, y):
796 793 from IPython.parallel.tests.test_view import point
797 794 return point(x, y)
798 795
799 796 view = self.client[-1]
800 797 p = view.apply_sync(namedtuplify, 1, 2)
801 798 self.assertEqual(p.x, 1)
802 799 self.assertEqual(p.y, 2)
803 800
804 801 def test_apply_namedtuple(self):
805 802 def echoxy(p):
806 803 return p.y, p.x
807 804
808 805 view = self.client[-1]
809 806 tup = view.apply_sync(echoxy, point(1, 2))
810 807 self.assertEqual(tup, (2,1))
811 808
@@ -1,178 +1,177 b''
1 1 """Experimental code for cleaner support of IPython syntax with unittest.
2 2
3 3 In IPython up until 0.10, we've used very hacked up nose machinery for running
4 4 tests with IPython special syntax, and this has proved to be extremely slow.
5 5 This module provides decorators to try a different approach, stemming from a
6 6 conversation Brian and I (FP) had about this problem Sept/09.
7 7
8 8 The goal is to be able to easily write simple functions that can be seen by
9 9 unittest as tests, and ultimately for these to support doctests with full
10 10 IPython syntax. Nose already offers this based on naming conventions and our
11 11 hackish plugins, but we are seeking to move away from nose dependencies if
12 12 possible.
13 13
14 14 This module follows a different approach, based on decorators.
15 15
16 16 - A decorator called @ipdoctest can mark any function as having a docstring
17 17 that should be viewed as a doctest, but after syntax conversion.
18 18
19 19 Authors
20 20 -------
21 21
22 22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 23 """
24 24
25 25 from __future__ import absolute_import
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Copyright (C) 2009-2011 The IPython Development Team
29 29 #
30 30 # Distributed under the terms of the BSD License. The full license is in
31 31 # the file COPYING, distributed as part of this software.
32 32 #-----------------------------------------------------------------------------
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Imports
36 36 #-----------------------------------------------------------------------------
37 37
38 38 # Stdlib
39 39 import re
40 import sys
41 40 import unittest
42 41 from doctest import DocTestFinder, DocTestRunner, TestResults
43 42
44 43 #-----------------------------------------------------------------------------
45 44 # Classes and functions
46 45 #-----------------------------------------------------------------------------
47 46
48 47 def count_failures(runner):
49 48 """Count number of failures in a doctest runner.
50 49
51 50 Code modeled after the summarize() method in doctest.
52 51 """
53 52 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
54 53
55 54
56 55 class IPython2PythonConverter(object):
57 56 """Convert IPython 'syntax' to valid Python.
58 57
59 58 Eventually this code may grow to be the full IPython syntax conversion
60 59 implementation, but for now it only does prompt convertion."""
61 60
62 61 def __init__(self):
63 62 self.rps1 = re.compile(r'In\ \[\d+\]: ')
64 63 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
65 64 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
66 65 self.pyps1 = '>>> '
67 66 self.pyps2 = '... '
68 67 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
69 68 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
70 69
71 70 def __call__(self, ds):
72 71 """Convert IPython prompts to python ones in a string."""
73 72 from . import globalipapp
74 73
75 74 pyps1 = '>>> '
76 75 pyps2 = '... '
77 76 pyout = ''
78 77
79 78 dnew = ds
80 79 dnew = self.rps1.sub(pyps1, dnew)
81 80 dnew = self.rps2.sub(pyps2, dnew)
82 81 dnew = self.rout.sub(pyout, dnew)
83 82 ip = globalipapp.get_ipython()
84 83
85 84 # Convert input IPython source into valid Python.
86 85 out = []
87 86 newline = out.append
88 87 for line in dnew.splitlines():
89 88
90 89 mps1 = self.rpyps1.match(line)
91 90 if mps1 is not None:
92 91 prompt, text = mps1.groups()
93 92 newline(prompt+ip.prefilter(text, False))
94 93 continue
95 94
96 95 mps2 = self.rpyps2.match(line)
97 96 if mps2 is not None:
98 97 prompt, text = mps2.groups()
99 98 newline(prompt+ip.prefilter(text, True))
100 99 continue
101 100
102 101 newline(line)
103 102 newline('') # ensure a closing newline, needed by doctest
104 103 #print "PYSRC:", '\n'.join(out) # dbg
105 104 return '\n'.join(out)
106 105
107 106 #return dnew
108 107
109 108
110 109 class Doc2UnitTester(object):
111 110 """Class whose instances act as a decorator for docstring testing.
112 111
113 112 In practice we're only likely to need one instance ever, made below (though
114 113 no attempt is made at turning it into a singleton, there is no need for
115 114 that).
116 115 """
117 116 def __init__(self, verbose=False):
118 117 """New decorator.
119 118
120 119 Parameters
121 120 ----------
122 121
123 122 verbose : boolean, optional (False)
124 123 Passed to the doctest finder and runner to control verbosity.
125 124 """
126 125 self.verbose = verbose
127 126 # We can reuse the same finder for all instances
128 127 self.finder = DocTestFinder(verbose=verbose, recurse=False)
129 128
130 129 def __call__(self, func):
131 130 """Use as a decorator: doctest a function's docstring as a unittest.
132 131
133 132 This version runs normal doctests, but the idea is to make it later run
134 133 ipython syntax instead."""
135 134
136 135 # Capture the enclosing instance with a different name, so the new
137 136 # class below can see it without confusion regarding its own 'self'
138 137 # that will point to the test instance at runtime
139 138 d2u = self
140 139
141 140 # Rewrite the function's docstring to have python syntax
142 141 if func.__doc__ is not None:
143 142 func.__doc__ = ip2py(func.__doc__)
144 143
145 144 # Now, create a tester object that is a real unittest instance, so
146 145 # normal unittest machinery (or Nose, or Trial) can find it.
147 146 class Tester(unittest.TestCase):
148 147 def test(self):
149 148 # Make a new runner per function to be tested
150 149 runner = DocTestRunner(verbose=d2u.verbose)
151 150 map(runner.run, d2u.finder.find(func, func.__name__))
152 151 failed = count_failures(runner)
153 152 if failed:
154 153 # Since we only looked at a single function's docstring,
155 154 # failed should contain at most one item. More than that
156 155 # is a case we can't handle and should error out on
157 156 if len(failed) > 1:
158 157 err = "Invalid number of test results:" % failed
159 158 raise ValueError(err)
160 159 # Report a normal failure.
161 160 self.fail('failed doctests: %s' % str(failed[0]))
162 161
163 162 # Rename it so test reports have the original signature.
164 163 Tester.__name__ = func.__name__
165 164 return Tester
166 165
167 166
168 167 def ipdocstring(func):
169 168 """Change the function docstring via ip2py.
170 169 """
171 170 if func.__doc__ is not None:
172 171 func.__doc__ = ip2py(func.__doc__)
173 172 return func
174 173
175 174
176 175 # Make an instance of the classes for public use
177 176 ipdoctest = Doc2UnitTester()
178 177 ip2py = IPython2PythonConverter()
General Comments 0
You need to be logged in to leave comments. Login now