This has probably been asked but I cannot find anything regarding a subprocess.call timeout when using python 2.7
5 Answers
A simple way I've always done timeouts with 2.7 is utilizing subprocess.poll() alongside time.sleep() with a delay. Here's a very basic example:
import subprocess import time x = #some amount of seconds delay = 1.0 timeout = int(x / delay) args = #a string or array of arguments task = subprocess.Popen(args) #while the process is still executing and we haven't timed-out yet while task.poll() is None and timeout > 0: #do other things too if necessary e.g. print, check resources, etc. time.sleep(delay) timeout -= delay If you set x = 600, then your timeout would amount to 10 minutes. While task.poll() will query whether or not the process has terminated. time.sleep(delay) will sleep for 1 second in this case, and then decrement the timeout by 1 second. You can play around with that part to your heart's content, but the basic concept is the same throughout.
Hope this helps!
subprocess.poll() https://docs.python.org/2/library/subprocess.html#popen-objects
3 Comments
task.terminate() does virtually the same.You could install subprocess32 module mentioned by @gps -- the backport of the subprocess module from Python 3.2/3.3 for use on 2.x. It works on Python 2.7 and it includes timeout support from Python 3.3.
subprocess.call() is just Popen().wait() and therefore to interrupt a long running process in timeout seconds:
#!/usr/bin/env python import time from subprocess import Popen p = Popen(*call_args) time.sleep(timeout) try: p.kill() except OSError: pass # ignore p.wait() If the child process may end sooner then a portable solution is to use Timer() as suggested in @sussudio's answer:
#!/usr/bin/env python from subprocess import Popen from threading import Timer def kill(p): try: p.kill() except OSError: pass # ignore p = Popen(*call_args) t = Timer(timeout, kill, [p]) t.start() p.wait() t.cancel() On Unix, you could use SIGALRM as suggested in @Alex Martelli's answer:
#!/usr/bin/env python import signal from subprocess import Popen class Alarm(Exception): pass def alarm_handler(signum, frame): raise Alarm signal.signal(signal.SIGALRM, alarm_handler) p = Popen(*call_args) signal.alarm(timeout) # raise Alarm in 5 minutes try: p.wait() signal.alarm(0) # reset the alarm except Alarm: p.kill() p.wait() To avoid using threads and signals here, subprocess module on Python 3 uses a busy loop with waitpid(WNOHANG) calls on Unix and winapi.WaitForSingleObject() on Windows.
Comments
You can try to use "easyprocess":
https://github.com/ponty/EasyProcess
It has many features that you need like "timeout".
Comments
You can use subprocess32 mentioned by @gps, which is backport of the subprocess standard library module from Python 3.2 - 3.5 for use on Python 2.
Firstly, install the subprocess32 module:
pip install subprocess32 Here's a code snippet:
>>> import subprocess32 >>> print subprocess32.check_output(["python", "--version"]) Python 2.7.12 >>> subprocess32.check_output(["sleep", "infinity"], timeout=3) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/subprocess32.py", line 340, in check_output raise TimeoutExpired(process.args, timeout, output=output) subprocess32.TimeoutExpired: Command '['sleep', 'infinity']' timed out after 3 seconds Notice, default timeout=None, which means never timeout.
Comments
In python 3.3 timeout argument was added.
https://docs.python.org/3/library/subprocess.html#subprocess.call