I have a bit of an issue here. I have a Python script which calls binaries compiled from C++. The Python script has its own set of outputs (to standard out and error), which are easily disable-able. The C++ binaries have their own set of outputs (to standard out and error, among others) as well; the source can be altered, but I am not the original author. This is an issue because I do not want the C++ output in my final program, and I also don't want future users to need to edit the C++ source.
What I'd like to be able to do is have some Python method which will catch the C++ code's output that is sent to standard out or error. Is this possible? If so, could someone point me in the right direction?
Thank you!!
-
This depends on the way you're calling the binaries. For example if you're using os.system you can pipe the output, but otherwise there are probably some methods to look into. How is the calling written in your script?bcc32– bcc322011年12月13日 21:58:55 +00:00Commented Dec 13, 2011 at 21:58
-
Sorry, I should have posted this in the message body: they are imported through a Python interface, so that Python thinks it's calling other Python modules.learner– learner2011年12月13日 22:05:33 +00:00Commented Dec 13, 2011 at 22:05
2 Answers 2
One way to do this is:
- Duplicate in python the file descriptors for
stdoutandstderrusingos.dup. - Redirect the original
stdoutandstderrusingreopen(from C'sstdio) to write to a file of your choice.
Note: reopen isn't available directly from python, but you should be able to call it as in the example below or using any other wrapper available.
After this is done:
- Every write to
coutandcerrin C++ will write to the output files. - Every
printstatement in python will write to the output files.
However, since the original descriptors are duplicated, you can still (see example below):
- Print to the original
stdout/stderrusingsdout.writeandstdout.err - Use
loggingmethods after configuring properly thestreamparameter
The following code uses instant library to test real C++ code that is wrapped into python using SWIG and that should be similar to the library that you have:
import sys, os
import logging
from instant import inline
print 'This is printed from python to stdout'
stdout = os.fdopen(os.dup(sys.stdout.fileno()), 'w')
stderr = os.fdopen(os.dup(sys.stderr.fileno()), 'w')
logging.basicConfig(stream=stderr, level=logging.DEBUG)
redirect = inline("""
void redirect(void) {
freopen("my_stdout.txt", "w", stdout);
freopen("my_stderr.txt", "w", stderr);
}
""")
redirect()
cout = inline("""
void cout(void) {
std::cout << "This is written from C++ to my_stdout.txt" << std::endl;
std::cerr << "This is written from C++ to my_stderr.txt" << std::endl;
}
""")
cout()
print 'This is written from python to my_stdout.txt'
stdout.write('This is printed from python to stdout\n')
stderr.write('This is printed from python to stderr\n')
logging.info('This is printed to stderr from python using logging')
The output for this example is:
$ python test.py
This is printed from python to stdout
This is printed from python to stdout
This is printed from python to stderr
INFO:root:This is printed to stderr from python using logging
$ cat my_stdout.txt
This is written from C++ to my_stdout.txt
This is written from python to my_stdout.txt
$ cat my_stderr.txt
This is written from C++ to my_stderr.txt
Note: First time the code is executed, you might get gcc compilation messages (I've removed them to make the example clearer).
5 Comments
StringIO objects contain all the output that would have been printed to sys.stdout and sys.stderr (because they have been patched). The real sys.stderr is known by logging so all logging statements print to the real sys.stderr. I assume the wrapper to your C++ library doesn't use logging. If that's a problem, you remove the logging part and print with _stdout.write and _stderr.write directly._stdout = sys.stdout) I see no change in output.sys.stdout and sys.stderr. I've rewritten my answer using reopen and testing with real C++ code and now it works fine.Are you using subprocess to compile the C++? If so, you can set where stderr and stdout go:
nowhere = StringIO()
subprocess.call("exit 1", shell=True, stdout=nowhere, stderr=nowhere)