views:

220

answers:

1

Hi, I'm using the subprocess module on python 2.5 to spawn a java program (the selenium server, to be precise) as follows:

import os
import subprocess

display = 0
log_file_path = "/tmp/selenium_log.txt"
selenium_port = 4455
selenium_folder_path = "/wherever/selenium/lies"

env = os.environ
env["DISPLAY"] = ":%d.0" % display
command = ["java", 
           "-server",
           "-jar", 
           'selenium-server.jar',
           "-port %d" % selenium_port]
log = open(log_file_path, 'a')
comm = ' '.join(command)
selenium_server_process = subprocess.Popen(comm,
                                           cwd=selenium_folder_path,
                                           stdout=log,
                                           stderr=log,
                                           env=env,
                                           shell=True)

This process is supposed to get killed once the automated tests are finished. I'm using os.kill to do this:

os.killpg(selenium_server_process.pid, signal.SIGTERM)
selenium_server_process.wait()

This does not work. The reason is that the shell subprocess spawns another process for java, and the pid of that process is unknown to my python code. I've tried killing the process group with os.killpg, but that kills also the python process which runs this code in the first place. Setting shell to false, thus avoiding java to run inside a shell environment, is also out of the question, due to other reasons.

Does anyone have an idea how I can kill the shell and any other processes generated by it?

Cheers, Ulas

+1  A: 

The obvious solution in this case is to not involve the shell:

import os
import subprocess

display = 0
log_file_path = "/tmp/selenium_log.txt"
selenium_port = 4455
selenium_folder_path = "/wherever/selenium/lies"

env = os.environ
env["DISPLAY"] = ":%d.0" % display
command = ["java", 
           "-server",
           "-jar", 
           'selenium-server.jar',
           "-port",
           str(selenium_port)]
log = open(log_file_path, 'a')
selenium_server_process = subprocess.Popen(command,
                                           cwd=selenium_folder_path,
                                           stdout=log,
                                           stderr=subprocess.STDOUT,
                                           env=env)

This will make the process be the Java process directly. Keep in mind that it may still spawn processes that are not part of the process group, so os.killpg may still not know about killing them.

If you have a reason to invoke the shell (the above code does not, and there are few things you cannot do without the shell, but suppose you do), you would have to make the shell pass you the pid of the process it started somehow. Doing this is not straightforward, and rather situational.

Thomas Wouters
Or, if you do involve the shell for any reason (let's say you want expansion/substitution/whatever), use "exec" at the beginning to avoid the shell forking. (Specifically, just adding "exec" at the beginning of "command" definition would have fixed your problem.)
moshez
@moshez, awesome! that did it. thanks a lot.
afroulas
Do you actually have a *reason* for involving the shell, though? There very rarely is.
Thomas Wouters