Archive
Terminate a script after X seconds
Problem
In Qt, there is a class called QTimer. With QTimer you can, for instance, terminate your application in X seconds. Example:
#!/usr/bin/env python
import sys
from PySide.QtCore import *
from PySide.QtGui import *
SEC = 1000 # 1 sec. is 1000 msec.
def main():
app = QApplication(sys.argv)
form = QDialog()
form.show()
# suicide in 3 seconds:
QTimer.singleShot(3 * SEC, app.quit)
app.exec_()
if __name__ == "__main__":
main()
Question: how to have the same effect in a command-line application?
Solution
I came up with the following solution:
#!/usr/bin/env python
import sys
from time import sleep
import signal
class MyTimer(object):
"""
Similar to Qt's QTimer. Call a function in a specified time.
Time is given in sec. Usage:
mt = MyTimer()
mt.singleShot(<sec>, <function_name>)
After setting it, you can still disable it:
mt.disable()
If you call it several times, any previously scheduled alarm
will be canceled (only one alarm can be scheduled at any time).
"""
def singleShot(self, sec, func):
self.f = func
signal.signal(signal.SIGALRM, self.handler)
signal.alarm(sec)
def handler(self, *args):
self.f()
def disable(self):
signal.alarm(0)
def main():
while True:
print '.',
sleep(0.5)
if __name__ == "__main__":
mt = MyTimer()
mt.singleShot(3, sys.exit)
main()
As can be seen, the main function has an eternal loop. However, this program will terminate in 3 seconds. I’m imitating QTimer’s singleshot. The differences: (1) you must create a MyTimer object, and (2) time is given in seconds, not in milliseconds. You can also write it in one line if you want: MyTimer().singleShot(3, sys.exit).
It is written in a general form, so instead of sys.exit, you can also call a different function.
Raise a timeout exception after X seconds
Problem
You make a call that may stuck (for instance downloading a webpage). How to timeout after some time?
Solution
I found the following tip at http://stackoverflow.com/questions/8464391 (Unix only):
import signal
import time
def test_request(arg=None):
"""Your http request."""
time.sleep(2)
return arg
class Timeout():
"""Timeout class using ALARM signal."""
class Timeout(Exception):
pass
def __init__(self, sec):
self.sec = sec
def __enter__(self):
signal.signal(signal.SIGALRM, self.raise_timeout)
signal.alarm(self.sec)
def __exit__(self, *args):
signal.alarm(0) # disable alarm
def raise_timeout(self, *args):
raise Timeout.Timeout()
def main():
# Run block of code with timeouts
try:
with Timeout(3):
print test_request("Request 1")
with Timeout(1):
print test_request("Request 2")
except Timeout.Timeout:
print "Timeout"
#############################################################################
if __name__ == "__main__":
main()
Note that time for signal.alarm must be specified in seconds (integer value).
Output:
Request 1 Timeout
