0

I'm working on a tool for data entry at my job where it basically takes a report ID number, opens a PDF to that page of that report, allows you to input the information and then saves it.

I'm completely new to instantiating new processes in python; this is the first time that I've really tried to do it. so basically, I have a relevant function:

def get_report(id):
    path = report_path(id)
    if not path:
        raise NameError
    page = get_page(path, id)
    proc = subprocess.Popen(["C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe", "/A", "page={}".format(page),
                             path])

in order to open the report in Adobe Acrobat and be able to input information while the report is still open, I determined that I had to use multiprocessing. So, as a result, in the main loop of the program, where it iterates through data and gets the report ID, I have this:

for row in rows:
    print 'Opening report for {}'.format(ID)
    arg = ID
    proc = Process(target=get_report, args=(arg,))
    proc.start()

    row[1] = raw_input('Enter the desired value: ')
    rows.updateRow(row)

    while proc.is_alive():
        pass

This way, one can enter data without the program hanging on the subprocess.Popen() command. However, if it simply continues on to the next record without closing the Acrobat window that pops up, then it won't actually open the next report. Hence the while proc.is_alive():, as it gives one a chance to close the window manually. I'd like to kill the process immediately after 'enter' is hit and the value entered, so it will go on and just open the next report with even less work. I tried several different things, ways to kill processes through the pid using os.kill(); I tried killing the subprocess, killing the process itself, killing both of them, and also tried using subprocess.call() instead of Popen() to see if it made a difference.

It didn't.

What am I missing here? How do I kill the process and close the window that it opened in? Is this even possible? Like I said, I have just about 0 experience with processes in python. If I'm doing something horribly wrong, please let me know!

Thanks in advance.

carusot42
  • 1,171
  • 10
  • 17

1 Answers1

3

To kill/terminate a subprocess, call proc.kill()/proc.terminate(). It may leave grandchildren processes running, see subprocess: deleting child processes in Windows

This way, one can enter data without the program hanging on the subprocess.Popen() command.

  1. Popen() starts the command. It does not wait for the command to finish. There are .wait() method and convenience functions such as call()
  2. Even if Popen(command).wait() returns i.e., if the corresponding external process has exited; it does not necessarily mean that the document is closed in the general case (the launcher app is done but the main application may persist).

i.e., the first step is to drop unnecessary multiprocessing.Process and call Popen() in the main process instead.

The second step is to make sure to start an executable that owns the opened document i.e., if it is killed the corresponding document won't stay opened: AcroRd32.exe might be already such program (test it: see whether call([r'..\AcroRd32.exe', ..]) waits for the document to be closed) or it might have a command-line switch that enables such behavior. See How do I launch a file in its default program, and then close it when the script finishes?


I tried killing the subprocess, killing the process itself, killing both of them, and also tried using subprocess.call() instead of Popen() to see if it made a difference.
It didn't.

If kill() and Popen() behave the same in your case then either you've made a mistake (they don't behave the same: you should create a minimal standalone code example with a dummy pdf that demonstrates the problem. Describe using words: what do you expect to happen (step by step) and what happens instead) or AcroRd32.exe is just a launcher app that I've described above (it just opens the document and immediately exits without waiting for the document to be closed).

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 2
    Thank you for the in-depth response. You're right, something in my code before was hanging it up. I removed the part with `multiprocessing` and and just using `Popen`; I saved its `PID` as a global variable in the function that calls it and am using `subprocess` to call `TASKKILL` on that process. It now works exactly as I had hoped. Thanks! – carusot42 Sep 25 '15 at 18:13
  • @carusot42, are you running `taskkill /t` to also kill child processes (at least findable child processes; Windows doesn't maintain a process tree, so orphaned processes occur frequently)? Otherwise why wouldn't `proc.kill()` work? On Windows, it's generally a bad idea to store the PID to kill a process. Process IDs are really just the process handle from the system handle table, so PIDs get reused. `Popen.kill` is safe because it uses the process handle. If you need `taskkill /t`, then first check that it's still alive, i.e. `proc.poll() is None`. – Eryk Sun Sep 25 '15 at 21:35