##// END OF EJS Templates
Merge pull request #1870 from minrk/captureio...
Fernando Perez -
r7411:024e3846 merge
parent child Browse files
Show More
@@ -0,0 +1,182 b''
1 {
2 "metadata": {
3 "name": "Capturing Output"
4 },
5 "nbformat": 3,
6 "worksheets": [
7 {
8 "cells": [
9 {
10 "cell_type": "heading",
11 "level": 1,
12 "source": [
13 "Capturing Output with <tt>%%capture</tt>"
14 ]
15 },
16 {
17 "cell_type": "markdown",
18 "source": [
19 "One of IPython's new cell magics is `%%capture`, which captures stdout/err for a cell,",
20 "and discards them or stores them in variables in your namespace."
21 ]
22 },
23 {
24 "cell_type": "code",
25 "input": [
26 "import sys"
27 ],
28 "language": "python",
29 "outputs": []
30 },
31 {
32 "cell_type": "markdown",
33 "source": [
34 "By default, it just swallows it up. This is a simple way to suppress unwanted output."
35 ]
36 },
37 {
38 "cell_type": "code",
39 "input": [
40 "%%capture",
41 "print 'hi, stdout'",
42 "print >> sys.stderr, 'hi, stderr'"
43 ],
44 "language": "python",
45 "outputs": []
46 },
47 {
48 "cell_type": "markdown",
49 "source": [
50 "If you specify a name, then stdout and stderr will be stored in an object in your namespace."
51 ]
52 },
53 {
54 "cell_type": "code",
55 "input": [
56 "%%capture captured",
57 "print 'hi, stdout'",
58 "print >> sys.stderr, 'hi, stderr'"
59 ],
60 "language": "python",
61 "outputs": []
62 },
63 {
64 "cell_type": "code",
65 "input": [
66 "captured"
67 ],
68 "language": "python",
69 "outputs": []
70 },
71 {
72 "cell_type": "markdown",
73 "source": [
74 "Calling the object writes the output to stdout/err as appropriate."
75 ]
76 },
77 {
78 "cell_type": "code",
79 "input": [
80 "captured()"
81 ],
82 "language": "python",
83 "outputs": []
84 },
85 {
86 "cell_type": "code",
87 "input": [
88 "captured.stdout"
89 ],
90 "language": "python",
91 "outputs": []
92 },
93 {
94 "cell_type": "code",
95 "input": [
96 "captured.stderr"
97 ],
98 "language": "python",
99 "outputs": []
100 },
101 {
102 "cell_type": "markdown",
103 "source": [
104 "`%%capture` only captures stdout/err, not displaypub, so you can still do plots and use the display protocol inside %%capture"
105 ]
106 },
107 {
108 "cell_type": "code",
109 "input": [
110 "%pylab inline"
111 ],
112 "language": "python",
113 "outputs": []
114 },
115 {
116 "cell_type": "code",
117 "input": [
118 "%%capture wontshutup",
119 "",
120 "print \"setting up X\"",
121 "x = np.linspace(0,5,1000)",
122 "print \"step 2: constructing y-data\"",
123 "y = np.sin(x)",
124 "print \"step 3: display info about y\"",
125 "plt.plot(x,y)",
126 "print \"okay, I'm done now\""
127 ],
128 "language": "python",
129 "outputs": []
130 },
131 {
132 "cell_type": "code",
133 "input": [
134 "wontshutup()"
135 ],
136 "language": "python",
137 "outputs": []
138 },
139 {
140 "cell_type": "markdown",
141 "source": [
142 "And you can selectively disable capturing stdout or stderr by passing `--no-stdout/err`."
143 ]
144 },
145 {
146 "cell_type": "code",
147 "input": [
148 "%%capture cap --no-stderr",
149 "print 'hi, stdout'",
150 "print >> sys.stderr, \"hello, stderr\""
151 ],
152 "language": "python",
153 "outputs": []
154 },
155 {
156 "cell_type": "code",
157 "input": [
158 "cap.stdout"
159 ],
160 "language": "python",
161 "outputs": []
162 },
163 {
164 "cell_type": "code",
165 "input": [
166 "cap.stderr"
167 ],
168 "language": "python",
169 "outputs": []
170 },
171 {
172 "cell_type": "code",
173 "input": [
174 ""
175 ],
176 "language": "python",
177 "outputs": []
178 }
179 ]
180 }
181 ]
182 } No newline at end of file
@@ -1,990 +1,1022 b''
1 """Implementation of execution-related magic functions.
1 """Implementation of execution-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import __builtin__ as builtin_mod
16 import __builtin__ as builtin_mod
17 import bdb
17 import bdb
18 import os
18 import os
19 import sys
19 import sys
20 import time
20 import time
21 from StringIO import StringIO
21 from StringIO import StringIO
22
22
23 # cProfile was added in Python2.5
23 # cProfile was added in Python2.5
24 try:
24 try:
25 import cProfile as profile
25 import cProfile as profile
26 import pstats
26 import pstats
27 except ImportError:
27 except ImportError:
28 # profile isn't bundled by default in Debian for license reasons
28 # profile isn't bundled by default in Debian for license reasons
29 try:
29 try:
30 import profile, pstats
30 import profile, pstats
31 except ImportError:
31 except ImportError:
32 profile = pstats = None
32 profile = pstats = None
33
33
34 # Our own packages
34 # Our own packages
35 from IPython.core import debugger, oinspect
35 from IPython.core import debugger, oinspect
36 from IPython.core import magic_arguments
36 from IPython.core import page
37 from IPython.core import page
37 from IPython.core.error import UsageError
38 from IPython.core.error import UsageError
38 from IPython.core.macro import Macro
39 from IPython.core.macro import Macro
39 from IPython.core.magic import (Magics, magics_class, line_magic,
40 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
40 line_cell_magic, on_off, needs_local_scope)
41 line_cell_magic, on_off, needs_local_scope)
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.io import capture_output
43 from IPython.utils.ipstruct import Struct
45 from IPython.utils.ipstruct import Struct
44 from IPython.utils.module_paths import find_mod
46 from IPython.utils.module_paths import find_mod
45 from IPython.utils.path import get_py_filename, unquote_filename
47 from IPython.utils.path import get_py_filename, unquote_filename
46 from IPython.utils.timing import clock, clock2
48 from IPython.utils.timing import clock, clock2
47 from IPython.utils.warn import warn, error
49 from IPython.utils.warn import warn, error
48
50
49 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
50 # Magic implementation classes
52 # Magic implementation classes
51 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
52
54
53 @magics_class
55 @magics_class
54 class ExecutionMagics(Magics):
56 class ExecutionMagics(Magics):
55 """Magics related to code execution, debugging, profiling, etc.
57 """Magics related to code execution, debugging, profiling, etc.
56
58
57 """
59 """
58
60
59 def __init__(self, shell):
61 def __init__(self, shell):
60 super(ExecutionMagics, self).__init__(shell)
62 super(ExecutionMagics, self).__init__(shell)
61 if profile is None:
63 if profile is None:
62 self.prun = self.profile_missing_notice
64 self.prun = self.profile_missing_notice
63 # Default execution function used to actually run user code.
65 # Default execution function used to actually run user code.
64 self.default_runner = None
66 self.default_runner = None
65
67
66 def profile_missing_notice(self, *args, **kwargs):
68 def profile_missing_notice(self, *args, **kwargs):
67 error("""\
69 error("""\
68 The profile module could not be found. It has been removed from the standard
70 The profile module could not be found. It has been removed from the standard
69 python packages because of its non-free license. To use profiling, install the
71 python packages because of its non-free license. To use profiling, install the
70 python-profiler package from non-free.""")
72 python-profiler package from non-free.""")
71
73
72 @skip_doctest
74 @skip_doctest
73 @line_cell_magic
75 @line_cell_magic
74 def prun(self, parameter_s='', cell=None, user_mode=True,
76 def prun(self, parameter_s='', cell=None, user_mode=True,
75 opts=None,arg_lst=None,prog_ns=None):
77 opts=None,arg_lst=None,prog_ns=None):
76
78
77 """Run a statement through the python code profiler.
79 """Run a statement through the python code profiler.
78
80
79 Usage, in line mode:
81 Usage, in line mode:
80 %prun [options] statement
82 %prun [options] statement
81
83
82 Usage, in cell mode:
84 Usage, in cell mode:
83 %%prun [options] [statement]
85 %%prun [options] [statement]
84 code...
86 code...
85 code...
87 code...
86
88
87 In cell mode, the additional code lines are appended to the (possibly
89 In cell mode, the additional code lines are appended to the (possibly
88 empty) statement in the first line. Cell mode allows you to easily
90 empty) statement in the first line. Cell mode allows you to easily
89 profile multiline blocks without having to put them in a separate
91 profile multiline blocks without having to put them in a separate
90 function.
92 function.
91
93
92 The given statement (which doesn't require quote marks) is run via the
94 The given statement (which doesn't require quote marks) is run via the
93 python profiler in a manner similar to the profile.run() function.
95 python profiler in a manner similar to the profile.run() function.
94 Namespaces are internally managed to work correctly; profile.run
96 Namespaces are internally managed to work correctly; profile.run
95 cannot be used in IPython because it makes certain assumptions about
97 cannot be used in IPython because it makes certain assumptions about
96 namespaces which do not hold under IPython.
98 namespaces which do not hold under IPython.
97
99
98 Options:
100 Options:
99
101
100 -l <limit>: you can place restrictions on what or how much of the
102 -l <limit>: you can place restrictions on what or how much of the
101 profile gets printed. The limit value can be:
103 profile gets printed. The limit value can be:
102
104
103 * A string: only information for function names containing this string
105 * A string: only information for function names containing this string
104 is printed.
106 is printed.
105
107
106 * An integer: only these many lines are printed.
108 * An integer: only these many lines are printed.
107
109
108 * A float (between 0 and 1): this fraction of the report is printed
110 * A float (between 0 and 1): this fraction of the report is printed
109 (for example, use a limit of 0.4 to see the topmost 40% only).
111 (for example, use a limit of 0.4 to see the topmost 40% only).
110
112
111 You can combine several limits with repeated use of the option. For
113 You can combine several limits with repeated use of the option. For
112 example, '-l __init__ -l 5' will print only the topmost 5 lines of
114 example, '-l __init__ -l 5' will print only the topmost 5 lines of
113 information about class constructors.
115 information about class constructors.
114
116
115 -r: return the pstats.Stats object generated by the profiling. This
117 -r: return the pstats.Stats object generated by the profiling. This
116 object has all the information about the profile in it, and you can
118 object has all the information about the profile in it, and you can
117 later use it for further analysis or in other functions.
119 later use it for further analysis or in other functions.
118
120
119 -s <key>: sort profile by given key. You can provide more than one key
121 -s <key>: sort profile by given key. You can provide more than one key
120 by using the option several times: '-s key1 -s key2 -s key3...'. The
122 by using the option several times: '-s key1 -s key2 -s key3...'. The
121 default sorting key is 'time'.
123 default sorting key is 'time'.
122
124
123 The following is copied verbatim from the profile documentation
125 The following is copied verbatim from the profile documentation
124 referenced below:
126 referenced below:
125
127
126 When more than one key is provided, additional keys are used as
128 When more than one key is provided, additional keys are used as
127 secondary criteria when the there is equality in all keys selected
129 secondary criteria when the there is equality in all keys selected
128 before them.
130 before them.
129
131
130 Abbreviations can be used for any key names, as long as the
132 Abbreviations can be used for any key names, as long as the
131 abbreviation is unambiguous. The following are the keys currently
133 abbreviation is unambiguous. The following are the keys currently
132 defined:
134 defined:
133
135
134 Valid Arg Meaning
136 Valid Arg Meaning
135 "calls" call count
137 "calls" call count
136 "cumulative" cumulative time
138 "cumulative" cumulative time
137 "file" file name
139 "file" file name
138 "module" file name
140 "module" file name
139 "pcalls" primitive call count
141 "pcalls" primitive call count
140 "line" line number
142 "line" line number
141 "name" function name
143 "name" function name
142 "nfl" name/file/line
144 "nfl" name/file/line
143 "stdname" standard name
145 "stdname" standard name
144 "time" internal time
146 "time" internal time
145
147
146 Note that all sorts on statistics are in descending order (placing
148 Note that all sorts on statistics are in descending order (placing
147 most time consuming items first), where as name, file, and line number
149 most time consuming items first), where as name, file, and line number
148 searches are in ascending order (i.e., alphabetical). The subtle
150 searches are in ascending order (i.e., alphabetical). The subtle
149 distinction between "nfl" and "stdname" is that the standard name is a
151 distinction between "nfl" and "stdname" is that the standard name is a
150 sort of the name as printed, which means that the embedded line
152 sort of the name as printed, which means that the embedded line
151 numbers get compared in an odd way. For example, lines 3, 20, and 40
153 numbers get compared in an odd way. For example, lines 3, 20, and 40
152 would (if the file names were the same) appear in the string order
154 would (if the file names were the same) appear in the string order
153 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
155 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
154 line numbers. In fact, sort_stats("nfl") is the same as
156 line numbers. In fact, sort_stats("nfl") is the same as
155 sort_stats("name", "file", "line").
157 sort_stats("name", "file", "line").
156
158
157 -T <filename>: save profile results as shown on screen to a text
159 -T <filename>: save profile results as shown on screen to a text
158 file. The profile is still shown on screen.
160 file. The profile is still shown on screen.
159
161
160 -D <filename>: save (via dump_stats) profile statistics to given
162 -D <filename>: save (via dump_stats) profile statistics to given
161 filename. This data is in a format understood by the pstats module, and
163 filename. This data is in a format understood by the pstats module, and
162 is generated by a call to the dump_stats() method of profile
164 is generated by a call to the dump_stats() method of profile
163 objects. The profile is still shown on screen.
165 objects. The profile is still shown on screen.
164
166
165 -q: suppress output to the pager. Best used with -T and/or -D above.
167 -q: suppress output to the pager. Best used with -T and/or -D above.
166
168
167 If you want to run complete programs under the profiler's control, use
169 If you want to run complete programs under the profiler's control, use
168 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
170 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
169 contains profiler specific options as described here.
171 contains profiler specific options as described here.
170
172
171 You can read the complete documentation for the profile module with::
173 You can read the complete documentation for the profile module with::
172
174
173 In [1]: import profile; profile.help()
175 In [1]: import profile; profile.help()
174 """
176 """
175
177
176 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
178 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
177
179
178 if user_mode: # regular user call
180 if user_mode: # regular user call
179 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q',
181 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q',
180 list_all=True, posix=False)
182 list_all=True, posix=False)
181 namespace = self.shell.user_ns
183 namespace = self.shell.user_ns
182 if cell is not None:
184 if cell is not None:
183 arg_str += '\n' + cell
185 arg_str += '\n' + cell
184 else: # called to run a program by %run -p
186 else: # called to run a program by %run -p
185 try:
187 try:
186 filename = get_py_filename(arg_lst[0])
188 filename = get_py_filename(arg_lst[0])
187 except IOError as e:
189 except IOError as e:
188 try:
190 try:
189 msg = str(e)
191 msg = str(e)
190 except UnicodeError:
192 except UnicodeError:
191 msg = e.message
193 msg = e.message
192 error(msg)
194 error(msg)
193 return
195 return
194
196
195 arg_str = 'execfile(filename,prog_ns)'
197 arg_str = 'execfile(filename,prog_ns)'
196 namespace = {
198 namespace = {
197 'execfile': self.shell.safe_execfile,
199 'execfile': self.shell.safe_execfile,
198 'prog_ns': prog_ns,
200 'prog_ns': prog_ns,
199 'filename': filename
201 'filename': filename
200 }
202 }
201
203
202 opts.merge(opts_def)
204 opts.merge(opts_def)
203
205
204 prof = profile.Profile()
206 prof = profile.Profile()
205 try:
207 try:
206 prof = prof.runctx(arg_str,namespace,namespace)
208 prof = prof.runctx(arg_str,namespace,namespace)
207 sys_exit = ''
209 sys_exit = ''
208 except SystemExit:
210 except SystemExit:
209 sys_exit = """*** SystemExit exception caught in code being profiled."""
211 sys_exit = """*** SystemExit exception caught in code being profiled."""
210
212
211 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
213 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
212
214
213 lims = opts.l
215 lims = opts.l
214 if lims:
216 if lims:
215 lims = [] # rebuild lims with ints/floats/strings
217 lims = [] # rebuild lims with ints/floats/strings
216 for lim in opts.l:
218 for lim in opts.l:
217 try:
219 try:
218 lims.append(int(lim))
220 lims.append(int(lim))
219 except ValueError:
221 except ValueError:
220 try:
222 try:
221 lims.append(float(lim))
223 lims.append(float(lim))
222 except ValueError:
224 except ValueError:
223 lims.append(lim)
225 lims.append(lim)
224
226
225 # Trap output.
227 # Trap output.
226 stdout_trap = StringIO()
228 stdout_trap = StringIO()
227
229
228 if hasattr(stats,'stream'):
230 if hasattr(stats,'stream'):
229 # In newer versions of python, the stats object has a 'stream'
231 # In newer versions of python, the stats object has a 'stream'
230 # attribute to write into.
232 # attribute to write into.
231 stats.stream = stdout_trap
233 stats.stream = stdout_trap
232 stats.print_stats(*lims)
234 stats.print_stats(*lims)
233 else:
235 else:
234 # For older versions, we manually redirect stdout during printing
236 # For older versions, we manually redirect stdout during printing
235 sys_stdout = sys.stdout
237 sys_stdout = sys.stdout
236 try:
238 try:
237 sys.stdout = stdout_trap
239 sys.stdout = stdout_trap
238 stats.print_stats(*lims)
240 stats.print_stats(*lims)
239 finally:
241 finally:
240 sys.stdout = sys_stdout
242 sys.stdout = sys_stdout
241
243
242 output = stdout_trap.getvalue()
244 output = stdout_trap.getvalue()
243 output = output.rstrip()
245 output = output.rstrip()
244
246
245 if 'q' not in opts:
247 if 'q' not in opts:
246 page.page(output)
248 page.page(output)
247 print sys_exit,
249 print sys_exit,
248
250
249 dump_file = opts.D[0]
251 dump_file = opts.D[0]
250 text_file = opts.T[0]
252 text_file = opts.T[0]
251 if dump_file:
253 if dump_file:
252 dump_file = unquote_filename(dump_file)
254 dump_file = unquote_filename(dump_file)
253 prof.dump_stats(dump_file)
255 prof.dump_stats(dump_file)
254 print '\n*** Profile stats marshalled to file',\
256 print '\n*** Profile stats marshalled to file',\
255 `dump_file`+'.',sys_exit
257 `dump_file`+'.',sys_exit
256 if text_file:
258 if text_file:
257 text_file = unquote_filename(text_file)
259 text_file = unquote_filename(text_file)
258 pfile = open(text_file,'w')
260 pfile = open(text_file,'w')
259 pfile.write(output)
261 pfile.write(output)
260 pfile.close()
262 pfile.close()
261 print '\n*** Profile printout saved to text file',\
263 print '\n*** Profile printout saved to text file',\
262 `text_file`+'.',sys_exit
264 `text_file`+'.',sys_exit
263
265
264 if opts.has_key('r'):
266 if opts.has_key('r'):
265 return stats
267 return stats
266 else:
268 else:
267 return None
269 return None
268
270
269 @line_magic
271 @line_magic
270 def pdb(self, parameter_s=''):
272 def pdb(self, parameter_s=''):
271 """Control the automatic calling of the pdb interactive debugger.
273 """Control the automatic calling of the pdb interactive debugger.
272
274
273 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
275 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
274 argument it works as a toggle.
276 argument it works as a toggle.
275
277
276 When an exception is triggered, IPython can optionally call the
278 When an exception is triggered, IPython can optionally call the
277 interactive pdb debugger after the traceback printout. %pdb toggles
279 interactive pdb debugger after the traceback printout. %pdb toggles
278 this feature on and off.
280 this feature on and off.
279
281
280 The initial state of this feature is set in your configuration
282 The initial state of this feature is set in your configuration
281 file (the option is ``InteractiveShell.pdb``).
283 file (the option is ``InteractiveShell.pdb``).
282
284
283 If you want to just activate the debugger AFTER an exception has fired,
285 If you want to just activate the debugger AFTER an exception has fired,
284 without having to type '%pdb on' and rerunning your code, you can use
286 without having to type '%pdb on' and rerunning your code, you can use
285 the %debug magic."""
287 the %debug magic."""
286
288
287 par = parameter_s.strip().lower()
289 par = parameter_s.strip().lower()
288
290
289 if par:
291 if par:
290 try:
292 try:
291 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
293 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
292 except KeyError:
294 except KeyError:
293 print ('Incorrect argument. Use on/1, off/0, '
295 print ('Incorrect argument. Use on/1, off/0, '
294 'or nothing for a toggle.')
296 'or nothing for a toggle.')
295 return
297 return
296 else:
298 else:
297 # toggle
299 # toggle
298 new_pdb = not self.shell.call_pdb
300 new_pdb = not self.shell.call_pdb
299
301
300 # set on the shell
302 # set on the shell
301 self.shell.call_pdb = new_pdb
303 self.shell.call_pdb = new_pdb
302 print 'Automatic pdb calling has been turned',on_off(new_pdb)
304 print 'Automatic pdb calling has been turned',on_off(new_pdb)
303
305
304 @line_magic
306 @line_magic
305 def debug(self, parameter_s=''):
307 def debug(self, parameter_s=''):
306 """Activate the interactive debugger in post-mortem mode.
308 """Activate the interactive debugger in post-mortem mode.
307
309
308 If an exception has just occurred, this lets you inspect its stack
310 If an exception has just occurred, this lets you inspect its stack
309 frames interactively. Note that this will always work only on the last
311 frames interactively. Note that this will always work only on the last
310 traceback that occurred, so you must call this quickly after an
312 traceback that occurred, so you must call this quickly after an
311 exception that you wish to inspect has fired, because if another one
313 exception that you wish to inspect has fired, because if another one
312 occurs, it clobbers the previous one.
314 occurs, it clobbers the previous one.
313
315
314 If you want IPython to automatically do this on every exception, see
316 If you want IPython to automatically do this on every exception, see
315 the %pdb magic for more details.
317 the %pdb magic for more details.
316 """
318 """
317 self.shell.debugger(force=True)
319 self.shell.debugger(force=True)
318
320
319 @line_magic
321 @line_magic
320 def tb(self, s):
322 def tb(self, s):
321 """Print the last traceback with the currently active exception mode.
323 """Print the last traceback with the currently active exception mode.
322
324
323 See %xmode for changing exception reporting modes."""
325 See %xmode for changing exception reporting modes."""
324 self.shell.showtraceback()
326 self.shell.showtraceback()
325
327
326 @skip_doctest
328 @skip_doctest
327 @line_magic
329 @line_magic
328 def run(self, parameter_s='', runner=None,
330 def run(self, parameter_s='', runner=None,
329 file_finder=get_py_filename):
331 file_finder=get_py_filename):
330 """Run the named file inside IPython as a program.
332 """Run the named file inside IPython as a program.
331
333
332 Usage:\\
334 Usage:\\
333 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
335 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
334
336
335 Parameters after the filename are passed as command-line arguments to
337 Parameters after the filename are passed as command-line arguments to
336 the program (put in sys.argv). Then, control returns to IPython's
338 the program (put in sys.argv). Then, control returns to IPython's
337 prompt.
339 prompt.
338
340
339 This is similar to running at a system prompt:\\
341 This is similar to running at a system prompt:\\
340 $ python file args\\
342 $ python file args\\
341 but with the advantage of giving you IPython's tracebacks, and of
343 but with the advantage of giving you IPython's tracebacks, and of
342 loading all variables into your interactive namespace for further use
344 loading all variables into your interactive namespace for further use
343 (unless -p is used, see below).
345 (unless -p is used, see below).
344
346
345 The file is executed in a namespace initially consisting only of
347 The file is executed in a namespace initially consisting only of
346 __name__=='__main__' and sys.argv constructed as indicated. It thus
348 __name__=='__main__' and sys.argv constructed as indicated. It thus
347 sees its environment as if it were being run as a stand-alone program
349 sees its environment as if it were being run as a stand-alone program
348 (except for sharing global objects such as previously imported
350 (except for sharing global objects such as previously imported
349 modules). But after execution, the IPython interactive namespace gets
351 modules). But after execution, the IPython interactive namespace gets
350 updated with all variables defined in the program (except for __name__
352 updated with all variables defined in the program (except for __name__
351 and sys.argv). This allows for very convenient loading of code for
353 and sys.argv). This allows for very convenient loading of code for
352 interactive work, while giving each program a 'clean sheet' to run in.
354 interactive work, while giving each program a 'clean sheet' to run in.
353
355
354 Options:
356 Options:
355
357
356 -n: __name__ is NOT set to '__main__', but to the running file's name
358 -n: __name__ is NOT set to '__main__', but to the running file's name
357 without extension (as python does under import). This allows running
359 without extension (as python does under import). This allows running
358 scripts and reloading the definitions in them without calling code
360 scripts and reloading the definitions in them without calling code
359 protected by an ' if __name__ == "__main__" ' clause.
361 protected by an ' if __name__ == "__main__" ' clause.
360
362
361 -i: run the file in IPython's namespace instead of an empty one. This
363 -i: run the file in IPython's namespace instead of an empty one. This
362 is useful if you are experimenting with code written in a text editor
364 is useful if you are experimenting with code written in a text editor
363 which depends on variables defined interactively.
365 which depends on variables defined interactively.
364
366
365 -e: ignore sys.exit() calls or SystemExit exceptions in the script
367 -e: ignore sys.exit() calls or SystemExit exceptions in the script
366 being run. This is particularly useful if IPython is being used to
368 being run. This is particularly useful if IPython is being used to
367 run unittests, which always exit with a sys.exit() call. In such
369 run unittests, which always exit with a sys.exit() call. In such
368 cases you are interested in the output of the test results, not in
370 cases you are interested in the output of the test results, not in
369 seeing a traceback of the unittest module.
371 seeing a traceback of the unittest module.
370
372
371 -t: print timing information at the end of the run. IPython will give
373 -t: print timing information at the end of the run. IPython will give
372 you an estimated CPU time consumption for your script, which under
374 you an estimated CPU time consumption for your script, which under
373 Unix uses the resource module to avoid the wraparound problems of
375 Unix uses the resource module to avoid the wraparound problems of
374 time.clock(). Under Unix, an estimate of time spent on system tasks
376 time.clock(). Under Unix, an estimate of time spent on system tasks
375 is also given (for Windows platforms this is reported as 0.0).
377 is also given (for Windows platforms this is reported as 0.0).
376
378
377 If -t is given, an additional -N<N> option can be given, where <N>
379 If -t is given, an additional -N<N> option can be given, where <N>
378 must be an integer indicating how many times you want the script to
380 must be an integer indicating how many times you want the script to
379 run. The final timing report will include total and per run results.
381 run. The final timing report will include total and per run results.
380
382
381 For example (testing the script uniq_stable.py)::
383 For example (testing the script uniq_stable.py)::
382
384
383 In [1]: run -t uniq_stable
385 In [1]: run -t uniq_stable
384
386
385 IPython CPU timings (estimated):\\
387 IPython CPU timings (estimated):\\
386 User : 0.19597 s.\\
388 User : 0.19597 s.\\
387 System: 0.0 s.\\
389 System: 0.0 s.\\
388
390
389 In [2]: run -t -N5 uniq_stable
391 In [2]: run -t -N5 uniq_stable
390
392
391 IPython CPU timings (estimated):\\
393 IPython CPU timings (estimated):\\
392 Total runs performed: 5\\
394 Total runs performed: 5\\
393 Times : Total Per run\\
395 Times : Total Per run\\
394 User : 0.910862 s, 0.1821724 s.\\
396 User : 0.910862 s, 0.1821724 s.\\
395 System: 0.0 s, 0.0 s.
397 System: 0.0 s, 0.0 s.
396
398
397 -d: run your program under the control of pdb, the Python debugger.
399 -d: run your program under the control of pdb, the Python debugger.
398 This allows you to execute your program step by step, watch variables,
400 This allows you to execute your program step by step, watch variables,
399 etc. Internally, what IPython does is similar to calling:
401 etc. Internally, what IPython does is similar to calling:
400
402
401 pdb.run('execfile("YOURFILENAME")')
403 pdb.run('execfile("YOURFILENAME")')
402
404
403 with a breakpoint set on line 1 of your file. You can change the line
405 with a breakpoint set on line 1 of your file. You can change the line
404 number for this automatic breakpoint to be <N> by using the -bN option
406 number for this automatic breakpoint to be <N> by using the -bN option
405 (where N must be an integer). For example::
407 (where N must be an integer). For example::
406
408
407 %run -d -b40 myscript
409 %run -d -b40 myscript
408
410
409 will set the first breakpoint at line 40 in myscript.py. Note that
411 will set the first breakpoint at line 40 in myscript.py. Note that
410 the first breakpoint must be set on a line which actually does
412 the first breakpoint must be set on a line which actually does
411 something (not a comment or docstring) for it to stop execution.
413 something (not a comment or docstring) for it to stop execution.
412
414
413 When the pdb debugger starts, you will see a (Pdb) prompt. You must
415 When the pdb debugger starts, you will see a (Pdb) prompt. You must
414 first enter 'c' (without quotes) to start execution up to the first
416 first enter 'c' (without quotes) to start execution up to the first
415 breakpoint.
417 breakpoint.
416
418
417 Entering 'help' gives information about the use of the debugger. You
419 Entering 'help' gives information about the use of the debugger. You
418 can easily see pdb's full documentation with "import pdb;pdb.help()"
420 can easily see pdb's full documentation with "import pdb;pdb.help()"
419 at a prompt.
421 at a prompt.
420
422
421 -p: run program under the control of the Python profiler module (which
423 -p: run program under the control of the Python profiler module (which
422 prints a detailed report of execution times, function calls, etc).
424 prints a detailed report of execution times, function calls, etc).
423
425
424 You can pass other options after -p which affect the behavior of the
426 You can pass other options after -p which affect the behavior of the
425 profiler itself. See the docs for %prun for details.
427 profiler itself. See the docs for %prun for details.
426
428
427 In this mode, the program's variables do NOT propagate back to the
429 In this mode, the program's variables do NOT propagate back to the
428 IPython interactive namespace (because they remain in the namespace
430 IPython interactive namespace (because they remain in the namespace
429 where the profiler executes them).
431 where the profiler executes them).
430
432
431 Internally this triggers a call to %prun, see its documentation for
433 Internally this triggers a call to %prun, see its documentation for
432 details on the options available specifically for profiling.
434 details on the options available specifically for profiling.
433
435
434 There is one special usage for which the text above doesn't apply:
436 There is one special usage for which the text above doesn't apply:
435 if the filename ends with .ipy, the file is run as ipython script,
437 if the filename ends with .ipy, the file is run as ipython script,
436 just as if the commands were written on IPython prompt.
438 just as if the commands were written on IPython prompt.
437
439
438 -m: specify module name to load instead of script path. Similar to
440 -m: specify module name to load instead of script path. Similar to
439 the -m option for the python interpreter. Use this option last if you
441 the -m option for the python interpreter. Use this option last if you
440 want to combine with other %run options. Unlike the python interpreter
442 want to combine with other %run options. Unlike the python interpreter
441 only source modules are allowed no .pyc or .pyo files.
443 only source modules are allowed no .pyc or .pyo files.
442 For example::
444 For example::
443
445
444 %run -m example
446 %run -m example
445
447
446 will run the example module.
448 will run the example module.
447
449
448 """
450 """
449
451
450 # get arguments and set sys.argv for program to be run.
452 # get arguments and set sys.argv for program to be run.
451 opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:',
453 opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:',
452 mode='list', list_all=1)
454 mode='list', list_all=1)
453 if "m" in opts:
455 if "m" in opts:
454 modulename = opts["m"][0]
456 modulename = opts["m"][0]
455 modpath = find_mod(modulename)
457 modpath = find_mod(modulename)
456 if modpath is None:
458 if modpath is None:
457 warn('%r is not a valid modulename on sys.path'%modulename)
459 warn('%r is not a valid modulename on sys.path'%modulename)
458 return
460 return
459 arg_lst = [modpath] + arg_lst
461 arg_lst = [modpath] + arg_lst
460 try:
462 try:
461 filename = file_finder(arg_lst[0])
463 filename = file_finder(arg_lst[0])
462 except IndexError:
464 except IndexError:
463 warn('you must provide at least a filename.')
465 warn('you must provide at least a filename.')
464 print '\n%run:\n', oinspect.getdoc(self.run)
466 print '\n%run:\n', oinspect.getdoc(self.run)
465 return
467 return
466 except IOError as e:
468 except IOError as e:
467 try:
469 try:
468 msg = str(e)
470 msg = str(e)
469 except UnicodeError:
471 except UnicodeError:
470 msg = e.message
472 msg = e.message
471 error(msg)
473 error(msg)
472 return
474 return
473
475
474 if filename.lower().endswith('.ipy'):
476 if filename.lower().endswith('.ipy'):
475 self.shell.safe_execfile_ipy(filename)
477 self.shell.safe_execfile_ipy(filename)
476 return
478 return
477
479
478 # Control the response to exit() calls made by the script being run
480 # Control the response to exit() calls made by the script being run
479 exit_ignore = 'e' in opts
481 exit_ignore = 'e' in opts
480
482
481 # Make sure that the running script gets a proper sys.argv as if it
483 # Make sure that the running script gets a proper sys.argv as if it
482 # were run from a system shell.
484 # were run from a system shell.
483 save_argv = sys.argv # save it for later restoring
485 save_argv = sys.argv # save it for later restoring
484
486
485 # simulate shell expansion on arguments, at least tilde expansion
487 # simulate shell expansion on arguments, at least tilde expansion
486 args = [ os.path.expanduser(a) for a in arg_lst[1:] ]
488 args = [ os.path.expanduser(a) for a in arg_lst[1:] ]
487
489
488 sys.argv = [filename] + args # put in the proper filename
490 sys.argv = [filename] + args # put in the proper filename
489 # protect sys.argv from potential unicode strings on Python 2:
491 # protect sys.argv from potential unicode strings on Python 2:
490 if not py3compat.PY3:
492 if not py3compat.PY3:
491 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
493 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
492
494
493 if 'i' in opts:
495 if 'i' in opts:
494 # Run in user's interactive namespace
496 # Run in user's interactive namespace
495 prog_ns = self.shell.user_ns
497 prog_ns = self.shell.user_ns
496 __name__save = self.shell.user_ns['__name__']
498 __name__save = self.shell.user_ns['__name__']
497 prog_ns['__name__'] = '__main__'
499 prog_ns['__name__'] = '__main__'
498 main_mod = self.shell.new_main_mod(prog_ns)
500 main_mod = self.shell.new_main_mod(prog_ns)
499 else:
501 else:
500 # Run in a fresh, empty namespace
502 # Run in a fresh, empty namespace
501 if 'n' in opts:
503 if 'n' in opts:
502 name = os.path.splitext(os.path.basename(filename))[0]
504 name = os.path.splitext(os.path.basename(filename))[0]
503 else:
505 else:
504 name = '__main__'
506 name = '__main__'
505
507
506 main_mod = self.shell.new_main_mod()
508 main_mod = self.shell.new_main_mod()
507 prog_ns = main_mod.__dict__
509 prog_ns = main_mod.__dict__
508 prog_ns['__name__'] = name
510 prog_ns['__name__'] = name
509
511
510 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
512 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
511 # set the __file__ global in the script's namespace
513 # set the __file__ global in the script's namespace
512 prog_ns['__file__'] = filename
514 prog_ns['__file__'] = filename
513
515
514 # pickle fix. See interactiveshell for an explanation. But we need to
516 # pickle fix. See interactiveshell for an explanation. But we need to
515 # make sure that, if we overwrite __main__, we replace it at the end
517 # make sure that, if we overwrite __main__, we replace it at the end
516 main_mod_name = prog_ns['__name__']
518 main_mod_name = prog_ns['__name__']
517
519
518 if main_mod_name == '__main__':
520 if main_mod_name == '__main__':
519 restore_main = sys.modules['__main__']
521 restore_main = sys.modules['__main__']
520 else:
522 else:
521 restore_main = False
523 restore_main = False
522
524
523 # This needs to be undone at the end to prevent holding references to
525 # This needs to be undone at the end to prevent holding references to
524 # every single object ever created.
526 # every single object ever created.
525 sys.modules[main_mod_name] = main_mod
527 sys.modules[main_mod_name] = main_mod
526
528
527 try:
529 try:
528 stats = None
530 stats = None
529 with self.shell.readline_no_record:
531 with self.shell.readline_no_record:
530 if 'p' in opts:
532 if 'p' in opts:
531 stats = self.prun('', None, False, opts, arg_lst, prog_ns)
533 stats = self.prun('', None, False, opts, arg_lst, prog_ns)
532 else:
534 else:
533 if 'd' in opts:
535 if 'd' in opts:
534 deb = debugger.Pdb(self.shell.colors)
536 deb = debugger.Pdb(self.shell.colors)
535 # reset Breakpoint state, which is moronically kept
537 # reset Breakpoint state, which is moronically kept
536 # in a class
538 # in a class
537 bdb.Breakpoint.next = 1
539 bdb.Breakpoint.next = 1
538 bdb.Breakpoint.bplist = {}
540 bdb.Breakpoint.bplist = {}
539 bdb.Breakpoint.bpbynumber = [None]
541 bdb.Breakpoint.bpbynumber = [None]
540 # Set an initial breakpoint to stop execution
542 # Set an initial breakpoint to stop execution
541 maxtries = 10
543 maxtries = 10
542 bp = int(opts.get('b', [1])[0])
544 bp = int(opts.get('b', [1])[0])
543 checkline = deb.checkline(filename, bp)
545 checkline = deb.checkline(filename, bp)
544 if not checkline:
546 if not checkline:
545 for bp in range(bp + 1, bp + maxtries + 1):
547 for bp in range(bp + 1, bp + maxtries + 1):
546 if deb.checkline(filename, bp):
548 if deb.checkline(filename, bp):
547 break
549 break
548 else:
550 else:
549 msg = ("\nI failed to find a valid line to set "
551 msg = ("\nI failed to find a valid line to set "
550 "a breakpoint\n"
552 "a breakpoint\n"
551 "after trying up to line: %s.\n"
553 "after trying up to line: %s.\n"
552 "Please set a valid breakpoint manually "
554 "Please set a valid breakpoint manually "
553 "with the -b option." % bp)
555 "with the -b option." % bp)
554 error(msg)
556 error(msg)
555 return
557 return
556 # if we find a good linenumber, set the breakpoint
558 # if we find a good linenumber, set the breakpoint
557 deb.do_break('%s:%s' % (filename, bp))
559 deb.do_break('%s:%s' % (filename, bp))
558 # Start file run
560 # Start file run
559 print "NOTE: Enter 'c' at the",
561 print "NOTE: Enter 'c' at the",
560 print "%s prompt to start your script." % deb.prompt
562 print "%s prompt to start your script." % deb.prompt
561 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
563 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
562 try:
564 try:
563 deb.run('execfile("%s", prog_ns)' % filename, ns)
565 deb.run('execfile("%s", prog_ns)' % filename, ns)
564
566
565 except:
567 except:
566 etype, value, tb = sys.exc_info()
568 etype, value, tb = sys.exc_info()
567 # Skip three frames in the traceback: the %run one,
569 # Skip three frames in the traceback: the %run one,
568 # one inside bdb.py, and the command-line typed by the
570 # one inside bdb.py, and the command-line typed by the
569 # user (run by exec in pdb itself).
571 # user (run by exec in pdb itself).
570 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
572 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
571 else:
573 else:
572 if runner is None:
574 if runner is None:
573 runner = self.default_runner
575 runner = self.default_runner
574 if runner is None:
576 if runner is None:
575 runner = self.shell.safe_execfile
577 runner = self.shell.safe_execfile
576 if 't' in opts:
578 if 't' in opts:
577 # timed execution
579 # timed execution
578 try:
580 try:
579 nruns = int(opts['N'][0])
581 nruns = int(opts['N'][0])
580 if nruns < 1:
582 if nruns < 1:
581 error('Number of runs must be >=1')
583 error('Number of runs must be >=1')
582 return
584 return
583 except (KeyError):
585 except (KeyError):
584 nruns = 1
586 nruns = 1
585 twall0 = time.time()
587 twall0 = time.time()
586 if nruns == 1:
588 if nruns == 1:
587 t0 = clock2()
589 t0 = clock2()
588 runner(filename, prog_ns, prog_ns,
590 runner(filename, prog_ns, prog_ns,
589 exit_ignore=exit_ignore)
591 exit_ignore=exit_ignore)
590 t1 = clock2()
592 t1 = clock2()
591 t_usr = t1[0] - t0[0]
593 t_usr = t1[0] - t0[0]
592 t_sys = t1[1] - t0[1]
594 t_sys = t1[1] - t0[1]
593 print "\nIPython CPU timings (estimated):"
595 print "\nIPython CPU timings (estimated):"
594 print " User : %10.2f s." % t_usr
596 print " User : %10.2f s." % t_usr
595 print " System : %10.2f s." % t_sys
597 print " System : %10.2f s." % t_sys
596 else:
598 else:
597 runs = range(nruns)
599 runs = range(nruns)
598 t0 = clock2()
600 t0 = clock2()
599 for nr in runs:
601 for nr in runs:
600 runner(filename, prog_ns, prog_ns,
602 runner(filename, prog_ns, prog_ns,
601 exit_ignore=exit_ignore)
603 exit_ignore=exit_ignore)
602 t1 = clock2()
604 t1 = clock2()
603 t_usr = t1[0] - t0[0]
605 t_usr = t1[0] - t0[0]
604 t_sys = t1[1] - t0[1]
606 t_sys = t1[1] - t0[1]
605 print "\nIPython CPU timings (estimated):"
607 print "\nIPython CPU timings (estimated):"
606 print "Total runs performed:", nruns
608 print "Total runs performed:", nruns
607 print " Times : %10.2f %10.2f" % ('Total', 'Per run')
609 print " Times : %10.2f %10.2f" % ('Total', 'Per run')
608 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
610 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
609 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
611 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
610 twall1 = time.time()
612 twall1 = time.time()
611 print "Wall time: %10.2f s." % (twall1 - twall0)
613 print "Wall time: %10.2f s." % (twall1 - twall0)
612
614
613 else:
615 else:
614 # regular execution
616 # regular execution
615 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
617 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
616
618
617 if 'i' in opts:
619 if 'i' in opts:
618 self.shell.user_ns['__name__'] = __name__save
620 self.shell.user_ns['__name__'] = __name__save
619 else:
621 else:
620 # The shell MUST hold a reference to prog_ns so after %run
622 # The shell MUST hold a reference to prog_ns so after %run
621 # exits, the python deletion mechanism doesn't zero it out
623 # exits, the python deletion mechanism doesn't zero it out
622 # (leaving dangling references).
624 # (leaving dangling references).
623 self.shell.cache_main_mod(prog_ns, filename)
625 self.shell.cache_main_mod(prog_ns, filename)
624 # update IPython interactive namespace
626 # update IPython interactive namespace
625
627
626 # Some forms of read errors on the file may mean the
628 # Some forms of read errors on the file may mean the
627 # __name__ key was never set; using pop we don't have to
629 # __name__ key was never set; using pop we don't have to
628 # worry about a possible KeyError.
630 # worry about a possible KeyError.
629 prog_ns.pop('__name__', None)
631 prog_ns.pop('__name__', None)
630
632
631 self.shell.user_ns.update(prog_ns)
633 self.shell.user_ns.update(prog_ns)
632 finally:
634 finally:
633 # It's a bit of a mystery why, but __builtins__ can change from
635 # It's a bit of a mystery why, but __builtins__ can change from
634 # being a module to becoming a dict missing some key data after
636 # being a module to becoming a dict missing some key data after
635 # %run. As best I can see, this is NOT something IPython is doing
637 # %run. As best I can see, this is NOT something IPython is doing
636 # at all, and similar problems have been reported before:
638 # at all, and similar problems have been reported before:
637 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
639 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
638 # Since this seems to be done by the interpreter itself, the best
640 # Since this seems to be done by the interpreter itself, the best
639 # we can do is to at least restore __builtins__ for the user on
641 # we can do is to at least restore __builtins__ for the user on
640 # exit.
642 # exit.
641 self.shell.user_ns['__builtins__'] = builtin_mod
643 self.shell.user_ns['__builtins__'] = builtin_mod
642
644
643 # Ensure key global structures are restored
645 # Ensure key global structures are restored
644 sys.argv = save_argv
646 sys.argv = save_argv
645 if restore_main:
647 if restore_main:
646 sys.modules['__main__'] = restore_main
648 sys.modules['__main__'] = restore_main
647 else:
649 else:
648 # Remove from sys.modules the reference to main_mod we'd
650 # Remove from sys.modules the reference to main_mod we'd
649 # added. Otherwise it will trap references to objects
651 # added. Otherwise it will trap references to objects
650 # contained therein.
652 # contained therein.
651 del sys.modules[main_mod_name]
653 del sys.modules[main_mod_name]
652
654
653 return stats
655 return stats
654
656
655 @skip_doctest
657 @skip_doctest
656 @line_cell_magic
658 @line_cell_magic
657 def timeit(self, line='', cell=None):
659 def timeit(self, line='', cell=None):
658 """Time execution of a Python statement or expression
660 """Time execution of a Python statement or expression
659
661
660 Usage, in line mode:
662 Usage, in line mode:
661 %timeit [-n<N> -r<R> [-t|-c]] statement
663 %timeit [-n<N> -r<R> [-t|-c]] statement
662 or in cell mode:
664 or in cell mode:
663 %%timeit [-n<N> -r<R> [-t|-c]] setup_code
665 %%timeit [-n<N> -r<R> [-t|-c]] setup_code
664 code
666 code
665 code...
667 code...
666
668
667 Time execution of a Python statement or expression using the timeit
669 Time execution of a Python statement or expression using the timeit
668 module. This function can be used both as a line and cell magic:
670 module. This function can be used both as a line and cell magic:
669
671
670 - In line mode you can time a single-line statement (though multiple
672 - In line mode you can time a single-line statement (though multiple
671 ones can be chained with using semicolons).
673 ones can be chained with using semicolons).
672
674
673 - In cell mode, the statement in the first line is used as setup code
675 - In cell mode, the statement in the first line is used as setup code
674 (executed but not timed) and the body of the cell is timed. The cell
676 (executed but not timed) and the body of the cell is timed. The cell
675 body has access to any variables created in the setup code.
677 body has access to any variables created in the setup code.
676
678
677 Options:
679 Options:
678 -n<N>: execute the given statement <N> times in a loop. If this value
680 -n<N>: execute the given statement <N> times in a loop. If this value
679 is not given, a fitting value is chosen.
681 is not given, a fitting value is chosen.
680
682
681 -r<R>: repeat the loop iteration <R> times and take the best result.
683 -r<R>: repeat the loop iteration <R> times and take the best result.
682 Default: 3
684 Default: 3
683
685
684 -t: use time.time to measure the time, which is the default on Unix.
686 -t: use time.time to measure the time, which is the default on Unix.
685 This function measures wall time.
687 This function measures wall time.
686
688
687 -c: use time.clock to measure the time, which is the default on
689 -c: use time.clock to measure the time, which is the default on
688 Windows and measures wall time. On Unix, resource.getrusage is used
690 Windows and measures wall time. On Unix, resource.getrusage is used
689 instead and returns the CPU user time.
691 instead and returns the CPU user time.
690
692
691 -p<P>: use a precision of <P> digits to display the timing result.
693 -p<P>: use a precision of <P> digits to display the timing result.
692 Default: 3
694 Default: 3
693
695
694
696
695 Examples
697 Examples
696 --------
698 --------
697 ::
699 ::
698
700
699 In [1]: %timeit pass
701 In [1]: %timeit pass
700 10000000 loops, best of 3: 53.3 ns per loop
702 10000000 loops, best of 3: 53.3 ns per loop
701
703
702 In [2]: u = None
704 In [2]: u = None
703
705
704 In [3]: %timeit u is None
706 In [3]: %timeit u is None
705 10000000 loops, best of 3: 184 ns per loop
707 10000000 loops, best of 3: 184 ns per loop
706
708
707 In [4]: %timeit -r 4 u == None
709 In [4]: %timeit -r 4 u == None
708 1000000 loops, best of 4: 242 ns per loop
710 1000000 loops, best of 4: 242 ns per loop
709
711
710 In [5]: import time
712 In [5]: import time
711
713
712 In [6]: %timeit -n1 time.sleep(2)
714 In [6]: %timeit -n1 time.sleep(2)
713 1 loops, best of 3: 2 s per loop
715 1 loops, best of 3: 2 s per loop
714
716
715
717
716 The times reported by %timeit will be slightly higher than those
718 The times reported by %timeit will be slightly higher than those
717 reported by the timeit.py script when variables are accessed. This is
719 reported by the timeit.py script when variables are accessed. This is
718 due to the fact that %timeit executes the statement in the namespace
720 due to the fact that %timeit executes the statement in the namespace
719 of the shell, compared with timeit.py, which uses a single setup
721 of the shell, compared with timeit.py, which uses a single setup
720 statement to import function or create variables. Generally, the bias
722 statement to import function or create variables. Generally, the bias
721 does not matter as long as results from timeit.py are not mixed with
723 does not matter as long as results from timeit.py are not mixed with
722 those from %timeit."""
724 those from %timeit."""
723
725
724 import timeit
726 import timeit
725 import math
727 import math
726
728
727 # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
729 # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
728 # certain terminals. Until we figure out a robust way of
730 # certain terminals. Until we figure out a robust way of
729 # auto-detecting if the terminal can deal with it, use plain 'us' for
731 # auto-detecting if the terminal can deal with it, use plain 'us' for
730 # microseconds. I am really NOT happy about disabling the proper
732 # microseconds. I am really NOT happy about disabling the proper
731 # 'micro' prefix, but crashing is worse... If anyone knows what the
733 # 'micro' prefix, but crashing is worse... If anyone knows what the
732 # right solution for this is, I'm all ears...
734 # right solution for this is, I'm all ears...
733 #
735 #
734 # Note: using
736 # Note: using
735 #
737 #
736 # s = u'\xb5'
738 # s = u'\xb5'
737 # s.encode(sys.getdefaultencoding())
739 # s.encode(sys.getdefaultencoding())
738 #
740 #
739 # is not sufficient, as I've seen terminals where that fails but
741 # is not sufficient, as I've seen terminals where that fails but
740 # print s
742 # print s
741 #
743 #
742 # succeeds
744 # succeeds
743 #
745 #
744 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
746 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
745
747
746 #units = [u"s", u"ms",u'\xb5',"ns"]
748 #units = [u"s", u"ms",u'\xb5',"ns"]
747 units = [u"s", u"ms",u'us',"ns"]
749 units = [u"s", u"ms",u'us',"ns"]
748
750
749 scaling = [1, 1e3, 1e6, 1e9]
751 scaling = [1, 1e3, 1e6, 1e9]
750
752
751 opts, stmt = self.parse_options(line,'n:r:tcp:',
753 opts, stmt = self.parse_options(line,'n:r:tcp:',
752 posix=False, strict=False)
754 posix=False, strict=False)
753 if stmt == "" and cell is None:
755 if stmt == "" and cell is None:
754 return
756 return
755 timefunc = timeit.default_timer
757 timefunc = timeit.default_timer
756 number = int(getattr(opts, "n", 0))
758 number = int(getattr(opts, "n", 0))
757 repeat = int(getattr(opts, "r", timeit.default_repeat))
759 repeat = int(getattr(opts, "r", timeit.default_repeat))
758 precision = int(getattr(opts, "p", 3))
760 precision = int(getattr(opts, "p", 3))
759 if hasattr(opts, "t"):
761 if hasattr(opts, "t"):
760 timefunc = time.time
762 timefunc = time.time
761 if hasattr(opts, "c"):
763 if hasattr(opts, "c"):
762 timefunc = clock
764 timefunc = clock
763
765
764 timer = timeit.Timer(timer=timefunc)
766 timer = timeit.Timer(timer=timefunc)
765 # this code has tight coupling to the inner workings of timeit.Timer,
767 # this code has tight coupling to the inner workings of timeit.Timer,
766 # but is there a better way to achieve that the code stmt has access
768 # but is there a better way to achieve that the code stmt has access
767 # to the shell namespace?
769 # to the shell namespace?
768
770
769 if cell is None:
771 if cell is None:
770 # called as line magic
772 # called as line magic
771 setup = 'pass'
773 setup = 'pass'
772 stmt = timeit.reindent(stmt, 8)
774 stmt = timeit.reindent(stmt, 8)
773 else:
775 else:
774 setup = timeit.reindent(stmt, 4)
776 setup = timeit.reindent(stmt, 4)
775 stmt = timeit.reindent(cell, 8)
777 stmt = timeit.reindent(cell, 8)
776
778
777 # From Python 3.3, this template uses new-style string formatting.
779 # From Python 3.3, this template uses new-style string formatting.
778 if sys.version_info >= (3, 3):
780 if sys.version_info >= (3, 3):
779 src = timeit.template.format(stmt=stmt, setup=setup)
781 src = timeit.template.format(stmt=stmt, setup=setup)
780 else:
782 else:
781 src = timeit.template % dict(stmt=stmt, setup=setup)
783 src = timeit.template % dict(stmt=stmt, setup=setup)
782
784
783 # Track compilation time so it can be reported if too long
785 # Track compilation time so it can be reported if too long
784 # Minimum time above which compilation time will be reported
786 # Minimum time above which compilation time will be reported
785 tc_min = 0.1
787 tc_min = 0.1
786
788
787 t0 = clock()
789 t0 = clock()
788 code = compile(src, "<magic-timeit>", "exec")
790 code = compile(src, "<magic-timeit>", "exec")
789 tc = clock()-t0
791 tc = clock()-t0
790
792
791 ns = {}
793 ns = {}
792 exec code in self.shell.user_ns, ns
794 exec code in self.shell.user_ns, ns
793 timer.inner = ns["inner"]
795 timer.inner = ns["inner"]
794
796
795 if number == 0:
797 if number == 0:
796 # determine number so that 0.2 <= total time < 2.0
798 # determine number so that 0.2 <= total time < 2.0
797 number = 1
799 number = 1
798 for i in range(1, 10):
800 for i in range(1, 10):
799 if timer.timeit(number) >= 0.2:
801 if timer.timeit(number) >= 0.2:
800 break
802 break
801 number *= 10
803 number *= 10
802
804
803 best = min(timer.repeat(repeat, number)) / number
805 best = min(timer.repeat(repeat, number)) / number
804
806
805 if best > 0.0 and best < 1000.0:
807 if best > 0.0 and best < 1000.0:
806 order = min(-int(math.floor(math.log10(best)) // 3), 3)
808 order = min(-int(math.floor(math.log10(best)) // 3), 3)
807 elif best >= 1000.0:
809 elif best >= 1000.0:
808 order = 0
810 order = 0
809 else:
811 else:
810 order = 3
812 order = 3
811 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
813 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
812 precision,
814 precision,
813 best * scaling[order],
815 best * scaling[order],
814 units[order])
816 units[order])
815 if tc > tc_min:
817 if tc > tc_min:
816 print "Compiler time: %.2f s" % tc
818 print "Compiler time: %.2f s" % tc
817
819
818 @skip_doctest
820 @skip_doctest
819 @needs_local_scope
821 @needs_local_scope
820 @line_magic
822 @line_magic
821 def time(self,parameter_s, user_locals):
823 def time(self,parameter_s, user_locals):
822 """Time execution of a Python statement or expression.
824 """Time execution of a Python statement or expression.
823
825
824 The CPU and wall clock times are printed, and the value of the
826 The CPU and wall clock times are printed, and the value of the
825 expression (if any) is returned. Note that under Win32, system time
827 expression (if any) is returned. Note that under Win32, system time
826 is always reported as 0, since it can not be measured.
828 is always reported as 0, since it can not be measured.
827
829
828 This function provides very basic timing functionality. In Python
830 This function provides very basic timing functionality. In Python
829 2.3, the timeit module offers more control and sophistication, so this
831 2.3, the timeit module offers more control and sophistication, so this
830 could be rewritten to use it (patches welcome).
832 could be rewritten to use it (patches welcome).
831
833
832 Examples
834 Examples
833 --------
835 --------
834 ::
836 ::
835
837
836 In [1]: time 2**128
838 In [1]: time 2**128
837 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
839 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
838 Wall time: 0.00
840 Wall time: 0.00
839 Out[1]: 340282366920938463463374607431768211456L
841 Out[1]: 340282366920938463463374607431768211456L
840
842
841 In [2]: n = 1000000
843 In [2]: n = 1000000
842
844
843 In [3]: time sum(range(n))
845 In [3]: time sum(range(n))
844 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
846 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
845 Wall time: 1.37
847 Wall time: 1.37
846 Out[3]: 499999500000L
848 Out[3]: 499999500000L
847
849
848 In [4]: time print 'hello world'
850 In [4]: time print 'hello world'
849 hello world
851 hello world
850 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
852 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
851 Wall time: 0.00
853 Wall time: 0.00
852
854
853 Note that the time needed by Python to compile the given expression
855 Note that the time needed by Python to compile the given expression
854 will be reported if it is more than 0.1s. In this example, the
856 will be reported if it is more than 0.1s. In this example, the
855 actual exponentiation is done by Python at compilation time, so while
857 actual exponentiation is done by Python at compilation time, so while
856 the expression can take a noticeable amount of time to compute, that
858 the expression can take a noticeable amount of time to compute, that
857 time is purely due to the compilation:
859 time is purely due to the compilation:
858
860
859 In [5]: time 3**9999;
861 In [5]: time 3**9999;
860 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
862 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
861 Wall time: 0.00 s
863 Wall time: 0.00 s
862
864
863 In [6]: time 3**999999;
865 In [6]: time 3**999999;
864 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
866 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
865 Wall time: 0.00 s
867 Wall time: 0.00 s
866 Compiler : 0.78 s
868 Compiler : 0.78 s
867 """
869 """
868
870
869 # fail immediately if the given expression can't be compiled
871 # fail immediately if the given expression can't be compiled
870
872
871 expr = self.shell.prefilter(parameter_s,False)
873 expr = self.shell.prefilter(parameter_s,False)
872
874
873 # Minimum time above which compilation time will be reported
875 # Minimum time above which compilation time will be reported
874 tc_min = 0.1
876 tc_min = 0.1
875
877
876 try:
878 try:
877 mode = 'eval'
879 mode = 'eval'
878 t0 = clock()
880 t0 = clock()
879 code = compile(expr,'<timed eval>',mode)
881 code = compile(expr,'<timed eval>',mode)
880 tc = clock()-t0
882 tc = clock()-t0
881 except SyntaxError:
883 except SyntaxError:
882 mode = 'exec'
884 mode = 'exec'
883 t0 = clock()
885 t0 = clock()
884 code = compile(expr,'<timed exec>',mode)
886 code = compile(expr,'<timed exec>',mode)
885 tc = clock()-t0
887 tc = clock()-t0
886 # skew measurement as little as possible
888 # skew measurement as little as possible
887 glob = self.shell.user_ns
889 glob = self.shell.user_ns
888 wtime = time.time
890 wtime = time.time
889 # time execution
891 # time execution
890 wall_st = wtime()
892 wall_st = wtime()
891 if mode=='eval':
893 if mode=='eval':
892 st = clock2()
894 st = clock2()
893 out = eval(code, glob, user_locals)
895 out = eval(code, glob, user_locals)
894 end = clock2()
896 end = clock2()
895 else:
897 else:
896 st = clock2()
898 st = clock2()
897 exec code in glob, user_locals
899 exec code in glob, user_locals
898 end = clock2()
900 end = clock2()
899 out = None
901 out = None
900 wall_end = wtime()
902 wall_end = wtime()
901 # Compute actual times and report
903 # Compute actual times and report
902 wall_time = wall_end-wall_st
904 wall_time = wall_end-wall_st
903 cpu_user = end[0]-st[0]
905 cpu_user = end[0]-st[0]
904 cpu_sys = end[1]-st[1]
906 cpu_sys = end[1]-st[1]
905 cpu_tot = cpu_user+cpu_sys
907 cpu_tot = cpu_user+cpu_sys
906 print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
908 print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
907 (cpu_user,cpu_sys,cpu_tot)
909 (cpu_user,cpu_sys,cpu_tot)
908 print "Wall time: %.2f s" % wall_time
910 print "Wall time: %.2f s" % wall_time
909 if tc > tc_min:
911 if tc > tc_min:
910 print "Compiler : %.2f s" % tc
912 print "Compiler : %.2f s" % tc
911 return out
913 return out
912
914
913 @skip_doctest
915 @skip_doctest
914 @line_magic
916 @line_magic
915 def macro(self, parameter_s=''):
917 def macro(self, parameter_s=''):
916 """Define a macro for future re-execution. It accepts ranges of history,
918 """Define a macro for future re-execution. It accepts ranges of history,
917 filenames or string objects.
919 filenames or string objects.
918
920
919 Usage:\\
921 Usage:\\
920 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
922 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
921
923
922 Options:
924 Options:
923
925
924 -r: use 'raw' input. By default, the 'processed' history is used,
926 -r: use 'raw' input. By default, the 'processed' history is used,
925 so that magics are loaded in their transformed version to valid
927 so that magics are loaded in their transformed version to valid
926 Python. If this option is given, the raw input as typed as the
928 Python. If this option is given, the raw input as typed as the
927 command line is used instead.
929 command line is used instead.
928
930
929 This will define a global variable called `name` which is a string
931 This will define a global variable called `name` which is a string
930 made of joining the slices and lines you specify (n1,n2,... numbers
932 made of joining the slices and lines you specify (n1,n2,... numbers
931 above) from your input history into a single string. This variable
933 above) from your input history into a single string. This variable
932 acts like an automatic function which re-executes those lines as if
934 acts like an automatic function which re-executes those lines as if
933 you had typed them. You just type 'name' at the prompt and the code
935 you had typed them. You just type 'name' at the prompt and the code
934 executes.
936 executes.
935
937
936 The syntax for indicating input ranges is described in %history.
938 The syntax for indicating input ranges is described in %history.
937
939
938 Note: as a 'hidden' feature, you can also use traditional python slice
940 Note: as a 'hidden' feature, you can also use traditional python slice
939 notation, where N:M means numbers N through M-1.
941 notation, where N:M means numbers N through M-1.
940
942
941 For example, if your history contains (%hist prints it)::
943 For example, if your history contains (%hist prints it)::
942
944
943 44: x=1
945 44: x=1
944 45: y=3
946 45: y=3
945 46: z=x+y
947 46: z=x+y
946 47: print x
948 47: print x
947 48: a=5
949 48: a=5
948 49: print 'x',x,'y',y
950 49: print 'x',x,'y',y
949
951
950 you can create a macro with lines 44 through 47 (included) and line 49
952 you can create a macro with lines 44 through 47 (included) and line 49
951 called my_macro with::
953 called my_macro with::
952
954
953 In [55]: %macro my_macro 44-47 49
955 In [55]: %macro my_macro 44-47 49
954
956
955 Now, typing `my_macro` (without quotes) will re-execute all this code
957 Now, typing `my_macro` (without quotes) will re-execute all this code
956 in one pass.
958 in one pass.
957
959
958 You don't need to give the line-numbers in order, and any given line
960 You don't need to give the line-numbers in order, and any given line
959 number can appear multiple times. You can assemble macros with any
961 number can appear multiple times. You can assemble macros with any
960 lines from your input history in any order.
962 lines from your input history in any order.
961
963
962 The macro is a simple object which holds its value in an attribute,
964 The macro is a simple object which holds its value in an attribute,
963 but IPython's display system checks for macros and executes them as
965 but IPython's display system checks for macros and executes them as
964 code instead of printing them when you type their name.
966 code instead of printing them when you type their name.
965
967
966 You can view a macro's contents by explicitly printing it with::
968 You can view a macro's contents by explicitly printing it with::
967
969
968 print macro_name
970 print macro_name
969
971
970 """
972 """
971 opts,args = self.parse_options(parameter_s,'r',mode='list')
973 opts,args = self.parse_options(parameter_s,'r',mode='list')
972 if not args: # List existing macros
974 if not args: # List existing macros
973 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
975 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
974 isinstance(v, Macro))
976 isinstance(v, Macro))
975 if len(args) == 1:
977 if len(args) == 1:
976 raise UsageError(
978 raise UsageError(
977 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
979 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
978 name, codefrom = args[0], " ".join(args[1:])
980 name, codefrom = args[0], " ".join(args[1:])
979
981
980 #print 'rng',ranges # dbg
982 #print 'rng',ranges # dbg
981 try:
983 try:
982 lines = self.shell.find_user_code(codefrom, 'r' in opts)
984 lines = self.shell.find_user_code(codefrom, 'r' in opts)
983 except (ValueError, TypeError) as e:
985 except (ValueError, TypeError) as e:
984 print e.args[0]
986 print e.args[0]
985 return
987 return
986 macro = Macro(lines)
988 macro = Macro(lines)
987 self.shell.define_macro(name, macro)
989 self.shell.define_macro(name, macro)
988 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
990 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
989 print '=== Macro contents: ==='
991 print '=== Macro contents: ==='
990 print macro,
992 print macro,
993
994 @magic_arguments.magic_arguments()
995 @magic_arguments.argument('output', type=str, default='', nargs='?',
996 help="""The name of the variable in which to store output.
997 This is a utils.io.CapturedIO object with stdout/err attributes
998 for the text of the captured output.
999
1000 CapturedOutput also has a show() method for displaying the output,
1001 and __call__ as well, so you can use that to quickly display the
1002 output.
1003
1004 If unspecified, captured output is discarded.
1005 """
1006 )
1007 @magic_arguments.argument('--no-stderr', action="store_true",
1008 help="""Don't capture stderr."""
1009 )
1010 @magic_arguments.argument('--no-stdout', action="store_true",
1011 help="""Don't capture stdout."""
1012 )
1013 @cell_magic
1014 def capture(self, line, cell):
1015 """run the cell, capturing stdout/err"""
1016 args = magic_arguments.parse_argstring(self.capture, line)
1017 out = not args.no_stdout
1018 err = not args.no_stderr
1019 with capture_output(out, err) as io:
1020 self.shell.run_cell(cell)
1021 if args.output:
1022 self.shell.user_ns[args.output] = io
@@ -1,213 +1,183 b''
1 """base class for parallel client tests
1 """base class for parallel client tests
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17 import time
17 import time
18 from StringIO import StringIO
18 from StringIO import StringIO
19
19
20 from nose import SkipTest
20 from nose import SkipTest
21
21
22 import zmq
22 import zmq
23 from zmq.tests import BaseZMQTestCase
23 from zmq.tests import BaseZMQTestCase
24
24
25 from IPython.external.decorator import decorator
25 from IPython.external.decorator import decorator
26
26
27 from IPython.parallel import error
27 from IPython.parallel import error
28 from IPython.parallel import Client
28 from IPython.parallel import Client
29
29
30 from IPython.parallel.tests import launchers, add_engines
30 from IPython.parallel.tests import launchers, add_engines
31
31
32 # simple tasks for use in apply tests
32 # simple tasks for use in apply tests
33
33
34 def segfault():
34 def segfault():
35 """this will segfault"""
35 """this will segfault"""
36 import ctypes
36 import ctypes
37 ctypes.memset(-1,0,1)
37 ctypes.memset(-1,0,1)
38
38
39 def crash():
39 def crash():
40 """from stdlib crashers in the test suite"""
40 """from stdlib crashers in the test suite"""
41 import types
41 import types
42 if sys.platform.startswith('win'):
42 if sys.platform.startswith('win'):
43 import ctypes
43 import ctypes
44 ctypes.windll.kernel32.SetErrorMode(0x0002);
44 ctypes.windll.kernel32.SetErrorMode(0x0002);
45 args = [ 0, 0, 0, 0, b'\x04\x71\x00\x00', (), (), (), '', '', 1, b'']
45 args = [ 0, 0, 0, 0, b'\x04\x71\x00\x00', (), (), (), '', '', 1, b'']
46 if sys.version_info[0] >= 3:
46 if sys.version_info[0] >= 3:
47 # Python3 adds 'kwonlyargcount' as the second argument to Code
47 # Python3 adds 'kwonlyargcount' as the second argument to Code
48 args.insert(1, 0)
48 args.insert(1, 0)
49
49
50 co = types.CodeType(*args)
50 co = types.CodeType(*args)
51 exec(co)
51 exec(co)
52
52
53 def wait(n):
53 def wait(n):
54 """sleep for a time"""
54 """sleep for a time"""
55 import time
55 import time
56 time.sleep(n)
56 time.sleep(n)
57 return n
57 return n
58
58
59 def raiser(eclass):
59 def raiser(eclass):
60 """raise an exception"""
60 """raise an exception"""
61 raise eclass()
61 raise eclass()
62
62
63 def generate_output():
63 def generate_output():
64 """function for testing output
64 """function for testing output
65
65
66 publishes two outputs of each type, and returns
66 publishes two outputs of each type, and returns
67 a rich displayable object.
67 a rich displayable object.
68 """
68 """
69
69
70 import sys
70 import sys
71 from IPython.core.display import display, HTML, Math
71 from IPython.core.display import display, HTML, Math
72
72
73 print "stdout"
73 print "stdout"
74 print >> sys.stderr, "stderr"
74 print >> sys.stderr, "stderr"
75
75
76 display(HTML("<b>HTML</b>"))
76 display(HTML("<b>HTML</b>"))
77
77
78 print "stdout2"
78 print "stdout2"
79 print >> sys.stderr, "stderr2"
79 print >> sys.stderr, "stderr2"
80
80
81 display(Math(r"\alpha=\beta"))
81 display(Math(r"\alpha=\beta"))
82
82
83 return Math("42")
83 return Math("42")
84
84
85 # test decorator for skipping tests when libraries are unavailable
85 # test decorator for skipping tests when libraries are unavailable
86 def skip_without(*names):
86 def skip_without(*names):
87 """skip a test if some names are not importable"""
87 """skip a test if some names are not importable"""
88 @decorator
88 @decorator
89 def skip_without_names(f, *args, **kwargs):
89 def skip_without_names(f, *args, **kwargs):
90 """decorator to skip tests in the absence of numpy."""
90 """decorator to skip tests in the absence of numpy."""
91 for name in names:
91 for name in names:
92 try:
92 try:
93 __import__(name)
93 __import__(name)
94 except ImportError:
94 except ImportError:
95 raise SkipTest
95 raise SkipTest
96 return f(*args, **kwargs)
96 return f(*args, **kwargs)
97 return skip_without_names
97 return skip_without_names
98
98
99 #-------------------------------------------------------------------------------
99 #-------------------------------------------------------------------------------
100 # Classes
100 # Classes
101 #-------------------------------------------------------------------------------
101 #-------------------------------------------------------------------------------
102
102
103 class CapturedIO(object):
104 """Simple object for containing captured stdout/err StringIO objects"""
105
106 def __init__(self, stdout, stderr):
107 self.stdout_io = stdout
108 self.stderr_io = stderr
109
110 @property
111 def stdout(self):
112 return self.stdout_io.getvalue()
113
114 @property
115 def stderr(self):
116 return self.stderr_io.getvalue()
117
118
119 class capture_output(object):
120 """context manager for capturing stdout/err"""
121
122 def __enter__(self):
123 self.sys_stdout = sys.stdout
124 self.sys_stderr = sys.stderr
125 stdout = sys.stdout = StringIO()
126 stderr = sys.stderr = StringIO()
127 return CapturedIO(stdout, stderr)
128
129 def __exit__(self, exc_type, exc_value, traceback):
130 sys.stdout = self.sys_stdout
131 sys.stderr = self.sys_stderr
132
133
103
134 class ClusterTestCase(BaseZMQTestCase):
104 class ClusterTestCase(BaseZMQTestCase):
135
105
136 def add_engines(self, n=1, block=True):
106 def add_engines(self, n=1, block=True):
137 """add multiple engines to our cluster"""
107 """add multiple engines to our cluster"""
138 self.engines.extend(add_engines(n))
108 self.engines.extend(add_engines(n))
139 if block:
109 if block:
140 self.wait_on_engines()
110 self.wait_on_engines()
141
111
142 def minimum_engines(self, n=1, block=True):
112 def minimum_engines(self, n=1, block=True):
143 """add engines until there are at least n connected"""
113 """add engines until there are at least n connected"""
144 self.engines.extend(add_engines(n, total=True))
114 self.engines.extend(add_engines(n, total=True))
145 if block:
115 if block:
146 self.wait_on_engines()
116 self.wait_on_engines()
147
117
148
118
149 def wait_on_engines(self, timeout=5):
119 def wait_on_engines(self, timeout=5):
150 """wait for our engines to connect."""
120 """wait for our engines to connect."""
151 n = len(self.engines)+self.base_engine_count
121 n = len(self.engines)+self.base_engine_count
152 tic = time.time()
122 tic = time.time()
153 while time.time()-tic < timeout and len(self.client.ids) < n:
123 while time.time()-tic < timeout and len(self.client.ids) < n:
154 time.sleep(0.1)
124 time.sleep(0.1)
155
125
156 assert not len(self.client.ids) < n, "waiting for engines timed out"
126 assert not len(self.client.ids) < n, "waiting for engines timed out"
157
127
158 def connect_client(self):
128 def connect_client(self):
159 """connect a client with my Context, and track its sockets for cleanup"""
129 """connect a client with my Context, and track its sockets for cleanup"""
160 c = Client(profile='iptest', context=self.context)
130 c = Client(profile='iptest', context=self.context)
161 for name in filter(lambda n:n.endswith('socket'), dir(c)):
131 for name in filter(lambda n:n.endswith('socket'), dir(c)):
162 s = getattr(c, name)
132 s = getattr(c, name)
163 s.setsockopt(zmq.LINGER, 0)
133 s.setsockopt(zmq.LINGER, 0)
164 self.sockets.append(s)
134 self.sockets.append(s)
165 return c
135 return c
166
136
167 def assertRaisesRemote(self, etype, f, *args, **kwargs):
137 def assertRaisesRemote(self, etype, f, *args, **kwargs):
168 try:
138 try:
169 try:
139 try:
170 f(*args, **kwargs)
140 f(*args, **kwargs)
171 except error.CompositeError as e:
141 except error.CompositeError as e:
172 e.raise_exception()
142 e.raise_exception()
173 except error.RemoteError as e:
143 except error.RemoteError as e:
174 self.assertEquals(etype.__name__, e.ename, "Should have raised %r, but raised %r"%(etype.__name__, e.ename))
144 self.assertEquals(etype.__name__, e.ename, "Should have raised %r, but raised %r"%(etype.__name__, e.ename))
175 else:
145 else:
176 self.fail("should have raised a RemoteError")
146 self.fail("should have raised a RemoteError")
177
147
178 def _wait_for(self, f, timeout=10):
148 def _wait_for(self, f, timeout=10):
179 """wait for a condition"""
149 """wait for a condition"""
180 tic = time.time()
150 tic = time.time()
181 while time.time() <= tic + timeout:
151 while time.time() <= tic + timeout:
182 if f():
152 if f():
183 return
153 return
184 time.sleep(0.1)
154 time.sleep(0.1)
185 self.client.spin()
155 self.client.spin()
186 if not f():
156 if not f():
187 print "Warning: Awaited condition never arrived"
157 print "Warning: Awaited condition never arrived"
188
158
189 def setUp(self):
159 def setUp(self):
190 BaseZMQTestCase.setUp(self)
160 BaseZMQTestCase.setUp(self)
191 self.client = self.connect_client()
161 self.client = self.connect_client()
192 # start every test with clean engine namespaces:
162 # start every test with clean engine namespaces:
193 self.client.clear(block=True)
163 self.client.clear(block=True)
194 self.base_engine_count=len(self.client.ids)
164 self.base_engine_count=len(self.client.ids)
195 self.engines=[]
165 self.engines=[]
196
166
197 def tearDown(self):
167 def tearDown(self):
198 # self.client.clear(block=True)
168 # self.client.clear(block=True)
199 # close fds:
169 # close fds:
200 for e in filter(lambda e: e.poll() is not None, launchers):
170 for e in filter(lambda e: e.poll() is not None, launchers):
201 launchers.remove(e)
171 launchers.remove(e)
202
172
203 # allow flushing of incoming messages to prevent crash on socket close
173 # allow flushing of incoming messages to prevent crash on socket close
204 self.client.wait(timeout=2)
174 self.client.wait(timeout=2)
205 # time.sleep(2)
175 # time.sleep(2)
206 self.client.spin()
176 self.client.spin()
207 self.client.close()
177 self.client.close()
208 BaseZMQTestCase.tearDown(self)
178 BaseZMQTestCase.tearDown(self)
209 # this will be redundant when pyzmq merges PR #88
179 # this will be redundant when pyzmq merges PR #88
210 # self.context.term()
180 # self.context.term()
211 # print tempfile.TemporaryFile().fileno(),
181 # print tempfile.TemporaryFile().fileno(),
212 # sys.stdout.flush()
182 # sys.stdout.flush()
213 No newline at end of file
183
@@ -1,266 +1,267 b''
1 """Tests for asyncresult.py
1 """Tests for asyncresult.py
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 import time
19 import time
20
20
21 from IPython.parallel.error import TimeoutError
21 from IPython.utils.io import capture_output
22
22
23 from IPython.parallel.error import TimeoutError
23 from IPython.parallel import error, Client
24 from IPython.parallel import error, Client
24 from IPython.parallel.tests import add_engines
25 from IPython.parallel.tests import add_engines
25 from .clienttest import ClusterTestCase, capture_output
26 from .clienttest import ClusterTestCase
26
27
27 def setup():
28 def setup():
28 add_engines(2, total=True)
29 add_engines(2, total=True)
29
30
30 def wait(n):
31 def wait(n):
31 import time
32 import time
32 time.sleep(n)
33 time.sleep(n)
33 return n
34 return n
34
35
35 class AsyncResultTest(ClusterTestCase):
36 class AsyncResultTest(ClusterTestCase):
36
37
37 def test_single_result_view(self):
38 def test_single_result_view(self):
38 """various one-target views get the right value for single_result"""
39 """various one-target views get the right value for single_result"""
39 eid = self.client.ids[-1]
40 eid = self.client.ids[-1]
40 ar = self.client[eid].apply_async(lambda : 42)
41 ar = self.client[eid].apply_async(lambda : 42)
41 self.assertEquals(ar.get(), 42)
42 self.assertEquals(ar.get(), 42)
42 ar = self.client[[eid]].apply_async(lambda : 42)
43 ar = self.client[[eid]].apply_async(lambda : 42)
43 self.assertEquals(ar.get(), [42])
44 self.assertEquals(ar.get(), [42])
44 ar = self.client[-1:].apply_async(lambda : 42)
45 ar = self.client[-1:].apply_async(lambda : 42)
45 self.assertEquals(ar.get(), [42])
46 self.assertEquals(ar.get(), [42])
46
47
47 def test_get_after_done(self):
48 def test_get_after_done(self):
48 ar = self.client[-1].apply_async(lambda : 42)
49 ar = self.client[-1].apply_async(lambda : 42)
49 ar.wait()
50 ar.wait()
50 self.assertTrue(ar.ready())
51 self.assertTrue(ar.ready())
51 self.assertEquals(ar.get(), 42)
52 self.assertEquals(ar.get(), 42)
52 self.assertEquals(ar.get(), 42)
53 self.assertEquals(ar.get(), 42)
53
54
54 def test_get_before_done(self):
55 def test_get_before_done(self):
55 ar = self.client[-1].apply_async(wait, 0.1)
56 ar = self.client[-1].apply_async(wait, 0.1)
56 self.assertRaises(TimeoutError, ar.get, 0)
57 self.assertRaises(TimeoutError, ar.get, 0)
57 ar.wait(0)
58 ar.wait(0)
58 self.assertFalse(ar.ready())
59 self.assertFalse(ar.ready())
59 self.assertEquals(ar.get(), 0.1)
60 self.assertEquals(ar.get(), 0.1)
60
61
61 def test_get_after_error(self):
62 def test_get_after_error(self):
62 ar = self.client[-1].apply_async(lambda : 1/0)
63 ar = self.client[-1].apply_async(lambda : 1/0)
63 ar.wait(10)
64 ar.wait(10)
64 self.assertRaisesRemote(ZeroDivisionError, ar.get)
65 self.assertRaisesRemote(ZeroDivisionError, ar.get)
65 self.assertRaisesRemote(ZeroDivisionError, ar.get)
66 self.assertRaisesRemote(ZeroDivisionError, ar.get)
66 self.assertRaisesRemote(ZeroDivisionError, ar.get_dict)
67 self.assertRaisesRemote(ZeroDivisionError, ar.get_dict)
67
68
68 def test_get_dict(self):
69 def test_get_dict(self):
69 n = len(self.client)
70 n = len(self.client)
70 ar = self.client[:].apply_async(lambda : 5)
71 ar = self.client[:].apply_async(lambda : 5)
71 self.assertEquals(ar.get(), [5]*n)
72 self.assertEquals(ar.get(), [5]*n)
72 d = ar.get_dict()
73 d = ar.get_dict()
73 self.assertEquals(sorted(d.keys()), sorted(self.client.ids))
74 self.assertEquals(sorted(d.keys()), sorted(self.client.ids))
74 for eid,r in d.iteritems():
75 for eid,r in d.iteritems():
75 self.assertEquals(r, 5)
76 self.assertEquals(r, 5)
76
77
77 def test_list_amr(self):
78 def test_list_amr(self):
78 ar = self.client.load_balanced_view().map_async(wait, [0.1]*5)
79 ar = self.client.load_balanced_view().map_async(wait, [0.1]*5)
79 rlist = list(ar)
80 rlist = list(ar)
80
81
81 def test_getattr(self):
82 def test_getattr(self):
82 ar = self.client[:].apply_async(wait, 0.5)
83 ar = self.client[:].apply_async(wait, 0.5)
83 self.assertRaises(AttributeError, lambda : ar._foo)
84 self.assertRaises(AttributeError, lambda : ar._foo)
84 self.assertRaises(AttributeError, lambda : ar.__length_hint__())
85 self.assertRaises(AttributeError, lambda : ar.__length_hint__())
85 self.assertRaises(AttributeError, lambda : ar.foo)
86 self.assertRaises(AttributeError, lambda : ar.foo)
86 self.assertRaises(AttributeError, lambda : ar.engine_id)
87 self.assertRaises(AttributeError, lambda : ar.engine_id)
87 self.assertFalse(hasattr(ar, '__length_hint__'))
88 self.assertFalse(hasattr(ar, '__length_hint__'))
88 self.assertFalse(hasattr(ar, 'foo'))
89 self.assertFalse(hasattr(ar, 'foo'))
89 self.assertFalse(hasattr(ar, 'engine_id'))
90 self.assertFalse(hasattr(ar, 'engine_id'))
90 ar.get(5)
91 ar.get(5)
91 self.assertRaises(AttributeError, lambda : ar._foo)
92 self.assertRaises(AttributeError, lambda : ar._foo)
92 self.assertRaises(AttributeError, lambda : ar.__length_hint__())
93 self.assertRaises(AttributeError, lambda : ar.__length_hint__())
93 self.assertRaises(AttributeError, lambda : ar.foo)
94 self.assertRaises(AttributeError, lambda : ar.foo)
94 self.assertTrue(isinstance(ar.engine_id, list))
95 self.assertTrue(isinstance(ar.engine_id, list))
95 self.assertEquals(ar.engine_id, ar['engine_id'])
96 self.assertEquals(ar.engine_id, ar['engine_id'])
96 self.assertFalse(hasattr(ar, '__length_hint__'))
97 self.assertFalse(hasattr(ar, '__length_hint__'))
97 self.assertFalse(hasattr(ar, 'foo'))
98 self.assertFalse(hasattr(ar, 'foo'))
98 self.assertTrue(hasattr(ar, 'engine_id'))
99 self.assertTrue(hasattr(ar, 'engine_id'))
99
100
100 def test_getitem(self):
101 def test_getitem(self):
101 ar = self.client[:].apply_async(wait, 0.5)
102 ar = self.client[:].apply_async(wait, 0.5)
102 self.assertRaises(TimeoutError, lambda : ar['foo'])
103 self.assertRaises(TimeoutError, lambda : ar['foo'])
103 self.assertRaises(TimeoutError, lambda : ar['engine_id'])
104 self.assertRaises(TimeoutError, lambda : ar['engine_id'])
104 ar.get(5)
105 ar.get(5)
105 self.assertRaises(KeyError, lambda : ar['foo'])
106 self.assertRaises(KeyError, lambda : ar['foo'])
106 self.assertTrue(isinstance(ar['engine_id'], list))
107 self.assertTrue(isinstance(ar['engine_id'], list))
107 self.assertEquals(ar.engine_id, ar['engine_id'])
108 self.assertEquals(ar.engine_id, ar['engine_id'])
108
109
109 def test_single_result(self):
110 def test_single_result(self):
110 ar = self.client[-1].apply_async(wait, 0.5)
111 ar = self.client[-1].apply_async(wait, 0.5)
111 self.assertRaises(TimeoutError, lambda : ar['foo'])
112 self.assertRaises(TimeoutError, lambda : ar['foo'])
112 self.assertRaises(TimeoutError, lambda : ar['engine_id'])
113 self.assertRaises(TimeoutError, lambda : ar['engine_id'])
113 self.assertTrue(ar.get(5) == 0.5)
114 self.assertTrue(ar.get(5) == 0.5)
114 self.assertTrue(isinstance(ar['engine_id'], int))
115 self.assertTrue(isinstance(ar['engine_id'], int))
115 self.assertTrue(isinstance(ar.engine_id, int))
116 self.assertTrue(isinstance(ar.engine_id, int))
116 self.assertEquals(ar.engine_id, ar['engine_id'])
117 self.assertEquals(ar.engine_id, ar['engine_id'])
117
118
118 def test_abort(self):
119 def test_abort(self):
119 e = self.client[-1]
120 e = self.client[-1]
120 ar = e.execute('import time; time.sleep(1)', block=False)
121 ar = e.execute('import time; time.sleep(1)', block=False)
121 ar2 = e.apply_async(lambda : 2)
122 ar2 = e.apply_async(lambda : 2)
122 ar2.abort()
123 ar2.abort()
123 self.assertRaises(error.TaskAborted, ar2.get)
124 self.assertRaises(error.TaskAborted, ar2.get)
124 ar.get()
125 ar.get()
125
126
126 def test_len(self):
127 def test_len(self):
127 v = self.client.load_balanced_view()
128 v = self.client.load_balanced_view()
128 ar = v.map_async(lambda x: x, range(10))
129 ar = v.map_async(lambda x: x, range(10))
129 self.assertEquals(len(ar), 10)
130 self.assertEquals(len(ar), 10)
130 ar = v.apply_async(lambda x: x, range(10))
131 ar = v.apply_async(lambda x: x, range(10))
131 self.assertEquals(len(ar), 1)
132 self.assertEquals(len(ar), 1)
132 ar = self.client[:].apply_async(lambda x: x, range(10))
133 ar = self.client[:].apply_async(lambda x: x, range(10))
133 self.assertEquals(len(ar), len(self.client.ids))
134 self.assertEquals(len(ar), len(self.client.ids))
134
135
135 def test_wall_time_single(self):
136 def test_wall_time_single(self):
136 v = self.client.load_balanced_view()
137 v = self.client.load_balanced_view()
137 ar = v.apply_async(time.sleep, 0.25)
138 ar = v.apply_async(time.sleep, 0.25)
138 self.assertRaises(TimeoutError, getattr, ar, 'wall_time')
139 self.assertRaises(TimeoutError, getattr, ar, 'wall_time')
139 ar.get(2)
140 ar.get(2)
140 self.assertTrue(ar.wall_time < 1.)
141 self.assertTrue(ar.wall_time < 1.)
141 self.assertTrue(ar.wall_time > 0.2)
142 self.assertTrue(ar.wall_time > 0.2)
142
143
143 def test_wall_time_multi(self):
144 def test_wall_time_multi(self):
144 self.minimum_engines(4)
145 self.minimum_engines(4)
145 v = self.client[:]
146 v = self.client[:]
146 ar = v.apply_async(time.sleep, 0.25)
147 ar = v.apply_async(time.sleep, 0.25)
147 self.assertRaises(TimeoutError, getattr, ar, 'wall_time')
148 self.assertRaises(TimeoutError, getattr, ar, 'wall_time')
148 ar.get(2)
149 ar.get(2)
149 self.assertTrue(ar.wall_time < 1.)
150 self.assertTrue(ar.wall_time < 1.)
150 self.assertTrue(ar.wall_time > 0.2)
151 self.assertTrue(ar.wall_time > 0.2)
151
152
152 def test_serial_time_single(self):
153 def test_serial_time_single(self):
153 v = self.client.load_balanced_view()
154 v = self.client.load_balanced_view()
154 ar = v.apply_async(time.sleep, 0.25)
155 ar = v.apply_async(time.sleep, 0.25)
155 self.assertRaises(TimeoutError, getattr, ar, 'serial_time')
156 self.assertRaises(TimeoutError, getattr, ar, 'serial_time')
156 ar.get(2)
157 ar.get(2)
157 self.assertTrue(ar.serial_time < 1.)
158 self.assertTrue(ar.serial_time < 1.)
158 self.assertTrue(ar.serial_time > 0.2)
159 self.assertTrue(ar.serial_time > 0.2)
159
160
160 def test_serial_time_multi(self):
161 def test_serial_time_multi(self):
161 self.minimum_engines(4)
162 self.minimum_engines(4)
162 v = self.client[:]
163 v = self.client[:]
163 ar = v.apply_async(time.sleep, 0.25)
164 ar = v.apply_async(time.sleep, 0.25)
164 self.assertRaises(TimeoutError, getattr, ar, 'serial_time')
165 self.assertRaises(TimeoutError, getattr, ar, 'serial_time')
165 ar.get(2)
166 ar.get(2)
166 self.assertTrue(ar.serial_time < 2.)
167 self.assertTrue(ar.serial_time < 2.)
167 self.assertTrue(ar.serial_time > 0.8)
168 self.assertTrue(ar.serial_time > 0.8)
168
169
169 def test_elapsed_single(self):
170 def test_elapsed_single(self):
170 v = self.client.load_balanced_view()
171 v = self.client.load_balanced_view()
171 ar = v.apply_async(time.sleep, 0.25)
172 ar = v.apply_async(time.sleep, 0.25)
172 while not ar.ready():
173 while not ar.ready():
173 time.sleep(0.01)
174 time.sleep(0.01)
174 self.assertTrue(ar.elapsed < 1)
175 self.assertTrue(ar.elapsed < 1)
175 self.assertTrue(ar.elapsed < 1)
176 self.assertTrue(ar.elapsed < 1)
176 ar.get(2)
177 ar.get(2)
177
178
178 def test_elapsed_multi(self):
179 def test_elapsed_multi(self):
179 v = self.client[:]
180 v = self.client[:]
180 ar = v.apply_async(time.sleep, 0.25)
181 ar = v.apply_async(time.sleep, 0.25)
181 while not ar.ready():
182 while not ar.ready():
182 time.sleep(0.01)
183 time.sleep(0.01)
183 self.assertTrue(ar.elapsed < 1)
184 self.assertTrue(ar.elapsed < 1)
184 self.assertTrue(ar.elapsed < 1)
185 self.assertTrue(ar.elapsed < 1)
185 ar.get(2)
186 ar.get(2)
186
187
187 def test_hubresult_timestamps(self):
188 def test_hubresult_timestamps(self):
188 self.minimum_engines(4)
189 self.minimum_engines(4)
189 v = self.client[:]
190 v = self.client[:]
190 ar = v.apply_async(time.sleep, 0.25)
191 ar = v.apply_async(time.sleep, 0.25)
191 ar.get(2)
192 ar.get(2)
192 rc2 = Client(profile='iptest')
193 rc2 = Client(profile='iptest')
193 # must have try/finally to close second Client, otherwise
194 # must have try/finally to close second Client, otherwise
194 # will have dangling sockets causing problems
195 # will have dangling sockets causing problems
195 try:
196 try:
196 time.sleep(0.25)
197 time.sleep(0.25)
197 hr = rc2.get_result(ar.msg_ids)
198 hr = rc2.get_result(ar.msg_ids)
198 self.assertTrue(hr.elapsed > 0., "got bad elapsed: %s" % hr.elapsed)
199 self.assertTrue(hr.elapsed > 0., "got bad elapsed: %s" % hr.elapsed)
199 hr.get(1)
200 hr.get(1)
200 self.assertTrue(hr.wall_time < ar.wall_time + 0.2, "got bad wall_time: %s > %s" % (hr.wall_time, ar.wall_time))
201 self.assertTrue(hr.wall_time < ar.wall_time + 0.2, "got bad wall_time: %s > %s" % (hr.wall_time, ar.wall_time))
201 self.assertEquals(hr.serial_time, ar.serial_time)
202 self.assertEquals(hr.serial_time, ar.serial_time)
202 finally:
203 finally:
203 rc2.close()
204 rc2.close()
204
205
205 def test_display_empty_streams_single(self):
206 def test_display_empty_streams_single(self):
206 """empty stdout/err are not displayed (single result)"""
207 """empty stdout/err are not displayed (single result)"""
207 self.minimum_engines(1)
208 self.minimum_engines(1)
208
209
209 v = self.client[-1]
210 v = self.client[-1]
210 ar = v.execute("print (5555)")
211 ar = v.execute("print (5555)")
211 ar.get(5)
212 ar.get(5)
212 with capture_output() as io:
213 with capture_output() as io:
213 ar.display_outputs()
214 ar.display_outputs()
214 self.assertEquals(io.stderr, '')
215 self.assertEquals(io.stderr, '')
215 self.assertEquals('5555\n', io.stdout)
216 self.assertEquals('5555\n', io.stdout)
216
217
217 ar = v.execute("a=5")
218 ar = v.execute("a=5")
218 ar.get(5)
219 ar.get(5)
219 with capture_output() as io:
220 with capture_output() as io:
220 ar.display_outputs()
221 ar.display_outputs()
221 self.assertEquals(io.stderr, '')
222 self.assertEquals(io.stderr, '')
222 self.assertEquals(io.stdout, '')
223 self.assertEquals(io.stdout, '')
223
224
224 def test_display_empty_streams_type(self):
225 def test_display_empty_streams_type(self):
225 """empty stdout/err are not displayed (groupby type)"""
226 """empty stdout/err are not displayed (groupby type)"""
226 self.minimum_engines(1)
227 self.minimum_engines(1)
227
228
228 v = self.client[:]
229 v = self.client[:]
229 ar = v.execute("print (5555)")
230 ar = v.execute("print (5555)")
230 ar.get(5)
231 ar.get(5)
231 with capture_output() as io:
232 with capture_output() as io:
232 ar.display_outputs()
233 ar.display_outputs()
233 self.assertEquals(io.stderr, '')
234 self.assertEquals(io.stderr, '')
234 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
235 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
235 self.assertFalse('\n\n' in io.stdout, io.stdout)
236 self.assertFalse('\n\n' in io.stdout, io.stdout)
236 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
237 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
237
238
238 ar = v.execute("a=5")
239 ar = v.execute("a=5")
239 ar.get(5)
240 ar.get(5)
240 with capture_output() as io:
241 with capture_output() as io:
241 ar.display_outputs()
242 ar.display_outputs()
242 self.assertEquals(io.stderr, '')
243 self.assertEquals(io.stderr, '')
243 self.assertEquals(io.stdout, '')
244 self.assertEquals(io.stdout, '')
244
245
245 def test_display_empty_streams_engine(self):
246 def test_display_empty_streams_engine(self):
246 """empty stdout/err are not displayed (groupby engine)"""
247 """empty stdout/err are not displayed (groupby engine)"""
247 self.minimum_engines(1)
248 self.minimum_engines(1)
248
249
249 v = self.client[:]
250 v = self.client[:]
250 ar = v.execute("print (5555)")
251 ar = v.execute("print (5555)")
251 ar.get(5)
252 ar.get(5)
252 with capture_output() as io:
253 with capture_output() as io:
253 ar.display_outputs('engine')
254 ar.display_outputs('engine')
254 self.assertEquals(io.stderr, '')
255 self.assertEquals(io.stderr, '')
255 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
256 self.assertEquals(io.stdout.count('5555'), len(v), io.stdout)
256 self.assertFalse('\n\n' in io.stdout, io.stdout)
257 self.assertFalse('\n\n' in io.stdout, io.stdout)
257 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
258 self.assertEquals(io.stdout.count('[stdout:'), len(v), io.stdout)
258
259
259 ar = v.execute("a=5")
260 ar = v.execute("a=5")
260 ar.get(5)
261 ar.get(5)
261 with capture_output() as io:
262 with capture_output() as io:
262 ar.display_outputs('engine')
263 ar.display_outputs('engine')
263 self.assertEquals(io.stderr, '')
264 self.assertEquals(io.stderr, '')
264 self.assertEquals(io.stdout, '')
265 self.assertEquals(io.stdout, '')
265
266
266
267
@@ -1,339 +1,340 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test Parallel magics
2 """Test Parallel magics
3
3
4 Authors:
4 Authors:
5
5
6 * Min RK
6 * Min RK
7 """
7 """
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 import re
19 import re
20 import sys
20 import sys
21 import time
21 import time
22
22
23 import zmq
23 import zmq
24 from nose import SkipTest
24 from nose import SkipTest
25
25
26 from IPython.testing import decorators as dec
26 from IPython.testing import decorators as dec
27 from IPython.testing.ipunittest import ParametricTestCase
27 from IPython.testing.ipunittest import ParametricTestCase
28 from IPython.utils.io import capture_output
28
29
29 from IPython import parallel as pmod
30 from IPython import parallel as pmod
30 from IPython.parallel import error
31 from IPython.parallel import error
31 from IPython.parallel import AsyncResult
32 from IPython.parallel import AsyncResult
32 from IPython.parallel.util import interactive
33 from IPython.parallel.util import interactive
33
34
34 from IPython.parallel.tests import add_engines
35 from IPython.parallel.tests import add_engines
35
36
36 from .clienttest import ClusterTestCase, capture_output, generate_output
37 from .clienttest import ClusterTestCase, generate_output
37
38
38 def setup():
39 def setup():
39 add_engines(3, total=True)
40 add_engines(3, total=True)
40
41
41 class TestParallelMagics(ClusterTestCase, ParametricTestCase):
42 class TestParallelMagics(ClusterTestCase, ParametricTestCase):
42
43
43 def test_px_blocking(self):
44 def test_px_blocking(self):
44 ip = get_ipython()
45 ip = get_ipython()
45 v = self.client[-1:]
46 v = self.client[-1:]
46 v.activate()
47 v.activate()
47 v.block=True
48 v.block=True
48
49
49 ip.magic('px a=5')
50 ip.magic('px a=5')
50 self.assertEquals(v['a'], [5])
51 self.assertEquals(v['a'], [5])
51 ip.magic('px a=10')
52 ip.magic('px a=10')
52 self.assertEquals(v['a'], [10])
53 self.assertEquals(v['a'], [10])
53 # just 'print a' works ~99% of the time, but this ensures that
54 # just 'print a' works ~99% of the time, but this ensures that
54 # the stdout message has arrived when the result is finished:
55 # the stdout message has arrived when the result is finished:
55 with capture_output() as io:
56 with capture_output() as io:
56 ip.magic(
57 ip.magic(
57 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
58 'px import sys,time;print(a);sys.stdout.flush();time.sleep(0.2)'
58 )
59 )
59 out = io.stdout
60 out = io.stdout
60 self.assertTrue('[stdout:' in out, out)
61 self.assertTrue('[stdout:' in out, out)
61 self.assertFalse('\n\n' in out)
62 self.assertFalse('\n\n' in out)
62 self.assertTrue(out.rstrip().endswith('10'))
63 self.assertTrue(out.rstrip().endswith('10'))
63 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
64 self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0')
64
65
65 def _check_generated_stderr(self, stderr, n):
66 def _check_generated_stderr(self, stderr, n):
66 expected = [
67 expected = [
67 r'\[stderr:\d+\]',
68 r'\[stderr:\d+\]',
68 '^stderr$',
69 '^stderr$',
69 '^stderr2$',
70 '^stderr2$',
70 ] * n
71 ] * n
71
72
72 self.assertFalse('\n\n' in stderr, stderr)
73 self.assertFalse('\n\n' in stderr, stderr)
73 lines = stderr.splitlines()
74 lines = stderr.splitlines()
74 self.assertEquals(len(lines), len(expected), stderr)
75 self.assertEquals(len(lines), len(expected), stderr)
75 for line,expect in zip(lines, expected):
76 for line,expect in zip(lines, expected):
76 if isinstance(expect, str):
77 if isinstance(expect, str):
77 expect = [expect]
78 expect = [expect]
78 for ex in expect:
79 for ex in expect:
79 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
80 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
80
81
81 def test_cellpx_block_args(self):
82 def test_cellpx_block_args(self):
82 """%%px --[no]block flags work"""
83 """%%px --[no]block flags work"""
83 ip = get_ipython()
84 ip = get_ipython()
84 v = self.client[-1:]
85 v = self.client[-1:]
85 v.activate()
86 v.activate()
86 v.block=False
87 v.block=False
87
88
88 for block in (True, False):
89 for block in (True, False):
89 v.block = block
90 v.block = block
90
91
91 with capture_output() as io:
92 with capture_output() as io:
92 ip.run_cell_magic("px", "", "1")
93 ip.run_cell_magic("px", "", "1")
93 if block:
94 if block:
94 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
95 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
95 else:
96 else:
96 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
97 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
97
98
98 with capture_output() as io:
99 with capture_output() as io:
99 ip.run_cell_magic("px", "--block", "1")
100 ip.run_cell_magic("px", "--block", "1")
100 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
101 self.assertTrue(io.stdout.startswith("Parallel"), io.stdout)
101
102
102 with capture_output() as io:
103 with capture_output() as io:
103 ip.run_cell_magic("px", "--noblock", "1")
104 ip.run_cell_magic("px", "--noblock", "1")
104 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
105 self.assertTrue(io.stdout.startswith("Async"), io.stdout)
105
106
106 def test_cellpx_groupby_engine(self):
107 def test_cellpx_groupby_engine(self):
107 """%%px --group-outputs=engine"""
108 """%%px --group-outputs=engine"""
108 ip = get_ipython()
109 ip = get_ipython()
109 v = self.client[:]
110 v = self.client[:]
110 v.block = True
111 v.block = True
111 v.activate()
112 v.activate()
112
113
113 v['generate_output'] = generate_output
114 v['generate_output'] = generate_output
114
115
115 with capture_output() as io:
116 with capture_output() as io:
116 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
117 ip.run_cell_magic('px', '--group-outputs=engine', 'generate_output()')
117
118
118 self.assertFalse('\n\n' in io.stdout)
119 self.assertFalse('\n\n' in io.stdout)
119 lines = io.stdout.splitlines()[1:]
120 lines = io.stdout.splitlines()[1:]
120 expected = [
121 expected = [
121 r'\[stdout:\d+\]',
122 r'\[stdout:\d+\]',
122 'stdout',
123 'stdout',
123 'stdout2',
124 'stdout2',
124 r'\[output:\d+\]',
125 r'\[output:\d+\]',
125 r'IPython\.core\.display\.HTML',
126 r'IPython\.core\.display\.HTML',
126 r'IPython\.core\.display\.Math',
127 r'IPython\.core\.display\.Math',
127 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
128 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math',
128 ] * len(v)
129 ] * len(v)
129
130
130 self.assertEquals(len(lines), len(expected), io.stdout)
131 self.assertEquals(len(lines), len(expected), io.stdout)
131 for line,expect in zip(lines, expected):
132 for line,expect in zip(lines, expected):
132 if isinstance(expect, str):
133 if isinstance(expect, str):
133 expect = [expect]
134 expect = [expect]
134 for ex in expect:
135 for ex in expect:
135 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
136 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
136
137
137 self._check_generated_stderr(io.stderr, len(v))
138 self._check_generated_stderr(io.stderr, len(v))
138
139
139
140
140 def test_cellpx_groupby_order(self):
141 def test_cellpx_groupby_order(self):
141 """%%px --group-outputs=order"""
142 """%%px --group-outputs=order"""
142 ip = get_ipython()
143 ip = get_ipython()
143 v = self.client[:]
144 v = self.client[:]
144 v.block = True
145 v.block = True
145 v.activate()
146 v.activate()
146
147
147 v['generate_output'] = generate_output
148 v['generate_output'] = generate_output
148
149
149 with capture_output() as io:
150 with capture_output() as io:
150 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
151 ip.run_cell_magic('px', '--group-outputs=order', 'generate_output()')
151
152
152 self.assertFalse('\n\n' in io.stdout)
153 self.assertFalse('\n\n' in io.stdout)
153 lines = io.stdout.splitlines()[1:]
154 lines = io.stdout.splitlines()[1:]
154 expected = []
155 expected = []
155 expected.extend([
156 expected.extend([
156 r'\[stdout:\d+\]',
157 r'\[stdout:\d+\]',
157 'stdout',
158 'stdout',
158 'stdout2',
159 'stdout2',
159 ] * len(v))
160 ] * len(v))
160 expected.extend([
161 expected.extend([
161 r'\[output:\d+\]',
162 r'\[output:\d+\]',
162 'IPython.core.display.HTML',
163 'IPython.core.display.HTML',
163 ] * len(v))
164 ] * len(v))
164 expected.extend([
165 expected.extend([
165 r'\[output:\d+\]',
166 r'\[output:\d+\]',
166 'IPython.core.display.Math',
167 'IPython.core.display.Math',
167 ] * len(v))
168 ] * len(v))
168 expected.extend([
169 expected.extend([
169 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
170 r'Out\[\d+:\d+\]:.*IPython\.core\.display\.Math'
170 ] * len(v))
171 ] * len(v))
171
172
172 self.assertEquals(len(lines), len(expected), io.stdout)
173 self.assertEquals(len(lines), len(expected), io.stdout)
173 for line,expect in zip(lines, expected):
174 for line,expect in zip(lines, expected):
174 if isinstance(expect, str):
175 if isinstance(expect, str):
175 expect = [expect]
176 expect = [expect]
176 for ex in expect:
177 for ex in expect:
177 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
178 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
178
179
179 self._check_generated_stderr(io.stderr, len(v))
180 self._check_generated_stderr(io.stderr, len(v))
180
181
181 def test_cellpx_groupby_type(self):
182 def test_cellpx_groupby_type(self):
182 """%%px --group-outputs=type"""
183 """%%px --group-outputs=type"""
183 ip = get_ipython()
184 ip = get_ipython()
184 v = self.client[:]
185 v = self.client[:]
185 v.block = True
186 v.block = True
186 v.activate()
187 v.activate()
187
188
188 v['generate_output'] = generate_output
189 v['generate_output'] = generate_output
189
190
190 with capture_output() as io:
191 with capture_output() as io:
191 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
192 ip.run_cell_magic('px', '--group-outputs=type', 'generate_output()')
192
193
193 self.assertFalse('\n\n' in io.stdout)
194 self.assertFalse('\n\n' in io.stdout)
194 lines = io.stdout.splitlines()[1:]
195 lines = io.stdout.splitlines()[1:]
195
196
196 expected = []
197 expected = []
197 expected.extend([
198 expected.extend([
198 r'\[stdout:\d+\]',
199 r'\[stdout:\d+\]',
199 'stdout',
200 'stdout',
200 'stdout2',
201 'stdout2',
201 ] * len(v))
202 ] * len(v))
202 expected.extend([
203 expected.extend([
203 r'\[output:\d+\]',
204 r'\[output:\d+\]',
204 r'IPython\.core\.display\.HTML',
205 r'IPython\.core\.display\.HTML',
205 r'IPython\.core\.display\.Math',
206 r'IPython\.core\.display\.Math',
206 ] * len(v))
207 ] * len(v))
207 expected.extend([
208 expected.extend([
208 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
209 (r'Out\[\d+:\d+\]', r'IPython\.core\.display\.Math')
209 ] * len(v))
210 ] * len(v))
210
211
211 self.assertEquals(len(lines), len(expected), io.stdout)
212 self.assertEquals(len(lines), len(expected), io.stdout)
212 for line,expect in zip(lines, expected):
213 for line,expect in zip(lines, expected):
213 if isinstance(expect, str):
214 if isinstance(expect, str):
214 expect = [expect]
215 expect = [expect]
215 for ex in expect:
216 for ex in expect:
216 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
217 self.assertTrue(re.search(ex, line) is not None, "Expected %r in %r" % (ex, line))
217
218
218 self._check_generated_stderr(io.stderr, len(v))
219 self._check_generated_stderr(io.stderr, len(v))
219
220
220
221
221 def test_px_nonblocking(self):
222 def test_px_nonblocking(self):
222 ip = get_ipython()
223 ip = get_ipython()
223 v = self.client[-1:]
224 v = self.client[-1:]
224 v.activate()
225 v.activate()
225 v.block=False
226 v.block=False
226
227
227 ip.magic('px a=5')
228 ip.magic('px a=5')
228 self.assertEquals(v['a'], [5])
229 self.assertEquals(v['a'], [5])
229 ip.magic('px a=10')
230 ip.magic('px a=10')
230 self.assertEquals(v['a'], [10])
231 self.assertEquals(v['a'], [10])
231 with capture_output() as io:
232 with capture_output() as io:
232 ar = ip.magic('px print (a)')
233 ar = ip.magic('px print (a)')
233 self.assertTrue(isinstance(ar, AsyncResult))
234 self.assertTrue(isinstance(ar, AsyncResult))
234 self.assertTrue('Async' in io.stdout)
235 self.assertTrue('Async' in io.stdout)
235 self.assertFalse('[stdout:' in io.stdout)
236 self.assertFalse('[stdout:' in io.stdout)
236 self.assertFalse('\n\n' in io.stdout)
237 self.assertFalse('\n\n' in io.stdout)
237
238
238 ar = ip.magic('px 1/0')
239 ar = ip.magic('px 1/0')
239 self.assertRaisesRemote(ZeroDivisionError, ar.get)
240 self.assertRaisesRemote(ZeroDivisionError, ar.get)
240
241
241 def test_autopx_blocking(self):
242 def test_autopx_blocking(self):
242 ip = get_ipython()
243 ip = get_ipython()
243 v = self.client[-1]
244 v = self.client[-1]
244 v.activate()
245 v.activate()
245 v.block=True
246 v.block=True
246
247
247 with capture_output() as io:
248 with capture_output() as io:
248 ip.magic('autopx')
249 ip.magic('autopx')
249 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
250 ip.run_cell('\n'.join(('a=5','b=12345','c=0')))
250 ip.run_cell('b*=2')
251 ip.run_cell('b*=2')
251 ip.run_cell('print (b)')
252 ip.run_cell('print (b)')
252 ip.run_cell('b')
253 ip.run_cell('b')
253 ip.run_cell("b/c")
254 ip.run_cell("b/c")
254 ip.magic('autopx')
255 ip.magic('autopx')
255
256
256 output = io.stdout
257 output = io.stdout
257
258
258 self.assertTrue(output.startswith('%autopx enabled'), output)
259 self.assertTrue(output.startswith('%autopx enabled'), output)
259 self.assertTrue(output.rstrip().endswith('%autopx disabled'), output)
260 self.assertTrue(output.rstrip().endswith('%autopx disabled'), output)
260 self.assertTrue('RemoteError: ZeroDivisionError' in output, output)
261 self.assertTrue('RemoteError: ZeroDivisionError' in output, output)
261 self.assertTrue('\nOut[' in output, output)
262 self.assertTrue('\nOut[' in output, output)
262 self.assertTrue(': 24690' in output, output)
263 self.assertTrue(': 24690' in output, output)
263 ar = v.get_result(-1)
264 ar = v.get_result(-1)
264 self.assertEquals(v['a'], 5)
265 self.assertEquals(v['a'], 5)
265 self.assertEquals(v['b'], 24690)
266 self.assertEquals(v['b'], 24690)
266 self.assertRaisesRemote(ZeroDivisionError, ar.get)
267 self.assertRaisesRemote(ZeroDivisionError, ar.get)
267
268
268 def test_autopx_nonblocking(self):
269 def test_autopx_nonblocking(self):
269 ip = get_ipython()
270 ip = get_ipython()
270 v = self.client[-1]
271 v = self.client[-1]
271 v.activate()
272 v.activate()
272 v.block=False
273 v.block=False
273
274
274 with capture_output() as io:
275 with capture_output() as io:
275 ip.magic('autopx')
276 ip.magic('autopx')
276 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
277 ip.run_cell('\n'.join(('a=5','b=10','c=0')))
277 ip.run_cell('print (b)')
278 ip.run_cell('print (b)')
278 ip.run_cell('import time; time.sleep(0.1)')
279 ip.run_cell('import time; time.sleep(0.1)')
279 ip.run_cell("b/c")
280 ip.run_cell("b/c")
280 ip.run_cell('b*=2')
281 ip.run_cell('b*=2')
281 ip.magic('autopx')
282 ip.magic('autopx')
282
283
283 output = io.stdout.rstrip()
284 output = io.stdout.rstrip()
284
285
285 self.assertTrue(output.startswith('%autopx enabled'))
286 self.assertTrue(output.startswith('%autopx enabled'))
286 self.assertTrue(output.endswith('%autopx disabled'))
287 self.assertTrue(output.endswith('%autopx disabled'))
287 self.assertFalse('ZeroDivisionError' in output)
288 self.assertFalse('ZeroDivisionError' in output)
288 ar = v.get_result(-2)
289 ar = v.get_result(-2)
289 self.assertRaisesRemote(ZeroDivisionError, ar.get)
290 self.assertRaisesRemote(ZeroDivisionError, ar.get)
290 # prevent TaskAborted on pulls, due to ZeroDivisionError
291 # prevent TaskAborted on pulls, due to ZeroDivisionError
291 time.sleep(0.5)
292 time.sleep(0.5)
292 self.assertEquals(v['a'], 5)
293 self.assertEquals(v['a'], 5)
293 # b*=2 will not fire, due to abort
294 # b*=2 will not fire, due to abort
294 self.assertEquals(v['b'], 10)
295 self.assertEquals(v['b'], 10)
295
296
296 def test_result(self):
297 def test_result(self):
297 ip = get_ipython()
298 ip = get_ipython()
298 v = self.client[-1]
299 v = self.client[-1]
299 v.activate()
300 v.activate()
300 data = dict(a=111,b=222)
301 data = dict(a=111,b=222)
301 v.push(data, block=True)
302 v.push(data, block=True)
302
303
303 ip.magic('px a')
304 ip.magic('px a')
304 ip.magic('px b')
305 ip.magic('px b')
305 for idx, name in [
306 for idx, name in [
306 ('', 'b'),
307 ('', 'b'),
307 ('-1', 'b'),
308 ('-1', 'b'),
308 ('2', 'b'),
309 ('2', 'b'),
309 ('1', 'a'),
310 ('1', 'a'),
310 ('-2', 'a'),
311 ('-2', 'a'),
311 ]:
312 ]:
312 with capture_output() as io:
313 with capture_output() as io:
313 ip.magic('result ' + idx)
314 ip.magic('result ' + idx)
314 output = io.stdout
315 output = io.stdout
315 msg = "expected %s output to include %s, but got: %s" % \
316 msg = "expected %s output to include %s, but got: %s" % \
316 ('%result '+idx, str(data[name]), output)
317 ('%result '+idx, str(data[name]), output)
317 self.assertTrue(str(data[name]) in output, msg)
318 self.assertTrue(str(data[name]) in output, msg)
318
319
319 @dec.skipif_not_matplotlib
320 @dec.skipif_not_matplotlib
320 def test_px_pylab(self):
321 def test_px_pylab(self):
321 """%pylab works on engines"""
322 """%pylab works on engines"""
322 ip = get_ipython()
323 ip = get_ipython()
323 v = self.client[-1]
324 v = self.client[-1]
324 v.block = True
325 v.block = True
325 v.activate()
326 v.activate()
326
327
327 with capture_output() as io:
328 with capture_output() as io:
328 ip.magic("px %pylab inline")
329 ip.magic("px %pylab inline")
329
330
330 self.assertTrue("Welcome to pylab" in io.stdout, io.stdout)
331 self.assertTrue("Welcome to pylab" in io.stdout, io.stdout)
331 self.assertTrue("backend_inline" in io.stdout, io.stdout)
332 self.assertTrue("backend_inline" in io.stdout, io.stdout)
332
333
333 with capture_output() as io:
334 with capture_output() as io:
334 ip.magic("px plot(rand(100))")
335 ip.magic("px plot(rand(100))")
335
336
336 self.assertTrue('Out[' in io.stdout, io.stdout)
337 self.assertTrue('Out[' in io.stdout, io.stdout)
337 self.assertTrue('matplotlib.lines' in io.stdout, io.stdout)
338 self.assertTrue('matplotlib.lines' in io.stdout, io.stdout)
338
339
339
340
@@ -1,323 +1,384 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 from StringIO import StringIO
20
21
21 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
22 # Code
23 # Code
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24
25
25
26
26 class IOStream:
27 class IOStream:
27
28
28 def __init__(self,stream, fallback=None):
29 def __init__(self,stream, fallback=None):
29 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if fallback is not None:
31 if fallback is not None:
31 stream = fallback
32 stream = fallback
32 else:
33 else:
33 raise ValueError("fallback required, but not specified")
34 raise ValueError("fallback required, but not specified")
34 self.stream = stream
35 self.stream = stream
35 self._swrite = stream.write
36 self._swrite = stream.write
36
37
37 # clone all methods not overridden:
38 # clone all methods not overridden:
38 def clone(meth):
39 def clone(meth):
39 return not hasattr(self, meth) and not meth.startswith('_')
40 return not hasattr(self, meth) and not meth.startswith('_')
40 for meth in filter(clone, dir(stream)):
41 for meth in filter(clone, dir(stream)):
41 setattr(self, meth, getattr(stream, meth))
42 setattr(self, meth, getattr(stream, meth))
42
43
43 def write(self,data):
44 def write(self,data):
44 try:
45 try:
45 self._swrite(data)
46 self._swrite(data)
46 except:
47 except:
47 try:
48 try:
48 # print handles some unicode issues which may trip a plain
49 # print handles some unicode issues which may trip a plain
49 # write() call. Emulate write() by using an empty end
50 # write() call. Emulate write() by using an empty end
50 # argument.
51 # argument.
51 print(data, end='', file=self.stream)
52 print(data, end='', file=self.stream)
52 except:
53 except:
53 # if we get here, something is seriously broken.
54 # if we get here, something is seriously broken.
54 print('ERROR - failed to write data to stream:', self.stream,
55 print('ERROR - failed to write data to stream:', self.stream,
55 file=sys.stderr)
56 file=sys.stderr)
56
57
57 def writelines(self, lines):
58 def writelines(self, lines):
58 if isinstance(lines, basestring):
59 if isinstance(lines, basestring):
59 lines = [lines]
60 lines = [lines]
60 for line in lines:
61 for line in lines:
61 self.write(line)
62 self.write(line)
62
63
63 # This class used to have a writeln method, but regular files and streams
64 # This class used to have a writeln method, but regular files and streams
64 # in Python don't have this method. We need to keep this completely
65 # in Python don't have this method. We need to keep this completely
65 # compatible so we removed it.
66 # compatible so we removed it.
66
67
67 @property
68 @property
68 def closed(self):
69 def closed(self):
69 return self.stream.closed
70 return self.stream.closed
70
71
71 def close(self):
72 def close(self):
72 pass
73 pass
73
74
74 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
75 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
75 devnull = open(os.devnull, 'a')
76 devnull = open(os.devnull, 'a')
76 stdin = IOStream(sys.stdin, fallback=devnull)
77 stdin = IOStream(sys.stdin, fallback=devnull)
77 stdout = IOStream(sys.stdout, fallback=devnull)
78 stdout = IOStream(sys.stdout, fallback=devnull)
78 stderr = IOStream(sys.stderr, fallback=devnull)
79 stderr = IOStream(sys.stderr, fallback=devnull)
79
80
80 class IOTerm:
81 class IOTerm:
81 """ Term holds the file or file-like objects for handling I/O operations.
82 """ Term holds the file or file-like objects for handling I/O operations.
82
83
83 These are normally just sys.stdin, sys.stdout and sys.stderr but for
84 These are normally just sys.stdin, sys.stdout and sys.stderr but for
84 Windows they can can replaced to allow editing the strings before they are
85 Windows they can can replaced to allow editing the strings before they are
85 displayed."""
86 displayed."""
86
87
87 # In the future, having IPython channel all its I/O operations through
88 # In the future, having IPython channel all its I/O operations through
88 # this class will make it easier to embed it into other environments which
89 # this class will make it easier to embed it into other environments which
89 # are not a normal terminal (such as a GUI-based shell)
90 # are not a normal terminal (such as a GUI-based shell)
90 def __init__(self, stdin=None, stdout=None, stderr=None):
91 def __init__(self, stdin=None, stdout=None, stderr=None):
91 mymodule = sys.modules[__name__]
92 mymodule = sys.modules[__name__]
92 self.stdin = IOStream(stdin, mymodule.stdin)
93 self.stdin = IOStream(stdin, mymodule.stdin)
93 self.stdout = IOStream(stdout, mymodule.stdout)
94 self.stdout = IOStream(stdout, mymodule.stdout)
94 self.stderr = IOStream(stderr, mymodule.stderr)
95 self.stderr = IOStream(stderr, mymodule.stderr)
95
96
96
97
97 class Tee(object):
98 class Tee(object):
98 """A class to duplicate an output stream to stdout/err.
99 """A class to duplicate an output stream to stdout/err.
99
100
100 This works in a manner very similar to the Unix 'tee' command.
101 This works in a manner very similar to the Unix 'tee' command.
101
102
102 When the object is closed or deleted, it closes the original file given to
103 When the object is closed or deleted, it closes the original file given to
103 it for duplication.
104 it for duplication.
104 """
105 """
105 # Inspired by:
106 # Inspired by:
106 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
107 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
107
108
108 def __init__(self, file_or_name, mode="w", channel='stdout'):
109 def __init__(self, file_or_name, mode="w", channel='stdout'):
109 """Construct a new Tee object.
110 """Construct a new Tee object.
110
111
111 Parameters
112 Parameters
112 ----------
113 ----------
113 file_or_name : filename or open filehandle (writable)
114 file_or_name : filename or open filehandle (writable)
114 File that will be duplicated
115 File that will be duplicated
115
116
116 mode : optional, valid mode for open().
117 mode : optional, valid mode for open().
117 If a filename was give, open with this mode.
118 If a filename was give, open with this mode.
118
119
119 channel : str, one of ['stdout', 'stderr']
120 channel : str, one of ['stdout', 'stderr']
120 """
121 """
121 if channel not in ['stdout', 'stderr']:
122 if channel not in ['stdout', 'stderr']:
122 raise ValueError('Invalid channel spec %s' % channel)
123 raise ValueError('Invalid channel spec %s' % channel)
123
124
124 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
125 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
125 self.file = file_or_name
126 self.file = file_or_name
126 else:
127 else:
127 self.file = open(file_or_name, mode)
128 self.file = open(file_or_name, mode)
128 self.channel = channel
129 self.channel = channel
129 self.ostream = getattr(sys, channel)
130 self.ostream = getattr(sys, channel)
130 setattr(sys, channel, self)
131 setattr(sys, channel, self)
131 self._closed = False
132 self._closed = False
132
133
133 def close(self):
134 def close(self):
134 """Close the file and restore the channel."""
135 """Close the file and restore the channel."""
135 self.flush()
136 self.flush()
136 setattr(sys, self.channel, self.ostream)
137 setattr(sys, self.channel, self.ostream)
137 self.file.close()
138 self.file.close()
138 self._closed = True
139 self._closed = True
139
140
140 def write(self, data):
141 def write(self, data):
141 """Write data to both channels."""
142 """Write data to both channels."""
142 self.file.write(data)
143 self.file.write(data)
143 self.ostream.write(data)
144 self.ostream.write(data)
144 self.ostream.flush()
145 self.ostream.flush()
145
146
146 def flush(self):
147 def flush(self):
147 """Flush both channels."""
148 """Flush both channels."""
148 self.file.flush()
149 self.file.flush()
149 self.ostream.flush()
150 self.ostream.flush()
150
151
151 def __del__(self):
152 def __del__(self):
152 if not self._closed:
153 if not self._closed:
153 self.close()
154 self.close()
154
155
155
156
156 def file_read(filename):
157 def file_read(filename):
157 """Read a file and close it. Returns the file source."""
158 """Read a file and close it. Returns the file source."""
158 fobj = open(filename,'r');
159 fobj = open(filename,'r');
159 source = fobj.read();
160 source = fobj.read();
160 fobj.close()
161 fobj.close()
161 return source
162 return source
162
163
163
164
164 def file_readlines(filename):
165 def file_readlines(filename):
165 """Read a file and close it. Returns the file source using readlines()."""
166 """Read a file and close it. Returns the file source using readlines()."""
166 fobj = open(filename,'r');
167 fobj = open(filename,'r');
167 lines = fobj.readlines();
168 lines = fobj.readlines();
168 fobj.close()
169 fobj.close()
169 return lines
170 return lines
170
171
171
172
172 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
173 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
173 """Take multiple lines of input.
174 """Take multiple lines of input.
174
175
175 A list with each line of input as a separate element is returned when a
176 A list with each line of input as a separate element is returned when a
176 termination string is entered (defaults to a single '.'). Input can also
177 termination string is entered (defaults to a single '.'). Input can also
177 terminate via EOF (^D in Unix, ^Z-RET in Windows).
178 terminate via EOF (^D in Unix, ^Z-RET in Windows).
178
179
179 Lines of input which end in \\ are joined into single entries (and a
180 Lines of input which end in \\ are joined into single entries (and a
180 secondary continuation prompt is issued as long as the user terminates
181 secondary continuation prompt is issued as long as the user terminates
181 lines with \\). This allows entering very long strings which are still
182 lines with \\). This allows entering very long strings which are still
182 meant to be treated as single entities.
183 meant to be treated as single entities.
183 """
184 """
184
185
185 try:
186 try:
186 if header:
187 if header:
187 header += '\n'
188 header += '\n'
188 lines = [raw_input(header + ps1)]
189 lines = [raw_input(header + ps1)]
189 except EOFError:
190 except EOFError:
190 return []
191 return []
191 terminate = [terminate_str]
192 terminate = [terminate_str]
192 try:
193 try:
193 while lines[-1:] != terminate:
194 while lines[-1:] != terminate:
194 new_line = raw_input(ps1)
195 new_line = raw_input(ps1)
195 while new_line.endswith('\\'):
196 while new_line.endswith('\\'):
196 new_line = new_line[:-1] + raw_input(ps2)
197 new_line = new_line[:-1] + raw_input(ps2)
197 lines.append(new_line)
198 lines.append(new_line)
198
199
199 return lines[:-1] # don't return the termination command
200 return lines[:-1] # don't return the termination command
200 except EOFError:
201 except EOFError:
201 print()
202 print()
202 return lines
203 return lines
203
204
204
205
205 def raw_input_ext(prompt='', ps2='... '):
206 def raw_input_ext(prompt='', ps2='... '):
206 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
207 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
207
208
208 line = raw_input(prompt)
209 line = raw_input(prompt)
209 while line.endswith('\\'):
210 while line.endswith('\\'):
210 line = line[:-1] + raw_input(ps2)
211 line = line[:-1] + raw_input(ps2)
211 return line
212 return line
212
213
213
214
214 def ask_yes_no(prompt,default=None):
215 def ask_yes_no(prompt,default=None):
215 """Asks a question and returns a boolean (y/n) answer.
216 """Asks a question and returns a boolean (y/n) answer.
216
217
217 If default is given (one of 'y','n'), it is used if the user input is
218 If default is given (one of 'y','n'), it is used if the user input is
218 empty. Otherwise the question is repeated until an answer is given.
219 empty. Otherwise the question is repeated until an answer is given.
219
220
220 An EOF is treated as the default answer. If there is no default, an
221 An EOF is treated as the default answer. If there is no default, an
221 exception is raised to prevent infinite loops.
222 exception is raised to prevent infinite loops.
222
223
223 Valid answers are: y/yes/n/no (match is not case sensitive)."""
224 Valid answers are: y/yes/n/no (match is not case sensitive)."""
224
225
225 answers = {'y':True,'n':False,'yes':True,'no':False}
226 answers = {'y':True,'n':False,'yes':True,'no':False}
226 ans = None
227 ans = None
227 while ans not in answers.keys():
228 while ans not in answers.keys():
228 try:
229 try:
229 ans = raw_input(prompt+' ').lower()
230 ans = raw_input(prompt+' ').lower()
230 if not ans: # response was an empty string
231 if not ans: # response was an empty string
231 ans = default
232 ans = default
232 except KeyboardInterrupt:
233 except KeyboardInterrupt:
233 pass
234 pass
234 except EOFError:
235 except EOFError:
235 if default in answers.keys():
236 if default in answers.keys():
236 ans = default
237 ans = default
237 print()
238 print()
238 else:
239 else:
239 raise
240 raise
240
241
241 return answers[ans]
242 return answers[ans]
242
243
243
244
244 class NLprinter:
245 class NLprinter:
245 """Print an arbitrarily nested list, indicating index numbers.
246 """Print an arbitrarily nested list, indicating index numbers.
246
247
247 An instance of this class called nlprint is available and callable as a
248 An instance of this class called nlprint is available and callable as a
248 function.
249 function.
249
250
250 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
251 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
251 and using 'sep' to separate the index from the value. """
252 and using 'sep' to separate the index from the value. """
252
253
253 def __init__(self):
254 def __init__(self):
254 self.depth = 0
255 self.depth = 0
255
256
256 def __call__(self,lst,pos='',**kw):
257 def __call__(self,lst,pos='',**kw):
257 """Prints the nested list numbering levels."""
258 """Prints the nested list numbering levels."""
258 kw.setdefault('indent',' ')
259 kw.setdefault('indent',' ')
259 kw.setdefault('sep',': ')
260 kw.setdefault('sep',': ')
260 kw.setdefault('start',0)
261 kw.setdefault('start',0)
261 kw.setdefault('stop',len(lst))
262 kw.setdefault('stop',len(lst))
262 # we need to remove start and stop from kw so they don't propagate
263 # we need to remove start and stop from kw so they don't propagate
263 # into a recursive call for a nested list.
264 # into a recursive call for a nested list.
264 start = kw['start']; del kw['start']
265 start = kw['start']; del kw['start']
265 stop = kw['stop']; del kw['stop']
266 stop = kw['stop']; del kw['stop']
266 if self.depth == 0 and 'header' in kw.keys():
267 if self.depth == 0 and 'header' in kw.keys():
267 print(kw['header'])
268 print(kw['header'])
268
269
269 for idx in range(start,stop):
270 for idx in range(start,stop):
270 elem = lst[idx]
271 elem = lst[idx]
271 newpos = pos + str(idx)
272 newpos = pos + str(idx)
272 if type(elem)==type([]):
273 if type(elem)==type([]):
273 self.depth += 1
274 self.depth += 1
274 self.__call__(elem, newpos+",", **kw)
275 self.__call__(elem, newpos+",", **kw)
275 self.depth -= 1
276 self.depth -= 1
276 else:
277 else:
277 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
278 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
278
279
279 nlprint = NLprinter()
280 nlprint = NLprinter()
280
281
281
282
282 def temp_pyfile(src, ext='.py'):
283 def temp_pyfile(src, ext='.py'):
283 """Make a temporary python file, return filename and filehandle.
284 """Make a temporary python file, return filename and filehandle.
284
285
285 Parameters
286 Parameters
286 ----------
287 ----------
287 src : string or list of strings (no need for ending newlines if list)
288 src : string or list of strings (no need for ending newlines if list)
288 Source code to be written to the file.
289 Source code to be written to the file.
289
290
290 ext : optional, string
291 ext : optional, string
291 Extension for the generated file.
292 Extension for the generated file.
292
293
293 Returns
294 Returns
294 -------
295 -------
295 (filename, open filehandle)
296 (filename, open filehandle)
296 It is the caller's responsibility to close the open file and unlink it.
297 It is the caller's responsibility to close the open file and unlink it.
297 """
298 """
298 fname = tempfile.mkstemp(ext)[1]
299 fname = tempfile.mkstemp(ext)[1]
299 f = open(fname,'w')
300 f = open(fname,'w')
300 f.write(src)
301 f.write(src)
301 f.flush()
302 f.flush()
302 return fname, f
303 return fname, f
303
304
304
305
305 def raw_print(*args, **kw):
306 def raw_print(*args, **kw):
306 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
307 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
307
308
308 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
309 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
309 file=sys.__stdout__)
310 file=sys.__stdout__)
310 sys.__stdout__.flush()
311 sys.__stdout__.flush()
311
312
312
313
313 def raw_print_err(*args, **kw):
314 def raw_print_err(*args, **kw):
314 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
315 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
315
316
316 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
317 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
317 file=sys.__stderr__)
318 file=sys.__stderr__)
318 sys.__stderr__.flush()
319 sys.__stderr__.flush()
319
320
320
321
321 # Short aliases for quick debugging, do NOT use these in production code.
322 # Short aliases for quick debugging, do NOT use these in production code.
322 rprint = raw_print
323 rprint = raw_print
323 rprinte = raw_print_err
324 rprinte = raw_print_err
325
326
327 class CapturedIO(object):
328 """Simple object for containing captured stdout/err StringIO objects"""
329
330 def __init__(self, stdout, stderr):
331 self._stdout = stdout
332 self._stderr = stderr
333
334 def __str__(self):
335 return self.stdout
336
337 @property
338 def stdout(self):
339 if not self._stdout:
340 return ''
341 return self._stdout.getvalue()
342
343 @property
344 def stderr(self):
345 if not self._stderr:
346 return ''
347 return self._stderr.getvalue()
348
349 def show(self):
350 """write my output to sys.stdout/err as appropriate"""
351 sys.stdout.write(self.stdout)
352 sys.stderr.write(self.stderr)
353 sys.stdout.flush()
354 sys.stderr.flush()
355
356 __call__ = show
357
358
359 class capture_output(object):
360 """context manager for capturing stdout/err"""
361 stdout = True
362 stderr = True
363
364 def __init__(self, stdout=True, stderr=True):
365 self.stdout = stdout
366 self.stderr = stderr
367
368 def __enter__(self):
369 self.sys_stdout = sys.stdout
370 self.sys_stderr = sys.stderr
371
372 stdout = stderr = False
373 if self.stdout:
374 stdout = sys.stdout = StringIO()
375 if self.stderr:
376 stderr = sys.stderr = StringIO()
377
378 return CapturedIO(stdout, stderr)
379
380 def __exit__(self, exc_type, exc_value, traceback):
381 sys.stdout = self.sys_stdout
382 sys.stderr = self.sys_stderr
383
384
@@ -1,75 +1,85 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for io.py"""
2 """Tests for io.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import sys
15 import sys
16
16
17 from StringIO import StringIO
17 from StringIO import StringIO
18 from subprocess import Popen, PIPE
18 from subprocess import Popen, PIPE
19
19
20 import nose.tools as nt
20 import nose.tools as nt
21
21
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23 from IPython.utils.io import Tee
23 from IPython.utils.io import Tee, capture_output
24 from IPython.utils.py3compat import doctest_refactor_print
24 from IPython.utils.py3compat import doctest_refactor_print
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Tests
27 # Tests
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30
30
31 def test_tee_simple():
31 def test_tee_simple():
32 "Very simple check with stdout only"
32 "Very simple check with stdout only"
33 chan = StringIO()
33 chan = StringIO()
34 text = 'Hello'
34 text = 'Hello'
35 tee = Tee(chan, channel='stdout')
35 tee = Tee(chan, channel='stdout')
36 print >> chan, text
36 print >> chan, text
37 nt.assert_equal(chan.getvalue(), text+"\n")
37 nt.assert_equal(chan.getvalue(), text+"\n")
38
38
39
39
40 class TeeTestCase(dec.ParametricTestCase):
40 class TeeTestCase(dec.ParametricTestCase):
41
41
42 def tchan(self, channel, check='close'):
42 def tchan(self, channel, check='close'):
43 trap = StringIO()
43 trap = StringIO()
44 chan = StringIO()
44 chan = StringIO()
45 text = 'Hello'
45 text = 'Hello'
46
46
47 std_ori = getattr(sys, channel)
47 std_ori = getattr(sys, channel)
48 setattr(sys, channel, trap)
48 setattr(sys, channel, trap)
49
49
50 tee = Tee(chan, channel=channel)
50 tee = Tee(chan, channel=channel)
51 print >> chan, text,
51 print >> chan, text,
52 setattr(sys, channel, std_ori)
52 setattr(sys, channel, std_ori)
53 trap_val = trap.getvalue()
53 trap_val = trap.getvalue()
54 nt.assert_equals(chan.getvalue(), text)
54 nt.assert_equals(chan.getvalue(), text)
55 if check=='close':
55 if check=='close':
56 tee.close()
56 tee.close()
57 else:
57 else:
58 del tee
58 del tee
59
59
60 def test(self):
60 def test(self):
61 for chan in ['stdout', 'stderr']:
61 for chan in ['stdout', 'stderr']:
62 for check in ['close', 'del']:
62 for check in ['close', 'del']:
63 yield self.tchan(chan, check)
63 yield self.tchan(chan, check)
64
64
65 def test_io_init():
65 def test_io_init():
66 """Test that io.stdin/out/err exist at startup"""
66 """Test that io.stdin/out/err exist at startup"""
67 for name in ('stdin', 'stdout', 'stderr'):
67 for name in ('stdin', 'stdout', 'stderr'):
68 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
68 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
69 p = Popen([sys.executable, '-c', cmd],
69 p = Popen([sys.executable, '-c', cmd],
70 stdout=PIPE)
70 stdout=PIPE)
71 p.wait()
71 p.wait()
72 classname = p.stdout.read().strip().decode('ascii')
72 classname = p.stdout.read().strip().decode('ascii')
73 # __class__ is a reference to the class object in Python 3, so we can't
73 # __class__ is a reference to the class object in Python 3, so we can't
74 # just test for string equality.
74 # just test for string equality.
75 assert 'IPython.utils.io.IOStream' in classname, classname
75 assert 'IPython.utils.io.IOStream' in classname, classname
76
77 def test_capture_output():
78 """capture_output() context works"""
79
80 with capture_output() as io:
81 print 'hi, stdout'
82 print >> sys.stderr, 'hi, stderr'
83
84 nt.assert_equals(io.stdout, 'hi, stdout\n')
85 nt.assert_equals(io.stderr, 'hi, stderr\n')
General Comments 0
You need to be logged in to leave comments. Login now