From c4691c7db9bc961b33881c87928acf017a4f7d85 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 19:15:32 +0100 Subject: [PATCH 01/84] Update timeout_decorator.py - now using wrapt - using wrapt instead of wraps - giving generally more accurate results when debugging with pydev docrunner / doctest (like linenumbers of exceptions when decorating a class method) - the default exception_message contains now also the function name timed out. - do not use signals on windows - it will not work anyway - deleted the TimeoutError Exception - we want to raise the original TimeoutError, not a custom Exception - just a matter of taste. --- timeout_decorator/timeout_decorator.py | 92 +++++++++++--------------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index f05da0f..c3f062b 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -1,19 +1,22 @@ +#! /opt/python3/bin/python3 +# -*- coding: utf-8 -*- + """ Timeout decorator. - :copyright: (c) 2012-2013 by PN. :license: MIT, see LICENSE for more details. + Rotek modified version using wrapt + """ -from __future__ import print_function -from __future__ import unicode_literals -from __future__ import division -import sys -import time import multiprocessing +import multiprocessing.pool +import platform import signal -from functools import wraps +import sys +import time +import wrapt # https://wrapt.readthedocs.io/en/latest/decorators.html ############################################################ # Timeout @@ -24,79 +27,64 @@ # 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 there is an exception message, the message is passed to the exception. """ if exception_message is None: raise exception() else: - raise exception(value=exception_message) + 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): - + @wrapt.decorator + def wrapper_signals(wrapped, instance, args, kwargs): + global exc_msg + if not exc_msg: + exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) if not seconds: - return function - - if use_signals: + return wrapped(*args, **kwargs) + else: 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) - try: - return function(*args, **kwargs) - finally: - if new_seconds: - signal.setitimer(signal.ITIMER_REAL, 0) - signal.signal(signal.SIGALRM, old) - return new_function + _raise_exception(timeout_exception, exc_msg) + old = signal.signal(signal.SIGALRM, handler) + signal.setitimer(signal.ITIMER_REAL, seconds) + try: + return wrapped(*args, **kwargs) + finally: + signal.setitimer(signal.ITIMER_REAL, 0) + signal.signal(signal.SIGALRM, old) + + @wrapt.decorator + def wrapper_no_signals(wrapped, instance, args, kwargs): + if not seconds: + return wrapped(*args, **kwargs) 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 + timeout_wrapper = _Timeout(wrapped, timeout_exception, exception_message, seconds) + return timeout_wrapper(*args, **kwargs) - return decorate + exc_msg=exception_message + if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway + return wrapper_signals + else: + return wrapper_no_signals 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 @@ -111,7 +99,6 @@ def _target(queue, function, *args, **kwargs): 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. @@ -131,7 +118,6 @@ def __init__(self, function, timeout_exception, exception_message, limit): 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. From 7ce5516edb0cd67397b5b42d292a2a3a5920db59 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 19:19:52 +0100 Subject: [PATCH 02/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index c3f062b..9c6c8a7 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -1,5 +1,3 @@ -#! /opt/python3/bin/python3 -# -*- coding: utf-8 -*- """ Timeout decorator. From 2714ec4cdc226267cdae7b7e763eff973c424ac5 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 19:34:18 +0100 Subject: [PATCH 03/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 9c6c8a7..c7b6b1d 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -68,10 +68,13 @@ def handler(signum, frame): @wrapt.decorator def wrapper_no_signals(wrapped, instance, args, kwargs): + global exc_msg + if not exc_msg: + exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) if not seconds: return wrapped(*args, **kwargs) else: - timeout_wrapper = _Timeout(wrapped, timeout_exception, exception_message, seconds) + timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, seconds) return timeout_wrapper(*args, **kwargs) exc_msg=exception_message From 9c54676673ff05a8fac40251c18060ef0c4abd88 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 19:56:36 +0100 Subject: [PATCH 04/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 536bc8f..941753d 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,9 +1,8 @@ """Timeout decorator tests.""" import time - +import wrapt import pytest -from timeout_decorator import timeout, TimeoutError @pytest.fixture(params=[False, True]) From 689afe00786172ecd8fd1837a52b27cfd56a48a3 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:00:37 +0100 Subject: [PATCH 05/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 941753d..7dcba4e 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -3,7 +3,7 @@ import wrapt import pytest - +from decorators_new import timeout @pytest.fixture(params=[False, True]) def use_signals(request): From d4d0c5c1a86d0120f27d0b91bac2c482b73da303 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:08:21 +0100 Subject: [PATCH 06/84] Create requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +wrapt From e36ee7b7029a005f0c4df096834a05ae81af889d Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:12:17 +0100 Subject: [PATCH 07/84] Create requirements.txt --- tests/requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/requirements.txt diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1 @@ +wrapt From 92a61e3ac68c8097400fcb42ab37d537c93e3555 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:16:47 +0100 Subject: [PATCH 08/84] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5cd4bb7..ccfbb93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ python: install: - if [[ $TRAVIS_PYTHON_VERSION == 3.2 ]]; then pip install -U "virtualenv<14.0.0"; fi - pip install python-coveralls tox tox-travis +- pip install wrapt script: tox --recreate after_success: - pip install -e . From e8c539fb0d597a4e91160a9812a65dbbc33bd8ca Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:17:25 +0100 Subject: [PATCH 09/84] Delete requirements.txt --- tests/requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/requirements.txt diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index ba11553..0000000 --- a/tests/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -wrapt From 79096c32f0e2ac44f7de2329122d067acadb818f Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:32:07 +0100 Subject: [PATCH 10/84] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccfbb93..fb878cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,7 @@ python: - '3.6' install: - if [[ $TRAVIS_PYTHON_VERSION == 3.2 ]]; then pip install -U "virtualenv<14.0.0"; fi -- pip install python-coveralls tox tox-travis -- pip install wrapt +- pip install python-coveralls tox tox-travis wrapt script: tox --recreate after_success: - pip install -e . From 569251fdec27b41d6a146beeadfca2b90760a616 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:35:06 +0100 Subject: [PATCH 11/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index c7b6b1d..f769291 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -52,7 +52,7 @@ def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exce def wrapper_signals(wrapped, instance, args, kwargs): global exc_msg if not exc_msg: - exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) + exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__, s=seconds) if not seconds: return wrapped(*args, **kwargs) else: @@ -78,7 +78,7 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): return timeout_wrapper(*args, **kwargs) exc_msg=exception_message - if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway + if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway return wrapper_signals else: return wrapper_no_signals From 0c2db0a6892e26bcfae902d5a81333225d54ecf3 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:35:33 +0100 Subject: [PATCH 12/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 7dcba4e..d8150fa 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,6 +1,5 @@ """Timeout decorator tests.""" import time -import wrapt import pytest from decorators_new import timeout From 16ca9f87b6237717a73d80b20b0f1ce44879d3c1 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 20:46:50 +0100 Subject: [PATCH 13/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index d8150fa..c2dcf30 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -2,7 +2,7 @@ import time import pytest -from decorators_new import timeout +from decorators import timeout @pytest.fixture(params=[False, True]) def use_signals(request): From 0194d2407d8118db53fcb254a99ed75109a7b7d3 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:17:02 +0100 Subject: [PATCH 14/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index f769291..d9c50e1 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -48,11 +48,15 @@ def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exce It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. """ + + + + @wrapt.decorator def wrapper_signals(wrapped, instance, args, kwargs): global exc_msg if not exc_msg: - exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__, s=seconds) + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) if not seconds: return wrapped(*args, **kwargs) else: @@ -70,15 +74,16 @@ def handler(signum, frame): def wrapper_no_signals(wrapped, instance, args, kwargs): global exc_msg if not exc_msg: - exc_msg = '{f} timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) if not seconds: return wrapped(*args, **kwargs) else: timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, seconds) return timeout_wrapper(*args, **kwargs) + global exc_msg exc_msg=exception_message - if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway + if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway return wrapper_signals else: return wrapper_no_signals From fdbf01bd7034fc0d550e378a51200e38ad42390a Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:18:10 +0100 Subject: [PATCH 15/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index c2dcf30..f7ee2c2 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,8 +1,8 @@ """Timeout decorator tests.""" import time import pytest +from timeout_decorator import timeout -from decorators import timeout @pytest.fixture(params=[False, True]) def use_signals(request): @@ -28,20 +28,20 @@ def f(self): def test_timeout_kwargs(use_signals): - @timeout(3, use_signals=use_signals) + @timeout(1, use_signals=use_signals) def f(): time.sleep(2) with pytest.raises(TimeoutError): - f(timeout=1) - + # f(timeout=1) - this keyword should NOT be allowed here ! what if the function uses a keyword argument 'timeout' ! + f() def test_timeout_alternate_exception(use_signals): - @timeout(3, use_signals=use_signals, timeout_exception=StopIteration) + @timeout(1, use_signals=use_signals, timeout_exception=StopIteration) def f(): time.sleep(2) with pytest.raises(StopIteration): - f(timeout=1) - + # f(timeout=1) - this keyword should NOT be allowed here ! what if the function uses a keyword argument 'timeout' ! + f() def test_timeout_no_seconds(use_signals): @timeout(use_signals=use_signals) @@ -98,5 +98,5 @@ def test_timeout_default_exception_message(): @timeout(seconds=1) def f(): time.sleep(2) - with pytest.raises(TimeoutError, match="Timed Out"): + with pytest.raises(TimeoutError, match="f Timed out after 1 seconds"): f() From 18be4a04e5210b272403eb5a081a6c2ee919214b Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:40:26 +0100 Subject: [PATCH 16/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index d9c50e1..8487551 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -1,4 +1,3 @@ - """ Timeout decorator. :copyright: (c) 2012-2013 by PN. @@ -55,15 +54,16 @@ def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exce @wrapt.decorator def wrapper_signals(wrapped, instance, args, kwargs): global exc_msg + new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) - if not seconds: + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=new_seconds) + if not new_seconds: return wrapped(*args, **kwargs) else: def handler(signum, frame): _raise_exception(timeout_exception, exc_msg) old = signal.signal(signal.SIGALRM, handler) - signal.setitimer(signal.ITIMER_REAL, seconds) + signal.setitimer(signal.ITIMER_REAL, new_seconds) try: return wrapped(*args, **kwargs) finally: @@ -73,12 +73,13 @@ def handler(signum, frame): @wrapt.decorator def wrapper_no_signals(wrapped, instance, args, kwargs): global exc_msg + new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=seconds) - if not seconds: + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=new_seconds) + if not new_seconds: return wrapped(*args, **kwargs) else: - timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, seconds) + timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, new_seconds) return timeout_wrapper(*args, **kwargs) global exc_msg @@ -131,9 +132,7 @@ def __call__(self, *args, **kwargs): 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 = multiprocessing.Process(target=_target, args=args, kwargs=kwargs) self.__process.daemon = True self.__process.start() self.__timeout = self.__limit + time.time() From 423fbb5a1e5d4349bcde2ecb88ff27dff96e0abf Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:41:42 +0100 Subject: [PATCH 17/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index f7ee2c2..1ba5c06 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,7 +1,7 @@ """Timeout decorator tests.""" import time import pytest -from timeout_decorator import timeout +from timeout_decorator timeout @pytest.fixture(params=[False, True]) @@ -32,16 +32,15 @@ def test_timeout_kwargs(use_signals): def f(): time.sleep(2) with pytest.raises(TimeoutError): - # f(timeout=1) - this keyword should NOT be allowed here ! what if the function uses a keyword argument 'timeout' ! - f() + f(dec_timeout=1) def test_timeout_alternate_exception(use_signals): @timeout(1, use_signals=use_signals, timeout_exception=StopIteration) def f(): time.sleep(2) with pytest.raises(StopIteration): - # f(timeout=1) - this keyword should NOT be allowed here ! what if the function uses a keyword argument 'timeout' ! - f() + f(dec_timeout=1) + def test_timeout_no_seconds(use_signals): @timeout(use_signals=use_signals) From 493f6f8f64b39c95f0ae3f5f352cd7ec9c796249 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:43:43 +0100 Subject: [PATCH 18/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 1ba5c06..8bd0b25 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,7 +1,7 @@ """Timeout decorator tests.""" import time import pytest -from timeout_decorator timeout +from timeout_decorator import timeout @pytest.fixture(params=[False, True]) From 5b93d6ba6b3668060cbd323379a5379b6d09c178 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 21:54:06 +0100 Subject: [PATCH 19/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 8487551..de2267a 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -13,7 +13,7 @@ import signal import sys import time -import wrapt # https://wrapt.readthedocs.io/en/latest/decorators.html +import wrapt ############################################################ # Timeout From 84c07e199cd6882849b6eb0c35af6a73e131a172 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:05:20 +0100 Subject: [PATCH 20/84] Create requirements-testing.txt --- requirements-testing.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements-testing.txt diff --git a/requirements-testing.txt b/requirements-testing.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/requirements-testing.txt @@ -0,0 +1 @@ +wrapt From 7f53db3131ad8af6e26fc54d57a4630f4dec20c3 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:05:53 +0100 Subject: [PATCH 21/84] Create requirements.txt --- tests/requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/requirements.txt diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1 @@ +wrapt From b339b9bd31799193027ecfa42c5cf8f7287a0f9a Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:06:14 +0100 Subject: [PATCH 22/84] Create requirements-testing.txt --- tests/requirements-testing.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/requirements-testing.txt diff --git a/tests/requirements-testing.txt b/tests/requirements-testing.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/tests/requirements-testing.txt @@ -0,0 +1 @@ +wrapt From 644be60671511be943b9011545d3f1178fb9c50d Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:18:04 +0100 Subject: [PATCH 23/84] Update tox.ini --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 9ba30b9..f59cd11 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ deps = py32: pytest<3.0 py{26,27,33,34,35,36}: pytest>=3.0 pytest-pep8==1.0.6 + wrapt [pytest] addopts = -vvl From fb219327f6a696f84bc814886c5e52bca1f00a5d Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:20:34 +0100 Subject: [PATCH 24/84] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e001557..d961d1e 100644 --- a/setup.py +++ b/setup.py @@ -34,5 +34,5 @@ author_email='pn.appdev@gmail.com', url='https://github.com/pnpnpn/timeout-decorator', packages=['timeout_decorator'], - install_requires=[], + install_requires=['wrapt'], classifiers=CLASSIFIERS) From b41d28fe465ec790ac6ca603dff24d442132ae32 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:22:36 +0100 Subject: [PATCH 25/84] Delete requirements-testing.txt --- tests/requirements-testing.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/requirements-testing.txt diff --git a/tests/requirements-testing.txt b/tests/requirements-testing.txt deleted file mode 100644 index ba11553..0000000 --- a/tests/requirements-testing.txt +++ /dev/null @@ -1 +0,0 @@ -wrapt From 3f61a34667198d4b4b52cea698919974719b3a1e Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:22:47 +0100 Subject: [PATCH 26/84] Delete requirements.txt --- tests/requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/requirements.txt diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index ba11553..0000000 --- a/tests/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -wrapt From b9f17644cc0d53497547a298062c7cb3b78c717a Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:23:39 +0100 Subject: [PATCH 27/84] Delete requirements-testing.txt --- requirements-testing.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements-testing.txt diff --git a/requirements-testing.txt b/requirements-testing.txt deleted file mode 100644 index ba11553..0000000 --- a/requirements-testing.txt +++ /dev/null @@ -1 +0,0 @@ -wrapt From 6378405e93d55fc672eb1639ef76f8c8560492ff Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:23:49 +0100 Subject: [PATCH 28/84] Delete requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ba11553..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -wrapt From 077f0a9e287da88d4435531bec7f5e2116deda3c Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:31:55 +0100 Subject: [PATCH 29/84] Update __init__.py --- timeout_decorator/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/timeout_decorator/__init__.py b/timeout_decorator/__init__.py index c802c55..6e331e4 100644 --- a/timeout_decorator/__init__.py +++ b/timeout_decorator/__init__.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from .timeout_decorator import timeout -from .timeout_decorator import TimeoutError __title__ = 'timeout_decorator' __version__ = '0.4.0' From 7ab0afdbd847747776a8a9867b156535a9338da7 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:38:57 +0100 Subject: [PATCH 30/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index de2267a..37c4f9c 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -56,7 +56,7 @@ def wrapper_signals(wrapped, instance, args, kwargs): global exc_msg new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=new_seconds) + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) if not new_seconds: return wrapped(*args, **kwargs) else: @@ -75,7 +75,7 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): global exc_msg new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__,s=new_seconds) + exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) if not new_seconds: return wrapped(*args, **kwargs) else: @@ -83,8 +83,9 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): return timeout_wrapper(*args, **kwargs) global exc_msg - exc_msg=exception_message - if use_signals and not platform.system().lower().startswith('win') : # never use signals with windows - it wont work anyway + exc_msg = exception_message + # never use signals with windows - it wont work anyway + if use_signals and not platform.system().lower().startswith('win') : return wrapper_signals else: return wrapper_no_signals From e767633787d17f73f7a34bfb0de3e314d2d00062 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:39:56 +0100 Subject: [PATCH 31/84] Update tox.ini --- tox.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index f59cd11..02bbb26 100644 --- a/tox.ini +++ b/tox.ini @@ -9,10 +9,9 @@ indexserver= commands= py.test timeout_decorator tests --pep8 deps = - py32: pytest<3.0 - py{26,27,33,34,35,36}: pytest>=3.0 + py32: pytest<3.0, wrapt + py{26,27,33,34,35,36}: pytest>=3.0, wrapt pytest-pep8==1.0.6 - wrapt [pytest] addopts = -vvl From d16e533d561259d22e4928b65df2d75f169f1c44 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:43:28 +0100 Subject: [PATCH 32/84] Update tox.ini --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 02bbb26..29728aa 100644 --- a/tox.ini +++ b/tox.ini @@ -10,8 +10,9 @@ commands= py.test timeout_decorator tests --pep8 deps = py32: pytest<3.0, wrapt - py{26,27,33,34,35,36}: pytest>=3.0, wrapt + py{26,27,33,34,35,36}: pytest>=3.0 pytest-pep8==1.0.6 + wrapt [pytest] addopts = -vvl From 1f5bee6c362b570a659073278f89da4b0829432e Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:45:42 +0100 Subject: [PATCH 33/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 37c4f9c..a87d34c 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -9,6 +9,7 @@ import multiprocessing import multiprocessing.pool +import os import platform import signal import sys From 133d6d1bb245f864b13d5dc2d6e5c9f27c328215 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:51:08 +0100 Subject: [PATCH 34/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index a87d34c..bdc8f30 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -48,10 +48,6 @@ def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exce It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. """ - - - - @wrapt.decorator def wrapper_signals(wrapped, instance, args, kwargs): global exc_msg @@ -86,7 +82,7 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): global exc_msg exc_msg = exception_message # never use signals with windows - it wont work anyway - if use_signals and not platform.system().lower().startswith('win') : + if use_signals and not platform.system().lower().startswith('win'): return wrapper_signals else: return wrapper_no_signals From 7d582ffae0193818de210212c8debd8601f217b7 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 22:54:50 +0100 Subject: [PATCH 35/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 8bd0b25..b3f02fe 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -34,6 +34,7 @@ def f(): with pytest.raises(TimeoutError): f(dec_timeout=1) + def test_timeout_alternate_exception(use_signals): @timeout(1, use_signals=use_signals, timeout_exception=StopIteration) def f(): @@ -68,7 +69,6 @@ def test_function_name(use_signals): @timeout(seconds=2, use_signals=use_signals) def func_name(): pass - assert func_name.__name__ == 'func_name' From 65e0067b816838791c0841f454781627cc5fdeee Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:05:03 +0100 Subject: [PATCH 36/84] Update tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 29728aa..f59cd11 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ indexserver= commands= py.test timeout_decorator tests --pep8 deps = - py32: pytest<3.0, wrapt + py32: pytest<3.0 py{26,27,33,34,35,36}: pytest>=3.0 pytest-pep8==1.0.6 wrapt From 97a7391159555f860ffd2e5f519ca82541095e3c Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:14:45 +0100 Subject: [PATCH 37/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index bdc8f30..afedf18 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -25,6 +25,9 @@ # in https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py +if sys.version_info <= (3,2): + TimeoutError = AssertionError + 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. From 588a38a7b246104a433acef36268f92e6a19a713 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:17:42 +0100 Subject: [PATCH 38/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index afedf18..39ed498 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -25,9 +25,10 @@ # in https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py -if sys.version_info <= (3,2): +if sys.version_info <= (3, 2): TimeoutError = AssertionError + 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. From 38634d98a54f4e2652912f5d38f71e2324e6e791 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:23:08 +0100 Subject: [PATCH 39/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index b3f02fe..071cdb6 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -4,6 +4,10 @@ from timeout_decorator import timeout +if sys.version_info <= (3, 2): + TimeoutError = AssertionError + + @pytest.fixture(params=[False, True]) def use_signals(request): """Use signals for timing out or not.""" From 0a10327ac37476088b81273a81675d6109e2c2f3 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:25:05 +0100 Subject: [PATCH 40/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 39ed498..edd570c 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -28,7 +28,7 @@ if sys.version_info <= (3, 2): TimeoutError = AssertionError - + 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. From a3d723bccf3f24217aedcf07146b367fef03b6c0 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:27:17 +0100 Subject: [PATCH 41/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 071cdb6..5d2b7b3 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,6 +1,7 @@ """Timeout decorator tests.""" -import time import pytest +import sys +import time from timeout_decorator import timeout From 9bcc713a4fcb7a4ba9cf8620de2ebda54ed3384c Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:37:51 +0100 Subject: [PATCH 42/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index edd570c..975ab28 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -25,10 +25,6 @@ # in https://code.google.com/p/verse-quiz/source/browse/trunk/timeout.py -if sys.version_info <= (3, 2): - TimeoutError = AssertionError - - 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. @@ -40,7 +36,7 @@ def _raise_exception(exception, exception_message): raise exception(exception_message) -def timeout(seconds=None, use_signals=True, timeout_exception=TimeoutError, exception_message=None): +def timeout(seconds=None, use_signals=True, timeout_exception=None, 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. @@ -83,6 +79,12 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, new_seconds) return timeout_wrapper(*args, **kwargs) + if not timeout_exception: + if sys.version_info < (3, 3): + timeout_exception=AssertionError # there is no TimeoutError below Python 3.3 + else: + timeout_exception=TimeoutError + global exc_msg exc_msg = exception_message # never use signals with windows - it wont work anyway From 2c7e1bab41977f2de14755013ac22dd64207f017 Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:38:29 +0100 Subject: [PATCH 43/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 5d2b7b3..566933b 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -5,7 +5,7 @@ from timeout_decorator import timeout -if sys.version_info <= (3, 2): +if sys.version_info < (3, 3): TimeoutError = AssertionError From 4de8277de4e6d98de79e4f6380e545b71d22ba4b Mon Sep 17 00:00:00 2001 From: bitranox Date: Fri, 3 Nov 2017 23:44:50 +0100 Subject: [PATCH 44/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 975ab28..2f523a5 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -81,9 +81,9 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): if not timeout_exception: if sys.version_info < (3, 3): - timeout_exception=AssertionError # there is no TimeoutError below Python 3.3 + timeout_exception = AssertionError # there is no TimeoutError below Python 3.3 else: - timeout_exception=TimeoutError + timeout_exception = TimeoutError global exc_msg exc_msg = exception_message From 3e9157f169aa32aacbca64aee329a27c4a5c623b Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 00:21:47 +0100 Subject: [PATCH 45/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 2f523a5..04346f1 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -50,7 +50,7 @@ def timeout(seconds=None, use_signals=True, timeout_exception=None, exception_me """ @wrapt.decorator def wrapper_signals(wrapped, instance, args, kwargs): - global exc_msg + exc_msg = exception_message new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) @@ -69,7 +69,7 @@ def handler(signum, frame): @wrapt.decorator def wrapper_no_signals(wrapped, instance, args, kwargs): - global exc_msg + exc_msg = exception_message new_seconds = kwargs.pop('dec_timeout', seconds) if not exc_msg: exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) @@ -85,8 +85,6 @@ def wrapper_no_signals(wrapped, instance, args, kwargs): else: timeout_exception = TimeoutError - global exc_msg - exc_msg = exception_message # never use signals with windows - it wont work anyway if use_signals and not platform.system().lower().startswith('win'): return wrapper_signals From 2cf1bb67915f0b0e483bc99f573e6596eec0c54e Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 19:13:40 +0100 Subject: [PATCH 46/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 04346f1..287809e 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -131,7 +131,6 @@ def __call__(self, *args, **kwargs): 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) From 3135b365d07e7fcd8bf62dc05590451538e90e4f Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 19:19:54 +0100 Subject: [PATCH 47/84] Update .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index fb878cf..748db6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,8 @@ python: - '3.4' - '3.5' - '3.6' +- 'pypy' +- 'pypy3' install: - if [[ $TRAVIS_PYTHON_VERSION == 3.2 ]]; then pip install -U "virtualenv<14.0.0"; fi - pip install python-coveralls tox tox-travis wrapt From 100c1a7f5d2469919fe44b6ed97c6bdb29dfd5af Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:14:14 +0100 Subject: [PATCH 48/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 79 +++++++++++--------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 287809e..a940a95 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -3,13 +3,11 @@ :copyright: (c) 2012-2013 by PN. :license: MIT, see LICENSE for more details. Rotek modified version using wrapt - """ import multiprocessing import multiprocessing.pool -import os import platform import signal import sys @@ -30,66 +28,55 @@ def _raise_exception(exception, exception_message): If there is no exception message, the default behaviour is maintained. If there is an exception message, the message is passed to the exception. """ - if exception_message is None: - raise exception() - else: - raise exception(exception_message) + if not exception: + if sys.version_info < (3, 3): + exception = AssertionError # there is no TimeoutError below Python 3.3 + else: + exception = TimeoutError + + raise exception(exception_message) -def timeout(seconds=None, use_signals=True, timeout_exception=None, exception_message=None): +def timeout(timeout=None, use_signals=True, timeout_exception=None, 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. + :param timeout: optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. This adds some flexibility to the usage: you can disable timing out depending on the settings. - :type seconds: float + :type timeout: 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. + When using multiprocessing, seconds 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. """ @wrapt.decorator - def wrapper_signals(wrapped, instance, args, kwargs): + def wrapper(wrapped, instance, args, kwargs): exc_msg = exception_message - new_seconds = kwargs.pop('dec_timeout', seconds) + new_timeout = kwargs.pop('dec_timeout', timeout) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) - if not new_seconds: + exc_msg = 'Function {f} Timed out after {s} timeout'.format(f=wrapped.__name__, s=new_timeout) + if not new_timeout: return wrapped(*args, **kwargs) else: - def handler(signum, frame): - _raise_exception(timeout_exception, exc_msg) - old = signal.signal(signal.SIGALRM, handler) - signal.setitimer(signal.ITIMER_REAL, new_seconds) - try: - return wrapped(*args, **kwargs) - finally: - signal.setitimer(signal.ITIMER_REAL, 0) - signal.signal(signal.SIGALRM, old) - - @wrapt.decorator - def wrapper_no_signals(wrapped, instance, args, kwargs): - exc_msg = exception_message - new_seconds = kwargs.pop('dec_timeout', seconds) - if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} seconds'.format(f=wrapped.__name__, s=new_seconds) - if not new_seconds: - return wrapped(*args, **kwargs) - else: - timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, new_seconds) - return timeout_wrapper(*args, **kwargs) - - if not timeout_exception: - if sys.version_info < (3, 3): - timeout_exception = AssertionError # there is no TimeoutError below Python 3.3 - else: - timeout_exception = TimeoutError + if b_signals: + def handler(signum, frame): + _raise_exception(timeout_exception, exc_msg) + old = signal.signal(signal.SIGALRM, handler) + signal.setitimer(signal.ITIMER_REAL, new_timeout) + try: + return wrapped(*args, **kwargs) + finally: + signal.setitimer(signal.ITIMER_REAL, 0) + signal.signal(signal.SIGALRM, old) + else: + timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, new_timeout) + return timeout_wrapper(*args, **kwargs) # never use signals with windows - it wont work anyway + b_signals=False if use_signals and not platform.system().lower().startswith('win'): - return wrapper_signals - else: - return wrapper_no_signals + b_signals=True + return wrapper def _target(queue, function, *args, **kwargs): @@ -133,7 +120,9 @@ def __call__(self, *args, **kwargs): """ self.__queue = multiprocessing.Queue(1) args = (self.__queue, self.__function) + args - self.__process = multiprocessing.Process(target=_target, args=args, kwargs=kwargs) + self.__process = multiprocessing.Process(target=_target, + args=args, + kwargs=kwargs) self.__process.daemon = True self.__process.start() self.__timeout = self.__limit + time.time() From b6885435beb656f999a9787703ccbfca103e16d8 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:14:59 +0100 Subject: [PATCH 49/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 566933b..e6e6f80 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,12 +1,12 @@ """Timeout decorator tests.""" +import time import pytest import sys -import time from timeout_decorator import timeout -if sys.version_info < (3, 3): - TimeoutError = AssertionError +if sys.version_info < (3, 3): # there is no TimeoutError < Python 3.2 + TimeoutError=AssertionError @pytest.fixture(params=[False, True]) @@ -64,22 +64,23 @@ def f(): def test_timeout_ok(use_signals): - @timeout(seconds=2, use_signals=use_signals) + @timeout(timeout=2, use_signals=use_signals) def f(): time.sleep(1) f() def test_function_name(use_signals): - @timeout(seconds=2, use_signals=use_signals) + @timeout(timeout=2, use_signals=use_signals) def func_name(): pass + assert func_name.__name__ == 'func_name' def test_timeout_pickle_error(): """Test that when a pickle error occurs a timeout error is raised.""" - @timeout(seconds=1, use_signals=False) + @timeout(timeout=1, use_signals=False) def f(): time.sleep(0.1) @@ -91,7 +92,7 @@ class Test(object): def test_timeout_custom_exception_message(): - @timeout(seconds=1, exception_message="Custom fail message") + @timeout(timeout=1, exception_message="Custom fail message") def f(): time.sleep(2) with pytest.raises(TimeoutError, match="Custom fail message"): @@ -99,8 +100,8 @@ def f(): def test_timeout_default_exception_message(): - @timeout(seconds=1) + @timeout(timeout=1) def f(): time.sleep(2) - with pytest.raises(TimeoutError, match="f Timed out after 1 seconds"): + with pytest.raises(TimeoutError, match="Function f Timed out after 1 timeout"): f() From 94d4b4746387a94147d8ae9623dc0986a5c5c9ac Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:19:51 +0100 Subject: [PATCH 50/84] Update timeout_decorator.py Fixing pep-8 errors --- timeout_decorator/timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index a940a95..fefa3bd 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -73,9 +73,9 @@ def handler(signum, frame): return timeout_wrapper(*args, **kwargs) # never use signals with windows - it wont work anyway - b_signals=False + b_signals = False if use_signals and not platform.system().lower().startswith('win'): - b_signals=True + b_signals = True return wrapper From 151992f1766743e6613c662ba45460fb9f31a010 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:23:24 +0100 Subject: [PATCH 51/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index e6e6f80..d0b485d 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,12 +1,12 @@ """Timeout decorator tests.""" -import time +from decorators import timeout import pytest import sys -from timeout_decorator import timeout +import time if sys.version_info < (3, 3): # there is no TimeoutError < Python 3.2 - TimeoutError=AssertionError + TimeoutError = AssertionError @pytest.fixture(params=[False, True]) From ed0d34d137bf12e66fbf5745bac0ba1bd34c7e95 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:26:12 +0100 Subject: [PATCH 52/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index d0b485d..f91dfb4 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,5 +1,5 @@ """Timeout decorator tests.""" -from decorators import timeout +from timeout-decorator import timeout import pytest import sys import time From d5514c456b23ab722e52c1f03753a6c50e0bc890 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 20:30:17 +0100 Subject: [PATCH 53/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index f91dfb4..1f91adb 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,5 +1,5 @@ """Timeout decorator tests.""" -from timeout-decorator import timeout +from timeout_decorator import timeout import pytest import sys import time From 779010576bf040d3bc9dedfcc7e47e6f63f647e4 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 21:22:59 +0100 Subject: [PATCH 54/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 1f91adb..77f816e 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -33,7 +33,7 @@ def f(self): def test_timeout_kwargs(use_signals): - @timeout(1, use_signals=use_signals) + @timeout(3, use_signals=use_signals) def f(): time.sleep(2) with pytest.raises(TimeoutError): @@ -41,7 +41,7 @@ def f(): def test_timeout_alternate_exception(use_signals): - @timeout(1, use_signals=use_signals, timeout_exception=StopIteration) + @timeout(3, use_signals=use_signals, timeout_exception=StopIteration) def f(): time.sleep(2) with pytest.raises(StopIteration): From cb67fbab79a74de13232ad033ed16f187f7ae696 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 21:26:48 +0100 Subject: [PATCH 55/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 77f816e..b8e4781 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,5 +1,5 @@ """Timeout decorator tests.""" -from timeout_decorator import timeout +from timeout_decorator import timeout # on github project import pytest import sys import time @@ -103,5 +103,5 @@ def test_timeout_default_exception_message(): @timeout(timeout=1) def f(): time.sleep(2) - with pytest.raises(TimeoutError, match="Function f Timed out after 1 timeout"): + with pytest.raises(TimeoutError, match="Function f timed out after 1 seconds"): f() From 1186c3751e3d00f2cd7c759a5720ab76fc09a31e Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 21:27:34 +0100 Subject: [PATCH 56/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index fefa3bd..db57efe 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -54,7 +54,7 @@ def wrapper(wrapped, instance, args, kwargs): exc_msg = exception_message new_timeout = kwargs.pop('dec_timeout', timeout) if not exc_msg: - exc_msg = 'Function {f} Timed out after {s} timeout'.format(f=wrapped.__name__, s=new_timeout) + exc_msg = 'Function {f} timed out after {s} seconds'.format(f=wrapped.__name__, s=new_timeout) if not new_timeout: return wrapped(*args, **kwargs) else: From 4aa0590b5add942a17b37726cc4a99470bcd315a Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 21:30:47 +0100 Subject: [PATCH 57/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index b8e4781..0a255e0 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,5 +1,5 @@ """Timeout decorator tests.""" -from timeout_decorator import timeout # on github project +from timeout_decorator import timeout import pytest import sys import time From 719dcb2082e306f3bd1eaff38d9673f010d1bfb2 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 22:30:40 +0100 Subject: [PATCH 58/84] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d961d1e..b657211 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ long_description=long_description, author='Patrick Ng', author_email='pn.appdev@gmail.com', - url='https://github.com/pnpnpn/timeout-decorator', + url='https://github.com/bitranox/timeout-decorator', packages=['timeout_decorator'], install_requires=['wrapt'], classifiers=CLASSIFIERS) From 6ace58aaf3673a3b8b3e842450ba61ad3fadb105 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 22:31:25 +0100 Subject: [PATCH 59/84] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 017607e..29a0d1c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ venv: # install all needed for development develop: venv - venv/bin/pip install -e . -r requirements-testing.txt tox + venv/bin/pip install -e . -r requirements.txt tox # clean the development envrironment clean: From 728fc9cc53694a8cdf008d476a8d38446fdae4d0 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sat, 4 Nov 2017 22:31:50 +0100 Subject: [PATCH 60/84] Create requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +wrapt From 2f3dec582e0683c56b3f0ccd526348781eb31e35 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:19:38 +0100 Subject: [PATCH 61/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index db57efe..f83100e 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -21,7 +21,8 @@ # 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 - +if sys.version_info < (3, 3): + TimeoutError = AssertionError # there is no TimeoutError below Python 3.3 def _raise_exception(exception, exception_message): """ This function checks if a exception message is given. @@ -29,11 +30,7 @@ def _raise_exception(exception, exception_message): If there is an exception message, the message is passed to the exception. """ if not exception: - if sys.version_info < (3, 3): - exception = AssertionError # there is no TimeoutError below Python 3.3 - else: - exception = TimeoutError - + exception = TimeoutError raise exception(exception_message) From 4bc09f3b9f371efed813f49b483c66875c3a02b9 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:22:29 +0100 Subject: [PATCH 62/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index f83100e..62df179 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -21,9 +21,12 @@ # 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 + + if sys.version_info < (3, 3): TimeoutError = AssertionError # there is no TimeoutError below Python 3.3 + 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. From 7461061f65653d8e22418cdc764c74f4c99f1f8c Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:32:47 +0100 Subject: [PATCH 63/84] Update timeout_decorator.py try inline types for function parameters --- timeout_decorator/timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 62df179..c5c7eb5 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -37,7 +37,7 @@ def _raise_exception(exception, exception_message): raise exception(exception_message) -def timeout(timeout=None, use_signals=True, timeout_exception=None, exception_message=None): +def timeout(timeout:float=None, use_signals:bool=True, timeout_exception:Exception=None, exception_message:str=None): """Add a timeout parameter to a function and return it. :param timeout: optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. This adds some flexibility to the usage: you can disable timing out depending on the settings. From 7e25e1ab946c0e5bafbc5c59641466be5dd6faf6 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:46:14 +0100 Subject: [PATCH 64/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 41 ++++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index c5c7eb5..a76a27b 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -37,17 +37,40 @@ def _raise_exception(exception, exception_message): raise exception(exception_message) -def timeout(timeout:float=None, use_signals:bool=True, timeout_exception:Exception=None, exception_message:str=None): +def timeout(timeout=None, use_signals=True, timeout_exception=None, exception_message=None): """Add a timeout parameter to a function and return it. - :param timeout: optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. - This adds some flexibility to the usage: you can disable timing out depending on the settings. - :type timeout: float + + Usage: + + @timeout(3) + def foo(): + pass + + Usage without decorating a function : + + def foo2(a,b,c): + pass + + timeout(3)(foo)(1,2,c=3) + + :param timeout: optional time limit in seconds or fractions of a second. If None is passed, + no seconds is applied. This adds some flexibility to the usage: you can disable timing + out depending on the settings. + :type timeout: float :param use_signals: flag indicating whether signals should be used for timing function out or the multiprocessing - When using multiprocessing, seconds 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. + When using multiprocessing, seconds granularity is limited to 10ths of a second. + :type use_signals: bool + :param timeout_exception: the Exception to be raised when timeout occurs, default = TimeoutException + :type timeout_exception: Exception + :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. + :type exception_message: str + :raises: TimeoutError if time limit is reached + :rtype: Exception + + :returns: the Result of the wrapped function + + It is illegal to pass anything other than a function as the first parameter. + The function is wrapped and returned to the caller. """ @wrapt.decorator def wrapper(wrapped, instance, args, kwargs): From 04dec992ea14941dd579d29082a6ff58aaf92ff1 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:49:53 +0100 Subject: [PATCH 65/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index a76a27b..2c2e738 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -40,7 +40,7 @@ def _raise_exception(exception, exception_message): def timeout(timeout=None, use_signals=True, timeout_exception=None, exception_message=None): """Add a timeout parameter to a function and return it. - Usage: + Usage: @timeout(3) def foo(): @@ -49,7 +49,7 @@ def foo(): Usage without decorating a function : def foo2(a,b,c): - pass + pass timeout(3)(foo)(1,2,c=3) @@ -62,11 +62,11 @@ def foo2(a,b,c): :type use_signals: bool :param timeout_exception: the Exception to be raised when timeout occurs, default = TimeoutException :type timeout_exception: Exception - :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. + :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. :type exception_message: str :raises: TimeoutError if time limit is reached :rtype: Exception - + :returns: the Result of the wrapped function It is illegal to pass anything other than a function as the first parameter. From 99c8e3a5ad22df77cb23ba2b3671f9f640535083 Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:55:03 +0100 Subject: [PATCH 66/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 2c2e738..f4be124 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -2,7 +2,6 @@ Timeout decorator. :copyright: (c) 2012-2013 by PN. :license: MIT, see LICENSE for more details. - Rotek modified version using wrapt """ @@ -20,7 +19,6 @@ # 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 if sys.version_info < (3, 3): @@ -53,7 +51,7 @@ def foo2(a,b,c): timeout(3)(foo)(1,2,c=3) - :param timeout: optional time limit in seconds or fractions of a second. If None is passed, + :param timeout: optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. This adds some flexibility to the usage: you can disable timing out depending on the settings. :type timeout: float @@ -69,7 +67,7 @@ def foo2(a,b,c): :returns: the Result of the wrapped function - It is illegal to pass anything other than a function as the first parameter. + It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. """ @wrapt.decorator From 5d84e627fe416da0079b993743683628f750859f Mon Sep 17 00:00:00 2001 From: bitranox Date: Sun, 5 Nov 2017 18:58:30 +0100 Subject: [PATCH 67/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index f4be124..9a92e28 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -49,7 +49,7 @@ def foo(): def foo2(a,b,c): pass - timeout(3)(foo)(1,2,c=3) + timeout(3)(foo2)(1,2,c=3) :param timeout: optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. This adds some flexibility to the usage: you can disable timing From 606acdedbbdf12d9d979330622f01dbc19cad6c3 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 9 Nov 2017 13:33:04 +0100 Subject: [PATCH 68/84] Update README.rst --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 4ae5017..2dcea7b 100644 --- a/README.rst +++ b/README.rst @@ -28,10 +28,10 @@ Usage @timeout_decorator.timeout(5) def mytest(): - print "Start" + print("Start") for i in range(1,10): time.sleep(1) - print "%d seconds have passed" % i + print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() @@ -45,10 +45,10 @@ Specify an alternate exception to raise on timeout: @timeout_decorator.timeout(5, timeout_exception=StopIteration) def mytest(): - print "Start" + print("Start") for i in range(1,10): time.sleep(1) - print "%d seconds have passed" % i + print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() @@ -73,7 +73,7 @@ case - by using multiprocessing. To use it, just pass print "Start" for i in range(1,10): time.sleep(1) - print "%d seconds have passed" % i + print("{} seconds have passed".format(i)) if __name__ == '__main__': mytest() From 6a39ee35a457266d5f7956ce314c784b1be51a2a Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Fri, 10 Nov 2017 20:16:56 +0100 Subject: [PATCH 69/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 94 ++++++++++++++++++++------ 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 9a92e28..e9e82b1 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -35,15 +35,23 @@ def _raise_exception(exception, exception_message): raise exception(exception_message) -def timeout(timeout=None, use_signals=True, timeout_exception=None, exception_message=None): +def timeout(dec_timeout=None, use_signals=True, timeout_exception=None, exception_message=None, dec_allow_eval=False): """Add a timeout parameter to a function and return it. + ToDo : Traceback information when using no_signals + integrate tblib in order to get exceptions when use_signals=False + (see https://pypi.python.org/pypi/tblib) + Usage: @timeout(3) def foo(): pass + Overriding the timeout: + + foo(dec_timeout=5) + Usage without decorating a function : def foo2(a,b,c): @@ -51,46 +59,88 @@ def foo2(a,b,c): timeout(3)(foo2)(1,2,c=3) - :param timeout: optional time limit in seconds or fractions of a second. If None is passed, - no seconds is applied. This adds some flexibility to the usage: you can disable timing - out depending on the settings. - :type timeout: float - :param use_signals: flag indicating whether signals should be used for timing function out or the multiprocessing - When using multiprocessing, seconds granularity is limited to 10ths of a second. - :type use_signals: bool - :param timeout_exception: the Exception to be raised when timeout occurs, default = TimeoutException - :type timeout_exception: Exception - :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. - :type exception_message: str - :raises: TimeoutError if time limit is reached - :rtype: Exception - - :returns: the Result of the wrapped function + Usage with eval (beware, security hazard, no user input values here): + read : https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html before usage ! + + def class Foo(object): + def __init__(self,x): + self.x=x + + @timeout('instance.x', dec_allow_eval=True) + def foo2(self): + print('swallow') + + @timeout(1) + def foo3(self): + print('parrot') + + # or override via kwarg : + my_foo = Foo(3) + my_foo.foo2(dec_timeout='instance.x * 2.5 +1') + my_foo.foo3(dec_timeout='instance.x * 2.5 +1', dec_allow_eval=True) + + + :param dec_timeout: * optional time limit in seconds or fractions of a second. If None is passed, + no seconds is applied. This adds some flexibility to the usage: you can disable timing + out depending on the settings. dec_timeout will always be overridden by a + kwarg passed to the wrapped function, class or class method. + :param use_signals: flag indicating whether signals should be used or the multiprocessing + when using multiprocessing, timeout granularity is limited to 10ths of a second. + :param timeout_exception: the Exception to be raised when timeout occurs, default = TimeoutException + :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. + :param dec_allow_eval: * allows a string in parameter dec_timeout what will be evaluated. Beware this can + be a security issue. This is very powerful, but is also very dangerous if you + accept strings to evaluate from untrusted input. + read: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html + + If enabled, the parameter of the function dec_timeout, or the parameter passed + by kwarg dec_timeout will be evaluated if its type is string. You can access : + wrapped (the function object) + instance Example: 'instance.x' - see example above or doku + args Example: 'args[0]' - the timeout is the first argument in args + kwargs Example: 'kwargs["max_time"] * 2' + + * all parameters starting with dec_ can be overridden via kwargs passed to the wrapped function. + + :type dec_timeout: float + :type use_signals: bool + :type timeout_exception: Exception + :type exception_message: str + + + :raises: TimeoutError if time limit is reached + + :returns: the Result of the wrapped function It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. + """ + @wrapt.decorator def wrapper(wrapped, instance, args, kwargs): - exc_msg = exception_message - new_timeout = kwargs.pop('dec_timeout', timeout) + exc_msg = exception_message # make mutable + decm_allow_eval = kwargs.pop('dec_allow_eval', dec_allow_eval) # make mutable and get possibly kwarg + decm_timeout = kwargs.pop('dec_timeout', dec_timeout) # make mutable and get possibly kwarg + if decm_allow_eval and isinstance(dec_timeout,str): + decm_timeout = eval(decm_timeout) # if allowed evaluate timeout if not exc_msg: - exc_msg = 'Function {f} timed out after {s} seconds'.format(f=wrapped.__name__, s=new_timeout) - if not new_timeout: + exc_msg = 'Function {f} timed out after {s} seconds'.format(f=wrapped.__name__, s=decm_timeout) + if not decm_timeout: return wrapped(*args, **kwargs) else: if b_signals: def handler(signum, frame): _raise_exception(timeout_exception, exc_msg) old = signal.signal(signal.SIGALRM, handler) - signal.setitimer(signal.ITIMER_REAL, new_timeout) + signal.setitimer(signal.ITIMER_REAL, decm_timeout) try: return wrapped(*args, **kwargs) finally: signal.setitimer(signal.ITIMER_REAL, 0) signal.signal(signal.SIGALRM, old) else: - timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, new_timeout) + timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, decm_timeout) return timeout_wrapper(*args, **kwargs) # never use signals with windows - it wont work anyway From 8fc2834b99a2b4eab3bc49268cf09bc09953b306 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Fri, 10 Nov 2017 20:18:19 +0100 Subject: [PATCH 70/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 0a255e0..8397872 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -5,7 +5,7 @@ import time -if sys.version_info < (3, 3): # there is no TimeoutError < Python 3.2 +if sys.version_info < (3, 3): # there is no TimeoutError < Python 3.3 TimeoutError = AssertionError @@ -64,14 +64,14 @@ def f(): def test_timeout_ok(use_signals): - @timeout(timeout=2, use_signals=use_signals) + @timeout(dec_timeout=2, use_signals=use_signals) def f(): time.sleep(1) f() def test_function_name(use_signals): - @timeout(timeout=2, use_signals=use_signals) + @timeout(dec_timeout=2, use_signals=use_signals) def func_name(): pass @@ -80,7 +80,7 @@ def func_name(): def test_timeout_pickle_error(): """Test that when a pickle error occurs a timeout error is raised.""" - @timeout(timeout=1, use_signals=False) + @timeout(dec_timeout=1, use_signals=False) def f(): time.sleep(0.1) @@ -92,7 +92,7 @@ class Test(object): def test_timeout_custom_exception_message(): - @timeout(timeout=1, exception_message="Custom fail message") + @timeout(dec_timeout=1, exception_message="Custom fail message") def f(): time.sleep(2) with pytest.raises(TimeoutError, match="Custom fail message"): @@ -100,7 +100,7 @@ def f(): def test_timeout_default_exception_message(): - @timeout(timeout=1) + @timeout(dec_timeout=1) def f(): time.sleep(2) with pytest.raises(TimeoutError, match="Function f timed out after 1 seconds"): From 773844d811affb759c7f490c4bd8c6f7a04e253f Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Fri, 10 Nov 2017 20:21:46 +0100 Subject: [PATCH 71/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index e9e82b1..7110c2a 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -89,7 +89,7 @@ def foo3(self): :param timeout_exception: the Exception to be raised when timeout occurs, default = TimeoutException :param exception_message: the Message for the Exception. Default: 'Function {f} timed out after {s} seconds. :param dec_allow_eval: * allows a string in parameter dec_timeout what will be evaluated. Beware this can - be a security issue. This is very powerful, but is also very dangerous if you + be a security issue. This is very powerful, but is also very dangerous if you accept strings to evaluate from untrusted input. read: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html @@ -122,7 +122,7 @@ def wrapper(wrapped, instance, args, kwargs): exc_msg = exception_message # make mutable decm_allow_eval = kwargs.pop('dec_allow_eval', dec_allow_eval) # make mutable and get possibly kwarg decm_timeout = kwargs.pop('dec_timeout', dec_timeout) # make mutable and get possibly kwarg - if decm_allow_eval and isinstance(dec_timeout,str): + if decm_allow_eval and isinstance(dec_timeout, str): decm_timeout = eval(decm_timeout) # if allowed evaluate timeout if not exc_msg: exc_msg = 'Function {f} timed out after {s} seconds'.format(f=wrapped.__name__, s=decm_timeout) From 6b6a330b189bdf7ace3b40bf95fca95a8bc36717 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Tue, 11 Sep 2018 08:08:28 +0200 Subject: [PATCH 72/84] Update .travis.yml --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 748db6d..0b17df5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ python: - '3.4' - '3.5' - '3.6' +- '3.7-dev' - 'pypy' - 'pypy3' install: @@ -18,10 +19,10 @@ after_success: - pip install -e . - py.test --cov=timeout_decorator --cov-report=term-missing tests - coveralls -deploy: - provider: pypi - user: png - password: - secure: ZXoq3kgfu+IICjhhmQZr0s0xE6bvWzH04GjdE/VL4BxdDdGI4fHEwudGEjzLXJbt2d09vNOO67Nqam+MwPWtq+WZEP69g/Fhyy4kbkuUl/CMeqashQzU/N+3lwv97Y2qvzTUwDnSoz4zyBFu67SSrovKruFsYaiH00bwvWcvLa0= - on: - python: 2.7 +# deploy: +# provider: pypi +# user: png +# password: +# secure: ZXoq3kgfu+IICjhhmQZr0s0xE6bvWzH04GjdE/VL4BxdDdGI4fHEwudGEjzLXJbt2d09vNOO67Nqam+MwPWtq+WZEP69g/Fhyy4kbkuUl/CMeqashQzU/N+3lwv97Y2qvzTUwDnSoz4zyBFu67SSrovKruFsYaiH00bwvWcvLa0= +# on: +# python: 2.7 From 83e6f098979c8c617107e218a06fa480d460fc26 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Tue, 11 Sep 2018 08:09:23 +0200 Subject: [PATCH 73/84] Update .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0b17df5..681da81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,6 @@ sudo: false python: - '2.6' - '2.7' -- '3.2' -- '3.3' - '3.4' - '3.5' - '3.6' From da1a85efa8f5e14be9da361835febc50a7db1381 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 12:17:34 +0200 Subject: [PATCH 74/84] Update timeout_decorator.py avoid zombie processes, thanks to woshihaoren --- timeout_decorator/timeout_decorator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 7110c2a..64a8689 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -205,7 +205,6 @@ 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 @@ -220,6 +219,8 @@ def value(self): """Read-only property containing data returned from function.""" if self.ready is True: flag, load = self.__queue.get() + self.__process.join(1) # when self.__queue.get() exits, maybe __process is still alive, + # then it might zombie the process. so lets join it explicitly if flag: return load raise load From a3118669c25d2109afb6f97cdaa89236e3367c98 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 12:23:13 +0200 Subject: [PATCH 75/84] Update timeout_decorator.py fix pep8 issues --- timeout_decorator/timeout_decorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 64a8689..b149f39 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -219,8 +219,8 @@ def value(self): """Read-only property containing data returned from function.""" if self.ready is True: flag, load = self.__queue.get() - self.__process.join(1) # when self.__queue.get() exits, maybe __process is still alive, - # then it might zombie the process. so lets join it explicitly + self.__process.join(1) # when self.__queue.get() exits, maybe __process is still alive, + # then it might zombie the process. so lets join it explicitly if flag: return load raise load From 9908a000d2efe00d6a7e5047003e49e9c18c976e Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 12:31:21 +0200 Subject: [PATCH 76/84] Update timeout_decorator.py fix pep8 --- timeout_decorator/timeout_decorator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index b149f39..1ed7f27 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -219,8 +219,9 @@ def value(self): """Read-only property containing data returned from function.""" if self.ready is True: flag, load = self.__queue.get() - self.__process.join(1) # when self.__queue.get() exits, maybe __process is still alive, - # then it might zombie the process. so lets join it explicitly + # when self.__queue.get() exits, maybe __process is still alive, + # then it might zombie the process. so lets join it explicitly + self.__process.join(1) if flag: return load raise load From 8101c74061759e415d8d42a0cdf2a5c07e74e2af Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:17:59 +0200 Subject: [PATCH 77/84] Update timeout_decorator.py --- timeout_decorator/timeout_decorator.py | 116 ++++++++++++------------- 1 file changed, 54 insertions(+), 62 deletions(-) diff --git a/timeout_decorator/timeout_decorator.py b/timeout_decorator/timeout_decorator.py index 1ed7f27..8cf34f8 100644 --- a/timeout_decorator/timeout_decorator.py +++ b/timeout_decorator/timeout_decorator.py @@ -1,15 +1,16 @@ """ Timeout decorator. - :copyright: (c) 2012-2013 by PN. + :copyright: (c) 2017 by Robert Nowotny :license: MIT, see LICENSE for more details. """ -import multiprocessing -import multiprocessing.pool +import dill # dill is much more tolerant then pickle, so lets use +import multiprocess # multiprocess instead of multiprocessing import platform import signal import sys +import threading import time import wrapt @@ -19,7 +20,7 @@ # http://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ # Used work of Stephen "Zero" Chappell - +# Used work of https://github.com/pnpnpn/timeout-decorator if sys.version_info < (3, 3): TimeoutError = AssertionError # there is no TimeoutError below Python 3.3 @@ -37,49 +38,34 @@ def _raise_exception(exception, exception_message): def timeout(dec_timeout=None, use_signals=True, timeout_exception=None, exception_message=None, dec_allow_eval=False): """Add a timeout parameter to a function and return it. - ToDo : Traceback information when using no_signals integrate tblib in order to get exceptions when use_signals=False (see https://pypi.python.org/pypi/tblib) - Usage: - @timeout(3) def foo(): pass - Overriding the timeout: - foo(dec_timeout=5) - Usage without decorating a function : - def foo2(a,b,c): pass - timeout(3)(foo2)(1,2,c=3) - Usage with eval (beware, security hazard, no user input values here): read : https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html before usage ! - def class Foo(object): def __init__(self,x): self.x=x - @timeout('instance.x', dec_allow_eval=True) def foo2(self): print('swallow') - @timeout(1) def foo3(self): print('parrot') - # or override via kwarg : my_foo = Foo(3) my_foo.foo2(dec_timeout='instance.x * 2.5 +1') my_foo.foo3(dec_timeout='instance.x * 2.5 +1', dec_allow_eval=True) - - :param dec_timeout: * optional time limit in seconds or fractions of a second. If None is passed, no seconds is applied. This adds some flexibility to the usage: you can disable timing out depending on the settings. dec_timeout will always be overridden by a @@ -92,33 +78,29 @@ def foo3(self): be a security issue. This is very powerful, but is also very dangerous if you accept strings to evaluate from untrusted input. read: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html - If enabled, the parameter of the function dec_timeout, or the parameter passed by kwarg dec_timeout will be evaluated if its type is string. You can access : wrapped (the function object) instance Example: 'instance.x' - see example above or doku args Example: 'args[0]' - the timeout is the first argument in args kwargs Example: 'kwargs["max_time"] * 2' - * all parameters starting with dec_ can be overridden via kwargs passed to the wrapped function. - :type dec_timeout: float :type use_signals: bool :type timeout_exception: Exception :type exception_message: str - - :raises: TimeoutError if time limit is reached - :returns: the Result of the wrapped function - It is illegal to pass anything other than a function as the first parameter. The function is wrapped and returned to the caller. - """ @wrapt.decorator def wrapper(wrapped, instance, args, kwargs): + if (not b_signals) and (not dill.pickles(wrapped)): + s_err = 'can not pickle {wn}, bad types {bt}'.format(wn=wrapped.__name__, bt=dill.detect.badtypes(wrapped)) + raise dill.PicklingError(s_err) + exc_msg = exception_message # make mutable decm_allow_eval = kwargs.pop('dec_allow_eval', dec_allow_eval) # make mutable and get possibly kwarg decm_timeout = kwargs.pop('dec_timeout', dec_timeout) # make mutable and get possibly kwarg @@ -143,14 +125,28 @@ def handler(signum, frame): timeout_wrapper = _Timeout(wrapped, timeout_exception, exc_msg, decm_timeout) return timeout_wrapper(*args, **kwargs) - # never use signals with windows - it wont work anyway - b_signals = False - if use_signals and not platform.system().lower().startswith('win'): - b_signals = True + # automatically disable signals when they cant be used + if can_use_timeout_signals(): + b_signals = use_signals + else: + b_signals = False + return wrapper -def _target(queue, function, *args, **kwargs): +def can_use_timeout_signals(): + """ gives True when we can use timeout signals, otherwise False""" + if platform.system().lower().startswith('win'): # on Windows we cant use Signals + return False + if sys.version_info < (3, 4): + # on old python use this method - we can only use Signals in the Main Thread + return isinstance(threading.current_thread(), threading._MainThread) + else: + # much nicer after python 3.4 - we can only use Signals in the Main Thread + return threading.current_thread() == threading.main_thread() + + +def _target(child_conn, 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 @@ -158,9 +154,11 @@ def _target(queue, function, *args, **kwargs): raised, it is returned to _Timeout to be raised by the value property. """ try: - queue.put((True, function(*args, **kwargs))) + child_conn.send((True, function(*args, **kwargs))) except: - queue.put((False, sys.exc_info()[1])) + child_conn.send((False, sys.exc_info()[1])) + finally: + child_conn.close() class _Timeout(object): @@ -179,9 +177,9 @@ def __init__(self, function, timeout_exception, exception_message, limit): 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() + self.__process = None + self.__parent_conn = None + self.__child_conn = None def __call__(self, *args, **kwargs): """Execute the embedded function object asynchronously. @@ -189,39 +187,33 @@ def __call__(self, *args, **kwargs): requires that "ready" be intermittently polled. If and when it is True, the "value" property may then be checked for returned data. """ - self.__queue = multiprocessing.Queue(1) - args = (self.__queue, self.__function) + args - self.__process = multiprocessing.Process(target=_target, - args=args, - kwargs=kwargs) + self.__parent_conn, self.__child_conn = multiprocess.Pipe(duplex=False) + + args = (self.__child_conn, self.__function) + args + self.__process = multiprocess.Process(target=_target, args=args, kwargs=kwargs) self.__process.daemon = True self.__process.start() - self.__timeout = self.__limit + time.time() - while not self.ready: - time.sleep(0.01) - return self.value + if self.__parent_conn.poll(self.__limit): + return self.value + else: + self.cancel() def cancel(self): """Terminate any possible execution of the embedded function.""" + self.__parent_conn.close() 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.__timeout < time.time(): - self.cancel() - return self.__queue.full() and not self.__queue.empty() + _raise_exception(self.__timeout_exception, self.__exception_message) @property def value(self): - """Read-only property containing data returned from function.""" - if self.ready is True: - flag, load = self.__queue.get() - # when self.__queue.get() exits, maybe __process is still alive, - # then it might zombie the process. so lets join it explicitly - self.__process.join(1) - if flag: - return load - raise load + flag, load = self.__parent_conn.recv() + self.__parent_conn.close() + # when self.__queue.get() exits, maybe __process is still alive, + # then it might zombie the process. so join it explicitly + self.__process.join(1) + + if flag: + return load + raise load From e5a896659f702407bbff924d0fbc9a7ba0cac95d Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:18:56 +0200 Subject: [PATCH 78/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 43 +++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 8397872..473d919 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,8 +1,9 @@ """Timeout decorator tests.""" -from timeout_decorator import timeout +from wrapt_timeout_decorator import timeout import pytest import sys import time +from dill import PicklingError if sys.version_info < (3, 3): # there is no TimeoutError < Python 3.3 @@ -23,15 +24,24 @@ def f(): f() -def test_timeout_class_method(use_signals): +def test_timeout_class_method_use_signals(): class c(): - @timeout(1, use_signals=use_signals) + @timeout(1, use_signals=True) def f(self): time.sleep(2) with pytest.raises(TimeoutError): c().f() +def test_timeout_class_method_dont_use_signals(): + class c(): + @timeout(1, use_signals=False) + def f(self): + time.sleep(2) + with pytest.raises(PicklingError): + c().f() + + def test_timeout_kwargs(use_signals): @timeout(3, use_signals=use_signals) def f(): @@ -75,11 +85,13 @@ def test_function_name(use_signals): def func_name(): pass + func_name() assert func_name.__name__ == 'func_name' def test_timeout_pickle_error(): - """Test that when a pickle error occurs a timeout error is raised.""" + """Test that when a pickle error occurs a timeout error is raised""" + # codecov start ignore @timeout(dec_timeout=1, use_signals=False) def f(): time.sleep(0.1) @@ -87,7 +99,8 @@ def f(): class Test(object): pass return Test() - with pytest.raises(TimeoutError): + # codecov end ignore + with pytest.raises(PicklingError): f() @@ -105,3 +118,23 @@ def f(): time.sleep(2) with pytest.raises(TimeoutError, match="Function f timed out after 1 seconds"): f() + + +def test_timeout_eval(use_signals): + """ Test Eval """ + @timeout(dec_timeout='args[0] * 2', use_signals=use_signals, dec_allow_eval=True) + def f(x): + time.sleep(0.4) + f(0.3) + with pytest.raises(TimeoutError): + f(0.1) + + +def test_exception(use_signals): + """ Test Exception """ + @timeout(0.4, use_signals=use_signals) + def f(): + raise AssertionError + + with pytest.raises(AssertionError): + f() From fab625aaeb1fee4d1799116e7b0464db45f1f7ae Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:22:20 +0200 Subject: [PATCH 79/84] Update test_timeout_decorator.py --- tests/test_timeout_decorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_timeout_decorator.py b/tests/test_timeout_decorator.py index 473d919..3692f8e 100644 --- a/tests/test_timeout_decorator.py +++ b/tests/test_timeout_decorator.py @@ -1,5 +1,5 @@ """Timeout decorator tests.""" -from wrapt_timeout_decorator import timeout +from timeout_decorator import timeout import pytest import sys import time From 1620b8c29ecd229113bc77c5b5a765a3b0911dc9 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:26:49 +0200 Subject: [PATCH 80/84] Update .travis.yml --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 681da81..385b023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,14 @@ python: - 'pypy3' install: - if [[ $TRAVIS_PYTHON_VERSION == 3.2 ]]; then pip install -U "virtualenv<14.0.0"; fi -- pip install python-coveralls tox tox-travis wrapt +- pip install tox tox-travis dill multiprocess wrapt pytest-cov coverage codecov script: tox --recreate + after_success: - pip install -e . -- py.test --cov=timeout_decorator --cov-report=term-missing tests -- coveralls +- py.test --cov=./ +- codecov + # deploy: # provider: pypi # user: png From 45289e50c06078c3cd98a52854c69bba9fcf25ca Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:30:36 +0200 Subject: [PATCH 81/84] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index ba11553..5007e07 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ +dill +multiprocess wrapt From 1ffc2be8213884b389482c11f0284b9ef2e6cf05 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 18:34:04 +0200 Subject: [PATCH 82/84] Update tox.ini --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index f59cd11..db05c13 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,9 @@ deps = py32: pytest<3.0 py{26,27,33,34,35,36}: pytest>=3.0 pytest-pep8==1.0.6 + dill wrapt + multiprocess [pytest] addopts = -vvl From 018ff70169cc4a4dcbacfaa2824aeb2324b2c7a5 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 19:11:05 +0200 Subject: [PATCH 83/84] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b657211..831b1ae 100644 --- a/setup.py +++ b/setup.py @@ -34,5 +34,5 @@ author_email='pn.appdev@gmail.com', url='https://github.com/bitranox/timeout-decorator', packages=['timeout_decorator'], - install_requires=['wrapt'], + install_requires=['dill', 'multiprocess', 'wrapt'], classifiers=CLASSIFIERS) From 0eaf7654a6cbb8a971c12a9043460ce39f3a8b31 Mon Sep 17 00:00:00 2001 From: Robert Nowotny Date: Thu, 13 Sep 2018 19:20:58 +0200 Subject: [PATCH 84/84] Update README.rst --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2dcea7b..045efa6 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ Timeout decorator ================= -|Build Status| |Pypi Status| |Coveralls Status| +|Build Status| |Pypi Status| |Codecov Status| Installation ------------ @@ -107,5 +107,5 @@ See `License file