##// END OF EJS Templates
Fix doctests in IPython.testing
Thomas Kluyver -
Show More
@@ -1,164 +1,161 b''
1 """Simple example using doctests.
1 """Simple example using doctests.
2
2
3 This file just contains doctests both using plain python and IPython prompts.
3 This file just contains doctests both using plain python and IPython prompts.
4 All tests should be loaded by nose.
4 All tests should be loaded by nose.
5 """
5 """
6 from IPython.utils.py3compat import doctest_refactor_print
6 from IPython.utils.py3compat import doctest_refactor_print
7
7
8 def pyfunc():
8 def pyfunc():
9 """Some pure python tests...
9 """Some pure python tests...
10
10
11 >>> pyfunc()
11 >>> pyfunc()
12 'pyfunc'
12 'pyfunc'
13
13
14 >>> import os
14 >>> import os
15
15
16 >>> 2+3
16 >>> 2+3
17 5
17 5
18
18
19 >>> for i in range(3):
19 >>> for i in range(3):
20 ... print i,
20 ... print(i, end=' ')
21 ... print i+1,
21 ... print(i+1, end=' ')
22 ...
22 ...
23 0 1 1 2 2 3
23 0 1 1 2 2 3
24 """
24 """
25 return 'pyfunc'
25 return 'pyfunc'
26
26
27 @doctest_refactor_print
27 @doctest_refactor_print
28 def ipfunc():
28 def ipfunc():
29 """Some ipython tests...
29 """Some ipython tests...
30
30
31 In [1]: import os
31 In [1]: import os
32
32
33 In [3]: 2+3
33 In [3]: 2+3
34 Out[3]: 5
34 Out[3]: 5
35
35
36 In [26]: for i in range(3):
36 In [26]: for i in range(3):
37 ....: print i,
37 ....: print(i, end=' ')
38 ....: print i+1,
38 ....: print(i+1, end=' ')
39 ....:
39 ....:
40 0 1 1 2 2 3
40 0 1 1 2 2 3
41
41
42
42
43 Examples that access the operating system work:
43 Examples that access the operating system work:
44
44
45 In [1]: !echo hello
45 In [1]: !echo hello
46 hello
46 hello
47
47
48 In [2]: !echo hello > /tmp/foo_iptest
48 In [2]: !echo hello > /tmp/foo_iptest
49
49
50 In [3]: !cat /tmp/foo_iptest
50 In [3]: !cat /tmp/foo_iptest
51 hello
51 hello
52
52
53 In [4]: rm -f /tmp/foo_iptest
53 In [4]: rm -f /tmp/foo_iptest
54
54
55 It's OK to use '_' for the last result, but do NOT try to use IPython's
55 It's OK to use '_' for the last result, but do NOT try to use IPython's
56 numbered history of _NN outputs, since those won't exist under the
56 numbered history of _NN outputs, since those won't exist under the
57 doctest environment:
57 doctest environment:
58
58
59 In [7]: 'hi'
59 In [7]: 'hi'
60 Out[7]: 'hi'
60 Out[7]: 'hi'
61
61
62 In [8]: print repr(_)
62 In [8]: print(repr(_))
63 'hi'
63 'hi'
64
64
65 In [7]: 3+4
65 In [7]: 3+4
66 Out[7]: 7
66 Out[7]: 7
67
67
68 In [8]: _+3
68 In [8]: _+3
69 Out[8]: 10
69 Out[8]: 10
70
70
71 In [9]: ipfunc()
71 In [9]: ipfunc()
72 Out[9]: 'ipfunc'
72 Out[9]: 'ipfunc'
73 """
73 """
74 return 'ipfunc'
74 return 'ipfunc'
75
75
76
76
77 def ranfunc():
77 def ranfunc():
78 """A function with some random output.
78 """A function with some random output.
79
79
80 Normal examples are verified as usual:
80 Normal examples are verified as usual:
81 >>> 1+3
81 >>> 1+3
82 4
82 4
83
83
84 But if you put '# random' in the output, it is ignored:
84 But if you put '# random' in the output, it is ignored:
85 >>> 1+3
85 >>> 1+3
86 junk goes here... # random
86 junk goes here... # random
87
87
88 >>> 1+2
88 >>> 1+2
89 again, anything goes #random
89 again, anything goes #random
90 if multiline, the random mark is only needed once.
90 if multiline, the random mark is only needed once.
91
91
92 >>> 1+2
92 >>> 1+2
93 You can also put the random marker at the end:
93 You can also put the random marker at the end:
94 # random
94 # random
95
95
96 >>> 1+2
96 >>> 1+2
97 # random
97 # random
98 .. or at the beginning.
98 .. or at the beginning.
99
99
100 More correct input is properly verified:
100 More correct input is properly verified:
101 >>> ranfunc()
101 >>> ranfunc()
102 'ranfunc'
102 'ranfunc'
103 """
103 """
104 return 'ranfunc'
104 return 'ranfunc'
105
105
106
106
107 def random_all():
107 def random_all():
108 """A function where we ignore the output of ALL examples.
108 """A function where we ignore the output of ALL examples.
109
109
110 Examples:
110 Examples:
111
111
112 # all-random
112 # all-random
113
113
114 This mark tells the testing machinery that all subsequent examples should
114 This mark tells the testing machinery that all subsequent examples should
115 be treated as random (ignoring their output). They are still executed,
115 be treated as random (ignoring their output). They are still executed,
116 so if a they raise an error, it will be detected as such, but their
116 so if a they raise an error, it will be detected as such, but their
117 output is completely ignored.
117 output is completely ignored.
118
118
119 >>> 1+3
119 >>> 1+3
120 junk goes here...
120 junk goes here...
121
121
122 >>> 1+3
122 >>> 1+3
123 klasdfj;
123 klasdfj;
124
124
125 >>> 1+2
125 >>> 1+2
126 again, anything goes
126 again, anything goes
127 blah...
127 blah...
128 """
128 """
129 pass
129 pass
130
130
131 @doctest_refactor_print
131 @doctest_refactor_print
132 def iprand():
132 def iprand():
133 """Some ipython tests with random output.
133 """Some ipython tests with random output.
134
134
135 In [7]: 3+4
135 In [7]: 3+4
136 Out[7]: 7
136 Out[7]: 7
137
137
138 In [8]: print 'hello'
138 In [8]: print('hello')
139 world # random
139 world # random
140
140
141 In [9]: iprand()
141 In [9]: iprand()
142 Out[9]: 'iprand'
142 Out[9]: 'iprand'
143 """
143 """
144 return 'iprand'
144 return 'iprand'
145
145
146 @doctest_refactor_print
146 @doctest_refactor_print
147 def iprand_all():
147 def iprand_all():
148 """Some ipython tests with fully random output.
148 """Some ipython tests with fully random output.
149
149
150 # all-random
150 # all-random
151
151
152 In [7]: 1
152 In [7]: 1
153 Out[7]: 99
153 Out[7]: 99
154
154
155 In [8]: print 'hello'
155 In [8]: print('hello')
156 world
156 world
157
157
158 In [9]: iprand_all()
158 In [9]: iprand_all()
159 Out[9]: 'junk'
159 Out[9]: 'junk'
160 """
160 """
161 return 'iprand_all'
161 return 'iprand_all'
162
163
164
@@ -1,33 +1,33 b''
1 """Simple example using doctests.
1 """Simple example using doctests.
2
2
3 This file just contains doctests both using plain python and IPython prompts.
3 This file just contains doctests both using plain python and IPython prompts.
4 All tests should be loaded by nose.
4 All tests should be loaded by nose.
5 """
5 """
6
6
7 def pyfunc():
7 def pyfunc():
8 """Some pure python tests...
8 """Some pure python tests...
9
9
10 >>> pyfunc()
10 >>> pyfunc()
11 'pyfunc'
11 'pyfunc'
12
12
13 >>> import os
13 >>> import os
14
14
15 >>> 2+3
15 >>> 2+3
16 5
16 5
17
17
18 >>> for i in range(3):
18 >>> for i in range(3):
19 ... print i,
19 ... print(i, end=' ')
20 ... print i+1,
20 ... print(i+1, end=' ')
21 ...
21 ...
22 0 1 1 2 2 3
22 0 1 1 2 2 3
23 """
23 """
24 return 'pyfunc'
24 return 'pyfunc'
25
25
26
26
27 def ipyfunc2():
27 def ipyfunc2():
28 """Some pure python tests...
28 """Some pure python tests...
29
29
30 >>> 1+1
30 >>> 1+1
31 2
31 2
32 """
32 """
33 return 'pyfunc2'
33 return 'pyfunc2'
@@ -1,444 +1,444 b''
1 """Generic testing tools.
1 """Generic testing tools.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 """
6 """
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2009 The IPython Development Team
11 # Copyright (C) 2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25
25
26 from contextlib import contextmanager
26 from contextlib import contextmanager
27 from io import StringIO
27 from io import StringIO
28 from subprocess import Popen, PIPE
28 from subprocess import Popen, PIPE
29
29
30 try:
30 try:
31 # These tools are used by parts of the runtime, so we make the nose
31 # These tools are used by parts of the runtime, so we make the nose
32 # dependency optional at this point. Nose is a hard dependency to run the
32 # dependency optional at this point. Nose is a hard dependency to run the
33 # test suite, but NOT to use ipython itself.
33 # test suite, but NOT to use ipython itself.
34 import nose.tools as nt
34 import nose.tools as nt
35 has_nose = True
35 has_nose = True
36 except ImportError:
36 except ImportError:
37 has_nose = False
37 has_nose = False
38
38
39 from IPython.config.loader import Config
39 from IPython.config.loader import Config
40 from IPython.utils.process import get_output_error_code
40 from IPython.utils.process import get_output_error_code
41 from IPython.utils.text import list_strings
41 from IPython.utils.text import list_strings
42 from IPython.utils.io import temp_pyfile, Tee
42 from IPython.utils.io import temp_pyfile, Tee
43 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.encoding import DEFAULT_ENCODING
44 from IPython.utils.encoding import DEFAULT_ENCODING
45
45
46 from . import decorators as dec
46 from . import decorators as dec
47 from . import skipdoctest
47 from . import skipdoctest
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Functions and classes
50 # Functions and classes
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 # The docstring for full_path doctests differently on win32 (different path
53 # The docstring for full_path doctests differently on win32 (different path
54 # separator) so just skip the doctest there. The example remains informative.
54 # separator) so just skip the doctest there. The example remains informative.
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
56
56
57 @doctest_deco
57 @doctest_deco
58 def full_path(startPath,files):
58 def full_path(startPath,files):
59 """Make full paths for all the listed files, based on startPath.
59 """Make full paths for all the listed files, based on startPath.
60
60
61 Only the base part of startPath is kept, since this routine is typically
61 Only the base part of startPath is kept, since this routine is typically
62 used with a script's __file__ variable as startPath. The base of startPath
62 used with a script's __file__ variable as startPath. The base of startPath
63 is then prepended to all the listed files, forming the output list.
63 is then prepended to all the listed files, forming the output list.
64
64
65 Parameters
65 Parameters
66 ----------
66 ----------
67 startPath : string
67 startPath : string
68 Initial path to use as the base for the results. This path is split
68 Initial path to use as the base for the results. This path is split
69 using os.path.split() and only its first component is kept.
69 using os.path.split() and only its first component is kept.
70
70
71 files : string or list
71 files : string or list
72 One or more files.
72 One or more files.
73
73
74 Examples
74 Examples
75 --------
75 --------
76
76
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 ['/foo/a.txt', '/foo/b.txt']
78 ['/foo/a.txt', '/foo/b.txt']
79
79
80 >>> full_path('/foo',['a.txt','b.txt'])
80 >>> full_path('/foo',['a.txt','b.txt'])
81 ['/a.txt', '/b.txt']
81 ['/a.txt', '/b.txt']
82
82
83 If a single file is given, the output is still a list:
83 If a single file is given, the output is still a list:
84 >>> full_path('/foo','a.txt')
84 >>> full_path('/foo','a.txt')
85 ['/a.txt']
85 ['/a.txt']
86 """
86 """
87
87
88 files = list_strings(files)
88 files = list_strings(files)
89 base = os.path.split(startPath)[0]
89 base = os.path.split(startPath)[0]
90 return [ os.path.join(base,f) for f in files ]
90 return [ os.path.join(base,f) for f in files ]
91
91
92
92
93 def parse_test_output(txt):
93 def parse_test_output(txt):
94 """Parse the output of a test run and return errors, failures.
94 """Parse the output of a test run and return errors, failures.
95
95
96 Parameters
96 Parameters
97 ----------
97 ----------
98 txt : str
98 txt : str
99 Text output of a test run, assumed to contain a line of one of the
99 Text output of a test run, assumed to contain a line of one of the
100 following forms::
100 following forms::
101
101
102 'FAILED (errors=1)'
102 'FAILED (errors=1)'
103 'FAILED (failures=1)'
103 'FAILED (failures=1)'
104 'FAILED (errors=1, failures=1)'
104 'FAILED (errors=1, failures=1)'
105
105
106 Returns
106 Returns
107 -------
107 -------
108 nerr, nfail: number of errors and failures.
108 nerr, nfail: number of errors and failures.
109 """
109 """
110
110
111 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
111 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
112 if err_m:
112 if err_m:
113 nerr = int(err_m.group(1))
113 nerr = int(err_m.group(1))
114 nfail = 0
114 nfail = 0
115 return nerr, nfail
115 return nerr, nfail
116
116
117 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
117 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
118 if fail_m:
118 if fail_m:
119 nerr = 0
119 nerr = 0
120 nfail = int(fail_m.group(1))
120 nfail = int(fail_m.group(1))
121 return nerr, nfail
121 return nerr, nfail
122
122
123 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
123 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
124 re.MULTILINE)
124 re.MULTILINE)
125 if both_m:
125 if both_m:
126 nerr = int(both_m.group(1))
126 nerr = int(both_m.group(1))
127 nfail = int(both_m.group(2))
127 nfail = int(both_m.group(2))
128 return nerr, nfail
128 return nerr, nfail
129
129
130 # If the input didn't match any of these forms, assume no error/failures
130 # If the input didn't match any of these forms, assume no error/failures
131 return 0, 0
131 return 0, 0
132
132
133
133
134 # So nose doesn't think this is a test
134 # So nose doesn't think this is a test
135 parse_test_output.__test__ = False
135 parse_test_output.__test__ = False
136
136
137
137
138 def default_argv():
138 def default_argv():
139 """Return a valid default argv for creating testing instances of ipython"""
139 """Return a valid default argv for creating testing instances of ipython"""
140
140
141 return ['--quick', # so no config file is loaded
141 return ['--quick', # so no config file is loaded
142 # Other defaults to minimize side effects on stdout
142 # Other defaults to minimize side effects on stdout
143 '--colors=NoColor', '--no-term-title','--no-banner',
143 '--colors=NoColor', '--no-term-title','--no-banner',
144 '--autocall=0']
144 '--autocall=0']
145
145
146
146
147 def default_config():
147 def default_config():
148 """Return a config object with good defaults for testing."""
148 """Return a config object with good defaults for testing."""
149 config = Config()
149 config = Config()
150 config.TerminalInteractiveShell.colors = 'NoColor'
150 config.TerminalInteractiveShell.colors = 'NoColor'
151 config.TerminalTerminalInteractiveShell.term_title = False,
151 config.TerminalTerminalInteractiveShell.term_title = False,
152 config.TerminalInteractiveShell.autocall = 0
152 config.TerminalInteractiveShell.autocall = 0
153 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
153 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
154 config.HistoryManager.db_cache_size = 10000
154 config.HistoryManager.db_cache_size = 10000
155 return config
155 return config
156
156
157
157
158 def get_ipython_cmd(as_string=False):
158 def get_ipython_cmd(as_string=False):
159 """
159 """
160 Return appropriate IPython command line name. By default, this will return
160 Return appropriate IPython command line name. By default, this will return
161 a list that can be used with subprocess.Popen, for example, but passing
161 a list that can be used with subprocess.Popen, for example, but passing
162 `as_string=True` allows for returning the IPython command as a string.
162 `as_string=True` allows for returning the IPython command as a string.
163
163
164 Parameters
164 Parameters
165 ----------
165 ----------
166 as_string: bool
166 as_string: bool
167 Flag to allow to return the command as a string.
167 Flag to allow to return the command as a string.
168 """
168 """
169 ipython_cmd = [sys.executable, "-m", "IPython"]
169 ipython_cmd = [sys.executable, "-m", "IPython"]
170
170
171 if as_string:
171 if as_string:
172 ipython_cmd = " ".join(ipython_cmd)
172 ipython_cmd = " ".join(ipython_cmd)
173
173
174 return ipython_cmd
174 return ipython_cmd
175
175
176 def ipexec(fname, options=None):
176 def ipexec(fname, options=None):
177 """Utility to call 'ipython filename'.
177 """Utility to call 'ipython filename'.
178
178
179 Starts IPython with a minimal and safe configuration to make startup as fast
179 Starts IPython with a minimal and safe configuration to make startup as fast
180 as possible.
180 as possible.
181
181
182 Note that this starts IPython in a subprocess!
182 Note that this starts IPython in a subprocess!
183
183
184 Parameters
184 Parameters
185 ----------
185 ----------
186 fname : str
186 fname : str
187 Name of file to be executed (should have .py or .ipy extension).
187 Name of file to be executed (should have .py or .ipy extension).
188
188
189 options : optional, list
189 options : optional, list
190 Extra command-line flags to be passed to IPython.
190 Extra command-line flags to be passed to IPython.
191
191
192 Returns
192 Returns
193 -------
193 -------
194 (stdout, stderr) of ipython subprocess.
194 (stdout, stderr) of ipython subprocess.
195 """
195 """
196 if options is None: options = []
196 if options is None: options = []
197
197
198 # For these subprocess calls, eliminate all prompt printing so we only see
198 # For these subprocess calls, eliminate all prompt printing so we only see
199 # output from script execution
199 # output from script execution
200 prompt_opts = [ '--PromptManager.in_template=""',
200 prompt_opts = [ '--PromptManager.in_template=""',
201 '--PromptManager.in2_template=""',
201 '--PromptManager.in2_template=""',
202 '--PromptManager.out_template=""'
202 '--PromptManager.out_template=""'
203 ]
203 ]
204 cmdargs = default_argv() + prompt_opts + options
204 cmdargs = default_argv() + prompt_opts + options
205
205
206 test_dir = os.path.dirname(__file__)
206 test_dir = os.path.dirname(__file__)
207
207
208 ipython_cmd = get_ipython_cmd()
208 ipython_cmd = get_ipython_cmd()
209 # Absolute path for filename
209 # Absolute path for filename
210 full_fname = os.path.join(test_dir, fname)
210 full_fname = os.path.join(test_dir, fname)
211 full_cmd = ipython_cmd + cmdargs + [full_fname]
211 full_cmd = ipython_cmd + cmdargs + [full_fname]
212 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
212 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
213 out, err = p.communicate()
213 out, err = p.communicate()
214 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
214 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
215 # `import readline` causes 'ESC[?1034h' to be output sometimes,
215 # `import readline` causes 'ESC[?1034h' to be output sometimes,
216 # so strip that out before doing comparisons
216 # so strip that out before doing comparisons
217 if out:
217 if out:
218 out = re.sub(r'\x1b\[[^h]+h', '', out)
218 out = re.sub(r'\x1b\[[^h]+h', '', out)
219 return out, err
219 return out, err
220
220
221
221
222 def ipexec_validate(fname, expected_out, expected_err='',
222 def ipexec_validate(fname, expected_out, expected_err='',
223 options=None):
223 options=None):
224 """Utility to call 'ipython filename' and validate output/error.
224 """Utility to call 'ipython filename' and validate output/error.
225
225
226 This function raises an AssertionError if the validation fails.
226 This function raises an AssertionError if the validation fails.
227
227
228 Note that this starts IPython in a subprocess!
228 Note that this starts IPython in a subprocess!
229
229
230 Parameters
230 Parameters
231 ----------
231 ----------
232 fname : str
232 fname : str
233 Name of the file to be executed (should have .py or .ipy extension).
233 Name of the file to be executed (should have .py or .ipy extension).
234
234
235 expected_out : str
235 expected_out : str
236 Expected stdout of the process.
236 Expected stdout of the process.
237
237
238 expected_err : optional, str
238 expected_err : optional, str
239 Expected stderr of the process.
239 Expected stderr of the process.
240
240
241 options : optional, list
241 options : optional, list
242 Extra command-line flags to be passed to IPython.
242 Extra command-line flags to be passed to IPython.
243
243
244 Returns
244 Returns
245 -------
245 -------
246 None
246 None
247 """
247 """
248
248
249 import nose.tools as nt
249 import nose.tools as nt
250
250
251 out, err = ipexec(fname, options)
251 out, err = ipexec(fname, options)
252 #print 'OUT', out # dbg
252 #print 'OUT', out # dbg
253 #print 'ERR', err # dbg
253 #print 'ERR', err # dbg
254 # If there are any errors, we must check those befor stdout, as they may be
254 # If there are any errors, we must check those befor stdout, as they may be
255 # more informative than simply having an empty stdout.
255 # more informative than simply having an empty stdout.
256 if err:
256 if err:
257 if expected_err:
257 if expected_err:
258 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
258 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
259 else:
259 else:
260 raise ValueError('Running file %r produced error: %r' %
260 raise ValueError('Running file %r produced error: %r' %
261 (fname, err))
261 (fname, err))
262 # If no errors or output on stderr was expected, match stdout
262 # If no errors or output on stderr was expected, match stdout
263 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
263 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
264
264
265
265
266 class TempFileMixin(object):
266 class TempFileMixin(object):
267 """Utility class to create temporary Python/IPython files.
267 """Utility class to create temporary Python/IPython files.
268
268
269 Meant as a mixin class for test cases."""
269 Meant as a mixin class for test cases."""
270
270
271 def mktmp(self, src, ext='.py'):
271 def mktmp(self, src, ext='.py'):
272 """Make a valid python temp file."""
272 """Make a valid python temp file."""
273 fname, f = temp_pyfile(src, ext)
273 fname, f = temp_pyfile(src, ext)
274 self.tmpfile = f
274 self.tmpfile = f
275 self.fname = fname
275 self.fname = fname
276
276
277 def tearDown(self):
277 def tearDown(self):
278 if hasattr(self, 'tmpfile'):
278 if hasattr(self, 'tmpfile'):
279 # If the tmpfile wasn't made because of skipped tests, like in
279 # If the tmpfile wasn't made because of skipped tests, like in
280 # win32, there's nothing to cleanup.
280 # win32, there's nothing to cleanup.
281 self.tmpfile.close()
281 self.tmpfile.close()
282 try:
282 try:
283 os.unlink(self.fname)
283 os.unlink(self.fname)
284 except:
284 except:
285 # On Windows, even though we close the file, we still can't
285 # On Windows, even though we close the file, we still can't
286 # delete it. I have no clue why
286 # delete it. I have no clue why
287 pass
287 pass
288
288
289 pair_fail_msg = ("Testing {0}\n\n"
289 pair_fail_msg = ("Testing {0}\n\n"
290 "In:\n"
290 "In:\n"
291 " {1!r}\n"
291 " {1!r}\n"
292 "Expected:\n"
292 "Expected:\n"
293 " {2!r}\n"
293 " {2!r}\n"
294 "Got:\n"
294 "Got:\n"
295 " {3!r}\n")
295 " {3!r}\n")
296 def check_pairs(func, pairs):
296 def check_pairs(func, pairs):
297 """Utility function for the common case of checking a function with a
297 """Utility function for the common case of checking a function with a
298 sequence of input/output pairs.
298 sequence of input/output pairs.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 func : callable
302 func : callable
303 The function to be tested. Should accept a single argument.
303 The function to be tested. Should accept a single argument.
304 pairs : iterable
304 pairs : iterable
305 A list of (input, expected_output) tuples.
305 A list of (input, expected_output) tuples.
306
306
307 Returns
307 Returns
308 -------
308 -------
309 None. Raises an AssertionError if any output does not match the expected
309 None. Raises an AssertionError if any output does not match the expected
310 value.
310 value.
311 """
311 """
312 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
312 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
313 for inp, expected in pairs:
313 for inp, expected in pairs:
314 out = func(inp)
314 out = func(inp)
315 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
315 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
316
316
317
317
318 if py3compat.PY3:
318 if py3compat.PY3:
319 MyStringIO = StringIO
319 MyStringIO = StringIO
320 else:
320 else:
321 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
321 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
322 # so we need a class that can handle both.
322 # so we need a class that can handle both.
323 class MyStringIO(StringIO):
323 class MyStringIO(StringIO):
324 def write(self, s):
324 def write(self, s):
325 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
325 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
326 super(MyStringIO, self).write(s)
326 super(MyStringIO, self).write(s)
327
327
328 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
328 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
329 -------
329 -------
330 {2!s}
330 {2!s}
331 -------
331 -------
332 """
332 """
333
333
334 class AssertPrints(object):
334 class AssertPrints(object):
335 """Context manager for testing that code prints certain text.
335 """Context manager for testing that code prints certain text.
336
336
337 Examples
337 Examples
338 --------
338 --------
339 >>> with AssertPrints("abc", suppress=False):
339 >>> with AssertPrints("abc", suppress=False):
340 ... print "abcd"
340 ... print("abcd")
341 ... print "def"
341 ... print("def")
342 ...
342 ...
343 abcd
343 abcd
344 def
344 def
345 """
345 """
346 def __init__(self, s, channel='stdout', suppress=True):
346 def __init__(self, s, channel='stdout', suppress=True):
347 self.s = s
347 self.s = s
348 if isinstance(self.s, py3compat.string_types):
348 if isinstance(self.s, py3compat.string_types):
349 self.s = [self.s]
349 self.s = [self.s]
350 self.channel = channel
350 self.channel = channel
351 self.suppress = suppress
351 self.suppress = suppress
352
352
353 def __enter__(self):
353 def __enter__(self):
354 self.orig_stream = getattr(sys, self.channel)
354 self.orig_stream = getattr(sys, self.channel)
355 self.buffer = MyStringIO()
355 self.buffer = MyStringIO()
356 self.tee = Tee(self.buffer, channel=self.channel)
356 self.tee = Tee(self.buffer, channel=self.channel)
357 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
357 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
358
358
359 def __exit__(self, etype, value, traceback):
359 def __exit__(self, etype, value, traceback):
360 if value is not None:
360 if value is not None:
361 # If an error was raised, don't check anything else
361 # If an error was raised, don't check anything else
362 return False
362 return False
363 self.tee.flush()
363 self.tee.flush()
364 setattr(sys, self.channel, self.orig_stream)
364 setattr(sys, self.channel, self.orig_stream)
365 printed = self.buffer.getvalue()
365 printed = self.buffer.getvalue()
366 for s in self.s:
366 for s in self.s:
367 assert s in printed, notprinted_msg.format(s, self.channel, printed)
367 assert s in printed, notprinted_msg.format(s, self.channel, printed)
368 return False
368 return False
369
369
370 printed_msg = """Found {0!r} in printed output (on {1}):
370 printed_msg = """Found {0!r} in printed output (on {1}):
371 -------
371 -------
372 {2!s}
372 {2!s}
373 -------
373 -------
374 """
374 """
375
375
376 class AssertNotPrints(AssertPrints):
376 class AssertNotPrints(AssertPrints):
377 """Context manager for checking that certain output *isn't* produced.
377 """Context manager for checking that certain output *isn't* produced.
378
378
379 Counterpart of AssertPrints"""
379 Counterpart of AssertPrints"""
380 def __exit__(self, etype, value, traceback):
380 def __exit__(self, etype, value, traceback):
381 if value is not None:
381 if value is not None:
382 # If an error was raised, don't check anything else
382 # If an error was raised, don't check anything else
383 return False
383 return False
384 self.tee.flush()
384 self.tee.flush()
385 setattr(sys, self.channel, self.orig_stream)
385 setattr(sys, self.channel, self.orig_stream)
386 printed = self.buffer.getvalue()
386 printed = self.buffer.getvalue()
387 for s in self.s:
387 for s in self.s:
388 assert s not in printed, printed_msg.format(s, self.channel, printed)
388 assert s not in printed, printed_msg.format(s, self.channel, printed)
389 return False
389 return False
390
390
391 @contextmanager
391 @contextmanager
392 def mute_warn():
392 def mute_warn():
393 from IPython.utils import warn
393 from IPython.utils import warn
394 save_warn = warn.warn
394 save_warn = warn.warn
395 warn.warn = lambda *a, **kw: None
395 warn.warn = lambda *a, **kw: None
396 try:
396 try:
397 yield
397 yield
398 finally:
398 finally:
399 warn.warn = save_warn
399 warn.warn = save_warn
400
400
401 @contextmanager
401 @contextmanager
402 def make_tempfile(name):
402 def make_tempfile(name):
403 """ Create an empty, named, temporary file for the duration of the context.
403 """ Create an empty, named, temporary file for the duration of the context.
404 """
404 """
405 f = open(name, 'w')
405 f = open(name, 'w')
406 f.close()
406 f.close()
407 try:
407 try:
408 yield
408 yield
409 finally:
409 finally:
410 os.unlink(name)
410 os.unlink(name)
411
411
412
412
413 @contextmanager
413 @contextmanager
414 def monkeypatch(obj, name, attr):
414 def monkeypatch(obj, name, attr):
415 """
415 """
416 Context manager to replace attribute named `name` in `obj` with `attr`.
416 Context manager to replace attribute named `name` in `obj` with `attr`.
417 """
417 """
418 orig = getattr(obj, name)
418 orig = getattr(obj, name)
419 setattr(obj, name, attr)
419 setattr(obj, name, attr)
420 yield
420 yield
421 setattr(obj, name, orig)
421 setattr(obj, name, orig)
422
422
423
423
424 def help_output_test(subcommand=''):
424 def help_output_test(subcommand=''):
425 """test that `ipython [subcommand] -h` works"""
425 """test that `ipython [subcommand] -h` works"""
426 cmd = ' '.join(get_ipython_cmd() + [subcommand, '-h'])
426 cmd = ' '.join(get_ipython_cmd() + [subcommand, '-h'])
427 out, err, rc = get_output_error_code(cmd)
427 out, err, rc = get_output_error_code(cmd)
428 nt.assert_equal(rc, 0, err)
428 nt.assert_equal(rc, 0, err)
429 nt.assert_not_in("Traceback", err)
429 nt.assert_not_in("Traceback", err)
430 nt.assert_in("Options", out)
430 nt.assert_in("Options", out)
431 nt.assert_in("--help-all", out)
431 nt.assert_in("--help-all", out)
432 return out, err
432 return out, err
433
433
434
434
435 def help_all_output_test(subcommand=''):
435 def help_all_output_test(subcommand=''):
436 """test that `ipython [subcommand] --help-all` works"""
436 """test that `ipython [subcommand] --help-all` works"""
437 cmd = ' '.join(get_ipython_cmd() + [subcommand, '--help-all'])
437 cmd = ' '.join(get_ipython_cmd() + [subcommand, '--help-all'])
438 out, err, rc = get_output_error_code(cmd)
438 out, err, rc = get_output_error_code(cmd)
439 nt.assert_equal(rc, 0, err)
439 nt.assert_equal(rc, 0, err)
440 nt.assert_not_in("Traceback", err)
440 nt.assert_not_in("Traceback", err)
441 nt.assert_in("Options", out)
441 nt.assert_in("Options", out)
442 nt.assert_in("Class parameters", out)
442 nt.assert_in("Class parameters", out)
443 return out, err
443 return out, err
444
444
General Comments 0
You need to be logged in to leave comments. Login now