Add missing files
This commit is contained in:
parent
a8e096d528
commit
ecef734547
35
func_timeout/StoppableThread.py
Normal file
35
func_timeout/StoppableThread.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
import ctypes
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
class StoppableThread(threading.Thread):
|
||||||
|
'''
|
||||||
|
StoppableThread - A thread that can be stopped by forcing an exception in the execution context.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def _stopThread(self, exception):
|
||||||
|
if self.isAlive() is False:
|
||||||
|
return True
|
||||||
|
|
||||||
|
joinThread = JoinThread(self, exception)
|
||||||
|
joinThread.start()
|
||||||
|
|
||||||
|
class JoinThread(threading.Thread):
|
||||||
|
'''
|
||||||
|
JoinThread - The workhouse that stops the StoppableThread
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, otherThread, exception):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.otherThread = otherThread
|
||||||
|
self.exception = exception
|
||||||
|
self.daemon = True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.otherThread.isAlive():
|
||||||
|
# We loop raising exception incase it's caught hopefully this breaks us far out.
|
||||||
|
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(self.otherThread.ident), ctypes.py_object(self.exception))
|
||||||
|
self.otherThread.join(2)
|
||||||
|
|
||||||
60
func_timeout/dafunc.py
Normal file
60
func_timeout/dafunc.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
from .exceptions import FunctionTimedOut
|
||||||
|
from .StoppableThread import StoppableThread
|
||||||
|
|
||||||
|
def func_timeout(timeout, func, args=(), kwargs=None):
|
||||||
|
'''
|
||||||
|
func_timeout - Runs the given function for up to #timeout# seconds.
|
||||||
|
|
||||||
|
Raises any exceptions #func# would raise, returns what #func# would return (unless timeout is exceeded), in which case it raises FunctionTimedOut
|
||||||
|
|
||||||
|
@param timeout <float> - Maximum number of seconds to run #func# before terminating
|
||||||
|
@param func <function> - The function to call
|
||||||
|
@param args <tuple> - Any ordered arguments to pass to the function
|
||||||
|
@param kwargs <dict/None> - Keyword arguments to pass to the function.
|
||||||
|
|
||||||
|
@raises - FunctionTimedOut if #timeout# is exceeded, otherwise anything #func# could raise will be raised
|
||||||
|
|
||||||
|
@return - The return value that #func# gives
|
||||||
|
'''
|
||||||
|
|
||||||
|
if not kwargs:
|
||||||
|
kwargs = {}
|
||||||
|
if not args:
|
||||||
|
args = ()
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
exception = []
|
||||||
|
isStopped = False
|
||||||
|
|
||||||
|
def funcwrap(args2, kwargs2):
|
||||||
|
try:
|
||||||
|
ret.append( func(*args2, **kwargs2) )
|
||||||
|
except Exception as e:
|
||||||
|
if isStopped is False:
|
||||||
|
# Don't capture stopping exception
|
||||||
|
exception.append(e)
|
||||||
|
|
||||||
|
thread = StoppableThread(target=funcwrap, args=(args, kwargs))
|
||||||
|
thread.daemon = True
|
||||||
|
|
||||||
|
thread.start()
|
||||||
|
thread.join(timeout)
|
||||||
|
|
||||||
|
stopException = None
|
||||||
|
if thread.isAlive():
|
||||||
|
isStopped = True
|
||||||
|
stopException = FunctionTimedOut('Function %s (args=%s) (kwargs=%s) timed out after %f seconds.\n' %(func.__name__, str(args), str(kwargs), timeout))
|
||||||
|
thread._stopThread(stopException)
|
||||||
|
thread.join(.1)
|
||||||
|
raise stopException
|
||||||
|
|
||||||
|
if exception:
|
||||||
|
raise exception[0]
|
||||||
|
|
||||||
|
if ret:
|
||||||
|
return ret[0]
|
||||||
|
|
||||||
|
|
||||||
4
func_timeout/exceptions.py
Normal file
4
func_timeout/exceptions.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class FunctionTimedOut(Exception):
|
||||||
|
pass
|
||||||
Loading…
Reference in New Issue
Block a user