##// END OF EJS Templates
BUG: redirector_output_trap was not closing properly the stdout.
gvaroquaux -
Show More
@@ -1,93 +1,93 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """
3 """
4 Trap stdout/stderr, including at the OS level. Calls a callback with
4 Trap stdout/stderr, including at the OS level. Calls a callback with
5 the output each time Python tries to write to the stdout or stderr.
5 the output each time Python tries to write to the stdout or stderr.
6 """
6 """
7
7
8 __docformat__ = "restructuredtext en"
8 __docformat__ = "restructuredtext en"
9
9
10 #-------------------------------------------------------------------------------
10 #-------------------------------------------------------------------------------
11 # Copyright (C) 2008 The IPython Development Team
11 # Copyright (C) 2008 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16
16
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20
20
21 from fd_redirector import FDRedirector, STDOUT, STDERR
21 from fd_redirector import FDRedirector, STDOUT, STDERR
22
22
23 from IPython.kernel.core.file_like import FileLike
23 from IPython.kernel.core.file_like import FileLike
24 from IPython.kernel.core.output_trap import OutputTrap
24 from IPython.kernel.core.output_trap import OutputTrap
25
25
26 class RedirectorOutputTrap(OutputTrap):
26 class RedirectorOutputTrap(OutputTrap):
27 """ Object which can trap text sent to stdout and stderr.
27 """ Object which can trap text sent to stdout and stderr.
28 """
28 """
29
29
30 #------------------------------------------------------------------------
30 #------------------------------------------------------------------------
31 # OutputTrap interface.
31 # OutputTrap interface.
32 #------------------------------------------------------------------------
32 #------------------------------------------------------------------------
33 def __init__(self, out_callback, err_callback):
33 def __init__(self, out_callback, err_callback):
34 # Callback invoked on write to stdout and stderr
34 # Callback invoked on write to stdout and stderr
35 self.out_callback = out_callback
35 self.out_callback = out_callback
36 self.err_callback = err_callback
36 self.err_callback = err_callback
37
37
38 # File descriptor redirectors, to capture non-Python
38 # File descriptor redirectors, to capture non-Python
39 # output.
39 # output.
40 self.out_redirector = FDRedirector(STDOUT)
40 self.out_redirector = FDRedirector(STDOUT)
41 self.err_redirector = FDRedirector(STDERR)
41 self.err_redirector = FDRedirector(STDERR)
42
42
43 # Call the base class with file like objects that will trigger
43 # Call the base class with file like objects that will trigger
44 # our callbacks
44 # our callbacks
45 OutputTrap.__init__(self, out=FileLike(self.on_out_write),
45 OutputTrap.__init__(self, out=FileLike(self.on_out_write),
46 err=FileLike(self.on_err_write), )
46 err=FileLike(self.on_err_write), )
47
47
48
48
49 def set(self):
49 def set(self):
50 """ Set the hooks: set the redirectors and call the base class.
50 """ Set the hooks: set the redirectors and call the base class.
51 """
51 """
52 self.out_redirector.start()
52 self.out_redirector.start()
53 #self.err_redirector.start()
53 self.err_redirector.start()
54 OutputTrap.set(self)
54 OutputTrap.set(self)
55
55
56
56
57 def unset(self):
57 def unset(self):
58 """ Remove the hooks: call the base class and stop the
58 """ Remove the hooks: call the base class and stop the
59 redirectors.
59 redirectors.
60 """
60 """
61 OutputTrap.unset(self)
61 OutputTrap.unset(self)
62 # Flush the redirectors before stopping them
62 # Flush the redirectors before stopping them
63 self.on_out_write('')
64 self.err_redirector.stop()
65 self.on_err_write('')
63 self.on_err_write('')
64 self.err_redirector.stop()
65 self.on_out_write('')
66 self.out_redirector.stop()
66 self.out_redirector.stop()
67
67
68
68
69 #------------------------------------------------------------------------
69 #------------------------------------------------------------------------
70 # Callbacks for synchronous output
70 # Callbacks for synchronous output
71 #------------------------------------------------------------------------
71 #------------------------------------------------------------------------
72 def on_out_write(self, string):
72 def on_out_write(self, string):
73 """ Callback called when there is some Python output on stdout.
73 """ Callback called when there is some Python output on stdout.
74 """
74 """
75 try:
75 try:
76 self.out_callback(self.out_redirector.getvalue() + string)
76 self.out_callback(self.out_redirector.getvalue() + string)
77 except:
77 except:
78 # If tracebacks are happening and we can't see them, it is
78 # If tracebacks are happening and we can't see them, it is
79 # quasy impossible to debug
79 # quasy impossible to debug
80 self.unset()
80 self.unset()
81 raise
81 raise
82
82
83 def on_err_write(self, string):
83 def on_err_write(self, string):
84 """ Callback called when there is some Python output on stderr.
84 """ Callback called when there is some Python output on stderr.
85 """
85 """
86 try:
86 try:
87 self.err_callback(self.err_redirector.getvalue() + string)
87 self.err_callback(self.err_redirector.getvalue() + string)
88 except:
88 except:
89 # If tracebacks are happening and we can't see them, it is
89 # If tracebacks are happening and we can't see them, it is
90 # quasy impossible to debug
90 # quasy impossible to debug
91 self.unset()
91 self.unset()
92 raise
92 raise
93
93
@@ -1,50 +1,81 b''
1 # encoding: utf-8
2
1 """
3 """
2 Test the output capture at the OS level, using file descriptors.
4 Test the output capture at the OS level, using file descriptors.
3 """
5 """
4
6
7 __docformat__ = "restructuredtext en"
8
9 #---------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #---------------------------------------------------------------------------
15
16
5 import os
17 import os
6 from cStringIO import StringIO
18 from cStringIO import StringIO
19 import sys
7
20
8
21
9 def test_redirector():
22 def test_redirector():
10 """ Checks that the redirector can be used to do synchronous capture.
23 """ Checks that the redirector can be used to do synchronous capture.
11 """
24 """
25 # Flush the stdout, so as not to have side effects between
26 # tests.
27 sys.stdout.flush()
28 sys.stderr.flush()
12 from IPython.kernel.core.fd_redirector import FDRedirector
29 from IPython.kernel.core.fd_redirector import FDRedirector
13 r = FDRedirector()
30 r = FDRedirector()
14 out = StringIO()
31 out = StringIO()
15 try:
32 try:
16 r.start()
33 r.start()
17 for i in range(10):
34 for i in range(10):
18 os.system('echo %ic' % i)
35 os.system('echo %ic' % i)
19 print >>out, r.getvalue(),
36 print >>out, r.getvalue(),
20 print >>out, i
37 print >>out, i
21 except:
38 except:
22 r.stop()
39 r.stop()
23 raise
40 raise
24 r.stop()
41 r.stop()
25 assert out.getvalue() == "".join("%ic\n%i\n" %(i, i) for i in range(10))
42 assert out.getvalue() == "".join("%ic\n%i\n" %(i, i) for i in range(10))
43 sys.stdout.flush()
44 sys.stderr.flush()
26
45
27
46
28 def test_redirector_output_trap():
47 def test_redirector_output_trap():
29 """ This test check not only that the redirector_output_trap does
48 """ This test check not only that the redirector_output_trap does
30 trap the output, but also that it does it in a gready way, that
49 trap the output, but also that it does it in a gready way, that
31 is by calling the callabck ASAP.
50 is by calling the callback ASAP.
32 """
51 """
52 # Flush the stdout, so as not to have side effects between
53 # tests.
54 sys.stdout.flush()
55 sys.stderr.flush()
33 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
56 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
34 out = StringIO()
57 out = StringIO()
35 trap = RedirectorOutputTrap(out.write, out.write)
58 trap = RedirectorOutputTrap(out.write, out.write)
36 try:
59 try:
37 trap.set()
60 trap.set()
38 for i in range(10):
61 for i in range(10):
39 os.system('echo %ic' % i)
62 os.system('echo %ic' % i)
40 print "%ip" % i
63 print "%ip" % i
41 print >>out, i
64 print >>out, i
42 except:
65 except:
43 trap.unset()
66 trap.unset()
44 raise
67 raise
45 trap.unset()
68 trap.unset()
69 sys.stdout.flush()
70 sys.stderr.flush()
46 assert out.getvalue() == "".join("%ic\n%ip\n%i\n" %(i, i, i)
71 assert out.getvalue() == "".join("%ic\n%ip\n%i\n" %(i, i, i)
47 for i in range(10))
72 for i in range(10))
48
73
49
74
75
76 if __name__ == '__main__':
77 print "Testing redirector...",
78 test_redirector()
79 test_redirector_output_trap()
80 print "Done."
50
81
General Comments 0
You need to be logged in to leave comments. Login now