I am working in Python 3.4, and I have behavior that I don't understand: if I redirect stdout to a file, I am able to capture text from child processes. However, when I redirect to a Python file object, I stop capturing that output. I would love an explanation of the (following) behavior.
I have:
from multiprocessing import Process
def worker():
print('forked output')
def output():
print('redirected')
p = Process(target=worker)
p.daemon = True
p.start()
p.join() # wait for subprocess to terminate
print('end')
The redirect_stdout
context manager in Python 3.4 makes grabbing stdout easy (in this instance).
from contextlib import redirect_stdout
from sys import stdout
from tempfile import TemporaryFile
with TemporaryFile(mode='w+', encoding=stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined above
buf.seek(0)
s = buf.read()
print('output from TemporaryFile:')
print(s)
I can then simply call the script to get the following output:
$ python stackoverflow.py
output from TemporaryFile:
redirected
forked output
end
This is exactly what I want, and works fine.
My confusion stems from the fact that if I if I switch TemporaryFile
with TextIOWrapper
, the behavior of my script changes.
from io import BytesIO, TextIOWrapper
with TextIOWrapper(BytesIO(), stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined at the start
buf.seek(0)
s = buf.read()
print('output from TextIO:')
print(s)
Now when I call the program, I lose the output from the forked process.
$ python stackoverflow.py
output from TextIO:
redirected
end
What is going on?
I suspect the problem has to do with the fact that the TextIOWrapper
object doesn't have a file descriptor, and that os.fork()
(used by multiprocessing
) may thus be replacing the TextIOWrapper
with another, but I admit some confusion there (especially given that stdout appears to be a TextIOWrapper
with fileno()
implemented).
>>> from sys import stdout
>>> stdout.fileno()
1
>>> stdout
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
Thanks for any information.
Redirecting stdout and stderr to a file: The I/O streams can be redirected by putting the n> operator in use, where n is the file descriptor number. For redirecting stdout, we use “1>” and for stderr, “2>” is added as an operator.
If you want to redirect both “stdout” and “stderr”, then use “&>” . Now we will use this redirection symbol to redirect the output into the file.
Since you're using multiprocessing, you should use the standard message passing primitives provided by that library. Do not call print()
from the subprocess; that's poor design.
If you're actually trying to make this work with someone else's (non-Python) code, use subprocess.check_output()
or another of the subprocess functions instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With