The Problem
I've been trying to write a program that logs uncaught exceptions and syntax errors for a subprocess. Easy, right? Just pipe stderr
to the right place.
However, the subprocess is another python program- I'll call it test.py
- that needs to run as if its output/errors are not being captured. That is, running the logger program needs to seem like the user has just run python test.py
as normal.
Further complicating the issue is the problem that raw_input
actually gets sent to stderr
if readline
is not used. Unfortunately, I can't just import readline
, since I don't have control over the files that are being run using my error logger.
Notes:
- I am fairly restricted on the machines that this code will run on. I can't install
pexpect
or edit the*customize.py
files (since the program will be run by a lot of different users). I really feel like there should be a stdlib solution anyway though... - This only has to work on macs.
- The motivation for this is that I'm part of a team researching the errors that new programmers get.
What I've Tried
I've tried the following methods, without success:
- just using
tee
as in the question How do I write stderr to a file while using "tee" with a pipe? (failed to produceraw_input
prompts); python implementations oftee
that I found in several SO questions had similar issues - overwriting
sys.excepthook
(failed to make it work for a subprocess) - this question's top answer seemed promising, but it failed to display
raw_input
prompts correctly. - the logging module seems useful for actually writing to a log file, but doesn't seem to get at the crux of the issue
- custom stderr readers
- endless googling
Based on @nneonneo 's advice in the question comments, I made this program that seems to get the job done. (Note that currently, the name of the logger file has to by "pylog" for the errors to be printed correctly to the end user.)
The tee-based answer that you've linked is not very suitable for your task. Though you could fix "
raw_input()
prompts" issue by using-u
option to disable buffering:A more suitable solution might be based on
pexpect
orpty
, example.You don't need to install
pexpect
it is pure Python you could put it along-side your code.Here's a tee-based analog (
test.py
is run non-interactively):It is necessary to merge stdout/stderr due to it is unclear where
raw_input()
,getpass.getpass()
might print their prompts.In this case the threads are not necessary too:
Note: the last example and tee-based solution don't capture
getpass.getpass()
prompt, butpexpect
andpty
-based solution do:I don't know whether
pty.spawn()
works on macs.