Python – Kill the Popen child process

popenpythonwindows

This is my first post to the community, but I've been learning what I can by searching for about 2 weeks now. I seem to have hit a dead end that I can't seem to find the answer by trial and error or reading through others posts.

All I'm trying to do at this point is kill the process that is created by Popen and the shell itself. I must add that I am new to programming, and this is my first "real" world side task.

The solutions I've seen say to create a group ID, but that is for Unix and I am on windows. Popen.kill() and Popen.terminate() do not kill the children of the shell. The program started by this code does not quit, it's PID is different then the PID of the shell. I am open to suggestions as I'm using this as both a learning tool and something that will be productive. Some of the other solutions just don't kill the process. I am able to kill it by DOS and the Python Interpreter, however I have to manually look up the PID from the TASKLIST and then type it in. I need to kill it from this program.

I'm building this code to save multiple documents of a MathCad template that reads in values of excel documents, and spits out a saved document with the new file name. Thanks in advance. Please forgive any newbie coding things you may see as I'm just trying to get my feet wet.

Additional tasks tried and updates (2/26/2014):

Tried killing the programs using subprocess.call('TASKKILL …) instead of subprocess.Popen. It does not kill the child created by the shell. Tried replacing proc = subprocess.Popen(' ….' shell=True ) with subprocess.call('….', shell=True) and the SendKeys functions no longer work. Tried the psutil function with the kill_proc_tree function and an "EOFError: [WinError 10054] An existing connection was forcibly closed by the remote host" pop up window. The child program still does not close.

If I remove the kill/terminate/close commands and just let the program run, the proc.pid is different than the os.getpid(). If I use the psutil.Process(proc.pid) – it says the process does not exist when the Python Interpreter will return its PID. If I get the MathCadPrime.exe PID = e.g. 1111 from TASKLIST and use psutil.Process(1111).parent, it shows no parents. This may be the reason why doing a TASKKILL on the shell doesn't close the children? I have posted my code exactly as I have it written to see if you gurus see something I don't.

#def kill_proc_tree(pid, including_parent=True):
#    parent = psutil.Process(pid)
#    for child in parent.get_children(recursive=True):
#        child.kill()
#    if including_parent:
#        parent.kill()

import subprocess
import win32api
import win32com.client
import time
import os
import signal
import psutil

# User files
file = "C:\Directory\SubDirectory\file.mcdx"


# Command line function
# /B /D - No command line window or explorer window    
proc = subprocess.Popen('start /B /D                                            \
        "C:\Program Files\PTC\Mathcad\Mathcad Prime 2.0\" "MathcadPrime.exe"    \
        "C:\Directory\SubDirectory\file.mcdx"', shell=True)

# Set and test for active window
    focus = False
    while (focus == False):
            focus = shell.AppActivate("MathCad Prime 2.0 - " + file)
            time.sleep(1)
            if (focus == True):
                break

# Send MathCad Prime commands
shell.SendKeys('%', 0)
time.sleep(0.5)
shell.SendKeys('c', 0)
time.sleep(0.1)
shell.SendKeys('c', 0)
time.sleep(2.0)
shell.SendKeys('%', 0)
time.sleep(0.5)
shell.SendKeys('f', 0)
time.sleep(0.1)
shell.SendKeys('s', 0)
time.sleep(4.0)



#Other methods to tried to kill children:

#Method 1:
#subprocess.call("TASKKILL /F /T /PID {pid}".format(pid=proc.pid))

#Method 2:
#subprocess.Popen("TASKKILL /F /T /PID {pid}".format(pid=proc.pid))

#Method 3:
#if (int(proc.pid) > 0):
#    os.kill(proc.pid, signal.SIGTERM)

#Method 4 (used with kill_proc_tree):
#proc1 = os.getpid()
#kill_proc_tree(proc1)

Best Answer

Thanks for all the help guys, you helped me come to a conclusion. Slightly different than suggested, but gets the job done every time. I'm at home, and not at work (so I'm writing this off the top of my head), but essentially all I did was write the TASKLIST to a text file and filter out just one string of code:

os.chdir('C:\Code')
subprocess.call('TASKLIST /fi "IMAGENAME eq MathcadPrime.exe" /nh /fo csv > task.txt)

Then parse out the PID:

doc = open('task.txt', 'rt')
parse = doc.read()
listing = parse.split(",")
PID = listing[1]
PID = int(PID.replace('"','').replace("'",""))
os.kill(PID, signal.SIGTERM)

I hope this may help someone else.