I am trying to kill a subprocess that expects a key press 'q' in the terminal in order to stop gracefully.
This executable has two modes of running (tried both):
- takes over the terminal with probably some sort of ncurses (considering it is Windows it is probably something else)
- just runs in the terminal as a regular command and waits for a key press
I have tried spawning the subprocess with subprocess.Popen(command_parts)
where command_parts
is a list with the executable and it's various flags.
I have added the following arguments to the Popen constructor in multiple combinations:
- no special flags
- with
creationflags=subprocess.DETACHED_PROCESS
- with
stdin=PIPE
I have tried sending to the stdin of the executable the following strings:
b"q"
b"q\n"
b"q\r\n"
I have tried communicating with the executable in the following ways:
subprocess_instance.communicate(input_stuff)
subprocess_instance.stdin.write(input_stuff); subprocess_instance.stdin.flush()
None of these attempts results in the executable gracefully shutting down, and just lingers forever as if nothing happened on the stdin.
Observations:
- the q keystroke works if simply running the executable from power shell
- the executable has to close gracefully otherwise it results in some undesired behaviour
- Python versions used: 3.8.*, 3.9.*
UPDATE:
I tried using a sample C program that waits for 'q':
#include <stdio.h>
#include <conio.h>
int main(int argc, char const *argv[]) {
printf("Hello world\n");
printf("Waiting for char ...\n");
while (1) {
unsigned int x = getch();
printf("PRESSED: %c\n", x);
if (x == 'q') {
printf("Quitting ...\r\n");
break;
};
}
printf("\n----\n");
printf("DONE\n\n");
return 0;
}
And then the script I tried to use to run it is:
import time
import subprocess as sp
import pathlib as plib
def main() -> None:
print("\nSTARTING")
print("Create subproces ...");
exe_path = plib.Path('guinea_pig_executable/bla.exe').absolute()
exe_path_str = str(exe_path)
exe = sp.Popen(
[exe_path_str],
stdin=sp.PIPE,
stdout=sp.PIPE,
stderr=sp.PIPE,
)
print("Wait ...")
time.sleep(5)
print("Try quitting ...")
try:
exe.communicate(b'q\r\n', timeout=2)
# exe.stdin.write(b'q')
# exe.stdin.flush()
except Exception as err:
print(repr(err))
print("Wait for sub proc to die ...")
try:
exe.wait(timeout=5)
except sp.TimeoutExpired as terr:
print("Timeout error", repr(terr))
exe.kill() # forcefully killing
print("\nEND\n---\n")
if __name__ == '__main__':
main()
The output I get is:
PS E:\workspace\try-kill-exe> python .\main.py
STARTING
Create subproces ...
Wait ...
Try quitting ...
TimeoutExpired(['E:\\workspace\\try-kill-exe\\guinea_pig_executable\\bla.exe'], 2)
Wait for sub proc to die ...
Timeout error TimeoutExpired(['E:\\workspace\\try-kill-exe\\guinea_pig_executable\\bla.exe'], 5)
END
---
What could be the cause for this? Is this something windows specific? Is it something that Python can't handle properly? What other things could I try?