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 |
|
|
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 call |
|
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