geometrian
geometrian

Reputation: 15387

Expose Python standard IO to Subprocess

On Python 3.5.1, I have the following:

output = subprocess.check_output(cmd).decode(encoding="UTF-8")

This calls the properly invoked command cmd. C++14 code in cmd looks like:

HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
assert(handle!=INVALID_HANDLE_VALUE); //Always passes
assert(handle!=nullptr);              //Always passes

CONSOLE_SCREEN_BUFFER_INFO csbi;
BOOL result = GetConsoleScreenBufferInfo(handle,&csbi);
assert(result!=0); //Always fails.  `GetLastError()` returns 6 (invalid handle) 

Running the above Python code causes the subprocess cmd to fail at the indicated line. According to the Python docs, in this case, the stdout/stderr should be inherited from the parent process (i.e., the Python interpreter). So, it shouldn't. In fact, the above works just fine for e.g. printfed output.

Attempting to redirect explicitly also fails:

#Traceback (most recent call last):
#  File "C:\dev\Python35\lib\subprocess.py", line 914, in __init__
#    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
#  File "C:\dev\Python35\lib\subprocess.py", line 1145, in _get_handles
#    c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
#io.UnsupportedOperation: fileno
p = subprocess.Popen(cmd.split(" "),stdout=sys.stdout,stderr=sys.stderr)

#Using `subprocess.PIPE` instead fails in the same way as the `subprocess.check_output(...)`
#example originally given above.

What's going wrong? How do I fix it?

Upvotes: 1

Views: 512

Answers (1)

jfs
jfs

Reputation: 414795

A pipe is not a console. check_output() uses stdout=PIPE internally. It won't redirect the console output (produced by WriteConsoleW()).

The first error (invalid handle) suggests that the standard output is not the console device.

Unless it is a desired behavior (to print outside of the standard output); use WriteFile() if stdout is not a console device.

The second error (io.UnsupportedOperation: fileno) suggests that sys.stdout is not a real file and therefore you can't pass it as stdout parameter to a subprocess (you could redirect subprocess' stdout using stdout=PIPE and print the output using print() or sys.stdout.write() method directly).

Upvotes: 2

Related Questions