##// END OF EJS Templates
Merge pull request #4165 from takluyver/parametric-begone...
Min RK -
r12407:f8a7c9a5 merge
parent child Browse files
Show More
@@ -1,121 +1,118 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (C) 2010-2011, IPython Development Team.
2 # Copyright (C) 2010-2011, IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 from nose.tools import assert_equal, assert_true
9 from nose.tools import assert_equal
10
10
11 from IPython.external import argparse
11 from IPython.external import argparse
12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
13 magic_arguments, parse_argstring, real_name)
13 magic_arguments, parse_argstring, real_name)
14 from IPython.testing.decorators import parametric
15
14
16
15
17 @magic_arguments()
16 @magic_arguments()
18 @argument('-f', '--foo', help="an argument")
17 @argument('-f', '--foo', help="an argument")
19 def magic_foo1(self, args):
18 def magic_foo1(self, args):
20 """ A docstring.
19 """ A docstring.
21 """
20 """
22 return parse_argstring(magic_foo1, args)
21 return parse_argstring(magic_foo1, args)
23
22
24
23
25 @magic_arguments()
24 @magic_arguments()
26 def magic_foo2(self, args):
25 def magic_foo2(self, args):
27 """ A docstring.
26 """ A docstring.
28 """
27 """
29 return parse_argstring(magic_foo2, args)
28 return parse_argstring(magic_foo2, args)
30
29
31
30
32 @magic_arguments()
31 @magic_arguments()
33 @argument('-f', '--foo', help="an argument")
32 @argument('-f', '--foo', help="an argument")
34 @argument_group('Group')
33 @argument_group('Group')
35 @argument('-b', '--bar', help="a grouped argument")
34 @argument('-b', '--bar', help="a grouped argument")
36 @argument_group('Second Group')
35 @argument_group('Second Group')
37 @argument('-z', '--baz', help="another grouped argument")
36 @argument('-z', '--baz', help="another grouped argument")
38 def magic_foo3(self, args):
37 def magic_foo3(self, args):
39 """ A docstring.
38 """ A docstring.
40 """
39 """
41 return parse_argstring(magic_foo3, args)
40 return parse_argstring(magic_foo3, args)
42
41
43
42
44 @magic_arguments()
43 @magic_arguments()
45 @kwds(argument_default=argparse.SUPPRESS)
44 @kwds(argument_default=argparse.SUPPRESS)
46 @argument('-f', '--foo', help="an argument")
45 @argument('-f', '--foo', help="an argument")
47 def magic_foo4(self, args):
46 def magic_foo4(self, args):
48 """ A docstring.
47 """ A docstring.
49 """
48 """
50 return parse_argstring(magic_foo4, args)
49 return parse_argstring(magic_foo4, args)
51
50
52
51
53 @magic_arguments('frobnicate')
52 @magic_arguments('frobnicate')
54 @argument('-f', '--foo', help="an argument")
53 @argument('-f', '--foo', help="an argument")
55 def magic_foo5(self, args):
54 def magic_foo5(self, args):
56 """ A docstring.
55 """ A docstring.
57 """
56 """
58 return parse_argstring(magic_foo5, args)
57 return parse_argstring(magic_foo5, args)
59
58
60
59
61 @magic_arguments()
60 @magic_arguments()
62 @argument('-f', '--foo', help="an argument")
61 @argument('-f', '--foo', help="an argument")
63 def magic_magic_foo(self, args):
62 def magic_magic_foo(self, args):
64 """ A docstring.
63 """ A docstring.
65 """
64 """
66 return parse_argstring(magic_magic_foo, args)
65 return parse_argstring(magic_magic_foo, args)
67
66
68
67
69 @magic_arguments()
68 @magic_arguments()
70 @argument('-f', '--foo', help="an argument")
69 @argument('-f', '--foo', help="an argument")
71 def foo(self, args):
70 def foo(self, args):
72 """ A docstring.
71 """ A docstring.
73 """
72 """
74 return parse_argstring(foo, args)
73 return parse_argstring(foo, args)
75
74
76
75
77 @parametric
78 def test_magic_arguments():
76 def test_magic_arguments():
79 # Ideally, these would be doctests, but I could not get it to work.
77 assert_equal(magic_foo1.__doc__, '%foo1 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
80 yield assert_equal(magic_foo1.__doc__, '%foo1 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
78 assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
81 yield assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
79 assert_equal(real_name(magic_foo1), 'foo1')
82 yield assert_equal(real_name(magic_foo1), 'foo1')
80 assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
83 yield assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
81 assert hasattr(magic_foo1, 'has_arguments')
84 yield assert_true(hasattr(magic_foo1, 'has_arguments'))
82
85
83 assert_equal(magic_foo2.__doc__, '%foo2\n\n A docstring.\n')
86 yield assert_equal(magic_foo2.__doc__, '%foo2\n\n A docstring.\n')
84 assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
87 yield assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
85 assert_equal(real_name(magic_foo2), 'foo2')
88 yield assert_equal(real_name(magic_foo2), 'foo2')
86 assert_equal(magic_foo2(None, ''), argparse.Namespace())
89 yield assert_equal(magic_foo2(None, ''), argparse.Namespace())
87 assert hasattr(magic_foo2, 'has_arguments')
90 yield assert_true(hasattr(magic_foo2, 'has_arguments'))
88
91
89 assert_equal(magic_foo3.__doc__, '%foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
92 yield assert_equal(magic_foo3.__doc__, '%foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
90 assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
93 yield assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
91 assert_equal(real_name(magic_foo3), 'foo3')
94 yield assert_equal(real_name(magic_foo3), 'foo3')
92 assert_equal(magic_foo3(None, ''),
95 yield assert_equal(magic_foo3(None, ''),
96 argparse.Namespace(bar=None, baz=None, foo=None))
93 argparse.Namespace(bar=None, baz=None, foo=None))
97 yield assert_true(hasattr(magic_foo3, 'has_arguments'))
94 assert hasattr(magic_foo3, 'has_arguments')
98
95
99 yield assert_equal(magic_foo4.__doc__, '%foo4 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
96 assert_equal(magic_foo4.__doc__, '%foo4 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
100 yield assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
97 assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
101 yield assert_equal(real_name(magic_foo4), 'foo4')
98 assert_equal(real_name(magic_foo4), 'foo4')
102 yield assert_equal(magic_foo4(None, ''), argparse.Namespace())
99 assert_equal(magic_foo4(None, ''), argparse.Namespace())
103 yield assert_true(hasattr(magic_foo4, 'has_arguments'))
100 assert hasattr(magic_foo4, 'has_arguments')
104
101
105 yield assert_equal(magic_foo5.__doc__, '%frobnicate [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
102 assert_equal(magic_foo5.__doc__, '%frobnicate [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
106 yield assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
103 assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
107 yield assert_equal(real_name(magic_foo5), 'frobnicate')
104 assert_equal(real_name(magic_foo5), 'frobnicate')
108 yield assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
105 assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
109 yield assert_true(hasattr(magic_foo5, 'has_arguments'))
106 assert hasattr(magic_foo5, 'has_arguments')
110
107
111 yield assert_equal(magic_magic_foo.__doc__, '%magic_foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
108 assert_equal(magic_magic_foo.__doc__, '%magic_foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
112 yield assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
109 assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
113 yield assert_equal(real_name(magic_magic_foo), 'magic_foo')
110 assert_equal(real_name(magic_magic_foo), 'magic_foo')
114 yield assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
111 assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
115 yield assert_true(hasattr(magic_magic_foo, 'has_arguments'))
112 assert hasattr(magic_magic_foo, 'has_arguments')
116
113
117 yield assert_equal(foo.__doc__, '%foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
114 assert_equal(foo.__doc__, '%foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
118 yield assert_equal(getattr(foo, 'argcmd_name', None), None)
115 assert_equal(getattr(foo, 'argcmd_name', None), None)
119 yield assert_equal(real_name(foo), 'foo')
116 assert_equal(real_name(foo), 'foo')
120 yield assert_equal(foo(None, ''), argparse.Namespace(foo=None))
117 assert_equal(foo(None, ''), argparse.Namespace(foo=None))
121 yield assert_true(hasattr(foo, 'has_arguments'))
118 assert hasattr(foo, 'has_arguments')
@@ -1,99 +1,95 b''
1 """Tests for input manipulation machinery."""
1 """Tests for input manipulation machinery."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 import nose.tools as nt
6 import nose.tools as nt
7
7
8 from IPython.core.prefilter import AutocallChecker
8 from IPython.core.prefilter import AutocallChecker
9 from IPython.testing import decorators as dec
10 from IPython.testing.globalipapp import get_ipython
9 from IPython.testing.globalipapp import get_ipython
11
10
12 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
13 # Tests
12 # Tests
14 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
15 ip = get_ipython()
14 ip = get_ipython()
16
15
17 @dec.parametric
18 def test_prefilter():
16 def test_prefilter():
19 """Test user input conversions"""
17 """Test user input conversions"""
20
18
21 # pairs of (raw, expected correct) input
19 # pairs of (raw, expected correct) input
22 pairs = [ ('2+2','2+2'),
20 pairs = [ ('2+2','2+2'),
23 ]
21 ]
24
22
25 for raw, correct in pairs:
23 for raw, correct in pairs:
26 yield nt.assert_equal(ip.prefilter(raw), correct)
24 nt.assert_equal(ip.prefilter(raw), correct)
27
25
28
26
29 @dec.parametric
30 def test_autocall_binops():
27 def test_autocall_binops():
31 """See https://github.com/ipython/ipython/issues/81"""
28 """See https://github.com/ipython/ipython/issues/81"""
32 ip.magic('autocall 2')
29 ip.magic('autocall 2')
33 f = lambda x: x
30 f = lambda x: x
34 ip.user_ns['f'] = f
31 ip.user_ns['f'] = f
35 try:
32 try:
36 yield nt.assert_equal(ip.prefilter('f 1'),'f(1)')
33 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
37 for t in ['f +1', 'f -1']:
34 for t in ['f +1', 'f -1']:
38 yield nt.assert_equal(ip.prefilter(t), t)
35 nt.assert_equal(ip.prefilter(t), t)
39
36
40 # Run tests again with a more permissive exclude_regexp, which will
37 # Run tests again with a more permissive exclude_regexp, which will
41 # allow transformation of binary operations ('f -1' -> 'f(-1)').
38 # allow transformation of binary operations ('f -1' -> 'f(-1)').
42 pm = ip.prefilter_manager
39 pm = ip.prefilter_manager
43 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
40 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
44 config=pm.config)
41 config=pm.config)
45 try:
42 try:
46 ac.priority = 1
43 ac.priority = 1
47 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
44 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
48 pm.sort_checkers()
45 pm.sort_checkers()
49
46
50 yield nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
47 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
51 yield nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
48 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
52 finally:
49 finally:
53 pm.unregister_checker(ac)
50 pm.unregister_checker(ac)
54 finally:
51 finally:
55 ip.magic('autocall 0')
52 ip.magic('autocall 0')
56 del ip.user_ns['f']
53 del ip.user_ns['f']
57
54
58
55
59 @dec.parametric
60 def test_issue_114():
56 def test_issue_114():
61 """Check that multiline string literals don't expand as magic
57 """Check that multiline string literals don't expand as magic
62 see http://github.com/ipython/ipython/issues/114"""
58 see http://github.com/ipython/ipython/issues/114"""
63
59
64 template = '"""\n%s\n"""'
60 template = '"""\n%s\n"""'
65 # Store the current value of multi_line_specials and turn it off before
61 # Store the current value of multi_line_specials and turn it off before
66 # running test, since it could be true (case in which the test doesn't make
62 # running test, since it could be true (case in which the test doesn't make
67 # sense, as multiline string literals *will* expand as magic in that case).
63 # sense, as multiline string literals *will* expand as magic in that case).
68 msp = ip.prefilter_manager.multi_line_specials
64 msp = ip.prefilter_manager.multi_line_specials
69 ip.prefilter_manager.multi_line_specials = False
65 ip.prefilter_manager.multi_line_specials = False
70 try:
66 try:
71 for mgk in ip.magics_manager.lsmagic()['line']:
67 for mgk in ip.magics_manager.lsmagic()['line']:
72 raw = template % mgk
68 raw = template % mgk
73 yield nt.assert_equal(ip.prefilter(raw), raw)
69 nt.assert_equal(ip.prefilter(raw), raw)
74 finally:
70 finally:
75 ip.prefilter_manager.multi_line_specials = msp
71 ip.prefilter_manager.multi_line_specials = msp
76
72
77
73
78 def test_prefilter_attribute_errors():
74 def test_prefilter_attribute_errors():
79 """Capture exceptions thrown by user objects on attribute access.
75 """Capture exceptions thrown by user objects on attribute access.
80
76
81 See http://github.com/ipython/ipython/issues/988."""
77 See http://github.com/ipython/ipython/issues/988."""
82
78
83 class X(object):
79 class X(object):
84 def __getattr__(self, k):
80 def __getattr__(self, k):
85 raise ValueError('broken object')
81 raise ValueError('broken object')
86 def __call__(self, x):
82 def __call__(self, x):
87 return x
83 return x
88
84
89 # Create a callable broken object
85 # Create a callable broken object
90 ip.user_ns['x'] = X()
86 ip.user_ns['x'] = X()
91 ip.magic('autocall 2')
87 ip.magic('autocall 2')
92 try:
88 try:
93 # Even if x throws an attribute error when looking at its rewrite
89 # Even if x throws an attribute error when looking at its rewrite
94 # attribute, we should not crash. So the test here is simply making
90 # attribute, we should not crash. So the test here is simply making
95 # the prefilter call and not having an exception.
91 # the prefilter call and not having an exception.
96 ip.prefilter('x 1')
92 ip.prefilter('x 1')
97 finally:
93 finally:
98 del ip.user_ns['x']
94 del ip.user_ns['x']
99 ip.magic('autocall 0')
95 ip.magic('autocall 0')
@@ -1,140 +1,138 b''
1 """Tests for pylab tools module.
1 """Tests for pylab tools module.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2011, the IPython Development Team.
4 # Copyright (c) 2011, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib imports
16 # Stdlib imports
17
17
18 # Third-party imports
18 # Third-party imports
19 import matplotlib; matplotlib.use('Agg')
19 import matplotlib; matplotlib.use('Agg')
20 import nose.tools as nt
20 import nose.tools as nt
21
21
22 from matplotlib import pyplot as plt
22 from matplotlib import pyplot as plt
23 import numpy as np
23 import numpy as np
24
24
25 # Our own imports
25 # Our own imports
26 from IPython.core.interactiveshell import InteractiveShell
26 from IPython.core.interactiveshell import InteractiveShell
27 from IPython.testing import decorators as dec
28 from .. import pylabtools as pt
27 from .. import pylabtools as pt
29
28
30 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
31 # Globals and constants
30 # Globals and constants
32 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
33
32
34 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
35 # Local utilities
34 # Local utilities
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37
36
38 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
39 # Classes and functions
38 # Classes and functions
40 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
41
40
42 @dec.parametric
43 def test_figure_to_svg():
41 def test_figure_to_svg():
44 # simple empty-figure test
42 # simple empty-figure test
45 fig = plt.figure()
43 fig = plt.figure()
46 yield nt.assert_equal(pt.print_figure(fig, 'svg'), None)
44 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
47
45
48 plt.close('all')
46 plt.close('all')
49
47
50 # simple check for at least svg-looking output
48 # simple check for at least svg-looking output
51 fig = plt.figure()
49 fig = plt.figure()
52 ax = fig.add_subplot(1,1,1)
50 ax = fig.add_subplot(1,1,1)
53 ax.plot([1,2,3])
51 ax.plot([1,2,3])
54 plt.draw()
52 plt.draw()
55 svg = pt.print_figure(fig, 'svg')[:100].lower()
53 svg = pt.print_figure(fig, 'svg')[:100].lower()
56 yield nt.assert_true('doctype svg' in svg)
54 nt.assert_in('doctype svg', svg)
57
55
58
56
59 def test_import_pylab():
57 def test_import_pylab():
60 ip = get_ipython()
58 ip = get_ipython()
61 ns = {}
59 ns = {}
62 pt.import_pylab(ns, import_all=False)
60 pt.import_pylab(ns, import_all=False)
63 nt.assert_true('plt' in ns)
61 nt.assert_true('plt' in ns)
64 nt.assert_equal(ns['np'], np)
62 nt.assert_equal(ns['np'], np)
65
63
66 class TestPylabSwitch(object):
64 class TestPylabSwitch(object):
67 class Shell(InteractiveShell):
65 class Shell(InteractiveShell):
68 def enable_gui(self, gui):
66 def enable_gui(self, gui):
69 pass
67 pass
70
68
71 def setup(self):
69 def setup(self):
72 import matplotlib
70 import matplotlib
73 def act_mpl(backend):
71 def act_mpl(backend):
74 matplotlib.rcParams['backend'] = backend
72 matplotlib.rcParams['backend'] = backend
75
73
76 # Save rcParams since they get modified
74 # Save rcParams since they get modified
77 self._saved_rcParams = matplotlib.rcParams
75 self._saved_rcParams = matplotlib.rcParams
78 matplotlib.rcParams = dict(backend='Qt4Agg')
76 matplotlib.rcParams = dict(backend='Qt4Agg')
79
77
80 # Mock out functions
78 # Mock out functions
81 self._save_am = pt.activate_matplotlib
79 self._save_am = pt.activate_matplotlib
82 pt.activate_matplotlib = act_mpl
80 pt.activate_matplotlib = act_mpl
83 self._save_ip = pt.import_pylab
81 self._save_ip = pt.import_pylab
84 pt.import_pylab = lambda *a,**kw:None
82 pt.import_pylab = lambda *a,**kw:None
85 self._save_cis = pt.configure_inline_support
83 self._save_cis = pt.configure_inline_support
86 pt.configure_inline_support = lambda *a,**kw:None
84 pt.configure_inline_support = lambda *a,**kw:None
87
85
88 def teardown(self):
86 def teardown(self):
89 pt.activate_matplotlib = self._save_am
87 pt.activate_matplotlib = self._save_am
90 pt.import_pylab = self._save_ip
88 pt.import_pylab = self._save_ip
91 pt.configure_inline_support = self._save_cis
89 pt.configure_inline_support = self._save_cis
92 import matplotlib
90 import matplotlib
93 matplotlib.rcParams = self._saved_rcParams
91 matplotlib.rcParams = self._saved_rcParams
94
92
95 def test_qt(self):
93 def test_qt(self):
96 s = self.Shell()
94 s = self.Shell()
97 gui, backend = s.enable_matplotlib(None)
95 gui, backend = s.enable_matplotlib(None)
98 nt.assert_equal(gui, 'qt')
96 nt.assert_equal(gui, 'qt')
99 nt.assert_equal(s.pylab_gui_select, 'qt')
97 nt.assert_equal(s.pylab_gui_select, 'qt')
100
98
101 gui, backend = s.enable_matplotlib('inline')
99 gui, backend = s.enable_matplotlib('inline')
102 nt.assert_equal(gui, 'inline')
100 nt.assert_equal(gui, 'inline')
103 nt.assert_equal(s.pylab_gui_select, 'qt')
101 nt.assert_equal(s.pylab_gui_select, 'qt')
104
102
105 gui, backend = s.enable_matplotlib('qt')
103 gui, backend = s.enable_matplotlib('qt')
106 nt.assert_equal(gui, 'qt')
104 nt.assert_equal(gui, 'qt')
107 nt.assert_equal(s.pylab_gui_select, 'qt')
105 nt.assert_equal(s.pylab_gui_select, 'qt')
108
106
109 gui, backend = s.enable_matplotlib('inline')
107 gui, backend = s.enable_matplotlib('inline')
110 nt.assert_equal(gui, 'inline')
108 nt.assert_equal(gui, 'inline')
111 nt.assert_equal(s.pylab_gui_select, 'qt')
109 nt.assert_equal(s.pylab_gui_select, 'qt')
112
110
113 gui, backend = s.enable_matplotlib()
111 gui, backend = s.enable_matplotlib()
114 nt.assert_equal(gui, 'qt')
112 nt.assert_equal(gui, 'qt')
115 nt.assert_equal(s.pylab_gui_select, 'qt')
113 nt.assert_equal(s.pylab_gui_select, 'qt')
116
114
117 def test_inline(self):
115 def test_inline(self):
118 s = self.Shell()
116 s = self.Shell()
119 gui, backend = s.enable_matplotlib('inline')
117 gui, backend = s.enable_matplotlib('inline')
120 nt.assert_equal(gui, 'inline')
118 nt.assert_equal(gui, 'inline')
121 nt.assert_equal(s.pylab_gui_select, None)
119 nt.assert_equal(s.pylab_gui_select, None)
122
120
123 gui, backend = s.enable_matplotlib('inline')
121 gui, backend = s.enable_matplotlib('inline')
124 nt.assert_equal(gui, 'inline')
122 nt.assert_equal(gui, 'inline')
125 nt.assert_equal(s.pylab_gui_select, None)
123 nt.assert_equal(s.pylab_gui_select, None)
126
124
127 gui, backend = s.enable_matplotlib('qt')
125 gui, backend = s.enable_matplotlib('qt')
128 nt.assert_equal(gui, 'qt')
126 nt.assert_equal(gui, 'qt')
129 nt.assert_equal(s.pylab_gui_select, 'qt')
127 nt.assert_equal(s.pylab_gui_select, 'qt')
130
128
131 def test_qt_gtk(self):
129 def test_qt_gtk(self):
132 s = self.Shell()
130 s = self.Shell()
133 gui, backend = s.enable_matplotlib('qt')
131 gui, backend = s.enable_matplotlib('qt')
134 nt.assert_equal(gui, 'qt')
132 nt.assert_equal(gui, 'qt')
135 nt.assert_equal(s.pylab_gui_select, 'qt')
133 nt.assert_equal(s.pylab_gui_select, 'qt')
136
134
137 gui, backend = s.enable_matplotlib('gtk')
135 gui, backend = s.enable_matplotlib('gtk')
138 nt.assert_equal(gui, 'qt')
136 nt.assert_equal(gui, 'qt')
139 nt.assert_equal(s.pylab_gui_select, 'qt')
137 nt.assert_equal(s.pylab_gui_select, 'qt')
140
138
@@ -1,331 +1,331 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 """Utility function for installing MathJax javascript library into
2 """Utility function for installing MathJax javascript library into
3 the notebook's 'static' directory, for offline use.
3 the notebook's 'static' directory, for offline use.
4
4
5 Authors:
5 Authors:
6
6
7 * Min RK
7 * Min RK
8 * Mark Sienkiewicz
8 * Mark Sienkiewicz
9 * Matthias Bussonnier
9 * Matthias Bussonnier
10
10
11 To download and install MathJax:
11 To download and install MathJax:
12
12
13 From Python:
13 From Python:
14
14
15 >>> from IPython.external.mathjax import install_mathjax
15 >>> from IPython.external.mathjax import install_mathjax
16 >>> install_mathjax()
16 >>> install_mathjax()
17
17
18 From the command line:
18 From the command line:
19
19
20 $ python -m IPython.external.mathjax
20 $ python -m IPython.external.mathjax
21
21
22 To a specific profile:
22 To a specific profile:
23
23
24 $ python -m IPython.external.mathjax --profile=research
24 $ python -m IPython.external.mathjax --profile=research
25
25
26 To install MathJax from a file you have already downloaded:
26 To install MathJax from a file you have already downloaded:
27
27
28 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
28 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
29 $ python -m IPython.external.mathjax mathjax-xxx.zip
29 $ python -m IPython.external.mathjax mathjax-xxx.zip
30
30
31 It will not install MathJax if it is already there. Use -r to
31 It will not install MathJax if it is already there. Use -r to
32 replace the existing copy of MathJax.
32 replace the existing copy of MathJax.
33
33
34 To find the directory where IPython would like MathJax installed:
34 To find the directory where IPython would like MathJax installed:
35
35
36 $ python -m IPython.external.mathjax -d
36 $ python -m IPython.external.mathjax -d
37
37
38 """
38 """
39
39
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Copyright (C) 2008-2011 The IPython Development Team
42 # Copyright (C) 2008-2011 The IPython Development Team
43 #
43 #
44 # Distributed under the terms of the BSD License. The full license is in
44 # Distributed under the terms of the BSD License. The full license is in
45 # the file COPYING, distributed as part of this software.
45 # the file COPYING, distributed as part of this software.
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Imports
50 # Imports
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 import os
53 import os
54 import shutil
54 import shutil
55 import sys
55 import sys
56 import tarfile
56 import tarfile
57 import urllib2
57 import urllib2
58 import zipfile
58 import zipfile
59
59
60
60
61 from IPython.utils.path import locate_profile
61 from IPython.utils.path import locate_profile
62 from IPython.external import argparse
62 from IPython.external import argparse
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 #
64 #
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 # Where mathjax will be installed.
67 # Where mathjax will be installed.
68
68
69 static = os.path.join(locate_profile('default'), 'static')
69 static = os.path.join(locate_profile('default'), 'static')
70 default_dest = os.path.join(static, 'mathjax')
70 default_dest = os.path.join(static, 'mathjax')
71
71
72 ##
72 ##
73
73
74 # Test for access to install mathjax.
74 # Test for access to install mathjax.
75
75
76 def check_perms(dest, replace=False):
76 def check_perms(dest, replace=False):
77 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
77 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
78 components = dest.split(os.path.sep)
78 components = dest.split(os.path.sep)
79 subpaths = [ os.path.sep+os.path.sep.join(components[1:i]) for i in range(1,len(components))]
79 subpaths = [ os.path.sep+os.path.sep.join(components[1:i]) for i in range(1,len(components))]
80
80
81 existing_path = filter(os.path.exists, subpaths)
81 existing_path = filter(os.path.exists, subpaths)
82 last_writable = existing_path[-1]
82 last_writable = existing_path[-1]
83 if not os.access(last_writable, os.W_OK):
83 if not os.access(last_writable, os.W_OK):
84 raise IOError("Need have write access to %s" % parent)
84 raise IOError("Need have write access to %s" % parent)
85 not_existing = [ path for path in subpaths if path not in existing_path]
85 not_existing = [ path for path in subpaths if path not in existing_path]
86 # subfolder we will create, will obviously be writable
86 # subfolder we will create, will obviously be writable
87 # should we still considere checking separately that
87 # should we still considere checking separately that
88 # ipython profiles have been created ?
88 # ipython profiles have been created ?
89 for folder in not_existing:
89 for folder in not_existing:
90 os.mkdir(folder)
90 os.mkdir(folder)
91
91
92 if os.path.exists(dest):
92 if os.path.exists(dest):
93 if replace:
93 if replace:
94 if not os.access(dest, os.W_OK):
94 if not os.access(dest, os.W_OK):
95 raise IOError("Need have write access to %s" % dest)
95 raise IOError("Need have write access to %s" % dest)
96 print "removing previous MathJax install"
96 print "removing previous MathJax install"
97 shutil.rmtree(dest)
97 shutil.rmtree(dest)
98 return True
98 return True
99 else:
99 else:
100 print "offline MathJax apparently already installed"
100 print "offline MathJax apparently already installed"
101 return False
101 return False
102 else :
102 else :
103 return True
103 return True
104
104
105 ##
105 ##
106
106
107 def extract_tar( fd, dest ) :
107 def extract_tar( fd, dest ) :
108 # use 'r|gz' stream mode, because socket file-like objects can't seek:
108 # use 'r|gz' stream mode, because socket file-like objects can't seek:
109 tar = tarfile.open(fileobj=fd, mode='r|gz')
109 tar = tarfile.open(fileobj=fd, mode='r|gz')
110
110
111 # we just happen to know that the first entry in the mathjax
111 # we just happen to know that the first entry in the mathjax
112 # archive is the directory that the remaining members are in.
112 # archive is the directory that the remaining members are in.
113 topdir = tar.firstmember.path
113 topdir = tar.firstmember.path
114
114
115 # extract the archive (contains a single directory) to the static/ directory
115 # extract the archive (contains a single directory) to the static/ directory
116 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
116 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
117 tar.extractall(parent)
117 tar.extractall(parent)
118
118
119 # it will be mathjax-MathJax-<sha>, rename to just mathjax
119 # it will be mathjax-MathJax-<sha>, rename to just mathjax
120 os.rename(os.path.join(parent, topdir), dest)
120 os.rename(os.path.join(parent, topdir), dest)
121
121
122 ##
122 ##
123
123
124 def extract_zip( fd, dest ) :
124 def extract_zip( fd, dest ) :
125 z = zipfile.ZipFile( fd, 'r' )
125 z = zipfile.ZipFile( fd, 'r' )
126
126
127 # we just happen to know that the first entry in the mathjax
127 # we just happen to know that the first entry in the mathjax
128 # archive is the directory that the remaining members are in.
128 # archive is the directory that the remaining members are in.
129 topdir = z.namelist()[0]
129 topdir = z.namelist()[0]
130
130
131 # extract the archive (contains a single directory) to the static/ directory
131 # extract the archive (contains a single directory) to the static/ directory
132 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
132 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
133 z.extractall( parent )
133 z.extractall( parent )
134
134
135 # it will be mathjax-MathJax-<sha>, rename to just mathjax
135 # it will be mathjax-MathJax-<sha>, rename to just mathjax
136 d = os.path.join(parent, topdir)
136 d = os.path.join(parent, topdir)
137 print d
137 print d
138 os.rename(os.path.join(parent, topdir), dest)
138 os.rename(os.path.join(parent, topdir), dest)
139
139
140 ##
140 ##
141
141
142 def install_mathjax(tag='v2.0', dest=default_dest, replace=False, file=None, extractor=extract_tar ):
142 def install_mathjax(tag='v2.0', dest=default_dest, replace=False, file=None, extractor=extract_tar ):
143 """Download and/or install MathJax for offline use.
143 """Download and/or install MathJax for offline use.
144
144
145 This will install mathjax to the 'static' dir in the IPython notebook
145 This will install mathjax to the 'static' dir in the IPython notebook
146 package, so it will fail if the caller does not have write access
146 package, so it will fail if the caller does not have write access
147 to that location.
147 to that location.
148
148
149 MathJax is a ~15MB download, and ~150MB installed.
149 MathJax is a ~15MB download, and ~150MB installed.
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153
153
154 replace : bool [False]
154 replace : bool [False]
155 Whether to remove and replace an existing install.
155 Whether to remove and replace an existing install.
156 dest : str [path to default profile]
156 dest : str [path to default profile]
157 Where to locally install mathjax
157 Where to locally install mathjax
158 tag : str ['v2.0']
158 tag : str ['v2.0']
159 Which tag to download. Default is 'v2.0', the current stable release,
159 Which tag to download. Default is 'v2.0', the current stable release,
160 but alternatives include 'v1.1a' and 'master'.
160 but alternatives include 'v1.1a' and 'master'.
161 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
161 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
162 File handle from which to untar/unzip/... mathjax
162 File handle from which to untar/unzip/... mathjax
163 extractor : function
163 extractor : function
164 Method tu use to untar/unzip/... `file`
164 Method tu use to untar/unzip/... `file`
165 """
165 """
166 if not check_perms(dest, replace) :
166 if not check_perms(dest, replace) :
167 return
167 return
168
168
169 if file is None :
169 if file is None :
170 # download mathjax
170 # download mathjax
171 mathjax_url = "https://github.com/mathjax/MathJax/tarball/%s" % tag
171 mathjax_url = "https://github.com/mathjax/MathJax/tarball/%s" % tag
172 print "Downloading mathjax source from %s" % mathjax_url
172 print "Downloading mathjax source from %s" % mathjax_url
173 response = urllib2.urlopen(mathjax_url)
173 response = urllib2.urlopen(mathjax_url)
174 file = response.fp
174 file = response.fp
175
175
176 print "Extracting to %s" % dest
176 print "Extracting to %s" % dest
177 extractor( file, dest )
177 extractor( file, dest )
178
178
179 ##
179 ##
180
180
181 def test_func( remove, dest) :
181 def test_func( remove, dest) :
182 """See if mathjax appears to be installed correctly"""
182 """See if mathjax appears to be installed correctly"""
183 status = 0
183 status = 0
184 if not os.path.isdir( dest ) :
184 if not os.path.isdir( dest ) :
185 print "%s directory not found" % dest
185 print "%s directory not found" % dest
186 status = 1
186 status = 1
187 if not os.path.exists( dest + "/MathJax.js" ) :
187 if not os.path.exists( dest + "/MathJax.js" ) :
188 print "MathJax.js not present in %s" % dest
188 print "MathJax.js not present in %s" % dest
189 status = 1
189 status = 1
190 print "ok"
190 print "ok"
191 if remove and os.path.exists(dest):
191 if remove and os.path.exists(dest):
192 shutil.rmtree( dest )
192 shutil.rmtree( dest )
193 return status
193 return status
194
194
195 ##
195 ##
196
196
197 def main() :
197 def main() :
198 # This main is just simple enough that it is not worth the
198 # This main is just simple enough that it is not worth the
199 # complexity of argparse
199 # complexity of argparse
200
200
201 # What directory is mathjax in?
201 # What directory is mathjax in?
202 parser = argparse.ArgumentParser(
202 parser = argparse.ArgumentParser(
203 description="""Install mathjax from internet or local archive""",
203 description="""Install mathjax from internet or local archive""",
204 )
204 )
205
205
206 parser.add_argument(
206 parser.add_argument(
207 '-p',
207 '-p',
208 '--profile',
208 '--profile',
209 default='default',
209 default='default',
210 help='profile to install MathJax to (default is default)')
210 help='profile to install MathJax to (default is default)')
211
211
212 parser.add_argument(
212 parser.add_argument(
213 '-i',
213 '-i',
214 '--install-dir',
214 '--install-dir',
215 help='custom installation directory')
215 help='custom installation directory')
216
216
217 parser.add_argument(
217 parser.add_argument(
218 '-d',
218 '-d',
219 '--dest',
219 '--dest',
220 action='store_true',
220 action='store_true',
221 help='print where current mathjax would be installed and exit')
221 help='print where current mathjax would be installed and exit')
222 parser.add_argument(
222 parser.add_argument(
223 '-r',
223 '-r',
224 '--replace',
224 '--replace',
225 action='store_true',
225 action='store_true',
226 help='Whether to replace current mathjax if it already exists')
226 help='Whether to replace current mathjax if it already exists')
227 parser.add_argument(
227 parser.add_argument(
228 '-t',
228 '-t',
229 '--test',
229 '--test',
230 action='store_true')
230 action='store_true')
231 parser.add_argument('tarball',
231 parser.add_argument('tarball',
232 help="the local tar/zip-ball containing mathjax",
232 help="the local tar/zip-ball containing mathjax",
233 nargs='?',
233 nargs='?',
234 metavar='tarball')
234 metavar='tarball')
235
235
236 pargs = parser.parse_args()
236 pargs = parser.parse_args()
237
237
238 if pargs.install_dir:
238 if pargs.install_dir:
239 # Explicit install_dir overrides profile
239 # Explicit install_dir overrides profile
240 dest = pargs.install_dir
240 dest = pargs.install_dir
241 else:
241 else:
242 profile = pargs.profile
242 profile = pargs.profile
243 dest = os.path.join(locate_profile(profile), 'static', 'mathjax')
243 dest = os.path.join(locate_profile(profile), 'static', 'mathjax')
244
244
245 if pargs.dest :
245 if pargs.dest :
246 print dest
246 print dest
247 return
247 return
248
248
249 # remove/replace existing mathjax?
249 # remove/replace existing mathjax?
250 if pargs.replace :
250 if pargs.replace :
251 replace = True
251 replace = True
252 else :
252 else :
253 replace = False
253 replace = False
254
254
255 # undocumented test interface
255 # undocumented test interface
256 if pargs.test :
256 if pargs.test :
257 return test_func( replace, dest)
257 return test_func( replace, dest)
258
258
259 # do it
259 # do it
260 if pargs.tarball :
260 if pargs.tarball :
261 fname = pargs.tarball
261 fname = pargs.tarball
262
262
263 # automatically detect zip/tar - could do something based
263 # automatically detect zip/tar - could do something based
264 # on file content, but really not cost-effective here.
264 # on file content, but really not cost-effective here.
265 if fname.endswith('.zip') :
265 if fname.endswith('.zip') :
266 extractor = extract_zip
266 extractor = extract_zip
267 else :
267 else :
268 extractor = extract_tar
268 extractor = extract_tar
269 # do it
269 # do it
270 install_mathjax(file=open(fname, "r"), replace=replace, extractor=extractor, dest=dest )
270 install_mathjax(file=open(fname, "r"), replace=replace, extractor=extractor, dest=dest )
271 else:
271 else:
272 install_mathjax(replace=replace, dest=dest)
272 install_mathjax(replace=replace, dest=dest)
273
273
274
274
275 if __name__ == '__main__' :
275 if __name__ == '__main__' :
276 sys.exit(main())
276 sys.exit(main())
277
277
278 __all__ = ['install_mathjax', 'main', 'dest']
278 __all__ = ['install_mathjax', 'main', 'default_dest']
279
279
280 """
280 """
281 Test notes:
281 Test notes:
282
282
283 IPython uses IPython.testing.iptest as a custom test controller
283 IPython uses IPython.testing.iptest as a custom test controller
284 (though it is based on nose). It might be possible to fit automatic
284 (though it is based on nose). It might be possible to fit automatic
285 tests of installation into that framework, but it looks awkward to me.
285 tests of installation into that framework, but it looks awkward to me.
286 So, here is a manual procedure for testing this automatic installer.
286 So, here is a manual procedure for testing this automatic installer.
287
287
288 Mark Sienkiewicz, 2012-08-06
288 Mark Sienkiewicz, 2012-08-06
289 first 8 letters of my last name @ stsci.edu
289 first 8 letters of my last name @ stsci.edu
290
290
291 # remove mathjax from the installed ipython instance
291 # remove mathjax from the installed ipython instance
292 # IOError ok if mathjax was never installed yet.
292 # IOError ok if mathjax was never installed yet.
293
293
294 python -m IPython.external.mathjax --test -r
294 python -m IPython.external.mathjax --test -r
295
295
296 # download and install mathjax from command line:
296 # download and install mathjax from command line:
297
297
298 python -m IPython.external.mathjax
298 python -m IPython.external.mathjax
299 python -m IPython.external.mathjax --test -r
299 python -m IPython.external.mathjax --test -r
300
300
301 # download and install from within python
301 # download and install from within python
302
302
303 python -c "from IPython.external.mathjax import install_mathjax; install_mathjax()"
303 python -c "from IPython.external.mathjax import install_mathjax; install_mathjax()"
304 python -m IPython.external.mathjax --test -r
304 python -m IPython.external.mathjax --test -r
305
305
306 # view http://www.mathjax.org/download/ in your browser
306 # view http://www.mathjax.org/download/ in your browser
307 # save-as the link for MathJax-2.0 near the bottom of the page.
307 # save-as the link for MathJax-2.0 near the bottom of the page.
308 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.zip
308 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.zip
309
309
310 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.zip
310 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.zip
311 python -m IPython.external.mathjax --test -r
311 python -m IPython.external.mathjax --test -r
312
312
313 # download https://github.com/mathjax/MathJax/tarball/v2.0 in your browser
313 # download https://github.com/mathjax/MathJax/tarball/v2.0 in your browser
314 # (this is the url used internally by install_mathjax)
314 # (this is the url used internally by install_mathjax)
315 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.tar.gz
315 # The file it offers is mathjax-MathJax-v2.0-20-g07669ac.tar.gz
316
316
317 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
317 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
318
318
319 python -m IPython.external.mathjax --test
319 python -m IPython.external.mathjax --test
320 # note no -r
320 # note no -r
321
321
322 # install it again while it is already there
322 # install it again while it is already there
323
323
324 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
324 python -m IPython.external.mathjax mathjax-MathJax-v2.0-20-g07669ac.tar.gz
325 # says "offline MathJax apparently already installed"
325 # says "offline MathJax apparently already installed"
326
326
327 python -m IPython.external.mathjax ~/mathjax-MathJax-v2.0-20-g07669ac.tar.gz
327 python -m IPython.external.mathjax ~/mathjax-MathJax-v2.0-20-g07669ac.tar.gz
328 python -m IPython.external.mathjax --test
328 python -m IPython.external.mathjax --test
329
329
330
330
331 """
331 """
@@ -1,60 +1,58 b''
1 """Tests for kernel utility functions
1 """Tests for kernel utility functions
2
2
3 Authors
3 Authors
4 -------
4 -------
5 * MinRK
5 * MinRK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2011, the IPython Development Team.
8 # Copyright (c) 2011, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Third-party imports
19 # Third-party imports
20 import nose.tools as nt
20 import nose.tools as nt
21
21
22 # Our own imports
22 # Our own imports
23 from IPython.testing import decorators as dec
24 from IPython.kernel.launcher import swallow_argv
23 from IPython.kernel.launcher import swallow_argv
25
24
26 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
27 # Classes and functions
26 # Classes and functions
28 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
29
28
30 @dec.parametric
31 def test_swallow_argv():
29 def test_swallow_argv():
32 tests = [
30 tests = [
33 # expected , argv , aliases, flags
31 # expected , argv , aliases, flags
34 (['-a', '5'], ['-a', '5'], None, None),
32 (['-a', '5'], ['-a', '5'], None, None),
35 (['5'], ['-a', '5'], None, ['a']),
33 (['5'], ['-a', '5'], None, ['a']),
36 ([], ['-a', '5'], ['a'], None),
34 ([], ['-a', '5'], ['a'], None),
37 ([], ['-a', '5'], ['a'], ['a']),
35 ([], ['-a', '5'], ['a'], ['a']),
38 ([], ['--foo'], None, ['foo']),
36 ([], ['--foo'], None, ['foo']),
39 ([], ['--foo'], ['foobar'], []),
37 ([], ['--foo'], ['foobar'], []),
40 ([], ['--foo', '5'], ['foo'], []),
38 ([], ['--foo', '5'], ['foo'], []),
41 ([], ['--foo=5'], ['foo'], []),
39 ([], ['--foo=5'], ['foo'], []),
42 (['--foo=5'], ['--foo=5'], [], ['foo']),
40 (['--foo=5'], ['--foo=5'], [], ['foo']),
43 (['5'], ['--foo', '5'], [], ['foo']),
41 (['5'], ['--foo', '5'], [], ['foo']),
44 (['bar'], ['--foo', '5', 'bar'], ['foo'], ['foo']),
42 (['bar'], ['--foo', '5', 'bar'], ['foo'], ['foo']),
45 (['bar'], ['--foo=5', 'bar'], ['foo'], ['foo']),
43 (['bar'], ['--foo=5', 'bar'], ['foo'], ['foo']),
46 (['5','bar'], ['--foo', '5', 'bar'], None, ['foo']),
44 (['5','bar'], ['--foo', '5', 'bar'], None, ['foo']),
47 (['bar'], ['--foo', '5', 'bar'], ['foo'], None),
45 (['bar'], ['--foo', '5', 'bar'], ['foo'], None),
48 (['bar'], ['--foo=5', 'bar'], ['foo'], None),
46 (['bar'], ['--foo=5', 'bar'], ['foo'], None),
49 ]
47 ]
50 for expected, argv, aliases, flags in tests:
48 for expected, argv, aliases, flags in tests:
51 stripped = swallow_argv(argv, aliases=aliases, flags=flags)
49 stripped = swallow_argv(argv, aliases=aliases, flags=flags)
52 message = '\n'.join(['',
50 message = '\n'.join(['',
53 "argv: %r" % argv,
51 "argv: %r" % argv,
54 "aliases: %r" % aliases,
52 "aliases: %r" % aliases,
55 "flags : %r" % flags,
53 "flags : %r" % flags,
56 "expected : %r" % expected,
54 "expected : %r" % expected,
57 "returned : %r" % stripped,
55 "returned : %r" % stripped,
58 ])
56 ])
59 yield nt.assert_equal(expected, stripped, message)
57 nt.assert_equal(expected, stripped, message)
60
58
@@ -1,516 +1,484 b''
1 """Test suite for our zeromq-based messaging specification.
1 """Test suite for our zeromq-based messaging specification.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import re
10 import re
11 from subprocess import PIPE
11 from subprocess import PIPE
12 from Queue import Empty
12 from Queue import Empty
13
13
14 import nose.tools as nt
14 import nose.tools as nt
15
15
16 from IPython.kernel import KernelManager
16 from IPython.kernel import KernelManager
17
17
18 from IPython.testing import decorators as dec
19 from IPython.utils.traitlets import (
18 from IPython.utils.traitlets import (
20 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum, Any,
19 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum, Any,
21 )
20 )
22
21
23 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
24 # Global setup and utilities
23 # Global setup and utilities
25 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
26
25
27 STARTUP_TIMEOUT = 60
26 STARTUP_TIMEOUT = 60
28 TIMEOUT = 15
27 TIMEOUT = 15
29
28
30 def setup():
29 def setup():
31 global KM, KC
30 global KM, KC
32 KM = KernelManager()
31 KM = KernelManager()
33 KM.start_kernel(stdout=PIPE, stderr=PIPE)
32 KM.start_kernel(stdout=PIPE, stderr=PIPE)
34 KC = KM.client()
33 KC = KM.client()
35 KC.start_channels()
34 KC.start_channels()
36
35
37 # wait for kernel to be ready
36 # wait for kernel to be ready
38 try:
37 try:
39 msg = KC.iopub_channel.get_msg(block=True, timeout=STARTUP_TIMEOUT)
38 msg = KC.iopub_channel.get_msg(block=True, timeout=STARTUP_TIMEOUT)
40 except Empty:
39 except Empty:
41 pass
40 pass
42 msg_id = KC.kernel_info()
41 msg_id = KC.kernel_info()
43 KC.get_shell_msg(block=True, timeout=STARTUP_TIMEOUT)
42 KC.get_shell_msg(block=True, timeout=STARTUP_TIMEOUT)
44 flush_channels()
43 flush_channels()
45
44
46
45
47 def teardown():
46 def teardown():
48 KC.stop_channels()
47 KC.stop_channels()
49 KM.shutdown_kernel()
48 KM.shutdown_kernel()
50
49
51
50
52 def flush_channels(kc=None):
51 def flush_channels(kc=None):
53 """flush any messages waiting on the queue"""
52 """flush any messages waiting on the queue"""
54 if kc is None:
53 if kc is None:
55 kc = KC
54 kc = KC
56 for channel in (kc.shell_channel, kc.iopub_channel):
55 for channel in (kc.shell_channel, kc.iopub_channel):
57 while True:
56 while True:
58 try:
57 try:
59 msg = channel.get_msg(block=True, timeout=0.1)
58 msg = channel.get_msg(block=True, timeout=0.1)
60 except Empty:
59 except Empty:
61 break
60 break
62 else:
61 else:
63 list(validate_message(msg))
62 validate_message(msg)
64
63
65
64
66 def execute(code='', kc=None, **kwargs):
65 def execute(code='', kc=None, **kwargs):
67 """wrapper for doing common steps for validating an execution request"""
66 """wrapper for doing common steps for validating an execution request"""
68 if kc is None:
67 if kc is None:
69 kc = KC
68 kc = KC
70 msg_id = kc.execute(code=code, **kwargs)
69 msg_id = kc.execute(code=code, **kwargs)
71 reply = kc.get_shell_msg(timeout=TIMEOUT)
70 reply = kc.get_shell_msg(timeout=TIMEOUT)
72 list(validate_message(reply, 'execute_reply', msg_id))
71 validate_message(reply, 'execute_reply', msg_id)
73 busy = kc.get_iopub_msg(timeout=TIMEOUT)
72 busy = kc.get_iopub_msg(timeout=TIMEOUT)
74 list(validate_message(busy, 'status', msg_id))
73 validate_message(busy, 'status', msg_id)
75 nt.assert_equal(busy['content']['execution_state'], 'busy')
74 nt.assert_equal(busy['content']['execution_state'], 'busy')
76
75
77 if not kwargs.get('silent'):
76 if not kwargs.get('silent'):
78 pyin = kc.get_iopub_msg(timeout=TIMEOUT)
77 pyin = kc.get_iopub_msg(timeout=TIMEOUT)
79 list(validate_message(pyin, 'pyin', msg_id))
78 validate_message(pyin, 'pyin', msg_id)
80 nt.assert_equal(pyin['content']['code'], code)
79 nt.assert_equal(pyin['content']['code'], code)
81
80
82 return msg_id, reply['content']
81 return msg_id, reply['content']
83
82
84 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
85 # MSG Spec References
84 # MSG Spec References
86 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
87
86
88
87
89 class Reference(HasTraits):
88 class Reference(HasTraits):
90
89
91 """
90 """
92 Base class for message spec specification testing.
91 Base class for message spec specification testing.
93
92
94 This class is the core of the message specification test. The
93 This class is the core of the message specification test. The
95 idea is that child classes implement trait attributes for each
94 idea is that child classes implement trait attributes for each
96 message keys, so that message keys can be tested against these
95 message keys, so that message keys can be tested against these
97 traits using :meth:`check` method.
96 traits using :meth:`check` method.
98
97
99 """
98 """
100
99
101 def check(self, d):
100 def check(self, d):
102 """validate a dict against our traits"""
101 """validate a dict against our traits"""
103 for key in self.trait_names():
102 for key in self.trait_names():
104 yield nt.assert_true(key in d, "Missing key: %r, should be found in %s" % (key, d))
103 nt.assert_in(key, d)
105 # FIXME: always allow None, probably not a good idea
104 # FIXME: always allow None, probably not a good idea
106 if d[key] is None:
105 if d[key] is None:
107 continue
106 continue
108 try:
107 try:
109 setattr(self, key, d[key])
108 setattr(self, key, d[key])
110 except TraitError as e:
109 except TraitError as e:
111 yield nt.assert_true(False, str(e))
110 nt.assert_true(False, str(e))
112
111
113
112
114 class RMessage(Reference):
113 class RMessage(Reference):
115 msg_id = Unicode()
114 msg_id = Unicode()
116 msg_type = Unicode()
115 msg_type = Unicode()
117 header = Dict()
116 header = Dict()
118 parent_header = Dict()
117 parent_header = Dict()
119 content = Dict()
118 content = Dict()
120
119
121 class RHeader(Reference):
120 class RHeader(Reference):
122 msg_id = Unicode()
121 msg_id = Unicode()
123 msg_type = Unicode()
122 msg_type = Unicode()
124 session = Unicode()
123 session = Unicode()
125 username = Unicode()
124 username = Unicode()
126
125
127 class RContent(Reference):
126 class RContent(Reference):
128 status = Enum((u'ok', u'error'))
127 status = Enum((u'ok', u'error'))
129
128
130
129
131 class ExecuteReply(Reference):
130 class ExecuteReply(Reference):
132 execution_count = Integer()
131 execution_count = Integer()
133 status = Enum((u'ok', u'error'))
132 status = Enum((u'ok', u'error'))
134
133
135 def check(self, d):
134 def check(self, d):
136 for tst in Reference.check(self, d):
135 Reference.check(self, d)
137 yield tst
138 if d['status'] == 'ok':
136 if d['status'] == 'ok':
139 for tst in ExecuteReplyOkay().check(d):
137 ExecuteReplyOkay().check(d)
140 yield tst
141 elif d['status'] == 'error':
138 elif d['status'] == 'error':
142 for tst in ExecuteReplyError().check(d):
139 ExecuteReplyError().check(d)
143 yield tst
144
140
145
141
146 class ExecuteReplyOkay(Reference):
142 class ExecuteReplyOkay(Reference):
147 payload = List(Dict)
143 payload = List(Dict)
148 user_variables = Dict()
144 user_variables = Dict()
149 user_expressions = Dict()
145 user_expressions = Dict()
150
146
151
147
152 class ExecuteReplyError(Reference):
148 class ExecuteReplyError(Reference):
153 ename = Unicode()
149 ename = Unicode()
154 evalue = Unicode()
150 evalue = Unicode()
155 traceback = List(Unicode)
151 traceback = List(Unicode)
156
152
157
153
158 class OInfoReply(Reference):
154 class OInfoReply(Reference):
159 name = Unicode()
155 name = Unicode()
160 found = Bool()
156 found = Bool()
161 ismagic = Bool()
157 ismagic = Bool()
162 isalias = Bool()
158 isalias = Bool()
163 namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
159 namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
164 type_name = Unicode()
160 type_name = Unicode()
165 string_form = Unicode()
161 string_form = Unicode()
166 base_class = Unicode()
162 base_class = Unicode()
167 length = Integer()
163 length = Integer()
168 file = Unicode()
164 file = Unicode()
169 definition = Unicode()
165 definition = Unicode()
170 argspec = Dict()
166 argspec = Dict()
171 init_definition = Unicode()
167 init_definition = Unicode()
172 docstring = Unicode()
168 docstring = Unicode()
173 init_docstring = Unicode()
169 init_docstring = Unicode()
174 class_docstring = Unicode()
170 class_docstring = Unicode()
175 call_def = Unicode()
171 call_def = Unicode()
176 call_docstring = Unicode()
172 call_docstring = Unicode()
177 source = Unicode()
173 source = Unicode()
178
174
179 def check(self, d):
175 def check(self, d):
180 for tst in Reference.check(self, d):
176 Reference.check(self, d)
181 yield tst
182 if d['argspec'] is not None:
177 if d['argspec'] is not None:
183 for tst in ArgSpec().check(d['argspec']):
178 ArgSpec().check(d['argspec'])
184 yield tst
185
179
186
180
187 class ArgSpec(Reference):
181 class ArgSpec(Reference):
188 args = List(Unicode)
182 args = List(Unicode)
189 varargs = Unicode()
183 varargs = Unicode()
190 varkw = Unicode()
184 varkw = Unicode()
191 defaults = List()
185 defaults = List()
192
186
193
187
194 class Status(Reference):
188 class Status(Reference):
195 execution_state = Enum((u'busy', u'idle', u'starting'))
189 execution_state = Enum((u'busy', u'idle', u'starting'))
196
190
197
191
198 class CompleteReply(Reference):
192 class CompleteReply(Reference):
199 matches = List(Unicode)
193 matches = List(Unicode)
200
194
201
195
202 def Version(num, trait=Integer):
196 def Version(num, trait=Integer):
203 return List(trait, default_value=[0] * num, minlen=num, maxlen=num)
197 return List(trait, default_value=[0] * num, minlen=num, maxlen=num)
204
198
205
199
206 class KernelInfoReply(Reference):
200 class KernelInfoReply(Reference):
207
201
208 protocol_version = Version(2)
202 protocol_version = Version(2)
209 ipython_version = Version(4, Any)
203 ipython_version = Version(4, Any)
210 language_version = Version(3)
204 language_version = Version(3)
211 language = Unicode()
205 language = Unicode()
212
206
213 def _ipython_version_changed(self, name, old, new):
207 def _ipython_version_changed(self, name, old, new):
214 for v in new:
208 for v in new:
215 nt.assert_true(
209 assert isinstance(v, int) or isinstance(v, basestring), \
216 isinstance(v, int) or isinstance(v, basestring),
210 'expected int or string as version component, got {0!r}'.format(v)
217 'expected int or string as version component, got {0!r}'
218 .format(v))
219
211
220
212
221 # IOPub messages
213 # IOPub messages
222
214
223 class PyIn(Reference):
215 class PyIn(Reference):
224 code = Unicode()
216 code = Unicode()
225 execution_count = Integer()
217 execution_count = Integer()
226
218
227
219
228 PyErr = ExecuteReplyError
220 PyErr = ExecuteReplyError
229
221
230
222
231 class Stream(Reference):
223 class Stream(Reference):
232 name = Enum((u'stdout', u'stderr'))
224 name = Enum((u'stdout', u'stderr'))
233 data = Unicode()
225 data = Unicode()
234
226
235
227
236 mime_pat = re.compile(r'\w+/\w+')
228 mime_pat = re.compile(r'\w+/\w+')
237
229
238 class DisplayData(Reference):
230 class DisplayData(Reference):
239 source = Unicode()
231 source = Unicode()
240 metadata = Dict()
232 metadata = Dict()
241 data = Dict()
233 data = Dict()
242 def _data_changed(self, name, old, new):
234 def _data_changed(self, name, old, new):
243 for k,v in new.iteritems():
235 for k,v in new.iteritems():
244 nt.assert_true(mime_pat.match(k))
236 assert mime_pat.match(k)
245 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
237 nt.assert_is_instance(v, basestring)
246
238
247
239
248 class PyOut(Reference):
240 class PyOut(Reference):
249 execution_count = Integer()
241 execution_count = Integer()
250 data = Dict()
242 data = Dict()
251 def _data_changed(self, name, old, new):
243 def _data_changed(self, name, old, new):
252 for k,v in new.iteritems():
244 for k,v in new.iteritems():
253 nt.assert_true(mime_pat.match(k))
245 assert mime_pat.match(k)
254 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
246 nt.assert_is_instance(v, basestring)
255
247
256
248
257 references = {
249 references = {
258 'execute_reply' : ExecuteReply(),
250 'execute_reply' : ExecuteReply(),
259 'object_info_reply' : OInfoReply(),
251 'object_info_reply' : OInfoReply(),
260 'status' : Status(),
252 'status' : Status(),
261 'complete_reply' : CompleteReply(),
253 'complete_reply' : CompleteReply(),
262 'kernel_info_reply': KernelInfoReply(),
254 'kernel_info_reply': KernelInfoReply(),
263 'pyin' : PyIn(),
255 'pyin' : PyIn(),
264 'pyout' : PyOut(),
256 'pyout' : PyOut(),
265 'pyerr' : PyErr(),
257 'pyerr' : PyErr(),
266 'stream' : Stream(),
258 'stream' : Stream(),
267 'display_data' : DisplayData(),
259 'display_data' : DisplayData(),
268 }
260 }
269 """
261 """
270 Specifications of `content` part of the reply messages.
262 Specifications of `content` part of the reply messages.
271 """
263 """
272
264
273
265
274 def validate_message(msg, msg_type=None, parent=None):
266 def validate_message(msg, msg_type=None, parent=None):
275 """validate a message
267 """validate a message
276
268
277 This is a generator, and must be iterated through to actually
269 This is a generator, and must be iterated through to actually
278 trigger each test.
270 trigger each test.
279
271
280 If msg_type and/or parent are given, the msg_type and/or parent msg_id
272 If msg_type and/or parent are given, the msg_type and/or parent msg_id
281 are compared with the given values.
273 are compared with the given values.
282 """
274 """
283 RMessage().check(msg)
275 RMessage().check(msg)
284 if msg_type:
276 if msg_type:
285 yield nt.assert_equal(msg['msg_type'], msg_type)
277 nt.assert_equal(msg['msg_type'], msg_type)
286 if parent:
278 if parent:
287 yield nt.assert_equal(msg['parent_header']['msg_id'], parent)
279 nt.assert_equal(msg['parent_header']['msg_id'], parent)
288 content = msg['content']
280 content = msg['content']
289 ref = references[msg['msg_type']]
281 ref = references[msg['msg_type']]
290 for tst in ref.check(content):
282 ref.check(content)
291 yield tst
292
283
293
284
294 #-----------------------------------------------------------------------------
285 #-----------------------------------------------------------------------------
295 # Tests
286 # Tests
296 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
297
288
298 # Shell channel
289 # Shell channel
299
290
300 @dec.parametric
301 def test_execute():
291 def test_execute():
302 flush_channels()
292 flush_channels()
303
293
304 msg_id = KC.execute(code='x=1')
294 msg_id = KC.execute(code='x=1')
305 reply = KC.get_shell_msg(timeout=TIMEOUT)
295 reply = KC.get_shell_msg(timeout=TIMEOUT)
306 for tst in validate_message(reply, 'execute_reply', msg_id):
296 validate_message(reply, 'execute_reply', msg_id)
307 yield tst
308
297
309
298
310 @dec.parametric
311 def test_execute_silent():
299 def test_execute_silent():
312 flush_channels()
300 flush_channels()
313 msg_id, reply = execute(code='x=1', silent=True)
301 msg_id, reply = execute(code='x=1', silent=True)
314
302
315 # flush status=idle
303 # flush status=idle
316 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
304 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
317 for tst in validate_message(status, 'status', msg_id):
305 validate_message(status, 'status', msg_id)
318 yield tst
319 nt.assert_equal(status['content']['execution_state'], 'idle')
306 nt.assert_equal(status['content']['execution_state'], 'idle')
320
307
321 yield nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
308 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
322 count = reply['execution_count']
309 count = reply['execution_count']
323
310
324 msg_id, reply = execute(code='x=2', silent=True)
311 msg_id, reply = execute(code='x=2', silent=True)
325
312
326 # flush status=idle
313 # flush status=idle
327 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
314 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
328 for tst in validate_message(status, 'status', msg_id):
315 validate_message(status, 'status', msg_id)
329 yield tst
316 nt.assert_equal(status['content']['execution_state'], 'idle')
330 yield nt.assert_equal(status['content']['execution_state'], 'idle')
331
317
332 yield nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
318 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
333 count_2 = reply['execution_count']
319 count_2 = reply['execution_count']
334 yield nt.assert_equal(count_2, count)
320 nt.assert_equal(count_2, count)
335
321
336
322
337 @dec.parametric
338 def test_execute_error():
323 def test_execute_error():
339 flush_channels()
324 flush_channels()
340
325
341 msg_id, reply = execute(code='1/0')
326 msg_id, reply = execute(code='1/0')
342 yield nt.assert_equal(reply['status'], 'error')
327 nt.assert_equal(reply['status'], 'error')
343 yield nt.assert_equal(reply['ename'], 'ZeroDivisionError')
328 nt.assert_equal(reply['ename'], 'ZeroDivisionError')
344
329
345 pyerr = KC.iopub_channel.get_msg(timeout=TIMEOUT)
330 pyerr = KC.iopub_channel.get_msg(timeout=TIMEOUT)
346 for tst in validate_message(pyerr, 'pyerr', msg_id):
331 validate_message(pyerr, 'pyerr', msg_id)
347 yield tst
348
332
349
333
350 def test_execute_inc():
334 def test_execute_inc():
351 """execute request should increment execution_count"""
335 """execute request should increment execution_count"""
352 flush_channels()
336 flush_channels()
353
337
354 msg_id, reply = execute(code='x=1')
338 msg_id, reply = execute(code='x=1')
355 count = reply['execution_count']
339 count = reply['execution_count']
356
340
357 flush_channels()
341 flush_channels()
358
342
359 msg_id, reply = execute(code='x=2')
343 msg_id, reply = execute(code='x=2')
360 count_2 = reply['execution_count']
344 count_2 = reply['execution_count']
361 nt.assert_equal(count_2, count+1)
345 nt.assert_equal(count_2, count+1)
362
346
363
347
364 def test_user_variables():
348 def test_user_variables():
365 flush_channels()
349 flush_channels()
366
350
367 msg_id, reply = execute(code='x=1', user_variables=['x'])
351 msg_id, reply = execute(code='x=1', user_variables=['x'])
368 user_variables = reply['user_variables']
352 user_variables = reply['user_variables']
369 nt.assert_equal(user_variables, {u'x': {
353 nt.assert_equal(user_variables, {u'x': {
370 u'status': u'ok',
354 u'status': u'ok',
371 u'data': {u'text/plain': u'1'},
355 u'data': {u'text/plain': u'1'},
372 u'metadata': {},
356 u'metadata': {},
373 }})
357 }})
374
358
375
359
376 def test_user_variables_fail():
360 def test_user_variables_fail():
377 flush_channels()
361 flush_channels()
378
362
379 msg_id, reply = execute(code='x=1', user_variables=['nosuchname'])
363 msg_id, reply = execute(code='x=1', user_variables=['nosuchname'])
380 user_variables = reply['user_variables']
364 user_variables = reply['user_variables']
381 foo = user_variables['nosuchname']
365 foo = user_variables['nosuchname']
382 nt.assert_equal(foo['status'], 'error')
366 nt.assert_equal(foo['status'], 'error')
383 nt.assert_equal(foo['ename'], 'KeyError')
367 nt.assert_equal(foo['ename'], 'KeyError')
384
368
385
369
386 def test_user_expressions():
370 def test_user_expressions():
387 flush_channels()
371 flush_channels()
388
372
389 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
373 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
390 user_expressions = reply['user_expressions']
374 user_expressions = reply['user_expressions']
391 nt.assert_equal(user_expressions, {u'foo': {
375 nt.assert_equal(user_expressions, {u'foo': {
392 u'status': u'ok',
376 u'status': u'ok',
393 u'data': {u'text/plain': u'2'},
377 u'data': {u'text/plain': u'2'},
394 u'metadata': {},
378 u'metadata': {},
395 }})
379 }})
396
380
397
381
398 def test_user_expressions_fail():
382 def test_user_expressions_fail():
399 flush_channels()
383 flush_channels()
400
384
401 msg_id, reply = execute(code='x=0', user_expressions=dict(foo='nosuchname'))
385 msg_id, reply = execute(code='x=0', user_expressions=dict(foo='nosuchname'))
402 user_expressions = reply['user_expressions']
386 user_expressions = reply['user_expressions']
403 foo = user_expressions['foo']
387 foo = user_expressions['foo']
404 nt.assert_equal(foo['status'], 'error')
388 nt.assert_equal(foo['status'], 'error')
405 nt.assert_equal(foo['ename'], 'NameError')
389 nt.assert_equal(foo['ename'], 'NameError')
406
390
407
391
408 @dec.parametric
409 def test_oinfo():
392 def test_oinfo():
410 flush_channels()
393 flush_channels()
411
394
412 msg_id = KC.object_info('a')
395 msg_id = KC.object_info('a')
413 reply = KC.get_shell_msg(timeout=TIMEOUT)
396 reply = KC.get_shell_msg(timeout=TIMEOUT)
414 for tst in validate_message(reply, 'object_info_reply', msg_id):
397 validate_message(reply, 'object_info_reply', msg_id)
415 yield tst
416
398
417
399
418 @dec.parametric
419 def test_oinfo_found():
400 def test_oinfo_found():
420 flush_channels()
401 flush_channels()
421
402
422 msg_id, reply = execute(code='a=5')
403 msg_id, reply = execute(code='a=5')
423
404
424 msg_id = KC.object_info('a')
405 msg_id = KC.object_info('a')
425 reply = KC.get_shell_msg(timeout=TIMEOUT)
406 reply = KC.get_shell_msg(timeout=TIMEOUT)
426 for tst in validate_message(reply, 'object_info_reply', msg_id):
407 validate_message(reply, 'object_info_reply', msg_id)
427 yield tst
428 content = reply['content']
408 content = reply['content']
429 yield nt.assert_true(content['found'])
409 assert content['found']
430 argspec = content['argspec']
410 argspec = content['argspec']
431 yield nt.assert_true(argspec is None, "didn't expect argspec dict, got %r" % argspec)
411 nt.assert_is(argspec, None)
432
412
433
413
434 @dec.parametric
435 def test_oinfo_detail():
414 def test_oinfo_detail():
436 flush_channels()
415 flush_channels()
437
416
438 msg_id, reply = execute(code='ip=get_ipython()')
417 msg_id, reply = execute(code='ip=get_ipython()')
439
418
440 msg_id = KC.object_info('ip.object_inspect', detail_level=2)
419 msg_id = KC.object_info('ip.object_inspect', detail_level=2)
441 reply = KC.get_shell_msg(timeout=TIMEOUT)
420 reply = KC.get_shell_msg(timeout=TIMEOUT)
442 for tst in validate_message(reply, 'object_info_reply', msg_id):
421 validate_message(reply, 'object_info_reply', msg_id)
443 yield tst
444 content = reply['content']
422 content = reply['content']
445 yield nt.assert_true(content['found'])
423 assert content['found']
446 argspec = content['argspec']
424 argspec = content['argspec']
447 yield nt.assert_true(isinstance(argspec, dict), "expected non-empty argspec dict, got %r" % argspec)
425 nt.assert_is_instance(argspec, dict, "expected non-empty argspec dict, got %r" % argspec)
448 yield nt.assert_equal(argspec['defaults'], [0])
426 nt.assert_equal(argspec['defaults'], [0])
449
427
450
428
451 @dec.parametric
452 def test_oinfo_not_found():
429 def test_oinfo_not_found():
453 flush_channels()
430 flush_channels()
454
431
455 msg_id = KC.object_info('dne')
432 msg_id = KC.object_info('dne')
456 reply = KC.get_shell_msg(timeout=TIMEOUT)
433 reply = KC.get_shell_msg(timeout=TIMEOUT)
457 for tst in validate_message(reply, 'object_info_reply', msg_id):
434 validate_message(reply, 'object_info_reply', msg_id)
458 yield tst
459 content = reply['content']
435 content = reply['content']
460 yield nt.assert_false(content['found'])
436 nt.assert_false(content['found'])
461
437
462
438
463 @dec.parametric
464 def test_complete():
439 def test_complete():
465 flush_channels()
440 flush_channels()
466
441
467 msg_id, reply = execute(code="alpha = albert = 5")
442 msg_id, reply = execute(code="alpha = albert = 5")
468
443
469 msg_id = KC.complete('al', 'al', 2)
444 msg_id = KC.complete('al', 'al', 2)
470 reply = KC.get_shell_msg(timeout=TIMEOUT)
445 reply = KC.get_shell_msg(timeout=TIMEOUT)
471 for tst in validate_message(reply, 'complete_reply', msg_id):
446 validate_message(reply, 'complete_reply', msg_id)
472 yield tst
473 matches = reply['content']['matches']
447 matches = reply['content']['matches']
474 for name in ('alpha', 'albert'):
448 for name in ('alpha', 'albert'):
475 yield nt.assert_true(name in matches, "Missing match: %r" % name)
449 nt.assert_in(name, matches)
476
450
477
451
478 @dec.parametric
479 def test_kernel_info_request():
452 def test_kernel_info_request():
480 flush_channels()
453 flush_channels()
481
454
482 msg_id = KC.kernel_info()
455 msg_id = KC.kernel_info()
483 reply = KC.get_shell_msg(timeout=TIMEOUT)
456 reply = KC.get_shell_msg(timeout=TIMEOUT)
484 for tst in validate_message(reply, 'kernel_info_reply', msg_id):
457 validate_message(reply, 'kernel_info_reply', msg_id)
485 yield tst
486
458
487
459
488 # IOPub channel
460 # IOPub channel
489
461
490
462
491 @dec.parametric
492 def test_stream():
463 def test_stream():
493 flush_channels()
464 flush_channels()
494
465
495 msg_id, reply = execute("print('hi')")
466 msg_id, reply = execute("print('hi')")
496
467
497 stdout = KC.iopub_channel.get_msg(timeout=TIMEOUT)
468 stdout = KC.iopub_channel.get_msg(timeout=TIMEOUT)
498 for tst in validate_message(stdout, 'stream', msg_id):
469 validate_message(stdout, 'stream', msg_id)
499 yield tst
500 content = stdout['content']
470 content = stdout['content']
501 yield nt.assert_equal(content['name'], u'stdout')
471 nt.assert_equal(content['name'], u'stdout')
502 yield nt.assert_equal(content['data'], u'hi\n')
472 nt.assert_equal(content['data'], u'hi\n')
503
473
504
474
505 @dec.parametric
506 def test_display_data():
475 def test_display_data():
507 flush_channels()
476 flush_channels()
508
477
509 msg_id, reply = execute("from IPython.core.display import display; display(1)")
478 msg_id, reply = execute("from IPython.core.display import display; display(1)")
510
479
511 display = KC.iopub_channel.get_msg(timeout=TIMEOUT)
480 display = KC.iopub_channel.get_msg(timeout=TIMEOUT)
512 for tst in validate_message(display, 'display_data', parent=msg_id):
481 validate_message(display, 'display_data', parent=msg_id)
513 yield tst
514 data = display['content']['data']
482 data = display['content']['data']
515 yield nt.assert_equal(data['text/plain'], u'1')
483 nt.assert_equal(data['text/plain'], u'1')
516
484
@@ -1,47 +1,41 b''
1 """Test the IPython.kernel public API
1 """Test the IPython.kernel public API
2
2
3 Authors
3 Authors
4 -------
4 -------
5 * MinRK
5 * MinRK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
8 # Copyright (c) 2013, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import nose.tools as nt
15 import nose.tools as nt
16
16
17 from IPython.testing import decorators as dec
18
19 from IPython.kernel import launcher, connect
17 from IPython.kernel import launcher, connect
20 from IPython import kernel
18 from IPython import kernel
21
19
22 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
23 # Classes and functions
21 # Classes and functions
24 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
25
23
26 @dec.parametric
27 def test_kms():
24 def test_kms():
28 for base in ("", "Multi"):
25 for base in ("", "Multi"):
29 KM = base + "KernelManager"
26 KM = base + "KernelManager"
30 yield nt.assert_true(KM in dir(kernel), KM)
27 nt.assert_in(KM, dir(kernel))
31
28
32 @dec.parametric
33 def test_kcs():
29 def test_kcs():
34 for base in ("", "Blocking"):
30 for base in ("", "Blocking"):
35 KM = base + "KernelClient"
31 KM = base + "KernelClient"
36 yield nt.assert_true(KM in dir(kernel), KM)
32 nt.assert_in(KM, dir(kernel))
37
33
38 @dec.parametric
39 def test_launcher():
34 def test_launcher():
40 for name in launcher.__all__:
35 for name in launcher.__all__:
41 yield nt.assert_true(name in dir(kernel), name)
36 nt.assert_in(name, dir(kernel))
42
37
43 @dec.parametric
44 def test_connect():
38 def test_connect():
45 for name in connect.__all__:
39 for name in connect.__all__:
46 yield nt.assert_true(name in dir(kernel), name)
40 nt.assert_in(name, dir(kernel))
47
41
@@ -1,241 +1,228 b''
1 """test serialization tools"""
1 """test serialization tools"""
2
2
3 #-------------------------------------------------------------------------------
3 #-------------------------------------------------------------------------------
4 # Copyright (C) 2011 The IPython Development Team
4 # Copyright (C) 2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9
9
10 #-------------------------------------------------------------------------------
10 #-------------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13
13
14 import pickle
14 import pickle
15 from collections import namedtuple
15 from collections import namedtuple
16
16
17 import nose.tools as nt
17 import nose.tools as nt
18
18
19 # from unittest import TestCaes
19 # from unittest import TestCaes
20 from IPython.kernel.zmq.serialize import serialize_object, unserialize_object
20 from IPython.kernel.zmq.serialize import serialize_object, unserialize_object
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22 from IPython.utils.pickleutil import CannedArray, CannedClass
22 from IPython.utils.pickleutil import CannedArray, CannedClass
23 from IPython.parallel import interactive
23 from IPython.parallel import interactive
24
24
25 #-------------------------------------------------------------------------------
25 #-------------------------------------------------------------------------------
26 # Globals and Utilities
26 # Globals and Utilities
27 #-------------------------------------------------------------------------------
27 #-------------------------------------------------------------------------------
28
28
29 def roundtrip(obj):
29 def roundtrip(obj):
30 """roundtrip an object through serialization"""
30 """roundtrip an object through serialization"""
31 bufs = serialize_object(obj)
31 bufs = serialize_object(obj)
32 obj2, remainder = unserialize_object(bufs)
32 obj2, remainder = unserialize_object(bufs)
33 nt.assert_equals(remainder, [])
33 nt.assert_equals(remainder, [])
34 return obj2
34 return obj2
35
35
36 class C(object):
36 class C(object):
37 """dummy class for """
37 """dummy class for """
38
38
39 def __init__(self, **kwargs):
39 def __init__(self, **kwargs):
40 for key,value in kwargs.iteritems():
40 for key,value in kwargs.iteritems():
41 setattr(self, key, value)
41 setattr(self, key, value)
42
42
43 SHAPES = ((100,), (1024,10), (10,8,6,5), (), (0,))
43 SHAPES = ((100,), (1024,10), (10,8,6,5), (), (0,))
44 DTYPES = ('uint8', 'float64', 'int32', [('g', 'float32')], '|S10')
44 DTYPES = ('uint8', 'float64', 'int32', [('g', 'float32')], '|S10')
45 #-------------------------------------------------------------------------------
45 #-------------------------------------------------------------------------------
46 # Tests
46 # Tests
47 #-------------------------------------------------------------------------------
47 #-------------------------------------------------------------------------------
48
48
49 @dec.parametric
50 def test_roundtrip_simple():
49 def test_roundtrip_simple():
51 for obj in [
50 for obj in [
52 'hello',
51 'hello',
53 dict(a='b', b=10),
52 dict(a='b', b=10),
54 [1,2,'hi'],
53 [1,2,'hi'],
55 (b'123', 'hello'),
54 (b'123', 'hello'),
56 ]:
55 ]:
57 obj2 = roundtrip(obj)
56 obj2 = roundtrip(obj)
58 yield nt.assert_equals(obj, obj2)
57 nt.assert_equal(obj, obj2)
59
58
60 @dec.parametric
61 def test_roundtrip_nested():
59 def test_roundtrip_nested():
62 for obj in [
60 for obj in [
63 dict(a=range(5), b={1:b'hello'}),
61 dict(a=range(5), b={1:b'hello'}),
64 [range(5),[range(3),(1,[b'whoda'])]],
62 [range(5),[range(3),(1,[b'whoda'])]],
65 ]:
63 ]:
66 obj2 = roundtrip(obj)
64 obj2 = roundtrip(obj)
67 yield nt.assert_equals(obj, obj2)
65 nt.assert_equal(obj, obj2)
68
66
69 @dec.parametric
70 def test_roundtrip_buffered():
67 def test_roundtrip_buffered():
71 for obj in [
68 for obj in [
72 dict(a=b"x"*1025),
69 dict(a=b"x"*1025),
73 b"hello"*500,
70 b"hello"*500,
74 [b"hello"*501, 1,2,3]
71 [b"hello"*501, 1,2,3]
75 ]:
72 ]:
76 bufs = serialize_object(obj)
73 bufs = serialize_object(obj)
77 yield nt.assert_equals(len(bufs), 2)
74 nt.assert_equal(len(bufs), 2)
78 obj2, remainder = unserialize_object(bufs)
75 obj2, remainder = unserialize_object(bufs)
79 yield nt.assert_equals(remainder, [])
76 nt.assert_equal(remainder, [])
80 yield nt.assert_equals(obj, obj2)
77 nt.assert_equal(obj, obj2)
81
78
82 def _scrub_nan(A):
79 def _scrub_nan(A):
83 """scrub nans out of empty arrays
80 """scrub nans out of empty arrays
84
81
85 since nan != nan
82 since nan != nan
86 """
83 """
87 import numpy
84 import numpy
88 if A.dtype.fields and A.shape:
85 if A.dtype.fields and A.shape:
89 for field in A.dtype.fields.keys():
86 for field in A.dtype.fields.keys():
90 try:
87 try:
91 A[field][numpy.isnan(A[field])] = 0
88 A[field][numpy.isnan(A[field])] = 0
92 except (TypeError, NotImplementedError):
89 except (TypeError, NotImplementedError):
93 # e.g. str dtype
90 # e.g. str dtype
94 pass
91 pass
95
92
96 @dec.parametric
97 @dec.skip_without('numpy')
93 @dec.skip_without('numpy')
98 def test_numpy():
94 def test_numpy():
99 import numpy
95 import numpy
100 from numpy.testing.utils import assert_array_equal
96 from numpy.testing.utils import assert_array_equal
101 for shape in SHAPES:
97 for shape in SHAPES:
102 for dtype in DTYPES:
98 for dtype in DTYPES:
103 A = numpy.empty(shape, dtype=dtype)
99 A = numpy.empty(shape, dtype=dtype)
104 _scrub_nan(A)
100 _scrub_nan(A)
105 bufs = serialize_object(A)
101 bufs = serialize_object(A)
106 B, r = unserialize_object(bufs)
102 B, r = unserialize_object(bufs)
107 yield nt.assert_equals(r, [])
103 nt.assert_equal(r, [])
108 yield nt.assert_equals(A.shape, B.shape)
104 nt.assert_equal(A.shape, B.shape)
109 yield nt.assert_equals(A.dtype, B.dtype)
105 nt.assert_equal(A.dtype, B.dtype)
110 yield assert_array_equal(A,B)
106 assert_array_equal(A,B)
111
107
112 @dec.parametric
113 @dec.skip_without('numpy')
108 @dec.skip_without('numpy')
114 def test_recarray():
109 def test_recarray():
115 import numpy
110 import numpy
116 from numpy.testing.utils import assert_array_equal
111 from numpy.testing.utils import assert_array_equal
117 for shape in SHAPES:
112 for shape in SHAPES:
118 for dtype in [
113 for dtype in [
119 [('f', float), ('s', '|S10')],
114 [('f', float), ('s', '|S10')],
120 [('n', int), ('s', '|S1'), ('u', 'uint32')],
115 [('n', int), ('s', '|S1'), ('u', 'uint32')],
121 ]:
116 ]:
122 A = numpy.empty(shape, dtype=dtype)
117 A = numpy.empty(shape, dtype=dtype)
123 _scrub_nan(A)
118 _scrub_nan(A)
124
119
125 bufs = serialize_object(A)
120 bufs = serialize_object(A)
126 B, r = unserialize_object(bufs)
121 B, r = unserialize_object(bufs)
127 yield nt.assert_equals(r, [])
122 nt.assert_equal(r, [])
128 yield nt.assert_equals(A.shape, B.shape)
123 nt.assert_equal(A.shape, B.shape)
129 yield nt.assert_equals(A.dtype, B.dtype)
124 nt.assert_equal(A.dtype, B.dtype)
130 yield assert_array_equal(A,B)
125 assert_array_equal(A,B)
131
126
132 @dec.parametric
133 @dec.skip_without('numpy')
127 @dec.skip_without('numpy')
134 def test_numpy_in_seq():
128 def test_numpy_in_seq():
135 import numpy
129 import numpy
136 from numpy.testing.utils import assert_array_equal
130 from numpy.testing.utils import assert_array_equal
137 for shape in SHAPES:
131 for shape in SHAPES:
138 for dtype in DTYPES:
132 for dtype in DTYPES:
139 A = numpy.empty(shape, dtype=dtype)
133 A = numpy.empty(shape, dtype=dtype)
140 _scrub_nan(A)
134 _scrub_nan(A)
141 bufs = serialize_object((A,1,2,b'hello'))
135 bufs = serialize_object((A,1,2,b'hello'))
142 canned = pickle.loads(bufs[0])
136 canned = pickle.loads(bufs[0])
143 yield nt.assert_true(canned[0], CannedArray)
137 nt.assert_is_instance(canned[0], CannedArray)
144 tup, r = unserialize_object(bufs)
138 tup, r = unserialize_object(bufs)
145 B = tup[0]
139 B = tup[0]
146 yield nt.assert_equals(r, [])
140 nt.assert_equal(r, [])
147 yield nt.assert_equals(A.shape, B.shape)
141 nt.assert_equal(A.shape, B.shape)
148 yield nt.assert_equals(A.dtype, B.dtype)
142 nt.assert_equal(A.dtype, B.dtype)
149 yield assert_array_equal(A,B)
143 assert_array_equal(A,B)
150
144
151 @dec.parametric
152 @dec.skip_without('numpy')
145 @dec.skip_without('numpy')
153 def test_numpy_in_dict():
146 def test_numpy_in_dict():
154 import numpy
147 import numpy
155 from numpy.testing.utils import assert_array_equal
148 from numpy.testing.utils import assert_array_equal
156 for shape in SHAPES:
149 for shape in SHAPES:
157 for dtype in DTYPES:
150 for dtype in DTYPES:
158 A = numpy.empty(shape, dtype=dtype)
151 A = numpy.empty(shape, dtype=dtype)
159 _scrub_nan(A)
152 _scrub_nan(A)
160 bufs = serialize_object(dict(a=A,b=1,c=range(20)))
153 bufs = serialize_object(dict(a=A,b=1,c=range(20)))
161 canned = pickle.loads(bufs[0])
154 canned = pickle.loads(bufs[0])
162 yield nt.assert_true(canned['a'], CannedArray)
155 nt.assert_is_instance(canned['a'], CannedArray)
163 d, r = unserialize_object(bufs)
156 d, r = unserialize_object(bufs)
164 B = d['a']
157 B = d['a']
165 yield nt.assert_equals(r, [])
158 nt.assert_equal(r, [])
166 yield nt.assert_equals(A.shape, B.shape)
159 nt.assert_equal(A.shape, B.shape)
167 yield nt.assert_equals(A.dtype, B.dtype)
160 nt.assert_equal(A.dtype, B.dtype)
168 yield assert_array_equal(A,B)
161 assert_array_equal(A,B)
169
162
170 @dec.parametric
171 def test_class():
163 def test_class():
172 @interactive
164 @interactive
173 class C(object):
165 class C(object):
174 a=5
166 a=5
175 bufs = serialize_object(dict(C=C))
167 bufs = serialize_object(dict(C=C))
176 canned = pickle.loads(bufs[0])
168 canned = pickle.loads(bufs[0])
177 yield nt.assert_true(canned['C'], CannedClass)
169 nt.assert_is_instance(canned['C'], CannedClass)
178 d, r = unserialize_object(bufs)
170 d, r = unserialize_object(bufs)
179 C2 = d['C']
171 C2 = d['C']
180 yield nt.assert_equal(C2.a, C.a)
172 nt.assert_equal(C2.a, C.a)
181
173
182 @dec.parametric
183 def test_class_oldstyle():
174 def test_class_oldstyle():
184 @interactive
175 @interactive
185 class C:
176 class C:
186 a=5
177 a=5
187
178
188 bufs = serialize_object(dict(C=C))
179 bufs = serialize_object(dict(C=C))
189 canned = pickle.loads(bufs[0])
180 canned = pickle.loads(bufs[0])
190 yield nt.assert_true(isinstance(canned['C'], CannedClass))
181 nt.assert_is_instance(canned['C'], CannedClass)
191 d, r = unserialize_object(bufs)
182 d, r = unserialize_object(bufs)
192 C2 = d['C']
183 C2 = d['C']
193 yield nt.assert_equal(C2.a, C.a)
184 nt.assert_equal(C2.a, C.a)
194
185
195 @dec.parametric
196 def test_tuple():
186 def test_tuple():
197 tup = (lambda x:x, 1)
187 tup = (lambda x:x, 1)
198 bufs = serialize_object(tup)
188 bufs = serialize_object(tup)
199 canned = pickle.loads(bufs[0])
189 canned = pickle.loads(bufs[0])
200 yield nt.assert_true(isinstance(canned, tuple))
190 nt.assert_is_instance(canned, tuple)
201 t2, r = unserialize_object(bufs)
191 t2, r = unserialize_object(bufs)
202 yield nt.assert_equal(t2[0](t2[1]), tup[0](tup[1]))
192 nt.assert_equal(t2[0](t2[1]), tup[0](tup[1]))
203
193
204 point = namedtuple('point', 'x y')
194 point = namedtuple('point', 'x y')
205
195
206 @dec.parametric
207 def test_namedtuple():
196 def test_namedtuple():
208 p = point(1,2)
197 p = point(1,2)
209 bufs = serialize_object(p)
198 bufs = serialize_object(p)
210 canned = pickle.loads(bufs[0])
199 canned = pickle.loads(bufs[0])
211 yield nt.assert_true(isinstance(canned, point))
200 nt.assert_is_instance(canned, point)
212 p2, r = unserialize_object(bufs, globals())
201 p2, r = unserialize_object(bufs, globals())
213 yield nt.assert_equal(p2.x, p.x)
202 nt.assert_equal(p2.x, p.x)
214 yield nt.assert_equal(p2.y, p.y)
203 nt.assert_equal(p2.y, p.y)
215
204
216 @dec.parametric
217 def test_list():
205 def test_list():
218 lis = [lambda x:x, 1]
206 lis = [lambda x:x, 1]
219 bufs = serialize_object(lis)
207 bufs = serialize_object(lis)
220 canned = pickle.loads(bufs[0])
208 canned = pickle.loads(bufs[0])
221 yield nt.assert_true(isinstance(canned, list))
209 nt.assert_is_instance(canned, list)
222 l2, r = unserialize_object(bufs)
210 l2, r = unserialize_object(bufs)
223 yield nt.assert_equal(l2[0](l2[1]), lis[0](lis[1]))
211 nt.assert_equal(l2[0](l2[1]), lis[0](lis[1]))
224
212
225 @dec.parametric
226 def test_class_inheritance():
213 def test_class_inheritance():
227 @interactive
214 @interactive
228 class C(object):
215 class C(object):
229 a=5
216 a=5
230
217
231 @interactive
218 @interactive
232 class D(C):
219 class D(C):
233 b=10
220 b=10
234
221
235 bufs = serialize_object(dict(D=D))
222 bufs = serialize_object(dict(D=D))
236 canned = pickle.loads(bufs[0])
223 canned = pickle.loads(bufs[0])
237 yield nt.assert_true(canned['D'], CannedClass)
224 nt.assert_is_instance(canned['D'], CannedClass)
238 d, r = unserialize_object(bufs)
225 d, r = unserialize_object(bufs)
239 D2 = d['D']
226 D2 = d['D']
240 yield nt.assert_equal(D2.a, D.a)
227 nt.assert_equal(D2.a, D.a)
241 yield nt.assert_equal(D2.b, D.b)
228 nt.assert_equal(D2.b, D.b)
@@ -1,84 +1,84 b''
1 """
1 """
2 Module with tests for ansi filters
2 Module with tests for ansi filters
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.utils.coloransi import TermColors
17 from IPython.utils.coloransi import TermColors
18
18
19 from ...tests.base import TestsBase
19 from ...tests.base import TestsBase
20 from ..ansi import strip_ansi, ansi2html, ansi2latex
20 from ..ansi import strip_ansi, ansi2html, ansi2latex
21
21
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Class
24 # Class
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class TestAnsi(TestsBase):
27 class TestAnsi(TestsBase):
28 """Contains test functions for ansi.py"""
28 """Contains test functions for ansi.py"""
29
29
30 def test_strip_ansi(self):
30 def test_strip_ansi(self):
31 """strip_ansi test"""
31 """strip_ansi test"""
32 correct_outputs = {
32 correct_outputs = {
33 '%s%s%s' % (TermColors.Green, TermColors.White, TermColors.Red) : '',
33 '%s%s%s' % (TermColors.Green, TermColors.White, TermColors.Red) : '',
34 'hello%s' % TermColors.Blue: 'hello',
34 'hello%s' % TermColors.Blue: 'hello',
35 'he%s%sllo' % (TermColors.Yellow, TermColors.Cyan) : 'hello',
35 'he%s%sllo' % (TermColors.Yellow, TermColors.Cyan) : 'hello',
36 '%shello' % TermColors.Blue : 'hello',
36 '%shello' % TermColors.Blue : 'hello',
37 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.Red) : 'hello',
37 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.Red) : 'hello',
38 'hel%slo' % TermColors.Green : 'hello',
38 'hel%slo' % TermColors.Green : 'hello',
39 'hello' : 'hello'}
39 'hello' : 'hello'}
40
40
41 for inval, outval in correct_outputs.items():
41 for inval, outval in correct_outputs.items():
42 yield self._try_strip_ansi(inval, outval)
42 self._try_strip_ansi(inval, outval)
43
43
44
44
45 def _try_strip_ansi(self, inval, outval):
45 def _try_strip_ansi(self, inval, outval):
46 self.assertEqual(outval, strip_ansi(inval))
46 self.assertEqual(outval, strip_ansi(inval))
47
47
48
48
49 def test_ansi2html(self):
49 def test_ansi2html(self):
50 """ansi2html test"""
50 """ansi2html test"""
51 correct_outputs = {
51 correct_outputs = {
52 '%s' % (TermColors.Red) : '<span class="ansired"></span>',
52 '%s' % (TermColors.Red) : '<span class="ansired"></span>',
53 'hello%s' % TermColors.Blue: 'hello<span class="ansiblue"></span>',
53 'hello%s' % TermColors.Blue: 'hello<span class="ansiblue"></span>',
54 'he%s%sllo' % (TermColors.Green, TermColors.Cyan) : 'he<span class="ansigreen"></span><span class="ansicyan">llo</span>',
54 'he%s%sllo' % (TermColors.Green, TermColors.Cyan) : 'he<span class="ansigreen"></span><span class="ansicyan">llo</span>',
55 '%shello' % TermColors.Yellow : '<span class="ansiyellow">hello</span>',
55 '%shello' % TermColors.Yellow : '<span class="ansiyellow">hello</span>',
56 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.White) : '<span class="ansigrey">h</span><span class="ansigrey">e</span><span class="ansigrey">l</span><span class="ansigrey">l</span><span class="ansigrey">o</span><span class="ansigrey"></span>',
56 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.White) : '<span class="ansigrey">h</span><span class="ansigrey">e</span><span class="ansigrey">l</span><span class="ansigrey">l</span><span class="ansigrey">o</span><span class="ansigrey"></span>',
57 'hel%slo' % TermColors.Green : 'hel<span class="ansigreen">lo</span>',
57 'hel%slo' % TermColors.Green : 'hel<span class="ansigreen">lo</span>',
58 'hello' : 'hello'}
58 'hello' : 'hello'}
59
59
60 for inval, outval in correct_outputs.items():
60 for inval, outval in correct_outputs.items():
61 yield self._try_ansi2html(inval, outval)
61 self._try_ansi2html(inval, outval)
62
62
63
63
64 def _try_ansi2html(self, inval, outval):
64 def _try_ansi2html(self, inval, outval):
65 self.fuzzy_compare(outval, ansi2html(inval))
65 self.fuzzy_compare(outval, ansi2html(inval))
66
66
67
67
68 def test_ansi2latex(self):
68 def test_ansi2latex(self):
69 """ansi2latex test"""
69 """ansi2latex test"""
70 correct_outputs = {
70 correct_outputs = {
71 '%s' % (TermColors.Red) : r'\red{}',
71 '%s' % (TermColors.Red) : r'\red{}',
72 'hello%s' % TermColors.Blue: r'hello\blue{}',
72 'hello%s' % TermColors.Blue: r'hello\blue{}',
73 'he%s%sllo' % (TermColors.Green, TermColors.Cyan) : r'he\green{}\cyan{llo}',
73 'he%s%sllo' % (TermColors.Green, TermColors.Cyan) : r'he\green{}\cyan{llo}',
74 '%shello' % TermColors.Yellow : r'\yellow{hello}',
74 '%shello' % TermColors.Yellow : r'\yellow{hello}',
75 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.White) : r'\white{h}\white{e}\white{l}\white{l}\white{o}\white{}',
75 '{0}h{0}e{0}l{0}l{0}o{0}'.format(TermColors.White) : r'\white{h}\white{e}\white{l}\white{l}\white{o}\white{}',
76 'hel%slo' % TermColors.Green : r'hel\green{lo}',
76 'hel%slo' % TermColors.Green : r'hel\green{lo}',
77 'hello' : 'hello'}
77 'hello' : 'hello'}
78
78
79 for inval, outval in correct_outputs.items():
79 for inval, outval in correct_outputs.items():
80 yield self._try_ansi2latex(inval, outval)
80 self._try_ansi2latex(inval, outval)
81
81
82
82
83 def _try_ansi2latex(self, inval, outval):
83 def _try_ansi2latex(self, inval, outval):
84 self.fuzzy_compare(outval, ansi2latex(inval), case_sensitive=True)
84 self.fuzzy_compare(outval, ansi2latex(inval), case_sensitive=True)
@@ -1,65 +1,65 b''
1 """
1 """
2 Module with tests for Highlight
2 Module with tests for Highlight
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from ...tests.base import TestsBase
17 from ...tests.base import TestsBase
18 from ..highlight import highlight2html, highlight2latex
18 from ..highlight import highlight2html, highlight2latex
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestHighlight(TestsBase):
25 class TestHighlight(TestsBase):
26 """Contains test functions for highlight.py"""
26 """Contains test functions for highlight.py"""
27
27
28 #Hello world test, magics test, blank string test
28 #Hello world test, magics test, blank string test
29 tests = [
29 tests = [
30 """
30 """
31 #Hello World Example
31 #Hello World Example
32
32
33 def say(text):
33 def say(text):
34 print(text)
34 print(text)
35
35
36 say('Hello World!')
36 say('Hello World!')
37 """,
37 """,
38 """
38 """
39 %%pylab
39 %%pylab
40 plot(x,y, 'r')
40 plot(x,y, 'r')
41 """
41 """
42 ]
42 ]
43
43
44 tokens = [
44 tokens = [
45 ['Hello World Example', 'say', 'text', 'print', 'def'],
45 ['Hello World Example', 'say', 'text', 'print', 'def'],
46 ['pylab', 'plot']]
46 ['pylab', 'plot']]
47
47
48
48
49 def test_highlight2html(self):
49 def test_highlight2html(self):
50 """highlight2html test"""
50 """highlight2html test"""
51 for index, test in enumerate(self.tests):
51 for index, test in enumerate(self.tests):
52 yield self._try_highlight(highlight2html, test, self.tokens[index])
52 self._try_highlight(highlight2html, test, self.tokens[index])
53
53
54
54
55 def test_highlight2latex(self):
55 def test_highlight2latex(self):
56 """highlight2latex test"""
56 """highlight2latex test"""
57 for index, test in enumerate(self.tests):
57 for index, test in enumerate(self.tests):
58 yield self._try_highlight(highlight2latex, test, self.tokens[index])
58 self._try_highlight(highlight2latex, test, self.tokens[index])
59
59
60
60
61 def _try_highlight(self, method, test, tokens):
61 def _try_highlight(self, method, test, tokens):
62 """Try highlighting source, look for key tokens"""
62 """Try highlighting source, look for key tokens"""
63 results = method(test)
63 results = method(test)
64 for token in tokens:
64 for token in tokens:
65 assert token in results
65 assert token in results
@@ -1,66 +1,66 b''
1 """
1 """
2 Module with tests for Latex
2 Module with tests for Latex
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from ...tests.base import TestsBase
17 from ...tests.base import TestsBase
18 from ..latex import escape_latex, strip_math_space
18 from ..latex import escape_latex, strip_math_space
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestLatex(TestsBase):
25 class TestLatex(TestsBase):
26
26
27
27
28 def test_escape_latex(self):
28 def test_escape_latex(self):
29 """escape_latex test"""
29 """escape_latex test"""
30 tests = [
30 tests = [
31 (r'How are \you doing today?', r'How are \textbackslash{}you doing today?'),
31 (r'How are \you doing today?', r'How are \textbackslash{}you doing today?'),
32 (r'\escapechar=`\A\catcode`\|=0 |string|foo', r'\textbackslash{}escapechar=`\textbackslash{}A\textbackslash{}catcode`\textbackslash{}|=0 |string|foo'),
32 (r'\escapechar=`\A\catcode`\|=0 |string|foo', r'\textbackslash{}escapechar=`\textbackslash{}A\textbackslash{}catcode`\textbackslash{}|=0 |string|foo'),
33 (r'# $ % & ~ _ ^ \ { }', r'\# \$ \% \& \textasciitilde{} \_ \^{} \textbackslash{} \{ \}'),
33 (r'# $ % & ~ _ ^ \ { }', r'\# \$ \% \& \textasciitilde{} \_ \^{} \textbackslash{} \{ \}'),
34 ('...', r'\ldots'),
34 ('...', r'\ldots'),
35 ('','')]
35 ('','')]
36
36
37 for test in tests:
37 for test in tests:
38 yield self._try_escape_latex(test[0], test[1])
38 self._try_escape_latex(test[0], test[1])
39
39
40
40
41 def _try_escape_latex(self, test, result):
41 def _try_escape_latex(self, test, result):
42 """Try to remove latex from string"""
42 """Try to remove latex from string"""
43 self.assertEqual(escape_latex(test), result)
43 self.assertEqual(escape_latex(test), result)
44
44
45
45
46 def test_strip_math_space(self):
46 def test_strip_math_space(self):
47 """strip_math_space test"""
47 """strip_math_space test"""
48 tests = [
48 tests = [
49 ('$e$','$e$'),
49 ('$e$','$e$'),
50 ('$ e $','$e$'),
50 ('$ e $','$e$'),
51 ('xxx$e^i$yyy','xxx$e^i$yyy'),
51 ('xxx$e^i$yyy','xxx$e^i$yyy'),
52 ('xxx$ e^i $yyy','xxx$e^i$yyy'),
52 ('xxx$ e^i $yyy','xxx$e^i$yyy'),
53 ('xxx$e^i $yyy','xxx$e^i$yyy'),
53 ('xxx$e^i $yyy','xxx$e^i$yyy'),
54 ('xxx$ e^i$yyy','xxx$e^i$yyy'),
54 ('xxx$ e^i$yyy','xxx$e^i$yyy'),
55 ('\$ e $ e $','\$ e $e$'),
55 ('\$ e $ e $','\$ e $e$'),
56 ('','')]
56 ('','')]
57
57
58 for test in tests:
58 for test in tests:
59 yield self._try_strip_math_space(test[0], test[1])
59 self._try_strip_math_space(test[0], test[1])
60
60
61
61
62 def _try_strip_math_space(self, test, result):
62 def _try_strip_math_space(self, test, result):
63 """
63 """
64 Try to remove spaces between dollar symbols and contents correctly
64 Try to remove spaces between dollar symbols and contents correctly
65 """
65 """
66 self.assertEqual(strip_math_space(test), result)
66 self.assertEqual(strip_math_space(test), result)
@@ -1,93 +1,93 b''
1
1
2 """
2 """
3 Module with tests for Markdown
3 Module with tests for Markdown
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from copy import copy
18 from copy import copy
19
19
20 from IPython.utils.py3compat import string_types
20 from IPython.utils.py3compat import string_types
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22
22
23 from ...tests.base import TestsBase
23 from ...tests.base import TestsBase
24 from ..markdown import markdown2latex, markdown2html, markdown2rst
24 from ..markdown import markdown2latex, markdown2html, markdown2rst
25
25
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Class
28 # Class
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class TestMarkdown(TestsBase):
31 class TestMarkdown(TestsBase):
32
32
33 tests = [
33 tests = [
34 '*test',
34 '*test',
35 '**test',
35 '**test',
36 '*test*',
36 '*test*',
37 '_test_',
37 '_test_',
38 '__test__',
38 '__test__',
39 '__*test*__',
39 '__*test*__',
40 '**test**',
40 '**test**',
41 '#test',
41 '#test',
42 '##test',
42 '##test',
43 'test\n----',
43 'test\n----',
44 'test [link](https://google.com/)']
44 'test [link](https://google.com/)']
45
45
46 tokens = [
46 tokens = [
47 '*test',
47 '*test',
48 '**test',
48 '**test',
49 'test',
49 'test',
50 'test',
50 'test',
51 'test',
51 'test',
52 'test',
52 'test',
53 'test',
53 'test',
54 'test',
54 'test',
55 'test',
55 'test',
56 'test',
56 'test',
57 ('test', 'https://google.com/')]
57 ('test', 'https://google.com/')]
58
58
59
59
60 @dec.onlyif_cmds_exist('pandoc')
60 @dec.onlyif_cmds_exist('pandoc')
61 def test_markdown2latex(self):
61 def test_markdown2latex(self):
62 """markdown2latex test"""
62 """markdown2latex test"""
63 for index, test in enumerate(self.tests):
63 for index, test in enumerate(self.tests):
64 yield self._try_markdown(markdown2latex, test, self.tokens[index])
64 self._try_markdown(markdown2latex, test, self.tokens[index])
65
65
66
66
67 @dec.onlyif_cmds_exist('pandoc')
67 @dec.onlyif_cmds_exist('pandoc')
68 def test_markdown2html(self):
68 def test_markdown2html(self):
69 """markdown2html test"""
69 """markdown2html test"""
70 for index, test in enumerate(self.tests):
70 for index, test in enumerate(self.tests):
71 yield self._try_markdown(markdown2html, test, self.tokens[index])
71 self._try_markdown(markdown2html, test, self.tokens[index])
72
72
73
73
74 @dec.onlyif_cmds_exist('pandoc')
74 @dec.onlyif_cmds_exist('pandoc')
75 def test_markdown2rst(self):
75 def test_markdown2rst(self):
76 """markdown2rst test"""
76 """markdown2rst test"""
77
77
78 #Modify token array for rst, escape asterik
78 #Modify token array for rst, escape asterik
79 tokens = copy(self.tokens)
79 tokens = copy(self.tokens)
80 tokens[0] = r'\*test'
80 tokens[0] = r'\*test'
81 tokens[1] = r'\*\*test'
81 tokens[1] = r'\*\*test'
82
82
83 for index, test in enumerate(self.tests):
83 for index, test in enumerate(self.tests):
84 yield self._try_markdown(markdown2rst, test, tokens[index])
84 self._try_markdown(markdown2rst, test, tokens[index])
85
85
86
86
87 def _try_markdown(self, method, test, tokens):
87 def _try_markdown(self, method, test, tokens):
88 results = method(test)
88 results = method(test)
89 if isinstance(tokens, string_types):
89 if isinstance(tokens, string_types):
90 assert tokens in results
90 assert tokens in results
91 else:
91 else:
92 for token in tokens:
92 for token in tokens:
93 assert token in results
93 assert token in results
@@ -1,128 +1,127 b''
1 """
1 """
2 Module with tests for Strings
2 Module with tests for Strings
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 import os
16 import os
17
17
18 from IPython.testing import decorators as dec
19 from ...tests.base import TestsBase
18 from ...tests.base import TestsBase
20 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
19 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
21 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
20 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
22 )
21 )
23
22
24
23
25 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
26 # Class
25 # Class
27 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
28
27
29 class TestStrings(TestsBase):
28 class TestStrings(TestsBase):
30
29
31 def test_wrap_text(self):
30 def test_wrap_text(self):
32 """wrap_text test"""
31 """wrap_text test"""
33 test_text = """
32 test_text = """
34 Tush! never tell me; I take it much unkindly
33 Tush! never tell me; I take it much unkindly
35 That thou, Iago, who hast had my purse
34 That thou, Iago, who hast had my purse
36 As if the strings were thine, shouldst know of this.
35 As if the strings were thine, shouldst know of this.
37 """
36 """
38 for length in [30,5,1]:
37 for length in [30,5,1]:
39 yield self._confirm_wrap_text(test_text, length)
38 self._confirm_wrap_text(test_text, length)
40
39
41
40
42 def _confirm_wrap_text(self, text, length):
41 def _confirm_wrap_text(self, text, length):
43 for line in wrap_text(text, length).split('\n'):
42 for line in wrap_text(text, length).split('\n'):
44 assert len(line) <= length
43 assert len(line) <= length
45
44
46
45
47 def test_html2text(self):
46 def test_html2text(self):
48 """html2text test"""
47 """html2text test"""
49 #TODO: More tests
48 #TODO: More tests
50 self.assertEqual(html2text('<name>joe</name>'), 'joe')
49 self.assertEqual(html2text('<name>joe</name>'), 'joe')
51
50
52
51
53 def test_add_anchor(self):
52 def test_add_anchor(self):
54 """add_anchor test"""
53 """add_anchor test"""
55 #TODO: More tests
54 #TODO: More tests
56 results = add_anchor('<b>Hello World!</b>')
55 results = add_anchor('<b>Hello World!</b>')
57 assert 'Hello World!' in results
56 assert 'Hello World!' in results
58 assert 'id="' in results
57 assert 'id="' in results
59 assert 'class="anchor-link"' in results
58 assert 'class="anchor-link"' in results
60 assert '<b' in results
59 assert '<b' in results
61 assert '</b>' in results
60 assert '</b>' in results
62
61
63
62
64 def test_strip_dollars(self):
63 def test_strip_dollars(self):
65 """strip_dollars test"""
64 """strip_dollars test"""
66 tests = [
65 tests = [
67 ('', ''),
66 ('', ''),
68 ('$$', ''),
67 ('$$', ''),
69 ('$H$', 'H'),
68 ('$H$', 'H'),
70 ('$He', 'He'),
69 ('$He', 'He'),
71 ('H$el', 'H$el'),
70 ('H$el', 'H$el'),
72 ('Hell$', 'Hell'),
71 ('Hell$', 'Hell'),
73 ('Hello', 'Hello'),
72 ('Hello', 'Hello'),
74 ('W$o$rld', 'W$o$rld')]
73 ('W$o$rld', 'W$o$rld')]
75 for test in tests:
74 for test in tests:
76 yield self._try_strip_dollars(test[0], test[1])
75 self._try_strip_dollars(test[0], test[1])
77
76
78
77
79 def _try_strip_dollars(self, test, result):
78 def _try_strip_dollars(self, test, result):
80 self.assertEqual(strip_dollars(test), result)
79 self.assertEqual(strip_dollars(test), result)
81
80
82
81
83 def test_strip_files_prefix(self):
82 def test_strip_files_prefix(self):
84 """strip_files_prefix test"""
83 """strip_files_prefix test"""
85 tests = [
84 tests = [
86 ('', ''),
85 ('', ''),
87 ('/files', '/files'),
86 ('/files', '/files'),
88 ('test="/files"', 'test="/files"'),
87 ('test="/files"', 'test="/files"'),
89 ('My files are in `files/`', 'My files are in `files/`'),
88 ('My files are in `files/`', 'My files are in `files/`'),
90 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>')]
89 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>')]
91 for test in tests:
90 for test in tests:
92 yield self._try_files_prefix(test[0], test[1])
91 self._try_files_prefix(test[0], test[1])
93
92
94
93
95 def _try_files_prefix(self, test, result):
94 def _try_files_prefix(self, test, result):
96 self.assertEqual(strip_files_prefix(test), result)
95 self.assertEqual(strip_files_prefix(test), result)
97
96
98
97
99 def test_comment_lines(self):
98 def test_comment_lines(self):
100 """comment_lines test"""
99 """comment_lines test"""
101 for line in comment_lines('hello\nworld\n!').split('\n'):
100 for line in comment_lines('hello\nworld\n!').split('\n'):
102 assert line.startswith('# ')
101 assert line.startswith('# ')
103 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
102 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
104 assert line.startswith('beep')
103 assert line.startswith('beep')
105
104
106
105
107 def test_get_lines(self):
106 def test_get_lines(self):
108 """get_lines test"""
107 """get_lines test"""
109 text = "hello\nworld\n!"
108 text = "hello\nworld\n!"
110 self.assertEqual(get_lines(text, start=1), "world\n!")
109 self.assertEqual(get_lines(text, start=1), "world\n!")
111 self.assertEqual(get_lines(text, end=2), "hello\nworld")
110 self.assertEqual(get_lines(text, end=2), "hello\nworld")
112 self.assertEqual(get_lines(text, start=2, end=5), "!")
111 self.assertEqual(get_lines(text, start=2, end=5), "!")
113 self.assertEqual(get_lines(text, start=-2), "world\n!")
112 self.assertEqual(get_lines(text, start=-2), "world\n!")
114
113
115
114
116 def test_ipython2python(self):
115 def test_ipython2python(self):
117 """ipython2python test"""
116 """ipython2python test"""
118 #TODO: More tests
117 #TODO: More tests
119 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
118 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
120 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
119 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
121 ignore_spaces=True, ignore_newlines=True)
120 ignore_spaces=True, ignore_newlines=True)
122
121
123 def test_posix_path(self):
122 def test_posix_path(self):
124 path_list = ['foo', 'bar']
123 path_list = ['foo', 'bar']
125 expected = '/'.join(path_list)
124 expected = '/'.join(path_list)
126 native = os.path.join(*path_list)
125 native = os.path.join(*path_list)
127 filtered = posix_path(native)
126 filtered = posix_path(native)
128 self.assertEqual(filtered, expected)
127 self.assertEqual(filtered, expected)
@@ -1,155 +1,155 b''
1 """
1 """
2 Contains base test class for nbconvert
2 Contains base test class for nbconvert
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
5 #Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 #Distributed under the terms of the Modified BSD License.
7 #Distributed under the terms of the Modified BSD License.
8 #
8 #
9 #The full license is in the file COPYING.txt, distributed with this software.
9 #The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import os
16 import os
17 import glob
17 import glob
18 import shutil
18 import shutil
19 import unittest
19
20
20 import IPython
21 import IPython
21 from IPython.utils.tempdir import TemporaryWorkingDirectory
22 from IPython.utils.tempdir import TemporaryWorkingDirectory
22 from IPython.utils.process import get_output_error_code
23 from IPython.utils.process import get_output_error_code
23 from IPython.testing.tools import get_ipython_cmd
24 from IPython.testing.tools import get_ipython_cmd
24 from IPython.testing.ipunittest import ParametricTestCase
25
25
26 # a trailing space allows for simpler concatenation with the other arguments
26 # a trailing space allows for simpler concatenation with the other arguments
27 ipy_cmd = get_ipython_cmd(as_string=True) + " "
27 ipy_cmd = get_ipython_cmd(as_string=True) + " "
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class TestsBase(ParametricTestCase):
34 class TestsBase(unittest.TestCase):
35 """Base tests class. Contains useful fuzzy comparison and nbconvert
35 """Base tests class. Contains useful fuzzy comparison and nbconvert
36 functions."""
36 functions."""
37
37
38
38
39 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
39 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
40 fuzzy_spacing=True, ignore_spaces=False,
40 fuzzy_spacing=True, ignore_spaces=False,
41 ignore_newlines=False, case_sensitive=False, leave_padding=False):
41 ignore_newlines=False, case_sensitive=False, leave_padding=False):
42 """
42 """
43 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
43 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
44 comparison that ignores insignificant differences in the two comparands.
44 comparison that ignores insignificant differences in the two comparands.
45 The significance of certain differences can be specified via the keyword
45 The significance of certain differences can be specified via the keyword
46 parameters of this method.
46 parameters of this method.
47 """
47 """
48
48
49 if not leave_padding:
49 if not leave_padding:
50 a = a.strip()
50 a = a.strip()
51 b = b.strip()
51 b = b.strip()
52
52
53 if ignore_newlines:
53 if ignore_newlines:
54 a = a.replace('\n', '')
54 a = a.replace('\n', '')
55 b = b.replace('\n', '')
55 b = b.replace('\n', '')
56
56
57 if newlines_are_spaces:
57 if newlines_are_spaces:
58 a = a.replace('\n', ' ')
58 a = a.replace('\n', ' ')
59 b = b.replace('\n', ' ')
59 b = b.replace('\n', ' ')
60
60
61 if tabs_are_spaces:
61 if tabs_are_spaces:
62 a = a.replace('\t', ' ')
62 a = a.replace('\t', ' ')
63 b = b.replace('\t', ' ')
63 b = b.replace('\t', ' ')
64
64
65 if ignore_spaces:
65 if ignore_spaces:
66 a = a.replace(' ', '')
66 a = a.replace(' ', '')
67 b = b.replace(' ', '')
67 b = b.replace(' ', '')
68
68
69 if fuzzy_spacing:
69 if fuzzy_spacing:
70 a = self.recursive_replace(a, ' ', ' ')
70 a = self.recursive_replace(a, ' ', ' ')
71 b = self.recursive_replace(b, ' ', ' ')
71 b = self.recursive_replace(b, ' ', ' ')
72
72
73 if not case_sensitive:
73 if not case_sensitive:
74 a = a.lower()
74 a = a.lower()
75 b = b.lower()
75 b = b.lower()
76
76
77 self.assertEqual(a, b)
77 self.assertEqual(a, b)
78
78
79
79
80 def recursive_replace(self, text, search, replacement):
80 def recursive_replace(self, text, search, replacement):
81 """
81 """
82 Performs a recursive replacement operation. Replaces all instances
82 Performs a recursive replacement operation. Replaces all instances
83 of a search string in a text string with a replacement string until
83 of a search string in a text string with a replacement string until
84 the search string no longer exists. Recursion is needed because the
84 the search string no longer exists. Recursion is needed because the
85 replacement string may generate additional search strings.
85 replacement string may generate additional search strings.
86
86
87 For example:
87 For example:
88 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
88 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
89 Another replacement yields "Hi" (the desired output)
89 Another replacement cds "Hi" (the desired output)
90
90
91 Parameters:
91 Parameters:
92 -----------
92 -----------
93 text : string
93 text : string
94 Text to replace in.
94 Text to replace in.
95 search : string
95 search : string
96 String to search for within "text"
96 String to search for within "text"
97 replacement : string
97 replacement : string
98 String to replace "search" with
98 String to replace "search" with
99 """
99 """
100 while search in text:
100 while search in text:
101 text = text.replace(search, replacement)
101 text = text.replace(search, replacement)
102 return text
102 return text
103
103
104 def create_temp_cwd(self, copy_filenames=None):
104 def create_temp_cwd(self, copy_filenames=None):
105 temp_dir = TemporaryWorkingDirectory()
105 temp_dir = TemporaryWorkingDirectory()
106
106
107 #Copy the files if requested.
107 #Copy the files if requested.
108 if copy_filenames is not None:
108 if copy_filenames is not None:
109 self.copy_files_to(copy_filenames)
109 self.copy_files_to(copy_filenames)
110
110
111 #Return directory handler
111 #Return directory handler
112 return temp_dir
112 return temp_dir
113
113
114
114
115 def copy_files_to(self, copy_filenames, dest='.'):
115 def copy_files_to(self, copy_filenames, dest='.'):
116 "Copy test files into the destination directory"
116 "Copy test files into the destination directory"
117 if not os.path.isdir(dest):
117 if not os.path.isdir(dest):
118 os.makedirs(dest)
118 os.makedirs(dest)
119 files_path = self._get_files_path()
119 files_path = self._get_files_path()
120 for pattern in copy_filenames:
120 for pattern in copy_filenames:
121 for match in glob.glob(os.path.join(files_path, pattern)):
121 for match in glob.glob(os.path.join(files_path, pattern)):
122 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
122 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
123
123
124
124
125 def _get_files_path(self):
125 def _get_files_path(self):
126
126
127 #Get the relative path to this module in the IPython directory.
127 #Get the relative path to this module in the IPython directory.
128 names = self.__module__.split('.')[1:-1]
128 names = self.__module__.split('.')[1:-1]
129 names.append('files')
129 names.append('files')
130
130
131 #Build a path using the IPython directory and the relative path we just
131 #Build a path using the IPython directory and the relative path we just
132 #found.
132 #found.
133 path = IPython.__path__[0]
133 path = IPython.__path__[0]
134 for name in names:
134 for name in names:
135 path = os.path.join(path, name)
135 path = os.path.join(path, name)
136 return path
136 return path
137
137
138
138
139 def call(self, parameters, ignore_return_code=False):
139 def call(self, parameters, ignore_return_code=False):
140 """
140 """
141 Execute a, IPython shell command, listening for both Errors and non-zero
141 Execute a, IPython shell command, listening for both Errors and non-zero
142 return codes.
142 return codes.
143
143
144 PARAMETERS:
144 PARAMETERS:
145 -----------
145 -----------
146 parameters : str
146 parameters : str
147 List of parameters to pass to IPython.
147 List of parameters to pass to IPython.
148 ignore_return_code : optional bool (default False)
148 ignore_return_code : optional bool (default False)
149 Throw an OSError if the return code
149 Throw an OSError if the return code
150 """
150 """
151
151
152 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
152 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
153 if not (retcode == 0 or ignore_return_code):
153 if not (retcode == 0 or ignore_return_code):
154 raise OSError(stderr)
154 raise OSError(stderr)
155 return stdout, stderr
155 return stdout, stderr
@@ -1,380 +1,374 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test Parallel magics
2 """Test Parallel magics
3
3
4 Authors:
4 Authors:
5
5
6 * Min RK
6 * Min RK
7 """
7 """
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 import re
19 import re
20 import sys
21 import time
20 import time
22
21
23 import zmq
24 from nose import SkipTest
25
22
26 from IPython.testing import decorators as dec
23 from IPython.testing import decorators as dec
27 from IPython.testing.ipunittest import ParametricTestCase
28 from IPython.utils.io import capture_output
24 from IPython.utils.io import capture_output
29
25
30 from IPython import parallel as pmod
26 from IPython import parallel as pmod
31 from IPython.parallel import error
32 from IPython.parallel import AsyncResult
27 from IPython.parallel import AsyncResult
33 from IPython.parallel.util import interactive
34
28
35 from IPython.parallel.tests import add_engines
29 from IPython.parallel.tests import add_engines
36
30
37 from .clienttest import ClusterTestCase, generate_output
31 from .clienttest import ClusterTestCase, generate_output
38
32
39 def setup():
33 def setup():
40 add_engines(3, total=True)
34 add_engines(3, total=True)
41
35
42 class TestParallelMagics(ClusterTestCase, ParametricTestCase):
36 class TestParallelMagics(ClusterTestCase):
43
37
44 def test_px_blocking(self):
38 def test_px_blocking(self):
45 ip = get_ipython()
39 ip = get_ipython()
46 v = self.client[-1:]
40 v = self.client[-1:]
47 v.activate()
41 v.activate()
48 v.block=True
42 v.block=True
49
43
50 ip.magic('px a=5')
44 ip.magic('px a=5')
51 self.assertEqual(v['a'], [5])
45 self.assertEqual(v['a'], [5])
52 ip.magic('px a=10')
46 ip.magic('px a=10')
53 self.assertEqual(v['a'], [10])
47 self.assertEqual(v['a'], [10])
54 # just 'print a' works ~99% of the time, but this ensures that
48 # just 'print a' works ~99% of the time, but this ensures that
55 # the stdout message has arrived when the result is finished:
49 # the stdout message has arrived when the result is finished:
56 with capture_output() as io:
50 with capture_output() as io:
57 ip.magic(
51 ip.magic(
58 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
52 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
59 )
53 )
60 self.assertIn('[stdout:', io.stdout)
54 self.assertIn('[stdout:', io.stdout)
61 self.assertNotIn('\n\n', io.stdout)
55 self.assertNotIn('\n\n', io.stdout)
62 assert io.stdout.rstrip().endswith('10')
56 assert io.stdout.rstrip().endswith('10')
63 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
57 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
64
58
65 def _check_generated_stderr(self, stderr, n):
59 def _check_generated_stderr(self, stderr, n):
66 expected = [
60 expected = [
67 r'\[stderr:\d+\]',
61 r'\[stderr:\d+\]',
68 '^stderr$',
62 '^stderr$',
69 '^stderr2$',
63 '^stderr2$',
70 ] * n
64 ] * n
71
65
72 self.assertNotIn('\n\n', stderr)
66 self.assertNotIn('\n\n', stderr)
73 lines = stderr.splitlines()
67 lines = stderr.splitlines()
74 self.assertEqual(len(lines), len(expected), stderr)
68 self.assertEqual(len(lines), len(expected), stderr)
75 for line,expect in zip(lines, expected):
69 for line,expect in zip(lines, expected):
76 if isinstance(expect, str):
70 if isinstance(expect, str):
77 expect = [expect]
71 expect = [expect]
78 for ex in expect:
72 for ex in expect:
79 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
73 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
80
74
81 def test_cellpx_block_args(self):
75 def test_cellpx_block_args(self):
82 """%%px --[no]block flags work"""
76 """%%px --[no]block flags work"""
83 ip = get_ipython()
77 ip = get_ipython()
84 v = self.client[-1:]
78 v = self.client[-1:]
85 v.activate()
79 v.activate()
86 v.block=False
80 v.block=False
87
81
88 for block in (True, False):
82 for block in (True, False):
89 v.block = block
83 v.block = block
90 ip.magic("pxconfig --verbose")
84 ip.magic("pxconfig --verbose")
91 with capture_output(display=False) as io:
85 with capture_output(display=False) as io:
92 ip.run_cell_magic("px", "", "1")
86 ip.run_cell_magic("px", "", "1")
93 if block:
87 if block:
94 assert io.stdout.startswith("Parallel"), io.stdout
88 assert io.stdout.startswith("Parallel"), io.stdout
95 else:
89 else:
96 assert io.stdout.startswith("Async"), io.stdout
90 assert io.stdout.startswith("Async"), io.stdout
97
91
98 with capture_output(display=False) as io:
92 with capture_output(display=False) as io:
99 ip.run_cell_magic("px", "--block", "1")
93 ip.run_cell_magic("px", "--block", "1")
100 assert io.stdout.startswith("Parallel"), io.stdout
94 assert io.stdout.startswith("Parallel"), io.stdout
101
95
102 with capture_output(display=False) as io:
96 with capture_output(display=False) as io:
103 ip.run_cell_magic("px", "--noblock", "1")
97 ip.run_cell_magic("px", "--noblock", "1")
104 assert io.stdout.startswith("Async"), io.stdout
98 assert io.stdout.startswith("Async"), io.stdout
105
99
106 def test_cellpx_groupby_engine(self):
100 def test_cellpx_groupby_engine(self):
107 """%%px --group-outputs=engine"""
101 """%%px --group-outputs=engine"""
108 ip = get_ipython()
102 ip = get_ipython()
109 v = self.client[:]
103 v = self.client[:]
110 v.block = True
104 v.block = True
111 v.activate()
105 v.activate()
112
106
113 v['generate_output'] = generate_output
107 v['generate_output'] = generate_output
114
108
115 with capture_output(display=False) as io:
109 with capture_output(display=False) as io:
116 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
110 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
117
111
118 self.assertNotIn('\n\n', io.stdout)
112 self.assertNotIn('\n\n', io.stdout)
119 lines = io.stdout.splitlines()
113 lines = io.stdout.splitlines()
120 expected = [
114 expected = [
121 r'\[stdout:\d+\]',
115 r'\[stdout:\d+\]',
122 'stdout',
116 'stdout',
123 'stdout2',
117 'stdout2',
124 r'\[output:\d+\]',
118 r'\[output:\d+\]',
125 r'IPython\.core\.display\.HTML',
119 r'IPython\.core\.display\.HTML',
126 r'IPython\.core\.display\.Math',
120 r'IPython\.core\.display\.Math',
127 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
121 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
128 ] * len(v)
122 ] * len(v)
129
123
130 self.assertEqual(len(lines), len(expected), io.stdout)
124 self.assertEqual(len(lines), len(expected), io.stdout)
131 for line,expect in zip(lines, expected):
125 for line,expect in zip(lines, expected):
132 if isinstance(expect, str):
126 if isinstance(expect, str):
133 expect = [expect]
127 expect = [expect]
134 for ex in expect:
128 for ex in expect:
135 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
129 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
136
130
137 self._check_generated_stderr(io.stderr, len(v))
131 self._check_generated_stderr(io.stderr, len(v))
138
132
139
133
140 def test_cellpx_groupby_order(self):
134 def test_cellpx_groupby_order(self):
141 """%%px --group-outputs=order"""
135 """%%px --group-outputs=order"""
142 ip = get_ipython()
136 ip = get_ipython()
143 v = self.client[:]
137 v = self.client[:]
144 v.block = True
138 v.block = True
145 v.activate()
139 v.activate()
146
140
147 v['generate_output'] = generate_output
141 v['generate_output'] = generate_output
148
142
149 with capture_output(display=False) as io:
143 with capture_output(display=False) as io:
150 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
144 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
151
145
152 self.assertNotIn('\n\n', io.stdout)
146 self.assertNotIn('\n\n', io.stdout)
153 lines = io.stdout.splitlines()
147 lines = io.stdout.splitlines()
154 expected = []
148 expected = []
155 expected.extend([
149 expected.extend([
156 r'\[stdout:\d+\]',
150 r'\[stdout:\d+\]',
157 'stdout',
151 'stdout',
158 'stdout2',
152 'stdout2',
159 ] * len(v))
153 ] * len(v))
160 expected.extend([
154 expected.extend([
161 r'\[output:\d+\]',
155 r'\[output:\d+\]',
162 'IPython.core.display.HTML',
156 'IPython.core.display.HTML',
163 ] * len(v))
157 ] * len(v))
164 expected.extend([
158 expected.extend([
165 r'\[output:\d+\]',
159 r'\[output:\d+\]',
166 'IPython.core.display.Math',
160 'IPython.core.display.Math',
167 ] * len(v))
161 ] * len(v))
168 expected.extend([
162 expected.extend([
169 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
163 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
170 ] * len(v))
164 ] * len(v))
171
165
172 self.assertEqual(len(lines), len(expected), io.stdout)
166 self.assertEqual(len(lines), len(expected), io.stdout)
173 for line,expect in zip(lines, expected):
167 for line,expect in zip(lines, expected):
174 if isinstance(expect, str):
168 if isinstance(expect, str):
175 expect = [expect]
169 expect = [expect]
176 for ex in expect:
170 for ex in expect:
177 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
171 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
178
172
179 self._check_generated_stderr(io.stderr, len(v))
173 self._check_generated_stderr(io.stderr, len(v))
180
174
181 def test_cellpx_groupby_type(self):
175 def test_cellpx_groupby_type(self):
182 """%%px --group-outputs=type"""
176 """%%px --group-outputs=type"""
183 ip = get_ipython()
177 ip = get_ipython()
184 v = self.client[:]
178 v = self.client[:]
185 v.block = True
179 v.block = True
186 v.activate()
180 v.activate()
187
181
188 v['generate_output'] = generate_output
182 v['generate_output'] = generate_output
189
183
190 with capture_output(display=False) as io:
184 with capture_output(display=False) as io:
191 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
185 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
192
186
193 self.assertNotIn('\n\n', io.stdout)
187 self.assertNotIn('\n\n', io.stdout)
194 lines = io.stdout.splitlines()
188 lines = io.stdout.splitlines()
195
189
196 expected = []
190 expected = []
197 expected.extend([
191 expected.extend([
198 r'\[stdout:\d+\]',
192 r'\[stdout:\d+\]',
199 'stdout',
193 'stdout',
200 'stdout2',
194 'stdout2',
201 ] * len(v))
195 ] * len(v))
202 expected.extend([
196 expected.extend([
203 r'\[output:\d+\]',
197 r'\[output:\d+\]',
204 r'IPython\.core\.display\.HTML',
198 r'IPython\.core\.display\.HTML',
205 r'IPython\.core\.display\.Math',
199 r'IPython\.core\.display\.Math',
206 ] * len(v))
200 ] * len(v))
207 expected.extend([
201 expected.extend([
208 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
202 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
209 ] * len(v))
203 ] * len(v))
210
204
211 self.assertEqual(len(lines), len(expected), io.stdout)
205 self.assertEqual(len(lines), len(expected), io.stdout)
212 for line,expect in zip(lines, expected):
206 for line,expect in zip(lines, expected):
213 if isinstance(expect, str):
207 if isinstance(expect, str):
214 expect = [expect]
208 expect = [expect]
215 for ex in expect:
209 for ex in expect:
216 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
210 assert re.search(ex, line) is not None, "Expected %r in %r" % (ex, line)
217
211
218 self._check_generated_stderr(io.stderr, len(v))
212 self._check_generated_stderr(io.stderr, len(v))
219
213
220
214
221 def test_px_nonblocking(self):
215 def test_px_nonblocking(self):
222 ip = get_ipython()
216 ip = get_ipython()
223 v = self.client[-1:]
217 v = self.client[-1:]
224 v.activate()
218 v.activate()
225 v.block=False
219 v.block=False
226
220
227 ip.magic('px a=5')
221 ip.magic('px a=5')
228 self.assertEqual(v['a'], [5])
222 self.assertEqual(v['a'], [5])
229 ip.magic('px a=10')
223 ip.magic('px a=10')
230 self.assertEqual(v['a'], [10])
224 self.assertEqual(v['a'], [10])
231 ip.magic('pxconfig --verbose')
225 ip.magic('pxconfig --verbose')
232 with capture_output() as io:
226 with capture_output() as io:
233 ar = ip.magic('px print (a)')
227 ar = ip.magic('px print (a)')
234 self.assertIsInstance(ar, AsyncResult)
228 self.assertIsInstance(ar, AsyncResult)
235 self.assertIn('Async', io.stdout)
229 self.assertIn('Async', io.stdout)
236 self.assertNotIn('[stdout:', io.stdout)
230 self.assertNotIn('[stdout:', io.stdout)
237 self.assertNotIn('\n\n', io.stdout)
231 self.assertNotIn('\n\n', io.stdout)
238
232
239 ar = ip.magic('px 1/0')
233 ar = ip.magic('px 1/0')
240 self.assertRaisesRemote(ZeroDivisionError, ar.get)
234 self.assertRaisesRemote(ZeroDivisionError, ar.get)
241
235
242 def test_autopx_blocking(self):
236 def test_autopx_blocking(self):
243 ip = get_ipython()
237 ip = get_ipython()
244 v = self.client[-1]
238 v = self.client[-1]
245 v.activate()
239 v.activate()
246 v.block=True
240 v.block=True
247
241
248 with capture_output(display=False) as io:
242 with capture_output(display=False) as io:
249 ip.magic('autopx')
243 ip.magic('autopx')
250 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
244 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
251 ip.run_cell('b*=2')
245 ip.run_cell('b*=2')
252 ip.run_cell('print (b)')
246 ip.run_cell('print (b)')
253 ip.run_cell('b')
247 ip.run_cell('b')
254 ip.run_cell("b/c")
248 ip.run_cell("b/c")
255 ip.magic('autopx')
249 ip.magic('autopx')
256
250
257 output = io.stdout
251 output = io.stdout
258
252
259 assert output.startswith('%autopx enabled'), output
253 assert output.startswith('%autopx enabled'), output
260 assert output.rstrip().endswith('%autopx disabled'), output
254 assert output.rstrip().endswith('%autopx disabled'), output
261 self.assertIn('ZeroDivisionError', output)
255 self.assertIn('ZeroDivisionError', output)
262 self.assertIn('\nOut[', output)
256 self.assertIn('\nOut[', output)
263 self.assertIn(': 24690', output)
257 self.assertIn(': 24690', output)
264 ar = v.get_result(-1)
258 ar = v.get_result(-1)
265 self.assertEqual(v['a'], 5)
259 self.assertEqual(v['a'], 5)
266 self.assertEqual(v['b'], 24690)
260 self.assertEqual(v['b'], 24690)
267 self.assertRaisesRemote(ZeroDivisionError, ar.get)
261 self.assertRaisesRemote(ZeroDivisionError, ar.get)
268
262
269 def test_autopx_nonblocking(self):
263 def test_autopx_nonblocking(self):
270 ip = get_ipython()
264 ip = get_ipython()
271 v = self.client[-1]
265 v = self.client[-1]
272 v.activate()
266 v.activate()
273 v.block=False
267 v.block=False
274
268
275 with capture_output() as io:
269 with capture_output() as io:
276 ip.magic('autopx')
270 ip.magic('autopx')
277 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
271 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
278 ip.run_cell('print (b)')
272 ip.run_cell('print (b)')
279 ip.run_cell('import time; time.sleep(0.1)')
273 ip.run_cell('import time; time.sleep(0.1)')
280 ip.run_cell("b/c")
274 ip.run_cell("b/c")
281 ip.run_cell('b*=2')
275 ip.run_cell('b*=2')
282 ip.magic('autopx')
276 ip.magic('autopx')
283
277
284 output = io.stdout.rstrip()
278 output = io.stdout.rstrip()
285
279
286 assert output.startswith('%autopx enabled'), output
280 assert output.startswith('%autopx enabled'), output
287 assert output.endswith('%autopx disabled'), output
281 assert output.endswith('%autopx disabled'), output
288 self.assertNotIn('ZeroDivisionError', output)
282 self.assertNotIn('ZeroDivisionError', output)
289 ar = v.get_result(-2)
283 ar = v.get_result(-2)
290 self.assertRaisesRemote(ZeroDivisionError, ar.get)
284 self.assertRaisesRemote(ZeroDivisionError, ar.get)
291 # prevent TaskAborted on pulls, due to ZeroDivisionError
285 # prevent TaskAborted on pulls, due to ZeroDivisionError
292 time.sleep(0.5)
286 time.sleep(0.5)
293 self.assertEqual(v['a'], 5)
287 self.assertEqual(v['a'], 5)
294 # b*=2 will not fire, due to abort
288 # b*=2 will not fire, due to abort
295 self.assertEqual(v['b'], 10)
289 self.assertEqual(v['b'], 10)
296
290
297 def test_result(self):
291 def test_result(self):
298 ip = get_ipython()
292 ip = get_ipython()
299 v = self.client[-1]
293 v = self.client[-1]
300 v.activate()
294 v.activate()
301 data = dict(a=111,b=222)
295 data = dict(a=111,b=222)
302 v.push(data, block=True)
296 v.push(data, block=True)
303
297
304 for name in ('a', 'b'):
298 for name in ('a', 'b'):
305 ip.magic('px ' + name)
299 ip.magic('px ' + name)
306 with capture_output(display=False) as io:
300 with capture_output(display=False) as io:
307 ip.magic('pxresult')
301 ip.magic('pxresult')
308 self.assertIn(str(data[name]), io.stdout)
302 self.assertIn(str(data[name]), io.stdout)
309
303
310 @dec.skipif_not_matplotlib
304 @dec.skipif_not_matplotlib
311 def test_px_pylab(self):
305 def test_px_pylab(self):
312 """%pylab works on engines"""
306 """%pylab works on engines"""
313 ip = get_ipython()
307 ip = get_ipython()
314 v = self.client[-1]
308 v = self.client[-1]
315 v.block = True
309 v.block = True
316 v.activate()
310 v.activate()
317
311
318 with capture_output() as io:
312 with capture_output() as io:
319 ip.magic("px %pylab inline")
313 ip.magic("px %pylab inline")
320
314
321 self.assertIn("Populating the interactive namespace from numpy and matplotlib", io.stdout)
315 self.assertIn("Populating the interactive namespace from numpy and matplotlib", io.stdout)
322
316
323 with capture_output(display=False) as io:
317 with capture_output(display=False) as io:
324 ip.magic("px plot(rand(100))")
318 ip.magic("px plot(rand(100))")
325 self.assertIn('Out[', io.stdout)
319 self.assertIn('Out[', io.stdout)
326 self.assertIn('matplotlib.lines', io.stdout)
320 self.assertIn('matplotlib.lines', io.stdout)
327
321
328 def test_pxconfig(self):
322 def test_pxconfig(self):
329 ip = get_ipython()
323 ip = get_ipython()
330 rc = self.client
324 rc = self.client
331 v = rc.activate(-1, '_tst')
325 v = rc.activate(-1, '_tst')
332 self.assertEqual(v.targets, rc.ids[-1])
326 self.assertEqual(v.targets, rc.ids[-1])
333 ip.magic("%pxconfig_tst -t :")
327 ip.magic("%pxconfig_tst -t :")
334 self.assertEqual(v.targets, rc.ids)
328 self.assertEqual(v.targets, rc.ids)
335 ip.magic("%pxconfig_tst -t ::2")
329 ip.magic("%pxconfig_tst -t ::2")
336 self.assertEqual(v.targets, rc.ids[::2])
330 self.assertEqual(v.targets, rc.ids[::2])
337 ip.magic("%pxconfig_tst -t 1::2")
331 ip.magic("%pxconfig_tst -t 1::2")
338 self.assertEqual(v.targets, rc.ids[1::2])
332 self.assertEqual(v.targets, rc.ids[1::2])
339 ip.magic("%pxconfig_tst -t 1")
333 ip.magic("%pxconfig_tst -t 1")
340 self.assertEqual(v.targets, 1)
334 self.assertEqual(v.targets, 1)
341 ip.magic("%pxconfig_tst --block")
335 ip.magic("%pxconfig_tst --block")
342 self.assertEqual(v.block, True)
336 self.assertEqual(v.block, True)
343 ip.magic("%pxconfig_tst --noblock")
337 ip.magic("%pxconfig_tst --noblock")
344 self.assertEqual(v.block, False)
338 self.assertEqual(v.block, False)
345
339
346 def test_cellpx_targets(self):
340 def test_cellpx_targets(self):
347 """%%px --targets doesn't change defaults"""
341 """%%px --targets doesn't change defaults"""
348 ip = get_ipython()
342 ip = get_ipython()
349 rc = self.client
343 rc = self.client
350 view = rc.activate(rc.ids)
344 view = rc.activate(rc.ids)
351 self.assertEqual(view.targets, rc.ids)
345 self.assertEqual(view.targets, rc.ids)
352 ip.magic('pxconfig --verbose')
346 ip.magic('pxconfig --verbose')
353 for cell in ("pass", "1/0"):
347 for cell in ("pass", "1/0"):
354 with capture_output(display=False) as io:
348 with capture_output(display=False) as io:
355 try:
349 try:
356 ip.run_cell_magic("px", "--targets all", cell)
350 ip.run_cell_magic("px", "--targets all", cell)
357 except pmod.RemoteError:
351 except pmod.RemoteError:
358 pass
352 pass
359 self.assertIn('engine(s): all', io.stdout)
353 self.assertIn('engine(s): all', io.stdout)
360 self.assertEqual(view.targets, rc.ids)
354 self.assertEqual(view.targets, rc.ids)
361
355
362
356
363 def test_cellpx_block(self):
357 def test_cellpx_block(self):
364 """%%px --block doesn't change default"""
358 """%%px --block doesn't change default"""
365 ip = get_ipython()
359 ip = get_ipython()
366 rc = self.client
360 rc = self.client
367 view = rc.activate(rc.ids)
361 view = rc.activate(rc.ids)
368 view.block = False
362 view.block = False
369 self.assertEqual(view.targets, rc.ids)
363 self.assertEqual(view.targets, rc.ids)
370 ip.magic('pxconfig --verbose')
364 ip.magic('pxconfig --verbose')
371 for cell in ("pass", "1/0"):
365 for cell in ("pass", "1/0"):
372 with capture_output(display=False) as io:
366 with capture_output(display=False) as io:
373 try:
367 try:
374 ip.run_cell_magic("px", "--block", cell)
368 ip.run_cell_magic("px", "--block", cell)
375 except pmod.RemoteError:
369 except pmod.RemoteError:
376 pass
370 pass
377 self.assertNotIn('Async', io.stdout)
371 self.assertNotIn('Async', io.stdout)
378 self.assertEqual(view.block, False)
372 self.assertEqual(view.block, False)
379
373
380
374
@@ -1,814 +1,808 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """test View objects
2 """test View objects
3
3
4 Authors:
4 Authors:
5
5
6 * Min RK
6 * Min RK
7 """
7 """
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 import base64
19 import base64
20 import sys
20 import sys
21 import platform
21 import platform
22 import time
22 import time
23 from collections import namedtuple
23 from collections import namedtuple
24 from tempfile import mktemp
24 from tempfile import mktemp
25 from StringIO import StringIO
26
25
27 import zmq
26 import zmq
28 from nose import SkipTest
29 from nose.plugins.attrib import attr
27 from nose.plugins.attrib import attr
30
28
31 from IPython.testing import decorators as dec
29 from IPython.testing import decorators as dec
32 from IPython.testing.ipunittest import ParametricTestCase
33 from IPython.utils.io import capture_output
30 from IPython.utils.io import capture_output
34
31
35 from IPython import parallel as pmod
32 from IPython import parallel as pmod
36 from IPython.parallel import error
33 from IPython.parallel import error
37 from IPython.parallel import AsyncResult, AsyncHubResult, AsyncMapResult
34 from IPython.parallel import AsyncResult, AsyncHubResult, AsyncMapResult
38 from IPython.parallel import DirectView
39 from IPython.parallel.util import interactive
35 from IPython.parallel.util import interactive
40
36
41 from IPython.parallel.tests import add_engines
37 from IPython.parallel.tests import add_engines
42
38
43 from .clienttest import ClusterTestCase, crash, wait, skip_without
39 from .clienttest import ClusterTestCase, crash, wait, skip_without
44
40
45 def setup():
41 def setup():
46 add_engines(3, total=True)
42 add_engines(3, total=True)
47
43
48 point = namedtuple("point", "x y")
44 point = namedtuple("point", "x y")
49
45
50 class TestView(ClusterTestCase, ParametricTestCase):
46 class TestView(ClusterTestCase):
51
47
52 def setUp(self):
48 def setUp(self):
53 # On Win XP, wait for resource cleanup, else parallel test group fails
49 # On Win XP, wait for resource cleanup, else parallel test group fails
54 if platform.system() == "Windows" and platform.win32_ver()[0] == "XP":
50 if platform.system() == "Windows" and platform.win32_ver()[0] == "XP":
55 # 1 sec fails. 1.5 sec seems ok. Using 2 sec for margin of safety
51 # 1 sec fails. 1.5 sec seems ok. Using 2 sec for margin of safety
56 time.sleep(2)
52 time.sleep(2)
57 super(TestView, self).setUp()
53 super(TestView, self).setUp()
58
54
59 @attr('crash')
55 @attr('crash')
60 def test_z_crash_mux(self):
56 def test_z_crash_mux(self):
61 """test graceful handling of engine death (direct)"""
57 """test graceful handling of engine death (direct)"""
62 # self.add_engines(1)
58 # self.add_engines(1)
63 eid = self.client.ids[-1]
59 eid = self.client.ids[-1]
64 ar = self.client[eid].apply_async(crash)
60 ar = self.client[eid].apply_async(crash)
65 self.assertRaisesRemote(error.EngineError, ar.get, 10)
61 self.assertRaisesRemote(error.EngineError, ar.get, 10)
66 eid = ar.engine_id
62 eid = ar.engine_id
67 tic = time.time()
63 tic = time.time()
68 while eid in self.client.ids and time.time()-tic < 5:
64 while eid in self.client.ids and time.time()-tic < 5:
69 time.sleep(.01)
65 time.sleep(.01)
70 self.client.spin()
66 self.client.spin()
71 self.assertFalse(eid in self.client.ids, "Engine should have died")
67 self.assertFalse(eid in self.client.ids, "Engine should have died")
72
68
73 def test_push_pull(self):
69 def test_push_pull(self):
74 """test pushing and pulling"""
70 """test pushing and pulling"""
75 data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'})
71 data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'})
76 t = self.client.ids[-1]
72 t = self.client.ids[-1]
77 v = self.client[t]
73 v = self.client[t]
78 push = v.push
74 push = v.push
79 pull = v.pull
75 pull = v.pull
80 v.block=True
76 v.block=True
81 nengines = len(self.client)
77 nengines = len(self.client)
82 push({'data':data})
78 push({'data':data})
83 d = pull('data')
79 d = pull('data')
84 self.assertEqual(d, data)
80 self.assertEqual(d, data)
85 self.client[:].push({'data':data})
81 self.client[:].push({'data':data})
86 d = self.client[:].pull('data', block=True)
82 d = self.client[:].pull('data', block=True)
87 self.assertEqual(d, nengines*[data])
83 self.assertEqual(d, nengines*[data])
88 ar = push({'data':data}, block=False)
84 ar = push({'data':data}, block=False)
89 self.assertTrue(isinstance(ar, AsyncResult))
85 self.assertTrue(isinstance(ar, AsyncResult))
90 r = ar.get()
86 r = ar.get()
91 ar = self.client[:].pull('data', block=False)
87 ar = self.client[:].pull('data', block=False)
92 self.assertTrue(isinstance(ar, AsyncResult))
88 self.assertTrue(isinstance(ar, AsyncResult))
93 r = ar.get()
89 r = ar.get()
94 self.assertEqual(r, nengines*[data])
90 self.assertEqual(r, nengines*[data])
95 self.client[:].push(dict(a=10,b=20))
91 self.client[:].push(dict(a=10,b=20))
96 r = self.client[:].pull(('a','b'), block=True)
92 r = self.client[:].pull(('a','b'), block=True)
97 self.assertEqual(r, nengines*[[10,20]])
93 self.assertEqual(r, nengines*[[10,20]])
98
94
99 def test_push_pull_function(self):
95 def test_push_pull_function(self):
100 "test pushing and pulling functions"
96 "test pushing and pulling functions"
101 def testf(x):
97 def testf(x):
102 return 2.0*x
98 return 2.0*x
103
99
104 t = self.client.ids[-1]
100 t = self.client.ids[-1]
105 v = self.client[t]
101 v = self.client[t]
106 v.block=True
102 v.block=True
107 push = v.push
103 push = v.push
108 pull = v.pull
104 pull = v.pull
109 execute = v.execute
105 execute = v.execute
110 push({'testf':testf})
106 push({'testf':testf})
111 r = pull('testf')
107 r = pull('testf')
112 self.assertEqual(r(1.0), testf(1.0))
108 self.assertEqual(r(1.0), testf(1.0))
113 execute('r = testf(10)')
109 execute('r = testf(10)')
114 r = pull('r')
110 r = pull('r')
115 self.assertEqual(r, testf(10))
111 self.assertEqual(r, testf(10))
116 ar = self.client[:].push({'testf':testf}, block=False)
112 ar = self.client[:].push({'testf':testf}, block=False)
117 ar.get()
113 ar.get()
118 ar = self.client[:].pull('testf', block=False)
114 ar = self.client[:].pull('testf', block=False)
119 rlist = ar.get()
115 rlist = ar.get()
120 for r in rlist:
116 for r in rlist:
121 self.assertEqual(r(1.0), testf(1.0))
117 self.assertEqual(r(1.0), testf(1.0))
122 execute("def g(x): return x*x")
118 execute("def g(x): return x*x")
123 r = pull(('testf','g'))
119 r = pull(('testf','g'))
124 self.assertEqual((r[0](10),r[1](10)), (testf(10), 100))
120 self.assertEqual((r[0](10),r[1](10)), (testf(10), 100))
125
121
126 def test_push_function_globals(self):
122 def test_push_function_globals(self):
127 """test that pushed functions have access to globals"""
123 """test that pushed functions have access to globals"""
128 @interactive
124 @interactive
129 def geta():
125 def geta():
130 return a
126 return a
131 # self.add_engines(1)
127 # self.add_engines(1)
132 v = self.client[-1]
128 v = self.client[-1]
133 v.block=True
129 v.block=True
134 v['f'] = geta
130 v['f'] = geta
135 self.assertRaisesRemote(NameError, v.execute, 'b=f()')
131 self.assertRaisesRemote(NameError, v.execute, 'b=f()')
136 v.execute('a=5')
132 v.execute('a=5')
137 v.execute('b=f()')
133 v.execute('b=f()')
138 self.assertEqual(v['b'], 5)
134 self.assertEqual(v['b'], 5)
139
135
140 def test_push_function_defaults(self):
136 def test_push_function_defaults(self):
141 """test that pushed functions preserve default args"""
137 """test that pushed functions preserve default args"""
142 def echo(a=10):
138 def echo(a=10):
143 return a
139 return a
144 v = self.client[-1]
140 v = self.client[-1]
145 v.block=True
141 v.block=True
146 v['f'] = echo
142 v['f'] = echo
147 v.execute('b=f()')
143 v.execute('b=f()')
148 self.assertEqual(v['b'], 10)
144 self.assertEqual(v['b'], 10)
149
145
150 def test_get_result(self):
146 def test_get_result(self):
151 """test getting results from the Hub."""
147 """test getting results from the Hub."""
152 c = pmod.Client(profile='iptest')
148 c = pmod.Client(profile='iptest')
153 # self.add_engines(1)
149 # self.add_engines(1)
154 t = c.ids[-1]
150 t = c.ids[-1]
155 v = c[t]
151 v = c[t]
156 v2 = self.client[t]
152 v2 = self.client[t]
157 ar = v.apply_async(wait, 1)
153 ar = v.apply_async(wait, 1)
158 # give the monitor time to notice the message
154 # give the monitor time to notice the message
159 time.sleep(.25)
155 time.sleep(.25)
160 ahr = v2.get_result(ar.msg_ids[0])
156 ahr = v2.get_result(ar.msg_ids[0])
161 self.assertTrue(isinstance(ahr, AsyncHubResult))
157 self.assertTrue(isinstance(ahr, AsyncHubResult))
162 self.assertEqual(ahr.get(), ar.get())
158 self.assertEqual(ahr.get(), ar.get())
163 ar2 = v2.get_result(ar.msg_ids[0])
159 ar2 = v2.get_result(ar.msg_ids[0])
164 self.assertFalse(isinstance(ar2, AsyncHubResult))
160 self.assertFalse(isinstance(ar2, AsyncHubResult))
165 c.spin()
161 c.spin()
166 c.close()
162 c.close()
167
163
168 def test_run_newline(self):
164 def test_run_newline(self):
169 """test that run appends newline to files"""
165 """test that run appends newline to files"""
170 tmpfile = mktemp()
166 tmpfile = mktemp()
171 with open(tmpfile, 'w') as f:
167 with open(tmpfile, 'w') as f:
172 f.write("""def g():
168 f.write("""def g():
173 return 5
169 return 5
174 """)
170 """)
175 v = self.client[-1]
171 v = self.client[-1]
176 v.run(tmpfile, block=True)
172 v.run(tmpfile, block=True)
177 self.assertEqual(v.apply_sync(lambda f: f(), pmod.Reference('g')), 5)
173 self.assertEqual(v.apply_sync(lambda f: f(), pmod.Reference('g')), 5)
178
174
179 def test_apply_tracked(self):
175 def test_apply_tracked(self):
180 """test tracking for apply"""
176 """test tracking for apply"""
181 # self.add_engines(1)
177 # self.add_engines(1)
182 t = self.client.ids[-1]
178 t = self.client.ids[-1]
183 v = self.client[t]
179 v = self.client[t]
184 v.block=False
180 v.block=False
185 def echo(n=1024*1024, **kwargs):
181 def echo(n=1024*1024, **kwargs):
186 with v.temp_flags(**kwargs):
182 with v.temp_flags(**kwargs):
187 return v.apply(lambda x: x, 'x'*n)
183 return v.apply(lambda x: x, 'x'*n)
188 ar = echo(1, track=False)
184 ar = echo(1, track=False)
189 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
185 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
190 self.assertTrue(ar.sent)
186 self.assertTrue(ar.sent)
191 ar = echo(track=True)
187 ar = echo(track=True)
192 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
188 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
193 self.assertEqual(ar.sent, ar._tracker.done)
189 self.assertEqual(ar.sent, ar._tracker.done)
194 ar._tracker.wait()
190 ar._tracker.wait()
195 self.assertTrue(ar.sent)
191 self.assertTrue(ar.sent)
196
192
197 def test_push_tracked(self):
193 def test_push_tracked(self):
198 t = self.client.ids[-1]
194 t = self.client.ids[-1]
199 ns = dict(x='x'*1024*1024)
195 ns = dict(x='x'*1024*1024)
200 v = self.client[t]
196 v = self.client[t]
201 ar = v.push(ns, block=False, track=False)
197 ar = v.push(ns, block=False, track=False)
202 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
198 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
203 self.assertTrue(ar.sent)
199 self.assertTrue(ar.sent)
204
200
205 ar = v.push(ns, block=False, track=True)
201 ar = v.push(ns, block=False, track=True)
206 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
202 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
207 ar._tracker.wait()
203 ar._tracker.wait()
208 self.assertEqual(ar.sent, ar._tracker.done)
204 self.assertEqual(ar.sent, ar._tracker.done)
209 self.assertTrue(ar.sent)
205 self.assertTrue(ar.sent)
210 ar.get()
206 ar.get()
211
207
212 def test_scatter_tracked(self):
208 def test_scatter_tracked(self):
213 t = self.client.ids
209 t = self.client.ids
214 x='x'*1024*1024
210 x='x'*1024*1024
215 ar = self.client[t].scatter('x', x, block=False, track=False)
211 ar = self.client[t].scatter('x', x, block=False, track=False)
216 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
212 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
217 self.assertTrue(ar.sent)
213 self.assertTrue(ar.sent)
218
214
219 ar = self.client[t].scatter('x', x, block=False, track=True)
215 ar = self.client[t].scatter('x', x, block=False, track=True)
220 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
216 self.assertTrue(isinstance(ar._tracker, zmq.MessageTracker))
221 self.assertEqual(ar.sent, ar._tracker.done)
217 self.assertEqual(ar.sent, ar._tracker.done)
222 ar._tracker.wait()
218 ar._tracker.wait()
223 self.assertTrue(ar.sent)
219 self.assertTrue(ar.sent)
224 ar.get()
220 ar.get()
225
221
226 def test_remote_reference(self):
222 def test_remote_reference(self):
227 v = self.client[-1]
223 v = self.client[-1]
228 v['a'] = 123
224 v['a'] = 123
229 ra = pmod.Reference('a')
225 ra = pmod.Reference('a')
230 b = v.apply_sync(lambda x: x, ra)
226 b = v.apply_sync(lambda x: x, ra)
231 self.assertEqual(b, 123)
227 self.assertEqual(b, 123)
232
228
233
229
234 def test_scatter_gather(self):
230 def test_scatter_gather(self):
235 view = self.client[:]
231 view = self.client[:]
236 seq1 = range(16)
232 seq1 = range(16)
237 view.scatter('a', seq1)
233 view.scatter('a', seq1)
238 seq2 = view.gather('a', block=True)
234 seq2 = view.gather('a', block=True)
239 self.assertEqual(seq2, seq1)
235 self.assertEqual(seq2, seq1)
240 self.assertRaisesRemote(NameError, view.gather, 'asdf', block=True)
236 self.assertRaisesRemote(NameError, view.gather, 'asdf', block=True)
241
237
242 @skip_without('numpy')
238 @skip_without('numpy')
243 def test_scatter_gather_numpy(self):
239 def test_scatter_gather_numpy(self):
244 import numpy
240 import numpy
245 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
241 from numpy.testing.utils import assert_array_equal
246 view = self.client[:]
242 view = self.client[:]
247 a = numpy.arange(64)
243 a = numpy.arange(64)
248 view.scatter('a', a, block=True)
244 view.scatter('a', a, block=True)
249 b = view.gather('a', block=True)
245 b = view.gather('a', block=True)
250 assert_array_equal(b, a)
246 assert_array_equal(b, a)
251
247
252 def test_scatter_gather_lazy(self):
248 def test_scatter_gather_lazy(self):
253 """scatter/gather with targets='all'"""
249 """scatter/gather with targets='all'"""
254 view = self.client.direct_view(targets='all')
250 view = self.client.direct_view(targets='all')
255 x = range(64)
251 x = range(64)
256 view.scatter('x', x)
252 view.scatter('x', x)
257 gathered = view.gather('x', block=True)
253 gathered = view.gather('x', block=True)
258 self.assertEqual(gathered, x)
254 self.assertEqual(gathered, x)
259
255
260
256
261 @dec.known_failure_py3
257 @dec.known_failure_py3
262 @skip_without('numpy')
258 @skip_without('numpy')
263 def test_push_numpy_nocopy(self):
259 def test_push_numpy_nocopy(self):
264 import numpy
260 import numpy
265 view = self.client[:]
261 view = self.client[:]
266 a = numpy.arange(64)
262 a = numpy.arange(64)
267 view['A'] = a
263 view['A'] = a
268 @interactive
264 @interactive
269 def check_writeable(x):
265 def check_writeable(x):
270 return x.flags.writeable
266 return x.flags.writeable
271
267
272 for flag in view.apply_sync(check_writeable, pmod.Reference('A')):
268 for flag in view.apply_sync(check_writeable, pmod.Reference('A')):
273 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
269 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
274
270
275 view.push(dict(B=a))
271 view.push(dict(B=a))
276 for flag in view.apply_sync(check_writeable, pmod.Reference('B')):
272 for flag in view.apply_sync(check_writeable, pmod.Reference('B')):
277 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
273 self.assertFalse(flag, "array is writeable, push shouldn't have pickled it")
278
274
279 @skip_without('numpy')
275 @skip_without('numpy')
280 def test_apply_numpy(self):
276 def test_apply_numpy(self):
281 """view.apply(f, ndarray)"""
277 """view.apply(f, ndarray)"""
282 import numpy
278 import numpy
283 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
279 from numpy.testing.utils import assert_array_equal
284
280
285 A = numpy.random.random((100,100))
281 A = numpy.random.random((100,100))
286 view = self.client[-1]
282 view = self.client[-1]
287 for dt in [ 'int32', 'uint8', 'float32', 'float64' ]:
283 for dt in [ 'int32', 'uint8', 'float32', 'float64' ]:
288 B = A.astype(dt)
284 B = A.astype(dt)
289 C = view.apply_sync(lambda x:x, B)
285 C = view.apply_sync(lambda x:x, B)
290 assert_array_equal(B,C)
286 assert_array_equal(B,C)
291
287
292 @skip_without('numpy')
288 @skip_without('numpy')
293 def test_push_pull_recarray(self):
289 def test_push_pull_recarray(self):
294 """push/pull recarrays"""
290 """push/pull recarrays"""
295 import numpy
291 import numpy
296 from numpy.testing.utils import assert_array_equal
292 from numpy.testing.utils import assert_array_equal
297
293
298 view = self.client[-1]
294 view = self.client[-1]
299
295
300 R = numpy.array([
296 R = numpy.array([
301 (1, 'hi', 0.),
297 (1, 'hi', 0.),
302 (2**30, 'there', 2.5),
298 (2**30, 'there', 2.5),
303 (-99999, 'world', -12345.6789),
299 (-99999, 'world', -12345.6789),
304 ], [('n', int), ('s', '|S10'), ('f', float)])
300 ], [('n', int), ('s', '|S10'), ('f', float)])
305
301
306 view['RR'] = R
302 view['RR'] = R
307 R2 = view['RR']
303 R2 = view['RR']
308
304
309 r_dtype, r_shape = view.apply_sync(interactive(lambda : (RR.dtype, RR.shape)))
305 r_dtype, r_shape = view.apply_sync(interactive(lambda : (RR.dtype, RR.shape)))
310 self.assertEqual(r_dtype, R.dtype)
306 self.assertEqual(r_dtype, R.dtype)
311 self.assertEqual(r_shape, R.shape)
307 self.assertEqual(r_shape, R.shape)
312 self.assertEqual(R2.dtype, R.dtype)
308 self.assertEqual(R2.dtype, R.dtype)
313 self.assertEqual(R2.shape, R.shape)
309 self.assertEqual(R2.shape, R.shape)
314 assert_array_equal(R2, R)
310 assert_array_equal(R2, R)
315
311
316 @skip_without('pandas')
312 @skip_without('pandas')
317 def test_push_pull_timeseries(self):
313 def test_push_pull_timeseries(self):
318 """push/pull pandas.TimeSeries"""
314 """push/pull pandas.TimeSeries"""
319 import pandas
315 import pandas
320
316
321 ts = pandas.TimeSeries(range(10))
317 ts = pandas.TimeSeries(range(10))
322
318
323 view = self.client[-1]
319 view = self.client[-1]
324
320
325 view.push(dict(ts=ts), block=True)
321 view.push(dict(ts=ts), block=True)
326 rts = view['ts']
322 rts = view['ts']
327
323
328 self.assertEqual(type(rts), type(ts))
324 self.assertEqual(type(rts), type(ts))
329 self.assertTrue((ts == rts).all())
325 self.assertTrue((ts == rts).all())
330
326
331 def test_map(self):
327 def test_map(self):
332 view = self.client[:]
328 view = self.client[:]
333 def f(x):
329 def f(x):
334 return x**2
330 return x**2
335 data = range(16)
331 data = range(16)
336 r = view.map_sync(f, data)
332 r = view.map_sync(f, data)
337 self.assertEqual(r, map(f, data))
333 self.assertEqual(r, map(f, data))
338
334
339 def test_map_iterable(self):
335 def test_map_iterable(self):
340 """test map on iterables (direct)"""
336 """test map on iterables (direct)"""
341 view = self.client[:]
337 view = self.client[:]
342 # 101 is prime, so it won't be evenly distributed
338 # 101 is prime, so it won't be evenly distributed
343 arr = range(101)
339 arr = range(101)
344 # ensure it will be an iterator, even in Python 3
340 # ensure it will be an iterator, even in Python 3
345 it = iter(arr)
341 it = iter(arr)
346 r = view.map_sync(lambda x: x, it)
342 r = view.map_sync(lambda x: x, it)
347 self.assertEqual(r, list(arr))
343 self.assertEqual(r, list(arr))
348
344
349 @skip_without('numpy')
345 @skip_without('numpy')
350 def test_map_numpy(self):
346 def test_map_numpy(self):
351 """test map on numpy arrays (direct)"""
347 """test map on numpy arrays (direct)"""
352 import numpy
348 import numpy
353 from numpy.testing.utils import assert_array_equal
349 from numpy.testing.utils import assert_array_equal
354
350
355 view = self.client[:]
351 view = self.client[:]
356 # 101 is prime, so it won't be evenly distributed
352 # 101 is prime, so it won't be evenly distributed
357 arr = numpy.arange(101)
353 arr = numpy.arange(101)
358 r = view.map_sync(lambda x: x, arr)
354 r = view.map_sync(lambda x: x, arr)
359 assert_array_equal(r, arr)
355 assert_array_equal(r, arr)
360
356
361 def test_scatter_gather_nonblocking(self):
357 def test_scatter_gather_nonblocking(self):
362 data = range(16)
358 data = range(16)
363 view = self.client[:]
359 view = self.client[:]
364 view.scatter('a', data, block=False)
360 view.scatter('a', data, block=False)
365 ar = view.gather('a', block=False)
361 ar = view.gather('a', block=False)
366 self.assertEqual(ar.get(), data)
362 self.assertEqual(ar.get(), data)
367
363
368 @skip_without('numpy')
364 @skip_without('numpy')
369 def test_scatter_gather_numpy_nonblocking(self):
365 def test_scatter_gather_numpy_nonblocking(self):
370 import numpy
366 import numpy
371 from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
367 from numpy.testing.utils import assert_array_equal
372 a = numpy.arange(64)
368 a = numpy.arange(64)
373 view = self.client[:]
369 view = self.client[:]
374 ar = view.scatter('a', a, block=False)
370 ar = view.scatter('a', a, block=False)
375 self.assertTrue(isinstance(ar, AsyncResult))
371 self.assertTrue(isinstance(ar, AsyncResult))
376 amr = view.gather('a', block=False)
372 amr = view.gather('a', block=False)
377 self.assertTrue(isinstance(amr, AsyncMapResult))
373 self.assertTrue(isinstance(amr, AsyncMapResult))
378 assert_array_equal(amr.get(), a)
374 assert_array_equal(amr.get(), a)
379
375
380 def test_execute(self):
376 def test_execute(self):
381 view = self.client[:]
377 view = self.client[:]
382 # self.client.debug=True
378 # self.client.debug=True
383 execute = view.execute
379 execute = view.execute
384 ar = execute('c=30', block=False)
380 ar = execute('c=30', block=False)
385 self.assertTrue(isinstance(ar, AsyncResult))
381 self.assertTrue(isinstance(ar, AsyncResult))
386 ar = execute('d=[0,1,2]', block=False)
382 ar = execute('d=[0,1,2]', block=False)
387 self.client.wait(ar, 1)
383 self.client.wait(ar, 1)
388 self.assertEqual(len(ar.get()), len(self.client))
384 self.assertEqual(len(ar.get()), len(self.client))
389 for c in view['c']:
385 for c in view['c']:
390 self.assertEqual(c, 30)
386 self.assertEqual(c, 30)
391
387
392 def test_abort(self):
388 def test_abort(self):
393 view = self.client[-1]
389 view = self.client[-1]
394 ar = view.execute('import time; time.sleep(1)', block=False)
390 ar = view.execute('import time; time.sleep(1)', block=False)
395 ar2 = view.apply_async(lambda : 2)
391 ar2 = view.apply_async(lambda : 2)
396 ar3 = view.apply_async(lambda : 3)
392 ar3 = view.apply_async(lambda : 3)
397 view.abort(ar2)
393 view.abort(ar2)
398 view.abort(ar3.msg_ids)
394 view.abort(ar3.msg_ids)
399 self.assertRaises(error.TaskAborted, ar2.get)
395 self.assertRaises(error.TaskAborted, ar2.get)
400 self.assertRaises(error.TaskAborted, ar3.get)
396 self.assertRaises(error.TaskAborted, ar3.get)
401
397
402 def test_abort_all(self):
398 def test_abort_all(self):
403 """view.abort() aborts all outstanding tasks"""
399 """view.abort() aborts all outstanding tasks"""
404 view = self.client[-1]
400 view = self.client[-1]
405 ars = [ view.apply_async(time.sleep, 0.25) for i in range(10) ]
401 ars = [ view.apply_async(time.sleep, 0.25) for i in range(10) ]
406 view.abort()
402 view.abort()
407 view.wait(timeout=5)
403 view.wait(timeout=5)
408 for ar in ars[5:]:
404 for ar in ars[5:]:
409 self.assertRaises(error.TaskAborted, ar.get)
405 self.assertRaises(error.TaskAborted, ar.get)
410
406
411 def test_temp_flags(self):
407 def test_temp_flags(self):
412 view = self.client[-1]
408 view = self.client[-1]
413 view.block=True
409 view.block=True
414 with view.temp_flags(block=False):
410 with view.temp_flags(block=False):
415 self.assertFalse(view.block)
411 self.assertFalse(view.block)
416 self.assertTrue(view.block)
412 self.assertTrue(view.block)
417
413
418 @dec.known_failure_py3
414 @dec.known_failure_py3
419 def test_importer(self):
415 def test_importer(self):
420 view = self.client[-1]
416 view = self.client[-1]
421 view.clear(block=True)
417 view.clear(block=True)
422 with view.importer:
418 with view.importer:
423 import re
419 import re
424
420
425 @interactive
421 @interactive
426 def findall(pat, s):
422 def findall(pat, s):
427 # this globals() step isn't necessary in real code
423 # this globals() step isn't necessary in real code
428 # only to prevent a closure in the test
424 # only to prevent a closure in the test
429 re = globals()['re']
425 re = globals()['re']
430 return re.findall(pat, s)
426 return re.findall(pat, s)
431
427
432 self.assertEqual(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
428 self.assertEqual(view.apply_sync(findall, '\w+', 'hello world'), 'hello world'.split())
433
429
434 def test_unicode_execute(self):
430 def test_unicode_execute(self):
435 """test executing unicode strings"""
431 """test executing unicode strings"""
436 v = self.client[-1]
432 v = self.client[-1]
437 v.block=True
433 v.block=True
438 if sys.version_info[0] >= 3:
434 if sys.version_info[0] >= 3:
439 code="a='é'"
435 code="a='é'"
440 else:
436 else:
441 code=u"a=u'é'"
437 code=u"a=u'é'"
442 v.execute(code)
438 v.execute(code)
443 self.assertEqual(v['a'], u'é')
439 self.assertEqual(v['a'], u'é')
444
440
445 def test_unicode_apply_result(self):
441 def test_unicode_apply_result(self):
446 """test unicode apply results"""
442 """test unicode apply results"""
447 v = self.client[-1]
443 v = self.client[-1]
448 r = v.apply_sync(lambda : u'é')
444 r = v.apply_sync(lambda : u'é')
449 self.assertEqual(r, u'é')
445 self.assertEqual(r, u'é')
450
446
451 def test_unicode_apply_arg(self):
447 def test_unicode_apply_arg(self):
452 """test passing unicode arguments to apply"""
448 """test passing unicode arguments to apply"""
453 v = self.client[-1]
449 v = self.client[-1]
454
450
455 @interactive
451 @interactive
456 def check_unicode(a, check):
452 def check_unicode(a, check):
457 assert isinstance(a, unicode), "%r is not unicode"%a
453 assert isinstance(a, unicode), "%r is not unicode"%a
458 assert isinstance(check, bytes), "%r is not bytes"%check
454 assert isinstance(check, bytes), "%r is not bytes"%check
459 assert a.encode('utf8') == check, "%s != %s"%(a,check)
455 assert a.encode('utf8') == check, "%s != %s"%(a,check)
460
456
461 for s in [ u'é', u'ßø®∫',u'asdf' ]:
457 for s in [ u'é', u'ßø®∫',u'asdf' ]:
462 try:
458 try:
463 v.apply_sync(check_unicode, s, s.encode('utf8'))
459 v.apply_sync(check_unicode, s, s.encode('utf8'))
464 except error.RemoteError as e:
460 except error.RemoteError as e:
465 if e.ename == 'AssertionError':
461 if e.ename == 'AssertionError':
466 self.fail(e.evalue)
462 self.fail(e.evalue)
467 else:
463 else:
468 raise e
464 raise e
469
465
470 def test_map_reference(self):
466 def test_map_reference(self):
471 """view.map(<Reference>, *seqs) should work"""
467 """view.map(<Reference>, *seqs) should work"""
472 v = self.client[:]
468 v = self.client[:]
473 v.scatter('n', self.client.ids, flatten=True)
469 v.scatter('n', self.client.ids, flatten=True)
474 v.execute("f = lambda x,y: x*y")
470 v.execute("f = lambda x,y: x*y")
475 rf = pmod.Reference('f')
471 rf = pmod.Reference('f')
476 nlist = list(range(10))
472 nlist = list(range(10))
477 mlist = nlist[::-1]
473 mlist = nlist[::-1]
478 expected = [ m*n for m,n in zip(mlist, nlist) ]
474 expected = [ m*n for m,n in zip(mlist, nlist) ]
479 result = v.map_sync(rf, mlist, nlist)
475 result = v.map_sync(rf, mlist, nlist)
480 self.assertEqual(result, expected)
476 self.assertEqual(result, expected)
481
477
482 def test_apply_reference(self):
478 def test_apply_reference(self):
483 """view.apply(<Reference>, *args) should work"""
479 """view.apply(<Reference>, *args) should work"""
484 v = self.client[:]
480 v = self.client[:]
485 v.scatter('n', self.client.ids, flatten=True)
481 v.scatter('n', self.client.ids, flatten=True)
486 v.execute("f = lambda x: n*x")
482 v.execute("f = lambda x: n*x")
487 rf = pmod.Reference('f')
483 rf = pmod.Reference('f')
488 result = v.apply_sync(rf, 5)
484 result = v.apply_sync(rf, 5)
489 expected = [ 5*id for id in self.client.ids ]
485 expected = [ 5*id for id in self.client.ids ]
490 self.assertEqual(result, expected)
486 self.assertEqual(result, expected)
491
487
492 def test_eval_reference(self):
488 def test_eval_reference(self):
493 v = self.client[self.client.ids[0]]
489 v = self.client[self.client.ids[0]]
494 v['g'] = range(5)
490 v['g'] = range(5)
495 rg = pmod.Reference('g[0]')
491 rg = pmod.Reference('g[0]')
496 echo = lambda x:x
492 echo = lambda x:x
497 self.assertEqual(v.apply_sync(echo, rg), 0)
493 self.assertEqual(v.apply_sync(echo, rg), 0)
498
494
499 def test_reference_nameerror(self):
495 def test_reference_nameerror(self):
500 v = self.client[self.client.ids[0]]
496 v = self.client[self.client.ids[0]]
501 r = pmod.Reference('elvis_has_left')
497 r = pmod.Reference('elvis_has_left')
502 echo = lambda x:x
498 echo = lambda x:x
503 self.assertRaisesRemote(NameError, v.apply_sync, echo, r)
499 self.assertRaisesRemote(NameError, v.apply_sync, echo, r)
504
500
505 def test_single_engine_map(self):
501 def test_single_engine_map(self):
506 e0 = self.client[self.client.ids[0]]
502 e0 = self.client[self.client.ids[0]]
507 r = range(5)
503 r = range(5)
508 check = [ -1*i for i in r ]
504 check = [ -1*i for i in r ]
509 result = e0.map_sync(lambda x: -1*x, r)
505 result = e0.map_sync(lambda x: -1*x, r)
510 self.assertEqual(result, check)
506 self.assertEqual(result, check)
511
507
512 def test_len(self):
508 def test_len(self):
513 """len(view) makes sense"""
509 """len(view) makes sense"""
514 e0 = self.client[self.client.ids[0]]
510 e0 = self.client[self.client.ids[0]]
515 yield self.assertEqual(len(e0), 1)
511 self.assertEqual(len(e0), 1)
516 v = self.client[:]
512 v = self.client[:]
517 yield self.assertEqual(len(v), len(self.client.ids))
513 self.assertEqual(len(v), len(self.client.ids))
518 v = self.client.direct_view('all')
514 v = self.client.direct_view('all')
519 yield self.assertEqual(len(v), len(self.client.ids))
515 self.assertEqual(len(v), len(self.client.ids))
520 v = self.client[:2]
516 v = self.client[:2]
521 yield self.assertEqual(len(v), 2)
517 self.assertEqual(len(v), 2)
522 v = self.client[:1]
518 v = self.client[:1]
523 yield self.assertEqual(len(v), 1)
519 self.assertEqual(len(v), 1)
524 v = self.client.load_balanced_view()
520 v = self.client.load_balanced_view()
525 yield self.assertEqual(len(v), len(self.client.ids))
521 self.assertEqual(len(v), len(self.client.ids))
526 # parametric tests seem to require manual closing?
527 self.client.close()
528
522
529
523
530 # begin execute tests
524 # begin execute tests
531
525
532 def test_execute_reply(self):
526 def test_execute_reply(self):
533 e0 = self.client[self.client.ids[0]]
527 e0 = self.client[self.client.ids[0]]
534 e0.block = True
528 e0.block = True
535 ar = e0.execute("5", silent=False)
529 ar = e0.execute("5", silent=False)
536 er = ar.get()
530 er = ar.get()
537 self.assertEqual(str(er), "<ExecuteReply[%i]: 5>" % er.execution_count)
531 self.assertEqual(str(er), "<ExecuteReply[%i]: 5>" % er.execution_count)
538 self.assertEqual(er.pyout['data']['text/plain'], '5')
532 self.assertEqual(er.pyout['data']['text/plain'], '5')
539
533
540 def test_execute_reply_rich(self):
534 def test_execute_reply_rich(self):
541 e0 = self.client[self.client.ids[0]]
535 e0 = self.client[self.client.ids[0]]
542 e0.block = True
536 e0.block = True
543 e0.execute("from IPython.display import Image, HTML")
537 e0.execute("from IPython.display import Image, HTML")
544 ar = e0.execute("Image(data=b'garbage', format='png', width=10)", silent=False)
538 ar = e0.execute("Image(data=b'garbage', format='png', width=10)", silent=False)
545 er = ar.get()
539 er = ar.get()
546 b64data = base64.encodestring(b'garbage').decode('ascii')
540 b64data = base64.encodestring(b'garbage').decode('ascii')
547 self.assertEqual(er._repr_png_(), (b64data, dict(width=10)))
541 self.assertEqual(er._repr_png_(), (b64data, dict(width=10)))
548 ar = e0.execute("HTML('<b>bold</b>')", silent=False)
542 ar = e0.execute("HTML('<b>bold</b>')", silent=False)
549 er = ar.get()
543 er = ar.get()
550 self.assertEqual(er._repr_html_(), "<b>bold</b>")
544 self.assertEqual(er._repr_html_(), "<b>bold</b>")
551
545
552 def test_execute_reply_stdout(self):
546 def test_execute_reply_stdout(self):
553 e0 = self.client[self.client.ids[0]]
547 e0 = self.client[self.client.ids[0]]
554 e0.block = True
548 e0.block = True
555 ar = e0.execute("print (5)", silent=False)
549 ar = e0.execute("print (5)", silent=False)
556 er = ar.get()
550 er = ar.get()
557 self.assertEqual(er.stdout.strip(), '5')
551 self.assertEqual(er.stdout.strip(), '5')
558
552
559 def test_execute_pyout(self):
553 def test_execute_pyout(self):
560 """execute triggers pyout with silent=False"""
554 """execute triggers pyout with silent=False"""
561 view = self.client[:]
555 view = self.client[:]
562 ar = view.execute("5", silent=False, block=True)
556 ar = view.execute("5", silent=False, block=True)
563
557
564 expected = [{'text/plain' : '5'}] * len(view)
558 expected = [{'text/plain' : '5'}] * len(view)
565 mimes = [ out['data'] for out in ar.pyout ]
559 mimes = [ out['data'] for out in ar.pyout ]
566 self.assertEqual(mimes, expected)
560 self.assertEqual(mimes, expected)
567
561
568 def test_execute_silent(self):
562 def test_execute_silent(self):
569 """execute does not trigger pyout with silent=True"""
563 """execute does not trigger pyout with silent=True"""
570 view = self.client[:]
564 view = self.client[:]
571 ar = view.execute("5", block=True)
565 ar = view.execute("5", block=True)
572 expected = [None] * len(view)
566 expected = [None] * len(view)
573 self.assertEqual(ar.pyout, expected)
567 self.assertEqual(ar.pyout, expected)
574
568
575 def test_execute_magic(self):
569 def test_execute_magic(self):
576 """execute accepts IPython commands"""
570 """execute accepts IPython commands"""
577 view = self.client[:]
571 view = self.client[:]
578 view.execute("a = 5")
572 view.execute("a = 5")
579 ar = view.execute("%whos", block=True)
573 ar = view.execute("%whos", block=True)
580 # this will raise, if that failed
574 # this will raise, if that failed
581 ar.get(5)
575 ar.get(5)
582 for stdout in ar.stdout:
576 for stdout in ar.stdout:
583 lines = stdout.splitlines()
577 lines = stdout.splitlines()
584 self.assertEqual(lines[0].split(), ['Variable', 'Type', 'Data/Info'])
578 self.assertEqual(lines[0].split(), ['Variable', 'Type', 'Data/Info'])
585 found = False
579 found = False
586 for line in lines[2:]:
580 for line in lines[2:]:
587 split = line.split()
581 split = line.split()
588 if split == ['a', 'int', '5']:
582 if split == ['a', 'int', '5']:
589 found = True
583 found = True
590 break
584 break
591 self.assertTrue(found, "whos output wrong: %s" % stdout)
585 self.assertTrue(found, "whos output wrong: %s" % stdout)
592
586
593 def test_execute_displaypub(self):
587 def test_execute_displaypub(self):
594 """execute tracks display_pub output"""
588 """execute tracks display_pub output"""
595 view = self.client[:]
589 view = self.client[:]
596 view.execute("from IPython.core.display import *")
590 view.execute("from IPython.core.display import *")
597 ar = view.execute("[ display(i) for i in range(5) ]", block=True)
591 ar = view.execute("[ display(i) for i in range(5) ]", block=True)
598
592
599 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
593 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
600 for outputs in ar.outputs:
594 for outputs in ar.outputs:
601 mimes = [ out['data'] for out in outputs ]
595 mimes = [ out['data'] for out in outputs ]
602 self.assertEqual(mimes, expected)
596 self.assertEqual(mimes, expected)
603
597
604 def test_apply_displaypub(self):
598 def test_apply_displaypub(self):
605 """apply tracks display_pub output"""
599 """apply tracks display_pub output"""
606 view = self.client[:]
600 view = self.client[:]
607 view.execute("from IPython.core.display import *")
601 view.execute("from IPython.core.display import *")
608
602
609 @interactive
603 @interactive
610 def publish():
604 def publish():
611 [ display(i) for i in range(5) ]
605 [ display(i) for i in range(5) ]
612
606
613 ar = view.apply_async(publish)
607 ar = view.apply_async(publish)
614 ar.get(5)
608 ar.get(5)
615 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
609 expected = [ {u'text/plain' : unicode(j)} for j in range(5) ]
616 for outputs in ar.outputs:
610 for outputs in ar.outputs:
617 mimes = [ out['data'] for out in outputs ]
611 mimes = [ out['data'] for out in outputs ]
618 self.assertEqual(mimes, expected)
612 self.assertEqual(mimes, expected)
619
613
620 def test_execute_raises(self):
614 def test_execute_raises(self):
621 """exceptions in execute requests raise appropriately"""
615 """exceptions in execute requests raise appropriately"""
622 view = self.client[-1]
616 view = self.client[-1]
623 ar = view.execute("1/0")
617 ar = view.execute("1/0")
624 self.assertRaisesRemote(ZeroDivisionError, ar.get, 2)
618 self.assertRaisesRemote(ZeroDivisionError, ar.get, 2)
625
619
626 def test_remoteerror_render_exception(self):
620 def test_remoteerror_render_exception(self):
627 """RemoteErrors get nice tracebacks"""
621 """RemoteErrors get nice tracebacks"""
628 view = self.client[-1]
622 view = self.client[-1]
629 ar = view.execute("1/0")
623 ar = view.execute("1/0")
630 ip = get_ipython()
624 ip = get_ipython()
631 ip.user_ns['ar'] = ar
625 ip.user_ns['ar'] = ar
632 with capture_output() as io:
626 with capture_output() as io:
633 ip.run_cell("ar.get(2)")
627 ip.run_cell("ar.get(2)")
634
628
635 self.assertTrue('ZeroDivisionError' in io.stdout, io.stdout)
629 self.assertTrue('ZeroDivisionError' in io.stdout, io.stdout)
636
630
637 def test_compositeerror_render_exception(self):
631 def test_compositeerror_render_exception(self):
638 """CompositeErrors get nice tracebacks"""
632 """CompositeErrors get nice tracebacks"""
639 view = self.client[:]
633 view = self.client[:]
640 ar = view.execute("1/0")
634 ar = view.execute("1/0")
641 ip = get_ipython()
635 ip = get_ipython()
642 ip.user_ns['ar'] = ar
636 ip.user_ns['ar'] = ar
643
637
644 with capture_output() as io:
638 with capture_output() as io:
645 ip.run_cell("ar.get(2)")
639 ip.run_cell("ar.get(2)")
646
640
647 count = min(error.CompositeError.tb_limit, len(view))
641 count = min(error.CompositeError.tb_limit, len(view))
648
642
649 self.assertEqual(io.stdout.count('ZeroDivisionError'), count * 2, io.stdout)
643 self.assertEqual(io.stdout.count('ZeroDivisionError'), count * 2, io.stdout)
650 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
644 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
651 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
645 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
652
646
653 def test_compositeerror_truncate(self):
647 def test_compositeerror_truncate(self):
654 """Truncate CompositeErrors with many exceptions"""
648 """Truncate CompositeErrors with many exceptions"""
655 view = self.client[:]
649 view = self.client[:]
656 msg_ids = []
650 msg_ids = []
657 for i in range(10):
651 for i in range(10):
658 ar = view.execute("1/0")
652 ar = view.execute("1/0")
659 msg_ids.extend(ar.msg_ids)
653 msg_ids.extend(ar.msg_ids)
660
654
661 ar = self.client.get_result(msg_ids)
655 ar = self.client.get_result(msg_ids)
662 try:
656 try:
663 ar.get()
657 ar.get()
664 except error.CompositeError as _e:
658 except error.CompositeError as _e:
665 e = _e
659 e = _e
666 else:
660 else:
667 self.fail("Should have raised CompositeError")
661 self.fail("Should have raised CompositeError")
668
662
669 lines = e.render_traceback()
663 lines = e.render_traceback()
670 with capture_output() as io:
664 with capture_output() as io:
671 e.print_traceback()
665 e.print_traceback()
672
666
673 self.assertTrue("more exceptions" in lines[-1])
667 self.assertTrue("more exceptions" in lines[-1])
674 count = e.tb_limit
668 count = e.tb_limit
675
669
676 self.assertEqual(io.stdout.count('ZeroDivisionError'), 2 * count, io.stdout)
670 self.assertEqual(io.stdout.count('ZeroDivisionError'), 2 * count, io.stdout)
677 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
671 self.assertEqual(io.stdout.count('by zero'), count, io.stdout)
678 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
672 self.assertEqual(io.stdout.count(':execute'), count, io.stdout)
679
673
680 @dec.skipif_not_matplotlib
674 @dec.skipif_not_matplotlib
681 def test_magic_pylab(self):
675 def test_magic_pylab(self):
682 """%pylab works on engines"""
676 """%pylab works on engines"""
683 view = self.client[-1]
677 view = self.client[-1]
684 ar = view.execute("%pylab inline")
678 ar = view.execute("%pylab inline")
685 # at least check if this raised:
679 # at least check if this raised:
686 reply = ar.get(5)
680 reply = ar.get(5)
687 # include imports, in case user config
681 # include imports, in case user config
688 ar = view.execute("plot(rand(100))", silent=False)
682 ar = view.execute("plot(rand(100))", silent=False)
689 reply = ar.get(5)
683 reply = ar.get(5)
690 self.assertEqual(len(reply.outputs), 1)
684 self.assertEqual(len(reply.outputs), 1)
691 output = reply.outputs[0]
685 output = reply.outputs[0]
692 self.assertTrue("data" in output)
686 self.assertTrue("data" in output)
693 data = output['data']
687 data = output['data']
694 self.assertTrue("image/png" in data)
688 self.assertTrue("image/png" in data)
695
689
696 def test_func_default_func(self):
690 def test_func_default_func(self):
697 """interactively defined function as apply func default"""
691 """interactively defined function as apply func default"""
698 def foo():
692 def foo():
699 return 'foo'
693 return 'foo'
700
694
701 def bar(f=foo):
695 def bar(f=foo):
702 return f()
696 return f()
703
697
704 view = self.client[-1]
698 view = self.client[-1]
705 ar = view.apply_async(bar)
699 ar = view.apply_async(bar)
706 r = ar.get(10)
700 r = ar.get(10)
707 self.assertEqual(r, 'foo')
701 self.assertEqual(r, 'foo')
708 def test_data_pub_single(self):
702 def test_data_pub_single(self):
709 view = self.client[-1]
703 view = self.client[-1]
710 ar = view.execute('\n'.join([
704 ar = view.execute('\n'.join([
711 'from IPython.kernel.zmq.datapub import publish_data',
705 'from IPython.kernel.zmq.datapub import publish_data',
712 'for i in range(5):',
706 'for i in range(5):',
713 ' publish_data(dict(i=i))'
707 ' publish_data(dict(i=i))'
714 ]), block=False)
708 ]), block=False)
715 self.assertTrue(isinstance(ar.data, dict))
709 self.assertTrue(isinstance(ar.data, dict))
716 ar.get(5)
710 ar.get(5)
717 self.assertEqual(ar.data, dict(i=4))
711 self.assertEqual(ar.data, dict(i=4))
718
712
719 def test_data_pub(self):
713 def test_data_pub(self):
720 view = self.client[:]
714 view = self.client[:]
721 ar = view.execute('\n'.join([
715 ar = view.execute('\n'.join([
722 'from IPython.kernel.zmq.datapub import publish_data',
716 'from IPython.kernel.zmq.datapub import publish_data',
723 'for i in range(5):',
717 'for i in range(5):',
724 ' publish_data(dict(i=i))'
718 ' publish_data(dict(i=i))'
725 ]), block=False)
719 ]), block=False)
726 self.assertTrue(all(isinstance(d, dict) for d in ar.data))
720 self.assertTrue(all(isinstance(d, dict) for d in ar.data))
727 ar.get(5)
721 ar.get(5)
728 self.assertEqual(ar.data, [dict(i=4)] * len(ar))
722 self.assertEqual(ar.data, [dict(i=4)] * len(ar))
729
723
730 def test_can_list_arg(self):
724 def test_can_list_arg(self):
731 """args in lists are canned"""
725 """args in lists are canned"""
732 view = self.client[-1]
726 view = self.client[-1]
733 view['a'] = 128
727 view['a'] = 128
734 rA = pmod.Reference('a')
728 rA = pmod.Reference('a')
735 ar = view.apply_async(lambda x: x, [rA])
729 ar = view.apply_async(lambda x: x, [rA])
736 r = ar.get(5)
730 r = ar.get(5)
737 self.assertEqual(r, [128])
731 self.assertEqual(r, [128])
738
732
739 def test_can_dict_arg(self):
733 def test_can_dict_arg(self):
740 """args in dicts are canned"""
734 """args in dicts are canned"""
741 view = self.client[-1]
735 view = self.client[-1]
742 view['a'] = 128
736 view['a'] = 128
743 rA = pmod.Reference('a')
737 rA = pmod.Reference('a')
744 ar = view.apply_async(lambda x: x, dict(foo=rA))
738 ar = view.apply_async(lambda x: x, dict(foo=rA))
745 r = ar.get(5)
739 r = ar.get(5)
746 self.assertEqual(r, dict(foo=128))
740 self.assertEqual(r, dict(foo=128))
747
741
748 def test_can_list_kwarg(self):
742 def test_can_list_kwarg(self):
749 """kwargs in lists are canned"""
743 """kwargs in lists are canned"""
750 view = self.client[-1]
744 view = self.client[-1]
751 view['a'] = 128
745 view['a'] = 128
752 rA = pmod.Reference('a')
746 rA = pmod.Reference('a')
753 ar = view.apply_async(lambda x=5: x, x=[rA])
747 ar = view.apply_async(lambda x=5: x, x=[rA])
754 r = ar.get(5)
748 r = ar.get(5)
755 self.assertEqual(r, [128])
749 self.assertEqual(r, [128])
756
750
757 def test_can_dict_kwarg(self):
751 def test_can_dict_kwarg(self):
758 """kwargs in dicts are canned"""
752 """kwargs in dicts are canned"""
759 view = self.client[-1]
753 view = self.client[-1]
760 view['a'] = 128
754 view['a'] = 128
761 rA = pmod.Reference('a')
755 rA = pmod.Reference('a')
762 ar = view.apply_async(lambda x=5: x, dict(foo=rA))
756 ar = view.apply_async(lambda x=5: x, dict(foo=rA))
763 r = ar.get(5)
757 r = ar.get(5)
764 self.assertEqual(r, dict(foo=128))
758 self.assertEqual(r, dict(foo=128))
765
759
766 def test_map_ref(self):
760 def test_map_ref(self):
767 """view.map works with references"""
761 """view.map works with references"""
768 view = self.client[:]
762 view = self.client[:]
769 ranks = sorted(self.client.ids)
763 ranks = sorted(self.client.ids)
770 view.scatter('rank', ranks, flatten=True)
764 view.scatter('rank', ranks, flatten=True)
771 rrank = pmod.Reference('rank')
765 rrank = pmod.Reference('rank')
772
766
773 amr = view.map_async(lambda x: x*2, [rrank] * len(view))
767 amr = view.map_async(lambda x: x*2, [rrank] * len(view))
774 drank = amr.get(5)
768 drank = amr.get(5)
775 self.assertEqual(drank, [ r*2 for r in ranks ])
769 self.assertEqual(drank, [ r*2 for r in ranks ])
776
770
777 def test_nested_getitem_setitem(self):
771 def test_nested_getitem_setitem(self):
778 """get and set with view['a.b']"""
772 """get and set with view['a.b']"""
779 view = self.client[-1]
773 view = self.client[-1]
780 view.execute('\n'.join([
774 view.execute('\n'.join([
781 'class A(object): pass',
775 'class A(object): pass',
782 'a = A()',
776 'a = A()',
783 'a.b = 128',
777 'a.b = 128',
784 ]), block=True)
778 ]), block=True)
785 ra = pmod.Reference('a')
779 ra = pmod.Reference('a')
786
780
787 r = view.apply_sync(lambda x: x.b, ra)
781 r = view.apply_sync(lambda x: x.b, ra)
788 self.assertEqual(r, 128)
782 self.assertEqual(r, 128)
789 self.assertEqual(view['a.b'], 128)
783 self.assertEqual(view['a.b'], 128)
790
784
791 view['a.b'] = 0
785 view['a.b'] = 0
792
786
793 r = view.apply_sync(lambda x: x.b, ra)
787 r = view.apply_sync(lambda x: x.b, ra)
794 self.assertEqual(r, 0)
788 self.assertEqual(r, 0)
795 self.assertEqual(view['a.b'], 0)
789 self.assertEqual(view['a.b'], 0)
796
790
797 def test_return_namedtuple(self):
791 def test_return_namedtuple(self):
798 def namedtuplify(x, y):
792 def namedtuplify(x, y):
799 from IPython.parallel.tests.test_view import point
793 from IPython.parallel.tests.test_view import point
800 return point(x, y)
794 return point(x, y)
801
795
802 view = self.client[-1]
796 view = self.client[-1]
803 p = view.apply_sync(namedtuplify, 1, 2)
797 p = view.apply_sync(namedtuplify, 1, 2)
804 self.assertEqual(p.x, 1)
798 self.assertEqual(p.x, 1)
805 self.assertEqual(p.y, 2)
799 self.assertEqual(p.y, 2)
806
800
807 def test_apply_namedtuple(self):
801 def test_apply_namedtuple(self):
808 def echoxy(p):
802 def echoxy(p):
809 return p.y, p.x
803 return p.y, p.x
810
804
811 view = self.client[-1]
805 view = self.client[-1]
812 tup = view.apply_sync(echoxy, point(1, 2))
806 tup = view.apply_sync(echoxy, point(1, 2))
813 self.assertEqual(tup, (2,1))
807 self.assertEqual(tup, (2,1))
814
808
@@ -1,391 +1,381 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Decorators for labeling test objects.
2 """Decorators for labeling test objects.
3
3
4 Decorators that merely return a modified version of the original function
4 Decorators that merely return a modified version of the original function
5 object are straightforward. Decorators that return a new function object need
5 object are straightforward. Decorators that return a new function object need
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 decorator, in order to preserve metadata such as function name, setup and
7 decorator, in order to preserve metadata such as function name, setup and
8 teardown functions and so on - see nose.tools for more information.
8 teardown functions and so on - see nose.tools for more information.
9
9
10 This module provides a set of useful decorators meant to be ready to use in
10 This module provides a set of useful decorators meant to be ready to use in
11 your own tests. See the bottom of the file for the ready-made ones, and if you
11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 find yourself writing a new one that may be of generic use, add it here.
12 find yourself writing a new one that may be of generic use, add it here.
13
13
14 Included decorators:
14 Included decorators:
15
15
16
16
17 Lightweight testing that remains unittest-compatible.
17 Lightweight testing that remains unittest-compatible.
18
18
19 - @parametric, for parametric test support that is vastly easier to use than
20 nose's for debugging. With ours, if a test fails, the stack under inspection
21 is that of the test and not that of the test framework.
22
23 - An @as_unittest decorator can be used to tag any normal parameter-less
19 - An @as_unittest decorator can be used to tag any normal parameter-less
24 function as a unittest TestCase. Then, both nose and normal unittest will
20 function as a unittest TestCase. Then, both nose and normal unittest will
25 recognize it as such. This will make it easier to migrate away from Nose if
21 recognize it as such. This will make it easier to migrate away from Nose if
26 we ever need/want to while maintaining very lightweight tests.
22 we ever need/want to while maintaining very lightweight tests.
27
23
28 NOTE: This file contains IPython-specific decorators. Using the machinery in
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
29 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
30 available, OR use equivalent code in IPython.external._decorators, which
26 available, OR use equivalent code in IPython.external._decorators, which
31 we've copied verbatim from numpy.
27 we've copied verbatim from numpy.
32
28
33 Authors
29 Authors
34 -------
30 -------
35
31
36 - Fernando Perez <Fernando.Perez@berkeley.edu>
32 - Fernando Perez <Fernando.Perez@berkeley.edu>
37 """
33 """
38
34
39 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
40 # Copyright (C) 2009-2011 The IPython Development Team
36 # Copyright (C) 2009-2011 The IPython Development Team
41 #
37 #
42 # Distributed under the terms of the BSD License. The full license is in
38 # Distributed under the terms of the BSD License. The full license is in
43 # the file COPYING, distributed as part of this software.
39 # the file COPYING, distributed as part of this software.
44 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
45
41
46 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
47 # Imports
43 # Imports
48 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
49
45
50 # Stdlib imports
46 # Stdlib imports
51 import sys
47 import sys
52 import os
48 import os
53 import tempfile
49 import tempfile
54 import unittest
50 import unittest
55
51
56 # Third-party imports
52 # Third-party imports
57
53
58 # This is Michele Simionato's decorator module, kept verbatim.
54 # This is Michele Simionato's decorator module, kept verbatim.
59 from IPython.external.decorator import decorator
55 from IPython.external.decorator import decorator
60
56
61 # We already have python3-compliant code for parametric tests
62 if sys.version[0]=='2':
63 from _paramtestpy2 import parametric
64 else:
65 from _paramtestpy3 import parametric
66
67 # Expose the unittest-driven decorators
57 # Expose the unittest-driven decorators
68 from ipunittest import ipdoctest, ipdocstring
58 from ipunittest import ipdoctest, ipdocstring
69
59
70 # Grab the numpy-specific decorators which we keep in a file that we
60 # Grab the numpy-specific decorators which we keep in a file that we
71 # occasionally update from upstream: decorators.py is a copy of
61 # occasionally update from upstream: decorators.py is a copy of
72 # numpy.testing.decorators, we expose all of it here.
62 # numpy.testing.decorators, we expose all of it here.
73 from IPython.external.decorators import *
63 from IPython.external.decorators import *
74
64
75 # For onlyif_cmd_exists decorator
65 # For onlyif_cmd_exists decorator
76 from IPython.utils.process import is_cmd_found
66 from IPython.utils.process import is_cmd_found
77
67
78 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
79 # Classes and functions
69 # Classes and functions
80 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
81
71
82 # Simple example of the basic idea
72 # Simple example of the basic idea
83 def as_unittest(func):
73 def as_unittest(func):
84 """Decorator to make a simple function into a normal test via unittest."""
74 """Decorator to make a simple function into a normal test via unittest."""
85 class Tester(unittest.TestCase):
75 class Tester(unittest.TestCase):
86 def test(self):
76 def test(self):
87 func()
77 func()
88
78
89 Tester.__name__ = func.__name__
79 Tester.__name__ = func.__name__
90
80
91 return Tester
81 return Tester
92
82
93 # Utility functions
83 # Utility functions
94
84
95 def apply_wrapper(wrapper,func):
85 def apply_wrapper(wrapper,func):
96 """Apply a wrapper to a function for decoration.
86 """Apply a wrapper to a function for decoration.
97
87
98 This mixes Michele Simionato's decorator tool with nose's make_decorator,
88 This mixes Michele Simionato's decorator tool with nose's make_decorator,
99 to apply a wrapper in a decorator so that all nose attributes, as well as
89 to apply a wrapper in a decorator so that all nose attributes, as well as
100 function signature and other properties, survive the decoration cleanly.
90 function signature and other properties, survive the decoration cleanly.
101 This will ensure that wrapped functions can still be well introspected via
91 This will ensure that wrapped functions can still be well introspected via
102 IPython, for example.
92 IPython, for example.
103 """
93 """
104 import nose.tools
94 import nose.tools
105
95
106 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
96 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
107
97
108
98
109 def make_label_dec(label,ds=None):
99 def make_label_dec(label,ds=None):
110 """Factory function to create a decorator that applies one or more labels.
100 """Factory function to create a decorator that applies one or more labels.
111
101
112 Parameters
102 Parameters
113 ----------
103 ----------
114 label : string or sequence
104 label : string or sequence
115 One or more labels that will be applied by the decorator to the functions
105 One or more labels that will be applied by the decorator to the functions
116 it decorates. Labels are attributes of the decorated function with their
106 it decorates. Labels are attributes of the decorated function with their
117 value set to True.
107 value set to True.
118
108
119 ds : string
109 ds : string
120 An optional docstring for the resulting decorator. If not given, a
110 An optional docstring for the resulting decorator. If not given, a
121 default docstring is auto-generated.
111 default docstring is auto-generated.
122
112
123 Returns
113 Returns
124 -------
114 -------
125 A decorator.
115 A decorator.
126
116
127 Examples
117 Examples
128 --------
118 --------
129
119
130 A simple labeling decorator:
120 A simple labeling decorator:
131
121
132 >>> slow = make_label_dec('slow')
122 >>> slow = make_label_dec('slow')
133 >>> slow.__doc__
123 >>> slow.__doc__
134 "Labels a test as 'slow'."
124 "Labels a test as 'slow'."
135
125
136 And one that uses multiple labels and a custom docstring:
126 And one that uses multiple labels and a custom docstring:
137
127
138 >>> rare = make_label_dec(['slow','hard'],
128 >>> rare = make_label_dec(['slow','hard'],
139 ... "Mix labels 'slow' and 'hard' for rare tests.")
129 ... "Mix labels 'slow' and 'hard' for rare tests.")
140 >>> rare.__doc__
130 >>> rare.__doc__
141 "Mix labels 'slow' and 'hard' for rare tests."
131 "Mix labels 'slow' and 'hard' for rare tests."
142
132
143 Now, let's test using this one:
133 Now, let's test using this one:
144 >>> @rare
134 >>> @rare
145 ... def f(): pass
135 ... def f(): pass
146 ...
136 ...
147 >>>
137 >>>
148 >>> f.slow
138 >>> f.slow
149 True
139 True
150 >>> f.hard
140 >>> f.hard
151 True
141 True
152 """
142 """
153
143
154 if isinstance(label,basestring):
144 if isinstance(label,basestring):
155 labels = [label]
145 labels = [label]
156 else:
146 else:
157 labels = label
147 labels = label
158
148
159 # Validate that the given label(s) are OK for use in setattr() by doing a
149 # Validate that the given label(s) are OK for use in setattr() by doing a
160 # dry run on a dummy function.
150 # dry run on a dummy function.
161 tmp = lambda : None
151 tmp = lambda : None
162 for label in labels:
152 for label in labels:
163 setattr(tmp,label,True)
153 setattr(tmp,label,True)
164
154
165 # This is the actual decorator we'll return
155 # This is the actual decorator we'll return
166 def decor(f):
156 def decor(f):
167 for label in labels:
157 for label in labels:
168 setattr(f,label,True)
158 setattr(f,label,True)
169 return f
159 return f
170
160
171 # Apply the user's docstring, or autogenerate a basic one
161 # Apply the user's docstring, or autogenerate a basic one
172 if ds is None:
162 if ds is None:
173 ds = "Labels a test as %r." % label
163 ds = "Labels a test as %r." % label
174 decor.__doc__ = ds
164 decor.__doc__ = ds
175
165
176 return decor
166 return decor
177
167
178
168
179 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
169 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
180 # preserve function metadata better and allows the skip condition to be a
170 # preserve function metadata better and allows the skip condition to be a
181 # callable.
171 # callable.
182 def skipif(skip_condition, msg=None):
172 def skipif(skip_condition, msg=None):
183 ''' Make function raise SkipTest exception if skip_condition is true
173 ''' Make function raise SkipTest exception if skip_condition is true
184
174
185 Parameters
175 Parameters
186 ----------
176 ----------
187 skip_condition : bool or callable.
177 skip_condition : bool or callable.
188 Flag to determine whether to skip test. If the condition is a
178 Flag to determine whether to skip test. If the condition is a
189 callable, it is used at runtime to dynamically make the decision. This
179 callable, it is used at runtime to dynamically make the decision. This
190 is useful for tests that may require costly imports, to delay the cost
180 is useful for tests that may require costly imports, to delay the cost
191 until the test suite is actually executed.
181 until the test suite is actually executed.
192 msg : string
182 msg : string
193 Message to give on raising a SkipTest exception
183 Message to give on raising a SkipTest exception
194
184
195 Returns
185 Returns
196 -------
186 -------
197 decorator : function
187 decorator : function
198 Decorator, which, when applied to a function, causes SkipTest
188 Decorator, which, when applied to a function, causes SkipTest
199 to be raised when the skip_condition was True, and the function
189 to be raised when the skip_condition was True, and the function
200 to be called normally otherwise.
190 to be called normally otherwise.
201
191
202 Notes
192 Notes
203 -----
193 -----
204 You will see from the code that we had to further decorate the
194 You will see from the code that we had to further decorate the
205 decorator with the nose.tools.make_decorator function in order to
195 decorator with the nose.tools.make_decorator function in order to
206 transmit function name, and various other metadata.
196 transmit function name, and various other metadata.
207 '''
197 '''
208
198
209 def skip_decorator(f):
199 def skip_decorator(f):
210 # Local import to avoid a hard nose dependency and only incur the
200 # Local import to avoid a hard nose dependency and only incur the
211 # import time overhead at actual test-time.
201 # import time overhead at actual test-time.
212 import nose
202 import nose
213
203
214 # Allow for both boolean or callable skip conditions.
204 # Allow for both boolean or callable skip conditions.
215 if callable(skip_condition):
205 if callable(skip_condition):
216 skip_val = skip_condition
206 skip_val = skip_condition
217 else:
207 else:
218 skip_val = lambda : skip_condition
208 skip_val = lambda : skip_condition
219
209
220 def get_msg(func,msg=None):
210 def get_msg(func,msg=None):
221 """Skip message with information about function being skipped."""
211 """Skip message with information about function being skipped."""
222 if msg is None: out = 'Test skipped due to test condition.'
212 if msg is None: out = 'Test skipped due to test condition.'
223 else: out = msg
213 else: out = msg
224 return "Skipping test: %s. %s" % (func.__name__,out)
214 return "Skipping test: %s. %s" % (func.__name__,out)
225
215
226 # We need to define *two* skippers because Python doesn't allow both
216 # We need to define *two* skippers because Python doesn't allow both
227 # return with value and yield inside the same function.
217 # return with value and yield inside the same function.
228 def skipper_func(*args, **kwargs):
218 def skipper_func(*args, **kwargs):
229 """Skipper for normal test functions."""
219 """Skipper for normal test functions."""
230 if skip_val():
220 if skip_val():
231 raise nose.SkipTest(get_msg(f,msg))
221 raise nose.SkipTest(get_msg(f,msg))
232 else:
222 else:
233 return f(*args, **kwargs)
223 return f(*args, **kwargs)
234
224
235 def skipper_gen(*args, **kwargs):
225 def skipper_gen(*args, **kwargs):
236 """Skipper for test generators."""
226 """Skipper for test generators."""
237 if skip_val():
227 if skip_val():
238 raise nose.SkipTest(get_msg(f,msg))
228 raise nose.SkipTest(get_msg(f,msg))
239 else:
229 else:
240 for x in f(*args, **kwargs):
230 for x in f(*args, **kwargs):
241 yield x
231 yield x
242
232
243 # Choose the right skipper to use when building the actual generator.
233 # Choose the right skipper to use when building the actual generator.
244 if nose.util.isgenerator(f):
234 if nose.util.isgenerator(f):
245 skipper = skipper_gen
235 skipper = skipper_gen
246 else:
236 else:
247 skipper = skipper_func
237 skipper = skipper_func
248
238
249 return nose.tools.make_decorator(f)(skipper)
239 return nose.tools.make_decorator(f)(skipper)
250
240
251 return skip_decorator
241 return skip_decorator
252
242
253 # A version with the condition set to true, common case just to attach a message
243 # A version with the condition set to true, common case just to attach a message
254 # to a skip decorator
244 # to a skip decorator
255 def skip(msg=None):
245 def skip(msg=None):
256 """Decorator factory - mark a test function for skipping from test suite.
246 """Decorator factory - mark a test function for skipping from test suite.
257
247
258 Parameters
248 Parameters
259 ----------
249 ----------
260 msg : string
250 msg : string
261 Optional message to be added.
251 Optional message to be added.
262
252
263 Returns
253 Returns
264 -------
254 -------
265 decorator : function
255 decorator : function
266 Decorator, which, when applied to a function, causes SkipTest
256 Decorator, which, when applied to a function, causes SkipTest
267 to be raised, with the optional message added.
257 to be raised, with the optional message added.
268 """
258 """
269
259
270 return skipif(True,msg)
260 return skipif(True,msg)
271
261
272
262
273 def onlyif(condition, msg):
263 def onlyif(condition, msg):
274 """The reverse from skipif, see skipif for details."""
264 """The reverse from skipif, see skipif for details."""
275
265
276 if callable(condition):
266 if callable(condition):
277 skip_condition = lambda : not condition()
267 skip_condition = lambda : not condition()
278 else:
268 else:
279 skip_condition = lambda : not condition
269 skip_condition = lambda : not condition
280
270
281 return skipif(skip_condition, msg)
271 return skipif(skip_condition, msg)
282
272
283 #-----------------------------------------------------------------------------
273 #-----------------------------------------------------------------------------
284 # Utility functions for decorators
274 # Utility functions for decorators
285 def module_not_available(module):
275 def module_not_available(module):
286 """Can module be imported? Returns true if module does NOT import.
276 """Can module be imported? Returns true if module does NOT import.
287
277
288 This is used to make a decorator to skip tests that require module to be
278 This is used to make a decorator to skip tests that require module to be
289 available, but delay the 'import numpy' to test execution time.
279 available, but delay the 'import numpy' to test execution time.
290 """
280 """
291 try:
281 try:
292 mod = __import__(module)
282 mod = __import__(module)
293 mod_not_avail = False
283 mod_not_avail = False
294 except ImportError:
284 except ImportError:
295 mod_not_avail = True
285 mod_not_avail = True
296
286
297 return mod_not_avail
287 return mod_not_avail
298
288
299
289
300 def decorated_dummy(dec, name):
290 def decorated_dummy(dec, name):
301 """Return a dummy function decorated with dec, with the given name.
291 """Return a dummy function decorated with dec, with the given name.
302
292
303 Examples
293 Examples
304 --------
294 --------
305 import IPython.testing.decorators as dec
295 import IPython.testing.decorators as dec
306 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
296 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
307 """
297 """
308 dummy = lambda: None
298 dummy = lambda: None
309 dummy.__name__ = name
299 dummy.__name__ = name
310 return dec(dummy)
300 return dec(dummy)
311
301
312 #-----------------------------------------------------------------------------
302 #-----------------------------------------------------------------------------
313 # Decorators for public use
303 # Decorators for public use
314
304
315 # Decorators to skip certain tests on specific platforms.
305 # Decorators to skip certain tests on specific platforms.
316 skip_win32 = skipif(sys.platform == 'win32',
306 skip_win32 = skipif(sys.platform == 'win32',
317 "This test does not run under Windows")
307 "This test does not run under Windows")
318 skip_linux = skipif(sys.platform.startswith('linux'),
308 skip_linux = skipif(sys.platform.startswith('linux'),
319 "This test does not run under Linux")
309 "This test does not run under Linux")
320 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
310 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
321
311
322
312
323 # Decorators to skip tests if not on specific platforms.
313 # Decorators to skip tests if not on specific platforms.
324 skip_if_not_win32 = skipif(sys.platform != 'win32',
314 skip_if_not_win32 = skipif(sys.platform != 'win32',
325 "This test only runs under Windows")
315 "This test only runs under Windows")
326 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
316 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
327 "This test only runs under Linux")
317 "This test only runs under Linux")
328 skip_if_not_osx = skipif(sys.platform != 'darwin',
318 skip_if_not_osx = skipif(sys.platform != 'darwin',
329 "This test only runs under OSX")
319 "This test only runs under OSX")
330
320
331
321
332 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
322 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
333 os.environ.get('DISPLAY', '') == '')
323 os.environ.get('DISPLAY', '') == '')
334 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
324 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
335
325
336 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
326 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
337
327
338 # not a decorator itself, returns a dummy function to be used as setup
328 # not a decorator itself, returns a dummy function to be used as setup
339 def skip_file_no_x11(name):
329 def skip_file_no_x11(name):
340 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
330 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
341
331
342 # Other skip decorators
332 # Other skip decorators
343
333
344 # generic skip without module
334 # generic skip without module
345 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
335 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
346
336
347 skipif_not_numpy = skip_without('numpy')
337 skipif_not_numpy = skip_without('numpy')
348
338
349 skipif_not_matplotlib = skip_without('matplotlib')
339 skipif_not_matplotlib = skip_without('matplotlib')
350
340
351 skipif_not_sympy = skip_without('sympy')
341 skipif_not_sympy = skip_without('sympy')
352
342
353 skip_known_failure = knownfailureif(True,'This test is known to fail')
343 skip_known_failure = knownfailureif(True,'This test is known to fail')
354
344
355 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
345 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
356 'This test is known to fail on Python 3.')
346 'This test is known to fail on Python 3.')
357
347
358 # A null 'decorator', useful to make more readable code that needs to pick
348 # A null 'decorator', useful to make more readable code that needs to pick
359 # between different decorators based on OS or other conditions
349 # between different decorators based on OS or other conditions
360 null_deco = lambda f: f
350 null_deco = lambda f: f
361
351
362 # Some tests only run where we can use unicode paths. Note that we can't just
352 # Some tests only run where we can use unicode paths. Note that we can't just
363 # check os.path.supports_unicode_filenames, which is always False on Linux.
353 # check os.path.supports_unicode_filenames, which is always False on Linux.
364 try:
354 try:
365 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
355 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
366 except UnicodeEncodeError:
356 except UnicodeEncodeError:
367 unicode_paths = False
357 unicode_paths = False
368 else:
358 else:
369 unicode_paths = True
359 unicode_paths = True
370 f.close()
360 f.close()
371
361
372 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
362 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
373 "where we can use unicode in filenames."))
363 "where we can use unicode in filenames."))
374
364
375
365
376 def onlyif_cmds_exist(*commands):
366 def onlyif_cmds_exist(*commands):
377 """
367 """
378 Decorator to skip test when at least one of `commands` is not found.
368 Decorator to skip test when at least one of `commands` is not found.
379 """
369 """
380 for cmd in commands:
370 for cmd in commands:
381 try:
371 try:
382 if not is_cmd_found(cmd):
372 if not is_cmd_found(cmd):
383 return skip("This test runs only if command '{0}' "
373 return skip("This test runs only if command '{0}' "
384 "is installed".format(cmd))
374 "is installed".format(cmd))
385 except ImportError as e:
375 except ImportError as e:
386 # is_cmd_found uses pywin32 on windows, which might not be available
376 # is_cmd_found uses pywin32 on windows, which might not be available
387 if sys.platform == 'win32' and 'pywin32' in e.message:
377 if sys.platform == 'win32' and 'pywin32' in e.message:
388 return skip("This test runs only if pywin32 and command '{0}' "
378 return skip("This test runs only if pywin32 and command '{0}' "
389 "is installed".format(cmd))
379 "is installed".format(cmd))
390 raise e
380 raise e
391 return null_deco
381 return null_deco
@@ -1,184 +1,177 b''
1 """Experimental code for cleaner support of IPython syntax with unittest.
1 """Experimental code for cleaner support of IPython syntax with unittest.
2
2
3 In IPython up until 0.10, we've used very hacked up nose machinery for running
3 In IPython up until 0.10, we've used very hacked up nose machinery for running
4 tests with IPython special syntax, and this has proved to be extremely slow.
4 tests with IPython special syntax, and this has proved to be extremely slow.
5 This module provides decorators to try a different approach, stemming from a
5 This module provides decorators to try a different approach, stemming from a
6 conversation Brian and I (FP) had about this problem Sept/09.
6 conversation Brian and I (FP) had about this problem Sept/09.
7
7
8 The goal is to be able to easily write simple functions that can be seen by
8 The goal is to be able to easily write simple functions that can be seen by
9 unittest as tests, and ultimately for these to support doctests with full
9 unittest as tests, and ultimately for these to support doctests with full
10 IPython syntax. Nose already offers this based on naming conventions and our
10 IPython syntax. Nose already offers this based on naming conventions and our
11 hackish plugins, but we are seeking to move away from nose dependencies if
11 hackish plugins, but we are seeking to move away from nose dependencies if
12 possible.
12 possible.
13
13
14 This module follows a different approach, based on decorators.
14 This module follows a different approach, based on decorators.
15
15
16 - A decorator called @ipdoctest can mark any function as having a docstring
16 - A decorator called @ipdoctest can mark any function as having a docstring
17 that should be viewed as a doctest, but after syntax conversion.
17 that should be viewed as a doctest, but after syntax conversion.
18
18
19 Authors
19 Authors
20 -------
20 -------
21
21
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 """
23 """
24
24
25 from __future__ import absolute_import
25 from __future__ import absolute_import
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Copyright (C) 2009-2011 The IPython Development Team
28 # Copyright (C) 2009-2011 The IPython Development Team
29 #
29 #
30 # Distributed under the terms of the BSD License. The full license is in
30 # Distributed under the terms of the BSD License. The full license is in
31 # the file COPYING, distributed as part of this software.
31 # the file COPYING, distributed as part of this software.
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Imports
35 # Imports
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 # Stdlib
38 # Stdlib
39 import re
39 import re
40 import sys
41 import unittest
40 import unittest
42 from doctest import DocTestFinder, DocTestRunner, TestResults
41 from doctest import DocTestFinder, DocTestRunner, TestResults
43
42
44 # We already have python3-compliant code for parametric tests
45 if sys.version[0]=='2':
46 from ._paramtestpy2 import ParametricTestCase
47 else:
48 from ._paramtestpy3 import ParametricTestCase
49
50 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
51 # Classes and functions
44 # Classes and functions
52 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
53
46
54 def count_failures(runner):
47 def count_failures(runner):
55 """Count number of failures in a doctest runner.
48 """Count number of failures in a doctest runner.
56
49
57 Code modeled after the summarize() method in doctest.
50 Code modeled after the summarize() method in doctest.
58 """
51 """
59 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
52 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
60
53
61
54
62 class IPython2PythonConverter(object):
55 class IPython2PythonConverter(object):
63 """Convert IPython 'syntax' to valid Python.
56 """Convert IPython 'syntax' to valid Python.
64
57
65 Eventually this code may grow to be the full IPython syntax conversion
58 Eventually this code may grow to be the full IPython syntax conversion
66 implementation, but for now it only does prompt convertion."""
59 implementation, but for now it only does prompt convertion."""
67
60
68 def __init__(self):
61 def __init__(self):
69 self.rps1 = re.compile(r'In\ \[\d+\]: ')
62 self.rps1 = re.compile(r'In\ \[\d+\]: ')
70 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
63 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
71 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
64 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
72 self.pyps1 = '>>> '
65 self.pyps1 = '>>> '
73 self.pyps2 = '... '
66 self.pyps2 = '... '
74 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
67 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
75 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
68 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
76
69
77 def __call__(self, ds):
70 def __call__(self, ds):
78 """Convert IPython prompts to python ones in a string."""
71 """Convert IPython prompts to python ones in a string."""
79 from . import globalipapp
72 from . import globalipapp
80
73
81 pyps1 = '>>> '
74 pyps1 = '>>> '
82 pyps2 = '... '
75 pyps2 = '... '
83 pyout = ''
76 pyout = ''
84
77
85 dnew = ds
78 dnew = ds
86 dnew = self.rps1.sub(pyps1, dnew)
79 dnew = self.rps1.sub(pyps1, dnew)
87 dnew = self.rps2.sub(pyps2, dnew)
80 dnew = self.rps2.sub(pyps2, dnew)
88 dnew = self.rout.sub(pyout, dnew)
81 dnew = self.rout.sub(pyout, dnew)
89 ip = globalipapp.get_ipython()
82 ip = globalipapp.get_ipython()
90
83
91 # Convert input IPython source into valid Python.
84 # Convert input IPython source into valid Python.
92 out = []
85 out = []
93 newline = out.append
86 newline = out.append
94 for line in dnew.splitlines():
87 for line in dnew.splitlines():
95
88
96 mps1 = self.rpyps1.match(line)
89 mps1 = self.rpyps1.match(line)
97 if mps1 is not None:
90 if mps1 is not None:
98 prompt, text = mps1.groups()
91 prompt, text = mps1.groups()
99 newline(prompt+ip.prefilter(text, False))
92 newline(prompt+ip.prefilter(text, False))
100 continue
93 continue
101
94
102 mps2 = self.rpyps2.match(line)
95 mps2 = self.rpyps2.match(line)
103 if mps2 is not None:
96 if mps2 is not None:
104 prompt, text = mps2.groups()
97 prompt, text = mps2.groups()
105 newline(prompt+ip.prefilter(text, True))
98 newline(prompt+ip.prefilter(text, True))
106 continue
99 continue
107
100
108 newline(line)
101 newline(line)
109 newline('') # ensure a closing newline, needed by doctest
102 newline('') # ensure a closing newline, needed by doctest
110 #print "PYSRC:", '\n'.join(out) # dbg
103 #print "PYSRC:", '\n'.join(out) # dbg
111 return '\n'.join(out)
104 return '\n'.join(out)
112
105
113 #return dnew
106 #return dnew
114
107
115
108
116 class Doc2UnitTester(object):
109 class Doc2UnitTester(object):
117 """Class whose instances act as a decorator for docstring testing.
110 """Class whose instances act as a decorator for docstring testing.
118
111
119 In practice we're only likely to need one instance ever, made below (though
112 In practice we're only likely to need one instance ever, made below (though
120 no attempt is made at turning it into a singleton, there is no need for
113 no attempt is made at turning it into a singleton, there is no need for
121 that).
114 that).
122 """
115 """
123 def __init__(self, verbose=False):
116 def __init__(self, verbose=False):
124 """New decorator.
117 """New decorator.
125
118
126 Parameters
119 Parameters
127 ----------
120 ----------
128
121
129 verbose : boolean, optional (False)
122 verbose : boolean, optional (False)
130 Passed to the doctest finder and runner to control verbosity.
123 Passed to the doctest finder and runner to control verbosity.
131 """
124 """
132 self.verbose = verbose
125 self.verbose = verbose
133 # We can reuse the same finder for all instances
126 # We can reuse the same finder for all instances
134 self.finder = DocTestFinder(verbose=verbose, recurse=False)
127 self.finder = DocTestFinder(verbose=verbose, recurse=False)
135
128
136 def __call__(self, func):
129 def __call__(self, func):
137 """Use as a decorator: doctest a function's docstring as a unittest.
130 """Use as a decorator: doctest a function's docstring as a unittest.
138
131
139 This version runs normal doctests, but the idea is to make it later run
132 This version runs normal doctests, but the idea is to make it later run
140 ipython syntax instead."""
133 ipython syntax instead."""
141
134
142 # Capture the enclosing instance with a different name, so the new
135 # Capture the enclosing instance with a different name, so the new
143 # class below can see it without confusion regarding its own 'self'
136 # class below can see it without confusion regarding its own 'self'
144 # that will point to the test instance at runtime
137 # that will point to the test instance at runtime
145 d2u = self
138 d2u = self
146
139
147 # Rewrite the function's docstring to have python syntax
140 # Rewrite the function's docstring to have python syntax
148 if func.__doc__ is not None:
141 if func.__doc__ is not None:
149 func.__doc__ = ip2py(func.__doc__)
142 func.__doc__ = ip2py(func.__doc__)
150
143
151 # Now, create a tester object that is a real unittest instance, so
144 # Now, create a tester object that is a real unittest instance, so
152 # normal unittest machinery (or Nose, or Trial) can find it.
145 # normal unittest machinery (or Nose, or Trial) can find it.
153 class Tester(unittest.TestCase):
146 class Tester(unittest.TestCase):
154 def test(self):
147 def test(self):
155 # Make a new runner per function to be tested
148 # Make a new runner per function to be tested
156 runner = DocTestRunner(verbose=d2u.verbose)
149 runner = DocTestRunner(verbose=d2u.verbose)
157 map(runner.run, d2u.finder.find(func, func.__name__))
150 map(runner.run, d2u.finder.find(func, func.__name__))
158 failed = count_failures(runner)
151 failed = count_failures(runner)
159 if failed:
152 if failed:
160 # Since we only looked at a single function's docstring,
153 # Since we only looked at a single function's docstring,
161 # failed should contain at most one item. More than that
154 # failed should contain at most one item. More than that
162 # is a case we can't handle and should error out on
155 # is a case we can't handle and should error out on
163 if len(failed) > 1:
156 if len(failed) > 1:
164 err = "Invalid number of test results:" % failed
157 err = "Invalid number of test results:" % failed
165 raise ValueError(err)
158 raise ValueError(err)
166 # Report a normal failure.
159 # Report a normal failure.
167 self.fail('failed doctests: %s' % str(failed[0]))
160 self.fail('failed doctests: %s' % str(failed[0]))
168
161
169 # Rename it so test reports have the original signature.
162 # Rename it so test reports have the original signature.
170 Tester.__name__ = func.__name__
163 Tester.__name__ = func.__name__
171 return Tester
164 return Tester
172
165
173
166
174 def ipdocstring(func):
167 def ipdocstring(func):
175 """Change the function docstring via ip2py.
168 """Change the function docstring via ip2py.
176 """
169 """
177 if func.__doc__ is not None:
170 if func.__doc__ is not None:
178 func.__doc__ = ip2py(func.__doc__)
171 func.__doc__ = ip2py(func.__doc__)
179 return func
172 return func
180
173
181
174
182 # Make an instance of the classes for public use
175 # Make an instance of the classes for public use
183 ipdoctest = Doc2UnitTester()
176 ipdoctest = Doc2UnitTester()
184 ip2py = IPython2PythonConverter()
177 ip2py = IPython2PythonConverter()
@@ -1,187 +1,168 b''
1 """Tests for the decorators we've created for IPython.
1 """Tests for the decorators we've created for IPython.
2 """
2 """
3
3
4 # Module imports
4 # Module imports
5 # Std lib
5 # Std lib
6 import inspect
6 import inspect
7 import sys
7 import sys
8
8
9 # Third party
9 # Third party
10 import nose.tools as nt
10 import nose.tools as nt
11
11
12 # Our own
12 # Our own
13 from IPython.testing import decorators as dec
13 from IPython.testing import decorators as dec
14 from IPython.testing.skipdoctest import skip_doctest
14 from IPython.testing.skipdoctest import skip_doctest
15 from IPython.testing.ipunittest import ParametricTestCase
16
15
17 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
18 # Utilities
17 # Utilities
19
18
20 # Note: copied from OInspect, kept here so the testing stuff doesn't create
19 # Note: copied from OInspect, kept here so the testing stuff doesn't create
21 # circular dependencies and is easier to reuse.
20 # circular dependencies and is easier to reuse.
22 def getargspec(obj):
21 def getargspec(obj):
23 """Get the names and default values of a function's arguments.
22 """Get the names and default values of a function's arguments.
24
23
25 A tuple of four things is returned: (args, varargs, varkw, defaults).
24 A tuple of four things is returned: (args, varargs, varkw, defaults).
26 'args' is a list of the argument names (it may contain nested lists).
25 'args' is a list of the argument names (it may contain nested lists).
27 'varargs' and 'varkw' are the names of the * and ** arguments or None.
26 'varargs' and 'varkw' are the names of the * and ** arguments or None.
28 'defaults' is an n-tuple of the default values of the last n arguments.
27 'defaults' is an n-tuple of the default values of the last n arguments.
29
28
30 Modified version of inspect.getargspec from the Python Standard
29 Modified version of inspect.getargspec from the Python Standard
31 Library."""
30 Library."""
32
31
33 if inspect.isfunction(obj):
32 if inspect.isfunction(obj):
34 func_obj = obj
33 func_obj = obj
35 elif inspect.ismethod(obj):
34 elif inspect.ismethod(obj):
36 func_obj = obj.im_func
35 func_obj = obj.im_func
37 else:
36 else:
38 raise TypeError('arg is not a Python function')
37 raise TypeError('arg is not a Python function')
39 args, varargs, varkw = inspect.getargs(func_obj.func_code)
38 args, varargs, varkw = inspect.getargs(func_obj.func_code)
40 return args, varargs, varkw, func_obj.func_defaults
39 return args, varargs, varkw, func_obj.func_defaults
41
40
42 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
43 # Testing functions
42 # Testing functions
44
43
45 @dec.as_unittest
44 @dec.as_unittest
46 def trivial():
45 def trivial():
47 """A trivial test"""
46 """A trivial test"""
48 pass
47 pass
49
48
50 # Some examples of parametric tests.
51
52 def is_smaller(i,j):
53 assert i<j,"%s !< %s" % (i,j)
54
55 class Tester(ParametricTestCase):
56
57 def test_parametric(self):
58 yield is_smaller(3, 4)
59 x, y = 1, 2
60 yield is_smaller(x, y)
61
62 @dec.parametric
63 def test_par_standalone():
64 yield is_smaller(3, 4)
65 x, y = 1, 2
66 yield is_smaller(x, y)
67
68
49
69 @dec.skip
50 @dec.skip
70 def test_deliberately_broken():
51 def test_deliberately_broken():
71 """A deliberately broken test - we want to skip this one."""
52 """A deliberately broken test - we want to skip this one."""
72 1/0
53 1/0
73
54
74 @dec.skip('Testing the skip decorator')
55 @dec.skip('Testing the skip decorator')
75 def test_deliberately_broken2():
56 def test_deliberately_broken2():
76 """Another deliberately broken test - we want to skip this one."""
57 """Another deliberately broken test - we want to skip this one."""
77 1/0
58 1/0
78
59
79
60
80 # Verify that we can correctly skip the doctest for a function at will, but
61 # Verify that we can correctly skip the doctest for a function at will, but
81 # that the docstring itself is NOT destroyed by the decorator.
62 # that the docstring itself is NOT destroyed by the decorator.
82 @skip_doctest
63 @skip_doctest
83 def doctest_bad(x,y=1,**k):
64 def doctest_bad(x,y=1,**k):
84 """A function whose doctest we need to skip.
65 """A function whose doctest we need to skip.
85
66
86 >>> 1+1
67 >>> 1+1
87 3
68 3
88 """
69 """
89 print 'x:',x
70 print 'x:',x
90 print 'y:',y
71 print 'y:',y
91 print 'k:',k
72 print 'k:',k
92
73
93
74
94 def call_doctest_bad():
75 def call_doctest_bad():
95 """Check that we can still call the decorated functions.
76 """Check that we can still call the decorated functions.
96
77
97 >>> doctest_bad(3,y=4)
78 >>> doctest_bad(3,y=4)
98 x: 3
79 x: 3
99 y: 4
80 y: 4
100 k: {}
81 k: {}
101 """
82 """
102 pass
83 pass
103
84
104
85
105 def test_skip_dt_decorator():
86 def test_skip_dt_decorator():
106 """Doctest-skipping decorator should preserve the docstring.
87 """Doctest-skipping decorator should preserve the docstring.
107 """
88 """
108 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
89 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
109 check = """A function whose doctest we need to skip.
90 check = """A function whose doctest we need to skip.
110
91
111 >>> 1+1
92 >>> 1+1
112 3
93 3
113 """
94 """
114 # Fetch the docstring from doctest_bad after decoration.
95 # Fetch the docstring from doctest_bad after decoration.
115 val = doctest_bad.__doc__
96 val = doctest_bad.__doc__
116
97
117 nt.assert_equal(check,val,"doctest_bad docstrings don't match")
98 nt.assert_equal(check,val,"doctest_bad docstrings don't match")
118
99
119
100
120 # Doctest skipping should work for class methods too
101 # Doctest skipping should work for class methods too
121 class FooClass(object):
102 class FooClass(object):
122 """FooClass
103 """FooClass
123
104
124 Example:
105 Example:
125
106
126 >>> 1+1
107 >>> 1+1
127 2
108 2
128 """
109 """
129
110
130 @skip_doctest
111 @skip_doctest
131 def __init__(self,x):
112 def __init__(self,x):
132 """Make a FooClass.
113 """Make a FooClass.
133
114
134 Example:
115 Example:
135
116
136 >>> f = FooClass(3)
117 >>> f = FooClass(3)
137 junk
118 junk
138 """
119 """
139 print 'Making a FooClass.'
120 print 'Making a FooClass.'
140 self.x = x
121 self.x = x
141
122
142 @skip_doctest
123 @skip_doctest
143 def bar(self,y):
124 def bar(self,y):
144 """Example:
125 """Example:
145
126
146 >>> ff = FooClass(3)
127 >>> ff = FooClass(3)
147 >>> ff.bar(0)
128 >>> ff.bar(0)
148 boom!
129 boom!
149 >>> 1/0
130 >>> 1/0
150 bam!
131 bam!
151 """
132 """
152 return 1/y
133 return 1/y
153
134
154 def baz(self,y):
135 def baz(self,y):
155 """Example:
136 """Example:
156
137
157 >>> ff2 = FooClass(3)
138 >>> ff2 = FooClass(3)
158 Making a FooClass.
139 Making a FooClass.
159 >>> ff2.baz(3)
140 >>> ff2.baz(3)
160 True
141 True
161 """
142 """
162 return self.x==y
143 return self.x==y
163
144
164
145
165 def test_skip_dt_decorator2():
146 def test_skip_dt_decorator2():
166 """Doctest-skipping decorator should preserve function signature.
147 """Doctest-skipping decorator should preserve function signature.
167 """
148 """
168 # Hardcoded correct answer
149 # Hardcoded correct answer
169 dtargs = (['x', 'y'], None, 'k', (1,))
150 dtargs = (['x', 'y'], None, 'k', (1,))
170 # Introspect out the value
151 # Introspect out the value
171 dtargsr = getargspec(doctest_bad)
152 dtargsr = getargspec(doctest_bad)
172 assert dtargsr==dtargs, \
153 assert dtargsr==dtargs, \
173 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
154 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
174
155
175
156
176 @dec.skip_linux
157 @dec.skip_linux
177 def test_linux():
158 def test_linux():
178 nt.assert_false(sys.platform.startswith('linux'),"This test can't run under linux")
159 nt.assert_false(sys.platform.startswith('linux'),"This test can't run under linux")
179
160
180 @dec.skip_win32
161 @dec.skip_win32
181 def test_win32():
162 def test_win32():
182 nt.assert_not_equal(sys.platform,'win32',"This test can't run under windows")
163 nt.assert_not_equal(sys.platform,'win32',"This test can't run under windows")
183
164
184 @dec.skip_osx
165 @dec.skip_osx
185 def test_osx():
166 def test_osx():
186 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
167 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
187
168
@@ -1,135 +1,133 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for testing.tools
3 Tests for testing.tools
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import with_statement
16 from __future__ import with_statement
17
17
18 import os
18 import os
19 import unittest
19 import unittest
20
20
21 import nose.tools as nt
21 import nose.tools as nt
22
22
23 from IPython.testing import decorators as dec
23 from IPython.testing import decorators as dec
24 from IPython.testing import tools as tt
24 from IPython.testing import tools as tt
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Tests
27 # Tests
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 @dec.skip_win32
30 @dec.skip_win32
31 def test_full_path_posix():
31 def test_full_path_posix():
32 spath = '/foo/bar.py'
32 spath = '/foo/bar.py'
33 result = tt.full_path(spath,['a.txt','b.txt'])
33 result = tt.full_path(spath,['a.txt','b.txt'])
34 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
34 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
35 spath = '/foo'
35 spath = '/foo'
36 result = tt.full_path(spath,['a.txt','b.txt'])
36 result = tt.full_path(spath,['a.txt','b.txt'])
37 nt.assert_equal(result, ['/a.txt', '/b.txt'])
37 nt.assert_equal(result, ['/a.txt', '/b.txt'])
38 result = tt.full_path(spath,'a.txt')
38 result = tt.full_path(spath,'a.txt')
39 nt.assert_equal(result, ['/a.txt'])
39 nt.assert_equal(result, ['/a.txt'])
40
40
41
41
42 @dec.skip_if_not_win32
42 @dec.skip_if_not_win32
43 def test_full_path_win32():
43 def test_full_path_win32():
44 spath = 'c:\\foo\\bar.py'
44 spath = 'c:\\foo\\bar.py'
45 result = tt.full_path(spath,['a.txt','b.txt'])
45 result = tt.full_path(spath,['a.txt','b.txt'])
46 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
46 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
47 spath = 'c:\\foo'
47 spath = 'c:\\foo'
48 result = tt.full_path(spath,['a.txt','b.txt'])
48 result = tt.full_path(spath,['a.txt','b.txt'])
49 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
49 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
50 result = tt.full_path(spath,'a.txt')
50 result = tt.full_path(spath,'a.txt')
51 nt.assert_equal(result, ['c:\\a.txt'])
51 nt.assert_equal(result, ['c:\\a.txt'])
52
52
53
53
54 @dec.parametric
55 def test_parser():
54 def test_parser():
56 err = ("FAILED (errors=1)", 1, 0)
55 err = ("FAILED (errors=1)", 1, 0)
57 fail = ("FAILED (failures=1)", 0, 1)
56 fail = ("FAILED (failures=1)", 0, 1)
58 both = ("FAILED (errors=1, failures=1)", 1, 1)
57 both = ("FAILED (errors=1, failures=1)", 1, 1)
59 for txt, nerr, nfail in [err, fail, both]:
58 for txt, nerr, nfail in [err, fail, both]:
60 nerr1, nfail1 = tt.parse_test_output(txt)
59 nerr1, nfail1 = tt.parse_test_output(txt)
61 yield nt.assert_equal(nerr, nerr1)
60 nt.assert_equal(nerr, nerr1)
62 yield nt.assert_equal(nfail, nfail1)
61 nt.assert_equal(nfail, nfail1)
62
63
63
64
65 @dec.parametric
66 def test_temp_pyfile():
64 def test_temp_pyfile():
67 src = 'pass\n'
65 src = 'pass\n'
68 fname, fh = tt.temp_pyfile(src)
66 fname, fh = tt.temp_pyfile(src)
69 yield nt.assert_true(os.path.isfile(fname))
67 assert os.path.isfile(fname)
70 fh.close()
68 fh.close()
71 with open(fname) as fh2:
69 with open(fname) as fh2:
72 src2 = fh2.read()
70 src2 = fh2.read()
73 yield nt.assert_equal(src2, src)
71 nt.assert_equal(src2, src)
74
72
75 class TestAssertPrints(unittest.TestCase):
73 class TestAssertPrints(unittest.TestCase):
76 def test_passing(self):
74 def test_passing(self):
77 with tt.AssertPrints("abc"):
75 with tt.AssertPrints("abc"):
78 print "abcd"
76 print "abcd"
79 print "def"
77 print "def"
80 print b"ghi"
78 print b"ghi"
81
79
82 def test_failing(self):
80 def test_failing(self):
83 def func():
81 def func():
84 with tt.AssertPrints("abc"):
82 with tt.AssertPrints("abc"):
85 print "acd"
83 print "acd"
86 print "def"
84 print "def"
87 print b"ghi"
85 print b"ghi"
88
86
89 self.assertRaises(AssertionError, func)
87 self.assertRaises(AssertionError, func)
90
88
91
89
92 class Test_ipexec_validate(unittest.TestCase, tt.TempFileMixin):
90 class Test_ipexec_validate(unittest.TestCase, tt.TempFileMixin):
93 def test_main_path(self):
91 def test_main_path(self):
94 """Test with only stdout results.
92 """Test with only stdout results.
95 """
93 """
96 self.mktmp("print('A')\n"
94 self.mktmp("print('A')\n"
97 "print('B')\n"
95 "print('B')\n"
98 )
96 )
99 out = "A\nB"
97 out = "A\nB"
100 tt.ipexec_validate(self.fname, out)
98 tt.ipexec_validate(self.fname, out)
101
99
102 def test_main_path2(self):
100 def test_main_path2(self):
103 """Test with only stdout results, expecting windows line endings.
101 """Test with only stdout results, expecting windows line endings.
104 """
102 """
105 self.mktmp("print('A')\n"
103 self.mktmp("print('A')\n"
106 "print('B')\n"
104 "print('B')\n"
107 )
105 )
108 out = "A\r\nB"
106 out = "A\r\nB"
109 tt.ipexec_validate(self.fname, out)
107 tt.ipexec_validate(self.fname, out)
110
108
111 def test_exception_path(self):
109 def test_exception_path(self):
112 """Test exception path in exception_validate.
110 """Test exception path in exception_validate.
113 """
111 """
114 self.mktmp("from __future__ import print_function\n"
112 self.mktmp("from __future__ import print_function\n"
115 "import sys\n"
113 "import sys\n"
116 "print('A')\n"
114 "print('A')\n"
117 "print('B')\n"
115 "print('B')\n"
118 "print('C', file=sys.stderr)\n"
116 "print('C', file=sys.stderr)\n"
119 "print('D', file=sys.stderr)\n"
117 "print('D', file=sys.stderr)\n"
120 )
118 )
121 out = "A\nB"
119 out = "A\nB"
122 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\nD")
120 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\nD")
123
121
124 def test_exception_path2(self):
122 def test_exception_path2(self):
125 """Test exception path in exception_validate, expecting windows line endings.
123 """Test exception path in exception_validate, expecting windows line endings.
126 """
124 """
127 self.mktmp("from __future__ import print_function\n"
125 self.mktmp("from __future__ import print_function\n"
128 "import sys\n"
126 "import sys\n"
129 "print('A')\n"
127 "print('A')\n"
130 "print('B')\n"
128 "print('B')\n"
131 "print('C', file=sys.stderr)\n"
129 "print('C', file=sys.stderr)\n"
132 "print('D', file=sys.stderr)\n"
130 "print('D', file=sys.stderr)\n"
133 )
131 )
134 out = "A\r\nB"
132 out = "A\r\nB"
135 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD")
133 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD")
@@ -1,86 +1,86 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for io.py"""
2 """Tests for io.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 import sys
16 import sys
17
17
18 from StringIO import StringIO
18 from StringIO import StringIO
19 from subprocess import Popen, PIPE
19 from subprocess import Popen, PIPE
20 import unittest
20
21
21 import nose.tools as nt
22 import nose.tools as nt
22
23
23 from IPython.testing.ipunittest import ParametricTestCase
24 from IPython.utils.io import Tee, capture_output
24 from IPython.utils.io import Tee, capture_output
25 from IPython.utils.py3compat import doctest_refactor_print
25 from IPython.utils.py3compat import doctest_refactor_print
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Tests
28 # Tests
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31
32 def test_tee_simple():
32 def test_tee_simple():
33 "Very simple check with stdout only"
33 "Very simple check with stdout only"
34 chan = StringIO()
34 chan = StringIO()
35 text = 'Hello'
35 text = 'Hello'
36 tee = Tee(chan, channel='stdout')
36 tee = Tee(chan, channel='stdout')
37 print(text, file=chan)
37 print(text, file=chan)
38 nt.assert_equal(chan.getvalue(), text+"\n")
38 nt.assert_equal(chan.getvalue(), text+"\n")
39
39
40
40
41 class TeeTestCase(ParametricTestCase):
41 class TeeTestCase(unittest.TestCase):
42
42
43 def tchan(self, channel, check='close'):
43 def tchan(self, channel, check='close'):
44 trap = StringIO()
44 trap = StringIO()
45 chan = StringIO()
45 chan = StringIO()
46 text = 'Hello'
46 text = 'Hello'
47
47
48 std_ori = getattr(sys, channel)
48 std_ori = getattr(sys, channel)
49 setattr(sys, channel, trap)
49 setattr(sys, channel, trap)
50
50
51 tee = Tee(chan, channel=channel)
51 tee = Tee(chan, channel=channel)
52 print(text, end='', file=chan)
52 print(text, end='', file=chan)
53 setattr(sys, channel, std_ori)
53 setattr(sys, channel, std_ori)
54 trap_val = trap.getvalue()
54 trap_val = trap.getvalue()
55 nt.assert_equal(chan.getvalue(), text)
55 nt.assert_equal(chan.getvalue(), text)
56 if check=='close':
56 if check=='close':
57 tee.close()
57 tee.close()
58 else:
58 else:
59 del tee
59 del tee
60
60
61 def test(self):
61 def test(self):
62 for chan in ['stdout', 'stderr']:
62 for chan in ['stdout', 'stderr']:
63 for check in ['close', 'del']:
63 for check in ['close', 'del']:
64 yield self.tchan(chan, check)
64 self.tchan(chan, check)
65
65
66 def test_io_init():
66 def test_io_init():
67 """Test that io.stdin/out/err exist at startup"""
67 """Test that io.stdin/out/err exist at startup"""
68 for name in ('stdin', 'stdout', 'stderr'):
68 for name in ('stdin', 'stdout', 'stderr'):
69 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
69 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
70 p = Popen([sys.executable, '-c', cmd],
70 p = Popen([sys.executable, '-c', cmd],
71 stdout=PIPE)
71 stdout=PIPE)
72 p.wait()
72 p.wait()
73 classname = p.stdout.read().strip().decode('ascii')
73 classname = p.stdout.read().strip().decode('ascii')
74 # __class__ is a reference to the class object in Python 3, so we can't
74 # __class__ is a reference to the class object in Python 3, so we can't
75 # just test for string equality.
75 # just test for string equality.
76 assert 'IPython.utils.io.IOStream' in classname, classname
76 assert 'IPython.utils.io.IOStream' in classname, classname
77
77
78 def test_capture_output():
78 def test_capture_output():
79 """capture_output() context works"""
79 """capture_output() context works"""
80
80
81 with capture_output() as io:
81 with capture_output() as io:
82 print('hi, stdout')
82 print('hi, stdout')
83 print('hi, stderr', file=sys.stderr)
83 print('hi, stderr', file=sys.stderr)
84
84
85 nt.assert_equal(io.stdout, 'hi, stdout\n')
85 nt.assert_equal(io.stdout, 'hi, stdout\n')
86 nt.assert_equal(io.stderr, 'hi, stderr\n')
86 nt.assert_equal(io.stderr, 'hi, stderr\n')
@@ -1,133 +1,131 b''
1 """Test suite for our JSON utilities.
1 """Test suite for our JSON utilities.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # stdlib
13 # stdlib
14 import datetime
14 import datetime
15 import json
15 import json
16 from base64 import decodestring
16 from base64 import decodestring
17
17
18 # third party
18 # third party
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 # our own
21 # our own
22 from IPython.testing import decorators as dec
23 from IPython.utils import jsonutil, tz
22 from IPython.utils import jsonutil, tz
24 from ..jsonutil import json_clean, encode_images
23 from ..jsonutil import json_clean, encode_images
25 from ..py3compat import unicode_to_str, str_to_bytes
24 from ..py3compat import unicode_to_str, str_to_bytes
26
25
27 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
28 # Test functions
27 # Test functions
29 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
30
29
31 def test():
30 def test():
32 # list of input/expected output. Use None for the expected output if it
31 # list of input/expected output. Use None for the expected output if it
33 # can be the same as the input.
32 # can be the same as the input.
34 pairs = [(1, None), # start with scalars
33 pairs = [(1, None), # start with scalars
35 (1.0, None),
34 (1.0, None),
36 ('a', None),
35 ('a', None),
37 (True, None),
36 (True, None),
38 (False, None),
37 (False, None),
39 (None, None),
38 (None, None),
40 # complex numbers for now just go to strings, as otherwise they
39 # complex numbers for now just go to strings, as otherwise they
41 # are unserializable
40 # are unserializable
42 (1j, '1j'),
41 (1j, '1j'),
43 # Containers
42 # Containers
44 ([1, 2], None),
43 ([1, 2], None),
45 ((1, 2), [1, 2]),
44 ((1, 2), [1, 2]),
46 (set([1, 2]), [1, 2]),
45 (set([1, 2]), [1, 2]),
47 (dict(x=1), None),
46 (dict(x=1), None),
48 ({'x': 1, 'y':[1,2,3], '1':'int'}, None),
47 ({'x': 1, 'y':[1,2,3], '1':'int'}, None),
49 # More exotic objects
48 # More exotic objects
50 ((x for x in range(3)), [0, 1, 2]),
49 ((x for x in range(3)), [0, 1, 2]),
51 (iter([1, 2]), [1, 2]),
50 (iter([1, 2]), [1, 2]),
52 ]
51 ]
53
52
54 for val, jval in pairs:
53 for val, jval in pairs:
55 if jval is None:
54 if jval is None:
56 jval = val
55 jval = val
57 out = json_clean(val)
56 out = json_clean(val)
58 # validate our cleanup
57 # validate our cleanup
59 nt.assert_equal(out, jval)
58 nt.assert_equal(out, jval)
60 # and ensure that what we return, indeed encodes cleanly
59 # and ensure that what we return, indeed encodes cleanly
61 json.loads(json.dumps(out))
60 json.loads(json.dumps(out))
62
61
63
62
64
63
65 @dec.parametric
66 def test_encode_images():
64 def test_encode_images():
67 # invalid data, but the header and footer are from real files
65 # invalid data, but the header and footer are from real files
68 pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82'
66 pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82'
69 jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9'
67 jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9'
70
68
71 fmt = {
69 fmt = {
72 'image/png' : pngdata,
70 'image/png' : pngdata,
73 'image/jpeg' : jpegdata,
71 'image/jpeg' : jpegdata,
74 }
72 }
75 encoded = encode_images(fmt)
73 encoded = encode_images(fmt)
76 for key, value in fmt.iteritems():
74 for key, value in fmt.iteritems():
77 # encoded has unicode, want bytes
75 # encoded has unicode, want bytes
78 decoded = decodestring(encoded[key].encode('ascii'))
76 decoded = decodestring(encoded[key].encode('ascii'))
79 yield nt.assert_equal(decoded, value)
77 nt.assert_equal(decoded, value)
80 encoded2 = encode_images(encoded)
78 encoded2 = encode_images(encoded)
81 yield nt.assert_equal(encoded, encoded2)
79 nt.assert_equal(encoded, encoded2)
82
80
83 b64_str = {}
81 b64_str = {}
84 for key, encoded in encoded.iteritems():
82 for key, encoded in encoded.iteritems():
85 b64_str[key] = unicode_to_str(encoded)
83 b64_str[key] = unicode_to_str(encoded)
86 encoded3 = encode_images(b64_str)
84 encoded3 = encode_images(b64_str)
87 yield nt.assert_equal(encoded3, b64_str)
85 nt.assert_equal(encoded3, b64_str)
88 for key, value in fmt.iteritems():
86 for key, value in fmt.iteritems():
89 # encoded3 has str, want bytes
87 # encoded3 has str, want bytes
90 decoded = decodestring(str_to_bytes(encoded3[key]))
88 decoded = decodestring(str_to_bytes(encoded3[key]))
91 yield nt.assert_equal(decoded, value)
89 nt.assert_equal(decoded, value)
92
90
93 def test_lambda():
91 def test_lambda():
94 jc = json_clean(lambda : 1)
92 jc = json_clean(lambda : 1)
95 assert isinstance(jc, str)
93 assert isinstance(jc, str)
96 assert '<lambda>' in jc
94 assert '<lambda>' in jc
97 json.dumps(jc)
95 json.dumps(jc)
98
96
99 def test_extract_dates():
97 def test_extract_dates():
100 timestamps = [
98 timestamps = [
101 '2013-07-03T16:34:52.249482',
99 '2013-07-03T16:34:52.249482',
102 '2013-07-03T16:34:52.249482Z',
100 '2013-07-03T16:34:52.249482Z',
103 '2013-07-03T16:34:52.249482Z-0800',
101 '2013-07-03T16:34:52.249482Z-0800',
104 '2013-07-03T16:34:52.249482Z+0800',
102 '2013-07-03T16:34:52.249482Z+0800',
105 '2013-07-03T16:34:52.249482Z+08:00',
103 '2013-07-03T16:34:52.249482Z+08:00',
106 '2013-07-03T16:34:52.249482Z-08:00',
104 '2013-07-03T16:34:52.249482Z-08:00',
107 '2013-07-03T16:34:52.249482-0800',
105 '2013-07-03T16:34:52.249482-0800',
108 '2013-07-03T16:34:52.249482+0800',
106 '2013-07-03T16:34:52.249482+0800',
109 '2013-07-03T16:34:52.249482+08:00',
107 '2013-07-03T16:34:52.249482+08:00',
110 '2013-07-03T16:34:52.249482-08:00',
108 '2013-07-03T16:34:52.249482-08:00',
111 ]
109 ]
112 extracted = jsonutil.extract_dates(timestamps)
110 extracted = jsonutil.extract_dates(timestamps)
113 ref = extracted[0]
111 ref = extracted[0]
114 for dt in extracted:
112 for dt in extracted:
115 nt.assert_true(isinstance(dt, datetime.datetime))
113 nt.assert_true(isinstance(dt, datetime.datetime))
116 nt.assert_equal(dt, ref)
114 nt.assert_equal(dt, ref)
117
115
118 def test_date_default():
116 def test_date_default():
119 data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow())
117 data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow())
120 jsondata = json.dumps(data, default=jsonutil.date_default)
118 jsondata = json.dumps(data, default=jsonutil.date_default)
121 nt.assert_in("+00", jsondata)
119 nt.assert_in("+00", jsondata)
122 nt.assert_equal(jsondata.count("+00"), 1)
120 nt.assert_equal(jsondata.count("+00"), 1)
123 extracted = jsonutil.extract_dates(json.loads(jsondata))
121 extracted = jsonutil.extract_dates(json.loads(jsondata))
124 for dt in extracted.values():
122 for dt in extracted.values():
125 nt.assert_true(isinstance(dt, datetime.datetime))
123 nt.assert_true(isinstance(dt, datetime.datetime))
126
124
127 def test_exception():
125 def test_exception():
128 bad_dicts = [{1:'number', '1':'string'},
126 bad_dicts = [{1:'number', '1':'string'},
129 {True:'bool', 'True':'string'},
127 {True:'bool', 'True':'string'},
130 ]
128 ]
131 for d in bad_dicts:
129 for d in bad_dicts:
132 nt.assert_raises(ValueError, json_clean, d)
130 nt.assert_raises(ValueError, json_clean, d)
133
131
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now