I answered my question while I was typing it out, but I’ll post it anyway in case it helps someone else. Turns out I was trying to close my file handles too soon after killing the process. Adding time.sleep(1.0) before closing them makes everything work as intended and the files are cleaned up.
Hey guys,
I’m stuck on Python 2.5 for a certain tool and using tempfile.mkstemp() to generate some files used by a subprocess in a separate thread from my main GUI. This subprocess can be killed at any time by the user (the process is a call to the P4 command-line client; P4Python blocks my PyQt GUI). Two part question:
- What is the “proper” way to end a subprocess on Python 2.5? Since Popen.send_signal(), Popen.terminate(), and Popen.kill() are not available I’m doing this:
p = subprocess.Popen(blah, blah, blah)
while True:
if p.poll() is not None or ui_thread == None:
if ui_thread.timeToCancel:
if sys.platform == 'win32':
import ctypes
PROCESS_TERMINATE = 1
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, p.pid)
ctypes.windll.kernel32.TerminateProcess(handle, -1)
ctypes.windll.kernel32.CloseHandle(handle)
# Get out of the loop
break
- If the proper way is some variation of what I’m doing, how do I clean up my temporary files? Currently I think the killed pid is still holding on to them and they cannot be removed using os.close() or os.remove()
If you just want to kill the process, with predjudice and no chance to formally shut itself down, then the code you have there looks correct. At least, that’s the same method we use in our process_kill function.
It’s the equivalent of killing the process in Task Manager, etc. You run the risk of files it’s writing being truncated and whatnot, but sometimes that’s fine.
I believe the other methods you listed simply signal the app/process to close itself. The process is free to ignore the request and keep on rolling.
Hey Adam!
I noticed the post on your blog about P4Python and thought I might ask you about a problem I’m having. Basically, I love P4Python for everything… except that no matter what I do it seems to block the main GUI thread in my PyQt application when doing anything lengthy (like a long sync command). I thought I was improving the tool by switching to P4Python instead of using subprocess to call P4 for each sync, but the latter was the only way the PyQt GUI would behave, even though I’m using a separate QThread to do the sync (which works fine with everything else I’m doing).
Maybe I’m just doing it wrong, though.
Ultimately I feel like I had to jump through some crazy hoops to get real-time output of what P4 is doing in my application. I resorted to piping stdout and stderr to temp files and reading them while the process is running. This seems to work well but I couldn’t get anything similar working with P4Python.
Can P4Python be used in a non-blocking way for large or lengthy processes?
P.S. The reason I’m asking this here is because the process I am killing is my call to p4 sync via the subprocess module, and then I read your blog, and then one thing lead to another culminating in a total hijacking of my own original thread topic.
Right, it’s normal that P4Python blocks until an operation is completely finished.
However, there is a new feature in their APIs starting with 2011.1 that allows you to get output in the middle of operations. You can register an “output handler” callback that fires after every file in an operation, allowing you to do things like update a progress bar or show the name of each file, etc. You can also handle errors as they happen.
I actually have a follow-up blog post half-written about this exact thing, with some working code examples. Until I finish posting that, here’s some raw info on it:
http://www.perforce.com/newsletters/2012/february/scripting-apis-error-handling