From 9104d8ca6267d6d8c77a25e7ab45e684636f3281 Mon Sep 17 00:00:00 2001 From: Tim Savannah Date: Mon, 14 Mar 2016 22:37:03 -0400 Subject: [PATCH] Initial Release --- .gitignore | 6 ++ MANIFEST.in | 7 +++ README.md | 57 ++++++++++++++++++- README.rst | 74 +++++++++++++++++++++++++ doc/func_timeout.html | 116 +++++++++++++++++++++++++++++++++++++++ func_timeout/__init__.py | 79 ++++++++++++++++++++++++++ setup.py | 56 +++++++++++++++++++ 7 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 doc/func_timeout.html create mode 100644 func_timeout/__init__.py create mode 100755 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..368810a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.pyc +*.pyo +*~ +build/ +dist/ +*.egg-info/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..fdfcb86 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +include setup.py +include LICENSE +include README.md +include README.rst +include MANIFEST.in +recursive-include func_timeout *.py +recursive-include doc *.html diff --git a/README.md b/README.md index 4e9936f..64012e4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,55 @@ -# func_timeout -Python module to support running any existing function with a given timeout +# func\_timeout +Python module to support running any existing function with a given timeout. + + +Package Includes +---------------- + +**func\_timeout** + +This is the function wherein you pass the timeout, the function you want to call, and any arguments, and it runs it for up to #timeout# seconds, and will return/raise anything the passed function would otherwise return or raise. + + 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 - Maximum number of seconds to run #func# before terminating + @param func - The function to call + @param args - Any ordered arguments to pass to the function + @param kwargs - 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 + ''' + +**FunctionTimedOut** + +Exception raised if the function times out + + +Example +------- +So, for esxample, if you have a function "doit('arg1', 'arg2')" that you want to limit to running for 5 seconds, with func\_timeout you can call it like this: + + + from func_timeout import func_timeout, FunctionTimedOut + + ... + + try: + + doitReturnValue = func_timeout(5, doit, args=('arg1', 'arg2')) + + except FunctionTimedOut: + print ( "doit('arg1', 'arg2') could not complete within 5 seconds and was terminated.\n") + except Exception as e: + # Handle any exceptions that doit might raise here + + +Support +------- + +I've tested func\_timeout with python 2.7 and python 3.5. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..9cd5908 --- /dev/null +++ b/README.rst @@ -0,0 +1,74 @@ +func_timeout +============= +Python module to support running any existing function with a given timeout. + + +Package Includes +---------------- + +**func_timeout** + +This is the function wherein you pass the timeout, the function you want to call, and any arguments, and it runs it for up to #timeout# seconds, and will return/raise anything the passed function would otherwise return or raise. + + 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 - Maximum number of seconds to run #func# before terminating + + @param func - The function to call + + @param args - Any ordered arguments to pass to the function + + @param kwargs - 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 + + ''' + +**FunctionTimedOut** + +Exception raised if the function times out + + +Example +------- +So, for esxample, if you have a function "doit('arg1', 'arg2')" that you want to limit to running for 5 seconds, with func_timeout you can call it like this: + + + from func_timeout import func_timeout, FunctionTimedOut + + + ... + + + try: + + + doitReturnValue = func_timeout(5, doit, args=('arg1', 'arg2')) + + + except FunctionTimedOut: + + print ( "doit('arg1', 'arg2') could not complete within 5 seconds and was terminated.\n") + + except Exception as e: + + # Handle any exceptions that doit might raise here + + + +Support +------- + +I've tested func_timeout with python 2.7 and python 3.5. diff --git a/doc/func_timeout.html b/doc/func_timeout.html new file mode 100644 index 0000000..569eb76 --- /dev/null +++ b/doc/func_timeout.html @@ -0,0 +1,116 @@ + +Python: package func_timeout + + + + + +
 
+ 
func_timeout (version 1.0.0)
index
+

Copyright (c) 2016 Tim Savannah All Rights Reserved.

+Licensed under the Lesser GNU Public License Version 3, LGPLv3. You should have recieved a copy of this with the source distribution as
+LICENSE, otherwise it is available at https://github.com/kata198/func_timeout/LICENSE

+

+ + + + + +
 
+Package Contents
       

+ + + + + +
 
+Classes
       
+
builtins.Exception(builtins.BaseException) +
+
+
FunctionTimedOut +
+
+
+

+ + + + + + + +
 
+class FunctionTimedOut(builtins.Exception)
   Common base class for all non-exit exceptions.
 
 
Method resolution order:
+
FunctionTimedOut
+
builtins.Exception
+
builtins.BaseException
+
builtins.object
+
+
+Data descriptors defined here:
+
__weakref__
+
list of weak references to the object (if defined)
+
+
+Methods inherited from builtins.Exception:
+
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
+ +
__new__(*args, **kwargs) from builtins.type
Create and return a new object.  See help(type) for accurate signature.
+ +
+Methods inherited from builtins.BaseException:
+
__delattr__(self, name, /)
Implement delattr(self, name).
+ +
__getattribute__(self, name, /)
Return getattr(self, name).
+ +
__reduce__(...)
helper for pickle
+ +
__repr__(self, /)
Return repr(self).
+ +
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
+ +
__setstate__(...)
+ +
__str__(self, /)
Return str(self).
+ +
with_traceback(...)
Exception.with_traceback(tb) --
+set self.__traceback__ to tb and return self.
+ +
+Data descriptors inherited from builtins.BaseException:
+
__cause__
+
exception cause
+
+
__context__
+
exception context
+
+
__dict__
+
+
__suppress_context__
+
+
__traceback__
+
+
args
+
+

+ + + + + +
 
+Functions
       
func_timeout(timeout, func, args=(), kwargs=None)
+

+ + + + + +
 
+Data
       __all__ = ('func_timeout', 'FunctionTimedOut')
+__version_tuple__ = (1, 0, 0)
+ diff --git a/func_timeout/__init__.py b/func_timeout/__init__.py new file mode 100644 index 0000000..59fd7f2 --- /dev/null +++ b/func_timeout/__init__.py @@ -0,0 +1,79 @@ +''' + Copyright (c) 2016 Tim Savannah All Rights Reserved. + + Licensed under the Lesser GNU Public License Version 3, LGPLv3. You should have recieved a copy of this with the source distribution as + LICENSE, otherwise it is available at https://github.com/kata198/func_timeout/LICENSE +''' + +import sys +import threading +import time + +__version__ = '1.0.0' +__version_tuple__ = (1, 0, 0) + +__all__ = ('func_timeout', 'FunctionTimedOut') + +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 - Maximum number of seconds to run #func# before terminating + @param func - The function to call + @param args - Any ordered arguments to pass to the function + @param kwargs - 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 = [] + + def funcwrap(args2, kwargs2): + sys.stdout.write('Args2: %s\nkwargs2: %s\n' %(str(args2), str(kwargs2))) + try: + ret.append( func(*args2, **kwargs2) ) + except Exception as e: + exception.append(e) + + thread = threading.Thread(target=funcwrap, args=(args, kwargs)) + + thread.start() + thread.join(timeout) + + if thread.isAlive(): + doRaiseCantStop = False + thread.isDaemon = True + try: + if hasattr(thread, '_tstate_lock'): + # 3.5 + thread._tstate_lock.release() + elif hasattr(thread, '_Thread__stop'): + # 2.7 + thread._Thread__stop() + else: + doRaiseCantStop = True + except: + pass + if doRaiseCantStop is True: + raise NotImplementedError('function timeouts not supported on this system.\n') + + if exception: + raise exception[0] + + if ret: + return ret[0] + + raise FunctionTimedOut('Function %s (args=%s) (kwargs=%s) timed out after %f seconds.\n' %(func.__name__, str(args), str(kwargs), timeout)) + +class FunctionTimedOut(Exception): + pass diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..ec3e8f4 --- /dev/null +++ b/setup.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +''' + Copyright (c) 2016 Tim Savannah All Rights Reserved. + This software is licensed under the terms of the Lesser GNU General Public License Version 2.1 (LGPLv2.1) + + You should have received a copy of this with the source distribution as LICENSE, + otherwise the most up to date license can be found at + https://github.com/kata198/func_timeout/LICENSE + +''' + +import os +import sys +from setuptools import setup + + +if __name__ == '__main__': + + dirName = os.path.dirname(__file__) + if dirName and os.getcwd() != dirName: + os.chdir(dirName) + + summary = 'Python module which allows you to specify timeouts when calling any existing function' + + try: + with open('README.rst', 'rt') as f: + long_description = f.read() + except Exception as e: + sys.stderr.write('Error reading from README.rst: %s\n' %(str(e),)) + log_description = summary + + setup(name='func_timeout', + version='1.0.0', + packages=['func_timeout'] + author='Tim Savannah', + author_email='kata198@gmail.com', + maintainer='Tim Savannah', + url='https://github.com/kata198/func_timeout', + maintainer_email='kata198@gmail.com', + description=summary, + long_description=long_description, + license='LGPLv2', + keywords=['function', 'timeout', 'call', 'terminate', 'runtime', 'max', 'seconds', 'after', 'execution'] + classifiers=['Development Status :: 5 - Production/Stable' + 'Programming Language :: Python', + 'License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2)' + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Topic :: Software Development :: Libraries :: Python Modules' + ] + ) + + +