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