Show More
@@ -0,0 +1,67 b'' | |||
|
1 | # encoding: utf-8 | |
|
2 | ||
|
3 | """ | |
|
4 | Stdout/stderr redirector, at the OS level, using file descriptors. | |
|
5 | """ | |
|
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 | ||
|
17 | import os | |
|
18 | import sys | |
|
19 | ||
|
20 | STDOUT = 1 | |
|
21 | STDERR = 2 | |
|
22 | ||
|
23 | class FDRedirector(object): | |
|
24 | """ Class to redirect output (stdout or stderr) at the OS level using | |
|
25 | file descriptors. | |
|
26 | """ | |
|
27 | ||
|
28 | def __init__(self, fd=STDOUT): | |
|
29 | """ fd is the file descriptor of the outpout you want to capture. | |
|
30 | It can be STDOUT or STERR. | |
|
31 | """ | |
|
32 | self.fd = fd | |
|
33 | self.started = False | |
|
34 | ||
|
35 | def start(self): | |
|
36 | if not self.started: | |
|
37 | self.oldhandle = os.dup(self.fd) | |
|
38 | self.piper, self.pipew = os.pipe() | |
|
39 | os.dup2(self.pipew, self.fd) | |
|
40 | os.close(self.pipew) | |
|
41 | ||
|
42 | self.started = True | |
|
43 | ||
|
44 | def flush(self): | |
|
45 | if self.fd == STDOUT: | |
|
46 | sys.stdout.flush() | |
|
47 | elif self.fd == STDERR: | |
|
48 | sys.stderr.flush() | |
|
49 | ||
|
50 | def stop(self): | |
|
51 | if self.started: | |
|
52 | self.flush() | |
|
53 | os.dup2(self.oldhandle, self.fd) | |
|
54 | os.close(self.oldhandle) | |
|
55 | f = os.fdopen(self.piper, 'r') | |
|
56 | output = f.read() | |
|
57 | f.close() | |
|
58 | ||
|
59 | self.started = False | |
|
60 | return output | |
|
61 | else: | |
|
62 | return '' | |
|
63 | ||
|
64 | def getvalue(self): | |
|
65 | output = self.stop() | |
|
66 | self.start() | |
|
67 | return output |
@@ -0,0 +1,79 b'' | |||
|
1 | # encoding: utf-8 | |
|
2 | ||
|
3 | """ | |
|
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. | |
|
6 | """ | |
|
7 | ||
|
8 | __docformat__ = "restructuredtext en" | |
|
9 | ||
|
10 | #------------------------------------------------------------------------------- | |
|
11 | # Copyright (C) 2008 The IPython Development Team | |
|
12 | # | |
|
13 | # Distributed under the terms of the BSD License. The full license is in | |
|
14 | # the file COPYING, distributed as part of this software. | |
|
15 | #------------------------------------------------------------------------------- | |
|
16 | ||
|
17 | #------------------------------------------------------------------------------- | |
|
18 | # Imports | |
|
19 | #------------------------------------------------------------------------------- | |
|
20 | ||
|
21 | from fd_redirector import FDRedirector, STDOUT, STDERR | |
|
22 | ||
|
23 | from IPython.kernel.core.file_like import FileLike | |
|
24 | from IPython.kernel.core.output_trap import OutputTrap | |
|
25 | ||
|
26 | class RedirectorOutputTrap(OutputTrap): | |
|
27 | """ Object which can trap text sent to stdout and stderr. | |
|
28 | """ | |
|
29 | ||
|
30 | #------------------------------------------------------------------------ | |
|
31 | # OutputTrap interface. | |
|
32 | #------------------------------------------------------------------------ | |
|
33 | def __init__(self, out_callback, err_callback): | |
|
34 | # Callback invoked on write to stdout and stderr | |
|
35 | self.out_callback = out_callback | |
|
36 | self.err_callback = err_callback | |
|
37 | ||
|
38 | # File descriptor redirectors, to capture non-Python | |
|
39 | # output. | |
|
40 | self.out_redirector = FDRedirector(STDOUT) | |
|
41 | self.err_redirector = FDRedirector(STDERR) | |
|
42 | ||
|
43 | # Call the base class with file like objects that will trigger | |
|
44 | # our callbacks | |
|
45 | OutputTrap.__init__(self, out=FileLike(self.on_out_write), | |
|
46 | err=FileLike(self.on_err_write), ) | |
|
47 | ||
|
48 | ||
|
49 | def set(self): | |
|
50 | """ Set the hooks: set the redirectors and call the base class. | |
|
51 | """ | |
|
52 | self.out_redirector.start() | |
|
53 | #self.err_redirector.start() | |
|
54 | OutputTrap.set(self) | |
|
55 | ||
|
56 | ||
|
57 | def unset(self): | |
|
58 | """ Remove the hooks: call the base class and stop the | |
|
59 | redirectors. | |
|
60 | """ | |
|
61 | OutputTrap.unset(self) | |
|
62 | self.err_redirector.stop() | |
|
63 | self.out_redirector.stop() | |
|
64 | ||
|
65 | ||
|
66 | #------------------------------------------------------------------------ | |
|
67 | # Callbacks for synchronous output | |
|
68 | #------------------------------------------------------------------------ | |
|
69 | def on_out_write(self, string): | |
|
70 | """ Callback called when there is some Python output on stdout. | |
|
71 | """ | |
|
72 | self.out_callback(self.out_redirector.getvalue() + string) | |
|
73 | ||
|
74 | def on_err_write(self, string): | |
|
75 | """ Callback called when there is some Python output on stderr. | |
|
76 | """ | |
|
77 | self.err_callback(self.err_redirector.getvalue() + string) | |
|
78 | ||
|
79 |
@@ -0,0 +1,50 b'' | |||
|
1 | """ | |
|
2 | Test the output capture at the OS level, using file descriptors. | |
|
3 | """ | |
|
4 | ||
|
5 | import os | |
|
6 | from cStringIO import StringIO | |
|
7 | ||
|
8 | ||
|
9 | def test_redirector(): | |
|
10 | """ Checks that the redirector can be used to do synchronous capture. | |
|
11 | """ | |
|
12 | from IPython.kernel.core.fd_redirector import FDRedirector | |
|
13 | r = FDRedirector() | |
|
14 | out = StringIO() | |
|
15 | try: | |
|
16 | r.start() | |
|
17 | for i in range(10): | |
|
18 | os.system('echo %ic' % i) | |
|
19 | print >>out, r.getvalue(), | |
|
20 | print >>out, i | |
|
21 | except: | |
|
22 | r.stop() | |
|
23 | raise | |
|
24 | r.stop() | |
|
25 | assert out.getvalue() == "".join("%ic\n%i\n" %(i, i) for i in range(10)) | |
|
26 | ||
|
27 | ||
|
28 | def test_redirector_output_trap(): | |
|
29 | """ 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 | |
|
31 | is by calling the callabck ASAP. | |
|
32 | """ | |
|
33 | from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap | |
|
34 | out = StringIO() | |
|
35 | trap = RedirectorOutputTrap(out.write, out.write) | |
|
36 | try: | |
|
37 | trap.set() | |
|
38 | for i in range(10): | |
|
39 | os.system('echo %ic' % i) | |
|
40 | print "%ip" % i | |
|
41 | print >>out, i | |
|
42 | except: | |
|
43 | trap.unset() | |
|
44 | raise | |
|
45 | trap.unset() | |
|
46 | assert out.getvalue() == "".join("%ic\n%ip\n%i\n" %(i, i, i) | |
|
47 | for i in range(10)) | |
|
48 | ||
|
49 | ||
|
50 |
General Comments 0
You need to be logged in to leave comments.
Login now