timeout-decorator-0.5.0/0000775000372000037200000000000013754075762016044 5ustar travistravis00000000000000timeout-decorator-0.5.0/MANIFEST.in0000664000372000037200000000001613754075706017575 0ustar travistravis00000000000000include *.rst timeout-decorator-0.5.0/timeout_decorator/0000775000372000037200000000000013754075762021574 5ustar travistravis00000000000000timeout-decorator-0.5.0/timeout_decorator/__init__.py0000664000372000037200000000024313754075706023702 0ustar travistravis00000000000000# -*- coding: utf-8 -*- from .timeout_decorator import timeout from .timeout_decorator import TimeoutError __title__ = 'timeout_decorator' __version__ = '0.5.0' timeout-decorator-0.5.0/timeout_decorator/timeout_decorator.py0000664000372000037200000001442313754075706025700 0ustar travistravis00000000000000""" Timeout decorator. :copyright: (c) 2012-2013 by PN. :license: MIT, see LICENSE for more details. """ from __future__ import print_function from __future__ import unicode_literals from __future__ import division import sys import time import multiprocessing import signal from functools import wraps ############################################################ # Timeout ############################################################ # http://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ # Used work of Stephen "Zero" Chappell # in https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py class TimeoutError(AssertionError): """Thrown when a timeout occurs in the `timeout` context manager.""" def __init__(self, value="Timed Out"): self.value = value def __str__(self): return repr(self.value) def _raise_exception(exception, exception_message): """ This function checks if a exception message is given. If there is no exception message, the default behaviour is maintained. If there is an exception message, the message is passed to the exception with the 'value' keyword. """ if exception_message is None: raise exception() else: raise exception(exception_message) def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exception_message=None): """Add a timeout parameter to a function and return it. :param seconds: optional time limit in seconds or fractions of a second. If None is passed, no timeout is applied. This adds some flexibility to the usage: you can disable timing out depending on the settings. :type seconds: float :param use_signals: flag indicating whether signals should be used for timing function out or the multiprocessing When using multiprocessing, timeout granularity is limited to 10ths of a second. :type use_signals: bool :raises: TimeoutError if time limit is reached It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. """ def decorate(function): if use_signals: def handler(signum, frame): _raise_exception(timeout_exception, exception_message) @wraps(function) def new_function(*args, **kwargs): new_seconds = kwargs.pop('timeout', seconds) if new_seconds: old = signal.signal(signal.SIGALRM, handler) signal.setitimer(signal.ITIMER_REAL, new_seconds) if not seconds: return function(*args, **kwargs) try: return function(*args, **kwargs) finally: if new_seconds: signal.setitimer(signal.ITIMER_REAL, 0) signal.signal(signal.SIGALRM, old) return new_function else: @wraps(function) def new_function(*args, **kwargs): timeout_wrapper = _Timeout(function, timeout_exception, exception_message, seconds) return timeout_wrapper(*args, **kwargs) return new_function return decorate def _target(queue, function, *args, **kwargs): """Run a function with arguments and return output via a queue. This is a helper function for the Process created in _Timeout. It runs the function with positional arguments and keyword arguments and then returns the function's output by way of a queue. If an exception gets raised, it is returned to _Timeout to be raised by the value property. """ try: queue.put((True, function(*args, **kwargs))) except: queue.put((False, sys.exc_info()[1])) class _Timeout(object): """Wrap a function and add a timeout (limit) attribute to it. Instances of this class are automatically generated by the add_timeout function defined above. Wrapping a function allows asynchronous calls to be made and termination of execution after a timeout has passed. """ def __init__(self, function, timeout_exception, exception_message, limit): """Initialize instance in preparation for being called.""" self.__limit = limit self.__function = function self.__timeout_exception = timeout_exception self.__exception_message = exception_message self.__name__ = function.__name__ self.__doc__ = function.__doc__ self.__timeout = time.time() self.__process = multiprocessing.Process() self.__queue = multiprocessing.Queue() def __call__(self, *args, **kwargs): """Execute the embedded function object asynchronously. The function given to the constructor is transparently called and requires that "ready" be intermittently polled. If and when it is True, the "value" property may then be checked for returned data. """ self.__limit = kwargs.pop('timeout', self.__limit) self.__queue = multiprocessing.Queue(1) args = (self.__queue, self.__function) + args self.__process = multiprocessing.Process(target=_target, args=args, kwargs=kwargs) self.__process.daemon = True self.__process.start() if self.__limit is not None: self.__timeout = self.__limit + time.time() while not self.ready: time.sleep(0.01) return self.value def cancel(self): """Terminate any possible execution of the embedded function.""" if self.__process.is_alive(): self.__process.terminate() _raise_exception(self.__timeout_exception, self.__exception_message) @property def ready(self): """Read-only property indicating status of "value" property.""" if self.__limit and self.__timeout < time.time(): self.cancel() return self.__queue.full() and not self.__queue.empty() @property def value(self): """Read-only property containing data returned from function.""" if self.ready is True: flag, load = self.__queue.get() if flag: return load raise load timeout-decorator-0.5.0/CHANGES.rst0000664000372000037200000000042713754075706017647 0ustar travistravis00000000000000Changelog ========= 0.3.1 ----- - Fixed issue with PicklingError causes the timeout to never be reached. 0.3.0 ----- - Added optional threading support via python multiprocessing (bubenkoff) - Switched to pytest test runner (bubenkoff) 0.2.1 ----- - Initial public release timeout-decorator-0.5.0/PKG-INFO0000664000372000037200000001114613754075762017144 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: timeout-decorator Version: 0.5.0 Summary: Timeout decorator Home-page: https://github.com/pnpnpn/timeout-decorator Author: Patrick Ng Author-email: pn.appdev@gmail.com License: UNKNOWN Description: Timeout decorator ================= |Build Status| |Pypi Status| |Coveralls Status| Installation ------------ From source code: :: python setup.py install From pypi: :: pip install timeout-decorator Usage ----- :: import time import timeout_decorator @timeout_decorator.timeout(5) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Specify an alternate exception to raise on timeout: :: import time import timeout_decorator @timeout_decorator.timeout(5, timeout_exception=StopIteration) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Multithreading -------------- By default, timeout-decorator uses signals to limit the execution time of the given function. This appoach does not work if your function is executed not in a main thread (for example if it's a worker thread of the web application). There is alternative timeout strategy for this case - by using multiprocessing. To use it, just pass ``use_signals=False`` to the timeout decorator function: :: import time import timeout_decorator @timeout_decorator.timeout(5, use_signals=False) def mytest(): print "Start" for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() .. warning:: Make sure that in case of multiprocessing strategy for timeout, your function does not return objects which cannot be pickled, otherwise it will fail at marshalling it between master and child processes. Acknowledgement --------------- Derived from http://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ and https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py Contribute ---------- I would love for you to fork and send me pull request for this project. Please contribute. License ------- This software is licensed under the `MIT license `_ See `License file `_ .. |Build Status| image:: https://travis-ci.org/pnpnpn/timeout-decorator.svg?branch=master :target: https://travis-ci.org/pnpnpn/timeout-decorator .. |Pypi Status| image:: https://badge.fury.io/py/timeout-decorator.svg :target: https://badge.fury.io/py/timeout-decorator .. |Coveralls Status| image:: https://coveralls.io/repos/pnpnpn/timeout-decorator/badge.png?branch=master :target: https://coveralls.io/r/pnpnpn/timeout-decorator Changelog ========= 0.3.1 ----- - Fixed issue with PicklingError causes the timeout to never be reached. 0.3.0 ----- - Added optional threading support via python multiprocessing (bubenkoff) - Switched to pytest test runner (bubenkoff) 0.2.1 ----- - Initial public release Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules timeout-decorator-0.5.0/setup.cfg0000664000372000037200000000004613754075762017665 0ustar travistravis00000000000000[egg_info] tag_build = tag_date = 0 timeout-decorator-0.5.0/README.rst0000664000372000037200000000536413754075706017541 0ustar travistravis00000000000000Timeout decorator ================= |Build Status| |Pypi Status| |Coveralls Status| Installation ------------ From source code: :: python setup.py install From pypi: :: pip install timeout-decorator Usage ----- :: import time import timeout_decorator @timeout_decorator.timeout(5) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Specify an alternate exception to raise on timeout: :: import time import timeout_decorator @timeout_decorator.timeout(5, timeout_exception=StopIteration) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Multithreading -------------- By default, timeout-decorator uses signals to limit the execution time of the given function. This appoach does not work if your function is executed not in a main thread (for example if it's a worker thread of the web application). There is alternative timeout strategy for this case - by using multiprocessing. To use it, just pass ``use_signals=False`` to the timeout decorator function: :: import time import timeout_decorator @timeout_decorator.timeout(5, use_signals=False) def mytest(): print "Start" for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() .. warning:: Make sure that in case of multiprocessing strategy for timeout, your function does not return objects which cannot be pickled, otherwise it will fail at marshalling it between master and child processes. Acknowledgement --------------- Derived from http://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ and https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py Contribute ---------- I would love for you to fork and send me pull request for this project. Please contribute. License ------- This software is licensed under the `MIT license `_ See `License file `_ .. |Build Status| image:: https://travis-ci.org/pnpnpn/timeout-decorator.svg?branch=master :target: https://travis-ci.org/pnpnpn/timeout-decorator .. |Pypi Status| image:: https://badge.fury.io/py/timeout-decorator.svg :target: https://badge.fury.io/py/timeout-decorator .. |Coveralls Status| image:: https://coveralls.io/repos/pnpnpn/timeout-decorator/badge.png?branch=master :target: https://coveralls.io/r/pnpnpn/timeout-decorator timeout-decorator-0.5.0/timeout_decorator.egg-info/0000775000372000037200000000000013754075762023266 5ustar travistravis00000000000000timeout-decorator-0.5.0/timeout_decorator.egg-info/PKG-INFO0000664000372000037200000001114613754075762024366 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: timeout-decorator Version: 0.5.0 Summary: Timeout decorator Home-page: https://github.com/pnpnpn/timeout-decorator Author: Patrick Ng Author-email: pn.appdev@gmail.com License: UNKNOWN Description: Timeout decorator ================= |Build Status| |Pypi Status| |Coveralls Status| Installation ------------ From source code: :: python setup.py install From pypi: :: pip install timeout-decorator Usage ----- :: import time import timeout_decorator @timeout_decorator.timeout(5) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Specify an alternate exception to raise on timeout: :: import time import timeout_decorator @timeout_decorator.timeout(5, timeout_exception=StopIteration) def mytest(): print("Start") for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() Multithreading -------------- By default, timeout-decorator uses signals to limit the execution time of the given function. This appoach does not work if your function is executed not in a main thread (for example if it's a worker thread of the web application). There is alternative timeout strategy for this case - by using multiprocessing. To use it, just pass ``use_signals=False`` to the timeout decorator function: :: import time import timeout_decorator @timeout_decorator.timeout(5, use_signals=False) def mytest(): print "Start" for i in range(1,10): time.sleep(1) print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() .. warning:: Make sure that in case of multiprocessing strategy for timeout, your function does not return objects which cannot be pickled, otherwise it will fail at marshalling it between master and child processes. Acknowledgement --------------- Derived from http://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ and https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py Contribute ---------- I would love for you to fork and send me pull request for this project. Please contribute. License ------- This software is licensed under the `MIT license `_ See `License file `_ .. |Build Status| image:: https://travis-ci.org/pnpnpn/timeout-decorator.svg?branch=master :target: https://travis-ci.org/pnpnpn/timeout-decorator .. |Pypi Status| image:: https://badge.fury.io/py/timeout-decorator.svg :target: https://badge.fury.io/py/timeout-decorator .. |Coveralls Status| image:: https://coveralls.io/repos/pnpnpn/timeout-decorator/badge.png?branch=master :target: https://coveralls.io/r/pnpnpn/timeout-decorator Changelog ========= 0.3.1 ----- - Fixed issue with PicklingError causes the timeout to never be reached. 0.3.0 ----- - Added optional threading support via python multiprocessing (bubenkoff) - Switched to pytest test runner (bubenkoff) 0.2.1 ----- - Initial public release Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules timeout-decorator-0.5.0/timeout_decorator.egg-info/dependency_links.txt0000664000372000037200000000000113754075762027334 0ustar travistravis00000000000000 timeout-decorator-0.5.0/timeout_decorator.egg-info/top_level.txt0000664000372000037200000000002213754075762026012 0ustar travistravis00000000000000timeout_decorator timeout-decorator-0.5.0/timeout_decorator.egg-info/SOURCES.txt0000664000372000037200000000042413754075762025152 0ustar travistravis00000000000000CHANGES.rst MANIFEST.in README.rst setup.py timeout_decorator/__init__.py timeout_decorator/timeout_decorator.py timeout_decorator.egg-info/PKG-INFO timeout_decorator.egg-info/SOURCES.txt timeout_decorator.egg-info/dependency_links.txt timeout_decorator.egg-info/top_level.txttimeout-decorator-0.5.0/setup.py0000664000372000037200000000202713754075706017555 0ustar travistravis00000000000000"""Setuptools entry point.""" import codecs import os try: from setuptools import setup except ImportError: from distutils.core import setup CLASSIFIERS = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules' ] dirname = os.path.dirname(__file__) long_description = ( codecs.open(os.path.join(dirname, 'README.rst'), encoding='utf-8').read() + '\n' + codecs.open(os.path.join(dirname, 'CHANGES.rst'), encoding='utf-8').read() ) setup( name='timeout-decorator', version='0.5.0', description='Timeout decorator', long_description=long_description, author='Patrick Ng', author_email='pn.appdev@gmail.com', url='https://github.com/pnpnpn/timeout-decorator', packages=['timeout_decorator'], install_requires=[], classifiers=CLASSIFIERS)