popen.py 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. from logging import error
  2. from subprocess import Popen
  3. from threading import Event
  4. from threading import Thread
  5. class PopenTimeout(Popen):
  6. '''
  7. Popen class with timeout for Python 2.7
  8. see https://stackoverflow.com/questions/1191374/using-module-subprocess-with-timeout
  9. '''
  10. def __init__(self, *args, **kwargs):
  11. self.timeout = kwargs.pop('timeout', 0)
  12. self.timer = None
  13. self.done = Event()
  14. Popen.__init__(self, *args, **kwargs)
  15. def __tkill(self):
  16. timeout = self.timeout
  17. if not self.done.wait(timeout):
  18. error('Terminating process {} by timeout of {} secs.'.format(self.pid, timeout))
  19. self.kill()
  20. def expirable(func):
  21. def wrapper(self, *args, **kwargs):
  22. # zero timeout means call of parent method
  23. if self.timeout == 0:
  24. return func(self, *args, **kwargs)
  25. # if timer is None, need to start it
  26. if self.timer is None:
  27. self.timer = thr = Thread(target=self.__tkill)
  28. thr.daemon = True
  29. thr.start()
  30. result = func(self, *args, **kwargs)
  31. self.done.set()
  32. return result
  33. return wrapper
  34. wait = expirable(Popen.wait)
  35. communicate = expirable(Popen.communicate)