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):
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:
creationflags=subprocess.DETACHED_PROCESS
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:
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?
There are multiple ways in which a python script can communicate with a subprocess when it comes to keypresses.
user32.dll
(credits to @john-hen -> inspired from https://stackoverflow.com/a/8117562/858565 )
Package: https://pypi.org/project/pywin32/
import win32console
def make_keydown_input(c) -> None:
input_record = win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
input_record.KeyDown = 1
input_record.RepeatCount = 1
input_record.Char = c
return input_record
console_handler = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
q_keydown = make_keydown_input('q')
console_handler.WriteConsoleInput([q_keydown])
Package: https://pypi.org/project/pynput/
import pynput
keyb_controller = pynput.keyboard.Controller()
keyb_controller.press('q')
Package: https://pypi.org/project/PyAutoGUI/
Examples: https://pyautogui.readthedocs.io/en/latest/keyboard.html
This is probably the simplest method.
import pyautogui
pyautogui.press('q')
user32.dll
Please refer to this answer: https://stackoverflow.com/a/13615802/858565
In the end you just have to call:
PressKey(0x51)
where 0x51
is the hex keycode for q
according to ( https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes )
Notice that all of these methods will apply the keypress in the context of the program that calls it. I have not tried it with multiprocessing.Process, perhaps it will react differently.
Probably to have a good isolated context one would have to run a specific subprocess in an isolated python script that simply receives messages from outside like via a socket.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.