The issue is most likely that many programs work differently if run interactively in a terminal or as part of a pipe line (i.e. called using subprocess
). It has very little to do with Python itself, but more with the Unix/Linux architecture.
As you have noted, it is possible to force a program to flush stdout
even when run in a pipe line, but it requires changes to the source code, by manually applying stdout.flush
calls.
Another way to print to screen, is to "trick" the program to think it is working with an interactive terminal, using a so called pseudo-terminal. There is a supporting module for this in the Python standard library, namely pty
. Using, that, you will not explicitly call subprocess.run
(or Popen
or ...). Instead you have to use the pty.spawn call:
def prout(fd):
data = os.read(fd, 1024)
while(data):
print(data.decode(), end="")
data = os.read(fd, 1024)
pty.spawn("./callee.py", prout)
As can be seen, this requires a special function for handling stdout
. Here above, I just print it to the terminal, but of course it is possible to do other thing with the text as well (such as log or parse...)
Another way to trick the program, is to use an external program, called unbuffer
. Unbuffer will take your script as input, and make the program think (as for the pty
call) that is called from a terminal. This is arguably simpler if unbuffer
is installed or you are allowed to install it on your system (it is part of the expect
package). All you have to do then, is to change your subprocess
call as
p=subprocess.Popen(["unbuffer", "./callee.py"], stdout=subprocess.PIPE)
and then of course handle the output as usual, e.g. with some code like
for line in p.stdout:
print(line.decode(), end="")
print(p.communicate()[0].decode(), end="")
or similar. But this last part I think you have already covered, as you seem to be doing something with the output.