{ "info": { "author": "Robert Nowotny", "author_email": "rnowotny1966@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "wrapt_timeout_decorator\n=======================\n\n|Pypi Status| |license| |maintenance| |jupyter|\n\n|Build Status| |Codecov Status| |Better Code| |code climate| |snyk security|\n\n.. |license| image:: https://img.shields.io/github/license/webcomics/pywine.svg\n :target: http://en.wikipedia.org/wiki/MIT_License\n.. |maintenance| image:: https://img.shields.io/maintenance/yes/2019.svg\n.. |Build Status| image:: https://travis-ci.org/bitranox/wrapt_timeout_decorator.svg?branch=master\n :target: https://travis-ci.org/bitranox/wrapt_timeout_decorator\n.. for the pypi status link note the dashes, not the underscore !\n.. |Pypi Status| image:: https://badge.fury.io/py/wrapt-timeout-decorator.svg\n :target: https://badge.fury.io/py/wrapt_timeout_decorator\n.. |Codecov Status| image:: https://codecov.io/gh/bitranox/wrapt_timeout_decorator/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/bitranox/wrapt_timeout_decorator\n.. |Better Code| image:: https://bettercodehub.com/edge/badge/bitranox/wrapt_timeout_decorator?branch=master\n :target: https://bettercodehub.com/results/bitranox/wrapt_timeout_decorator\n.. |snyk security| image:: https://snyk.io/test/github/bitranox/wrapt_timeout_decorator/badge.svg\n :target: https://snyk.io/test/github/bitranox/wrapt_timeout_decorator\n.. |jupyter| image:: https://mybinder.org/badge.svg\n :target: https://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=jupyter_test_wrapt_timeout_decorator.ipynb\n.. |code climate| image:: https://api.codeclimate.com/v1/badges/2b2b6589f80589689c2b/maintainability\n :target: https://codeclimate.com/github/bitranox/wrapt_timeout_decorator/maintainability\n :alt: Maintainability\n\nthere are many timeout decorators out there - that one focuses on correctness when using with Classes, methods,\nclass methods, static methods and so on, preserving also the traceback information for Pycharm debugging.\n\nThere is also a powerful eval function, it allows to read the desired timeout value even from Class attributes.\n\nIt is very flexible and can be used with python >= 3.5, pypy3 and probably other dialects.\n\nThere are two timeout strategies implemented, the ubiquitous method using \"Signals\" and the second using Multiprocessing.\nUsing \"Signals\" is slick and lean, but there are nasty caveats, please check section `Caveats using Signals`_\n\nThe default strategy is therefore using Multiprocessing, but You can also use Signals, You have been warned !\n\nDue to the lack of signals on Windows, or for threaded functions (in a subthread) where signals cant be used, Your only choice is Multiprocessing,\nthis is set automatically.\n\nUnder Windows the decorated function and results needs to be pickable.\nFor that purpose we use \"multiprocess\" and \"dill\" instead of \"multiprocessing\" and \"pickle\", in order to be able to use this decorator on more sophisticated objects.\nCommunication to the subprocess is done via \"multiprocess.pipe\" instead of \"queue\", which is faster and might also work on Amazon AWS.\n\n`100% code coverage `_, mypy static type checking, tested under `Linux, OsX, Windows and Wine `_, automatic daily builds and monitoring\n\n----\n\n- `Try it Online`_\n- `Installation and Upgrade`_\n- `Basic Usage`_\n- `use with Windows`_\n- `Caveats using Signals`_\n- `nested Timeouts`_\n- `Alternative Exception`_\n- `Parameters`_\n- `Override Parameters`_\n- `Multithreading`_\n- `use as function not as decorator`_\n- `use powerful eval function`_\n- `detect pickle errors`_\n- `Logging in decorated functions`_\n- `hard timeout`_ or - when the timout should start ?\n- `Requirements`_\n- `Acknowledgements`_\n- `Contribute`_\n- `Report Issues `_\n- `Pull Request `_\n- `Code of Conduct `_\n- `License`_\n- `Changelog`_\n\n----\n\nTry it Online\n-------------\n\nYou might try it right away in Jupyter Notebook by using the \"launch binder\" badge, or click `here `_\n\nInstallation and Upgrade\n------------------------\n\nFrom source code:\n\n.. code-block:: bash\n\n # normal install\n python setup.py install\n # test without installing\n python setup.py test\n\nvia pip latest Release:\n\n.. code-block:: bash\n\n # latest Release from pypi\n pip install wrapt_timeout_decorator\n\n # test without installing\n pip install wrapt_timeout_decorator --install-option test\n\nvia pip latest Development Version:\n\n.. code-block:: bash\n\n # upgrade all dependencies regardless of version number (PREFERRED)\n pip install --upgrade git+https://github.com/bitranox/wrapt_timeout_decorator.git --upgrade-strategy eager\n # normal install\n pip install --upgrade git+https://github.com/bitranox/wrapt_timeout_decorator.git\n # test without installing\n pip install git+https://github.com/bitranox/wrapt_timeout_decorator.git --install-option test\n\nvia requirements.txt:\n\n.. code-block:: bash\n\n # Insert following line in Your requirements.txt:\n # for the latest Release:\n wrapt_timeout_decorator\n # for the latest Development Version :\n git+https://github.com/bitranox/wrapt_timeout_decorator.git\n\n # to install and upgrade all modules mentioned in requirements.txt:\n pip install --upgrade -r //requirements.txt\n\nvia python:\n\n.. code-block:: python\n\n # for the latest Release\n python -m pip install upgrade wrapt_timeout_decorator\n\n # for the latest Development Version\n python -m pip install upgrade git+https://github.com/bitranox/wrapt_timeout_decorator.git\n\nBasic Usage\n-----------\n\n.. code-block:: py\n\n import time\n from wrapt_timeout_decorator import *\n\n @timeout(5)\n def mytest(message):\n # this example does NOT work on windows, please check the section\n # \"use with Windows\" in the README.rst\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed'.format(i))\n\n if __name__ == '__main__':\n mytest('starting')\n\nuse with Windows\n----------------\n\nFor the impatient:\n\nAll You need to do is to put the decorated function into another Module, NOT in the main program.\n\nFor those who want to dive deeper :\n\n\nOn Windows the main module is imported again (but with a name != 'main') because Python is trying to simulate\na forking-like behavior on a system that doesn't support forking. multiprocessing tries to create an environment\nsimilar to Your main process by importing the main module again with a different name. Thats why You need to shield\nthe entry point of Your program with the famous \" if __name__ == '__main__': \"\n\n.. code-block:: py\n\n import lib_foo\n\n def some_module():\n lib_foo.function_foo()\n\n def main():\n some_module()\n\n\n # here the subprocess stops loading, because __name__ is NOT '__main__'\n if __name__ = '__main__':\n main()\n\nThis is a problem of Windows OS, because the Windows Operating System does not support \"fork\"\n\nYou can find more information on that here:\n\nhttps://stackoverflow.com/questions/45110287/workaround-for-using-name-main-in-python-multiprocessing\n\nhttps://docs.python.org/2/library/multiprocessing.html#windows\n\nSince main.py is loaded again with a different name but \"__main__\", the decorated function now points to objects that do not exist anymore, therefore You need to put the decorated Classes and functions into another module.\nIn general (especially on windows) , the main() program should not have anything but the main function, the real thing should happen in the modules.\nI am also used to put all settings or configurations in a different file - so all processes or threads can access them (and also to keep them in one place together, not to forget typing hints and name completion in Your favorite editor)\n\nThe \"dill\" serializer is able to serialize also the __main__ context, that means the objects in our example are pickled to \"__main__.lib_foo\", \"__main__.some_module\",\"__main__.main\" etc.\nWe would not have this limitation when using \"pickle\" with the downside that \"pickle\" can not serialize following types:\n\nfunctions with yields, nested functions, lambdas, cell, method, unboundmethod, module, code, methodwrapper,\ndictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, wrapperdescriptor, xrange, slice,\nnotimplemented, ellipsis, quit\n\nadditional dill supports:\n\nsave and load python interpreter sessions, save and extract the source code from functions and classes, interactively diagnose pickling errors\n\nTo support more types with the decorator, we selected dill as serializer, with the small downside that methods and classes can not be decorated in the __main__ context, but need to reside in a module.\n\nYou can find more information on that here:\nhttps://stackoverflow.com/questions/45616584/serializing-an-object-in-main-with-pickle-or-dill\n\n**Timing :** Since spawning takes some unknown timespan (all imports needs to be done again !), You can specify when the timeout should start, please read the section `hard timeout`_\n\nHere an example that will work on Linux but wont work on Windows (the variable \"name\" and the function \"sleep\" wont be found in the spawned process :\n\n\n.. code-block:: py\n\n main.py:\n\n from time import sleep\n from wrapt_timeout_decorator import *\n\n name=\"my_var_name\"\n\n @timeout(5, use_signals=False)\n def mytest():\n # this example does NOT work on windows, please check the example below !\n # You need to move this function into a module to be able to run it on windows.\n print(\"Start \", name)\n for i in range(1,10):\n sleep(1)\n print(\"{} seconds have passed\".format(i))\n return i\n\n\n if __name__ == '__main__':\n mytest()\n\n\nhere the same example, which will work on Windows:\n\n\n.. code-block:: py\n\n\n # my_program_main.py:\n\n import lib_test\n\n def main():\n lib_test.mytest()\n\n if __name__ == '__main__':\n main()\n\n\n.. code-block:: py\n\n\n # conf_my_program.py:\n\n class ConfMyProgram(object):\n def __init__(self):\n self.name:str = 'my_var_name'\n\n conf_my_program = ConfMyProgram()\n\n\n.. code-block:: py\n\n # lib_test.py:\n\n from wrapt_timeout_decorator import *\n from time import sleep\n from conf_my_program import conf_my_program\n\n # use_signals = False is not really necessary here, it is set automatically under Windows\n # but You can force NOT to use Signals under Linux\n @timeout(5, use_signals=False)\n def mytest():\n print(\"Start \", conf_my_program.name)\n for i in range(1,10):\n sleep(1)\n print(\"{} seconds have passed\".format(i))\n return i\n\nCaveats using Signals\n---------------------\n\nas ABADGER1999 points out in his blog https://anonbadger.wordpress.com/2018/12/15/python-signal-handlers-and-exceptions/\nusing signals and the TimeoutException is probably not the best idea - because it can be catched in the decorated function.\n\nOf course You can use Your own Exception, derived from the Base Exception Class, but the code might still not work as expected -\nsee the next example - You may try it out in `jupyter `_:\n\n.. code-block:: py\n\n import time\n from wrapt_timeout_decorator import *\n\n # caveats when using signals - the TimeoutError raised by the signal may be catched\n # inside the decorated function.\n # So You might use Your own Exception, derived from the base Exception Class.\n # In Python-3.7.1 stdlib there are over 300 pieces of code that will catch your timeout\n # if you were to base an exception on Exception. If you base your exception on BaseException,\n # there are still 231 places that can potentially catch your exception.\n # You should use use_signals=False if You want to make sure that the timeout is handled correctly !\n # therefore the default value for use_signals = False on this decorator !\n\n @timeout(5, use_signals=True)\n def mytest(message):\n try:\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed - lets assume we read a big file here'.format(i))\n # TimeoutError is a Subclass of OSError - therefore it is catched here !\n except OSError:\n for i in range(1,10):\n time.sleep(1)\n print('Whats going on here ? - Ooops the Timeout Exception is catched by the OSError ! {}'.format(i))\n except Exception:\n # even worse !\n pass\n except:\n # the worst - and exists more then 300x in actual Python 3.7 stdlib Code !\n # so You never really can rely that You catch the TimeoutError when using Signals !\n pass\n\n\n if __name__ == '__main__':\n try:\n mytest('starting')\n print('no Timeout Occured')\n except TimeoutError():\n # this will never be printed because the decorated function catches implicitly the TimeoutError !\n print('Timeout Occured')\n\nnested Timeouts\n----------------\n\nsince there is only ONE ALARM Signal on Unix per process, You need to use use_signals = False for nested timeouts.\nThe outmost decorator might use Signals, all nested Decorators needs to use use_signals=False (the default)\nYou may try it out in `jupyter `_:\n\n.. code-block:: py\n\n # main.py\n import mylib\n\n # this example will work on Windows and Linux\n # since the decorated function is not in the __main__ scope but in another module !\n\n if __name__ == '__main__':\n mylib.outer()\n\n\n.. code-block:: py\n\n # mylib.py\n from wrapt_timeout_decorator import *\n import time\n\n # this example will work on Windows and Linux\n # since the decorated function is not in the __main__ scope but in another module !\n\n @timeout(1, use_signals=True)\n def outer():\n inner()\n\n @timeout(5)\n def inner():\n time.sleep(3)\n print(\"Should never be printed if you call outer()\")\n\nAlternative Exception\n---------------------\n\nSpecify an alternate exception to raise on timeout:\n\n.. code-block:: py\n\n import time\n from wrapt_timeout_decorator import *\n\n @timeout(5, timeout_exception=StopIteration)\n def mytest(message):\n # this example does NOT work on windows, please check the section\n # \"use with Windows\" in the README.rst\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed'.format(i))\n\n if __name__ == '__main__':\n mytest('starting')\n\nParameters\n----------\n\n.. code-block:: py\n\n @timeout(dec_timeout, use_signals, timeout_exception, exception_message, dec_allow_eval, dec_hard_timeout)\n def decorated_function(*args, **kwargs):\n # interesting things happens here ...\n ...\n\n \"\"\"\n dec_timeout the timeout period in seconds, or a string that can be evaluated when dec_allow_eval = True\n type: float, integer or string\n default: None (no Timeout set)\n can be overridden by passing the kwarg dec_timeout to the decorated function*\n\n use_signals if to use signals (linux, osx) to realize the timeout. The most accurate method but with caveats.\n By default the Wrapt Timeout Decorator does NOT use signals !\n Please note that signals can only be used in the main thread and only on linux. In all other cases\n (not the main thread, or under Windows) signals cant be used anyway and will be disabled automatically.\n In general You dont need to set use_signals Yourself. Please read the section - `Caveats using Signals`_\n type: boolean\n default: False\n can be overridden by passing the kwarg use_signals to the decorated function*\n\n timeout_exception the Exception that will be raised if a timeout occurs.\n type: exception\n default: TimeoutError, on Python < 3.3: Assertion Error (since TimeoutError does not exist on that Python Versions)\n\n exception_message custom Exception message.\n type: str\n default : 'Function {function_name} timed out after {dec_timeout} seconds' (will be formatted)\n\n dec_allow_eval will allow to evaluate the parameter dec_timeout.\n If enabled, the parameter of the function dec_timeout, or the parameter passed\n by kwarg dec_timeout will be evaluated if its type is string. You can access :\n wrapped (the decorated function object and all the exposed objects below)\n instance Example: 'instance.x' - see example above or doku\n args Example: 'args[0]' - the timeout is the first argument in args\n kwargs Example: 'kwargs[\"max_time\"] * 2'\n type: bool\n default: false\n can be overridden by passing the kwarg dec_allow_eval to the decorated function*\n\n dec_hard_timeout only relevant when signals can not be used. In that case a new process needs to be created.\n The creation of the process on windows might take 0.5 seconds and more, depending on the size\n of the main module and modules to be imported. Especially useful for small timeout periods.\n\n dec_hard_timeout = True : the decorated function will time out after dec_timeout, no matter what -\n that means if You set 0.1 seconds here, the subprocess can not be created in that time and the\n function will always time out and never run.\n\n dec_hard_timeout = False : the decorated function will time out after the called function\n is allowed to run for dec_timeout seconds. The time needed to create that process is not considered.\n That means if You set 0.1 seconds here, and the time to create the subprocess is 0.5 seconds,\n the decorated function will time out after 0.6 seconds in total, allowing the decorated function to run\n for 0.1 seconds.\n\n type: bool\n default: false\n can be overridden by passing the kwarg dec_hard_timeout to the decorated function*\n\n * that means the decorated_function must not use that kwarg itself, since this kwarg will be popped from the kwargs\n \"\"\"\n\nOverride Parameters\n-------------------\n\ndecorator parameters starting with \\dec_* and use_signals can be overridden by kwargs with the same name :\n\n.. code-block:: py\n\n\n import time\n from wrapt_timeout_decorator import *\n\n @timeout(dec_timeout=5, use_signals=False)\n def mytest(message):\n # this example does NOT work on windows, please check the section\n # \"use with Windows\" in the README.rst\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed'.format(i))\n\n if __name__ == '__main__':\n mytest('starting',dec_timeout=12) # override the decorators setting. The kwarg dec_timeout will be not\n # passed to the decorated function.\n\nMultithreading\n--------------\n\nBy default, timeout-decorator uses signals to limit the execution time\nof the given function. This approach does not work if your function is\nexecuted not in the main thread (for example if it's a worker thread of\nthe web application) or when the operating system does not support signals (aka Windows).\nThere is an alternative timeout strategy for this case - by using multiprocessing.\nThis is done automatically, so you dont need to set ``use_signals=False``.\nYou can force not to use signals on Linux by passing the parameter ``use_signals=False`` to the timeout\ndecorator function for testing. If Your program should (also) run on Windows, I recommend to test under\nWindows, since Windows does not support forking (read more under Section ``use with Windows``).\nThe following Code will run on Linux but NOT on Windows :\n\n.. code-block:: py\n\n import time\n from wrapt_timeout_decorator import *\n\n @timeout(5, use_signals=False)\n def mytest(message):\n # this example does NOT work on windows, please check the section\n # \"use with Windows\" in the README.rst\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed'.format(i))\n\n if __name__ == '__main__':\n mytest('starting')\n\n.. warning::\n Make sure that in case of multiprocessing strategy for timeout, your function does not return objects which cannot\n be pickled, otherwise it will fail at marshalling it between master and child processes. To cover more cases,\n we use multiprocess and dill instead of multiprocessing and pickle.\n\n Since Signals will not work on Windows, it is disabled by default, whatever You set.\n\nuse as function not as decorator\n--------------------------------\n\nYou can use the timout also as function, without using as decorator:\n\n.. code-block:: py\n\n import time\n from wrapt_timeout_decorator import *\n\n def mytest(message):\n print(message)\n for i in range(1,10):\n time.sleep(1)\n print('{} seconds have passed'.format(i))\n\n if __name__ == '__main__':\n timeout(dec_timeout=5)(mytest)('starting')\n\nuse powerful eval function\n--------------------------\n\nThis is very powerful, but can be also very dangerous if you accept strings to evaluate from UNTRUSTED input.\n\nread: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html\n\nIf enabled, the parameter of the function dec_timeout, or the parameter passed by kwarg dec_timeout will\nbe evaluated if its type is string.\n\nYou can access :\n\n- \"wrapped\"\n (the decorated function and his attributes)\n\n- \"instance\"\n Example: 'instance.x' - an attribute of the instance of the class instance\n\n- \"args\"\n Example: 'args[0]' - the timeout is the first argument in args\n\n- \"kwargs\"\n Example: 'kwargs[\"max_time\"] * 2'\n\n- and of course all attributes You can think of - that makes it powerful but dangerous.\n by default allow_eval is disabled - but You can enable it in order to cover some edge cases without\n modifying the timeout decorator.\n\n\n.. code-block:: py\n\n # this example does NOT work on windows, please check the section\n # \"use with Windows\" in the README.rst\n def class ClassTest4(object):\n def __init__(self,x):\n self.x=x\n\n @timeout('instance.x', dec_allow_eval=True)\n def test_method(self):\n print('swallow')\n\n @timeout(1)\n def foo3(self):\n print('parrot')\n\n @timeout(dec_timeout='args[0] + kwargs.pop(\"more_time\",0)', dec_allow_eval=True)\n def foo4(self,base_delay):\n time.sleep(base_delay)\n print('knight')\n\n\n if __name__ == '__main__':\n # or override via kwarg :\n my_foo = ClassTest4(3)\n my_foo.test_method(dec_timeout='instance.x * 2.5 +1')\n my_foo.foo3(dec_timeout='instance.x * 2.5 +1', dec_allow_eval=True)\n my_foo.foo4(1,more_time=3) # this will time out in 4 seconds\n\ndetect pickle errors\n--------------------\n\nremember that decorated functions (and their results !) needs to be pickable under Windows. In order to detect pickle problems You can use :\n\n.. code-block:: py\n\n from wrapt_timeout_decorator import *\n # always remember that the \"object_to_pickle\" should not be defined within the main context\n detect_unpickable_objects(object_to_pickle, dill_trace=True) # type: (Any, bool) -> Dict\n\nLogging in decorated functions\n------------------------------\n\nwhen signals=False (on Windows), logging in the wrapped function can be tricky. Since a new process is\ncreated, we can not use the logger object of the main process. Further development is needed to\nconnect to the main process logger via a socket or queue.\n\nWhen the wrapped function is using logger=logging.getLogger(), a new Logger Object is created.\nSetting up that Logger can be tricky (File Logging from two Processes is not supported ...)\nI think I will use a socket to implement that (SocketHandler and some Receiver Thread)\n\nUntil then, You need to set up Your own new logger in the decorated function, if logging is needed.\nAgain - keep in mind that You can not write to the same logfile from different processes !\n(although there are logging modules which can do that)\n\nhard timeout\n------------\n\nwhen use_signals = False (this is the only method available on Windows), the timeout function is realized by starting\nanother process and terminate that process after the given timeout.\nUnder Linux fork() of a new process is very fast, under Windows it might take some considerable time,\nbecause the main context needs to be reloaded on spawn().\nSpawning of a small module might take something like 0.5 seconds and more.\n\nBy default, when using signals=False, the timeout begins after the new process is created.\n\nThis means that the timeout given, is the time the decorated process is allowed to run, not included the time excluding the time to setup the process itself.\nThis is especially important if You use small timeout periods :\n\nfor Instance:\n\n\n.. code-block:: py\n\n @timeout(0.1)\n def test():\n time.sleep(0.2)\n\n\nthe total time to timeout on linux with use_signals = False will be around 0.1 seconds, but on windows this can take\nabout 0.6 seconds: 0.5 seconds to spawn the new process, and giving the function test() 0.1 seconds to run !\n\nIf You need that a decorated function should timeout exactly** after the given timeout period, You can pass\nthe parameter dec_hard_timeout=True. in this case the called function will timeout exactly** after the given time,\nno matter how long it took to spawn the process itself. In that case, if You set up the timeout too short,\nthe process might never run and will always timeout during spawning.\n\n** well, more or less exactly - it still takes some short time to return from the spawned process - so be extra cautious on very short timeouts !\n\nRequirements\n------------\n\nfollowing modules will be automatically installed :\n\n.. code-block:: shell\n\n ## Test Requirements\n ## following Requirements will be installed temporarily for\n ## \"setup.py install test\" or \"pip install --install-option test\"\n typing ; python_version < \"3.5\"\n pathlib; python_version < \"3.4\"\n mypy ; platform_python_implementation != \"PyPy\" and python_version >= \"3.5\"\n pytest\n pytest-pep8 ; python_version < \"3.5\"\n pytest-codestyle ; python_version >= \"3.5\"\n pytest-mypy ; platform_python_implementation != \"PyPy\" and python_version >= \"3.5\"\n pytest-runner\n\n ## Project Requirements\n dill\n multiprocess\n wrapt\n\nAcknowledgements\n----------------\n\nDerived from\n\nhttps://github.com/pnpnpn/timeout-decorator\n\nhttp://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/\n\nthanks to abadger1999 for pointing out caveats when using signals, see :\nhttps://anonbadger.wordpress.com/2018/12/15/python-signal-handlers-and-exceptions/\n\nspecial thanks to \"uncle bob\" Robert C. Martin, especially for his books on \"clean code\" and \"clean architecture\"\n\nContribute\n----------\n\nI would love for you to fork and send me pull request for this project.\n- `please Contribute `_\n\nLicense\n-------\n\nThis software is licensed under the `MIT license `_\n\n-----------------------------------------------------------------\n\n.. Changelog link comes from the included document !\n\nChangelog\n=========\n\n1.3.1\n-----\n2019-09-02: strict mypy static type checking, housekeeping\n\n1.3.0\n-----\n2019-05-03: pointing out caveats when using signals, the decorator defaults now to NOT using Signals !\n\n1.2.9\n-----\n2019-05-03: support nested decorators, mypy static type checking\n\n1.2.8\n-----\n2019-04-23: import multiprocess as multiprocess, not as multiprocessing - that might brake other packages\n\n1.2.0\n------\n2019-04-09: initial PyPi release\n\n1.1.0\n-----\n2019-04-03: added pickle analyze convenience function\n\n1.0.9\n-----\n2019-03-27: added OsX and Windows tests, added parameter dec_hard_timeout for Windows, 100% Code Coverage\n\n1.0.8\n-----\n2019-02-26: complete refractoring and code cleaning\n\n1.0.7\n-----\n2019-02-25: fix pickle detection, added some tests, codecov now correctly combining the coverage of all tests\n\n1.0.6\n-----\n2019-02-24: fix pickle detection when use_signals = False, drop Python2.6 support since wrapt dropped it.\n\n1.0.5\n-----\n2018-09-13: use multiprocessing.pipe instead of queue\nIf we are not able to use signals, we need to spawn a new process.\nThis was done in the past by pickling the target function and put it on a queue -\nnow this is done with a half-duplex pipe.\n\n- it is faster\n- it probably can work on Amazon AWS, since there You must not use queues\n\n1.0.4\n-----\n\n2017-12-02: automatic detection if we are in the main thread. Signals can only be used in the main thread. If the decorator is running in a subthread, we automatically disable signals.\n\n\n1.0.3\n-----\n\n2017-11-30: using dill and multiprocess to enhance windows functionality\n\n\n1.0.0\n-----\n\n2017-11-10: Initial public release\n\n\n\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/bitranox/wrapt_timeout_decorator", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "wrapt-timeout-decorator", "package_url": "https://pypi.org/project/wrapt-timeout-decorator/", "platform": "", "project_url": "https://pypi.org/project/wrapt-timeout-decorator/", "project_urls": { "Homepage": "https://github.com/bitranox/wrapt_timeout_decorator" }, "release_url": "https://pypi.org/project/wrapt-timeout-decorator/1.3.1/", "requires_dist": [ "pathlib", "dill", "multiprocess", "wrapt", "typing ; python_version < \"3.5\"" ], "requires_python": "", "summary": "wrapt_timeout_decorator", "version": "1.3.1" }, "last_serial": 5773033, "releases": { "1.2.6": [ { "comment_text": "", "digests": { "md5": "0b3226683bd57e3fbcb2dadf0b1782de", "sha256": "7f009c2bf7872895efeb44aa1bbcdec1845042799c6f7a75aec41689b5f29645" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.6-py3-none-any.whl", "has_sig": false, "md5_digest": "0b3226683bd57e3fbcb2dadf0b1782de", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14909, "upload_time": "2019-04-10T13:17:46", "url": "https://files.pythonhosted.org/packages/b6/08/4e328e3b4b9ac98650aaace2f4f972115a81ceb58221c713fab5c3f59c66/wrapt_timeout_decorator-1.2.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d9eb777879f99e07b6f5cc5eaec72e00", "sha256": "fe023c2ce8cf84cf01e1e319a0f52fc3d7e545d93f61e8003db16b4c5b7d3df0" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.6.tar.gz", "has_sig": false, "md5_digest": "d9eb777879f99e07b6f5cc5eaec72e00", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15543, "upload_time": "2019-04-10T13:17:47", "url": "https://files.pythonhosted.org/packages/99/4d/39111f148c1277e049d68b2a57378cb425ecc10e8cad163827351d6a0254/wrapt_timeout_decorator-1.2.6.tar.gz" } ], "1.2.8": [ { "comment_text": "", "digests": { "md5": "746300f4d8a3f1ea82b02547c2982597", "sha256": "23cf6b03c73f308aaa6332a03897ad6dcb4727b7cc7f7730072ae5bf8a31372a" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.8-py3-none-any.whl", "has_sig": false, "md5_digest": "746300f4d8a3f1ea82b02547c2982597", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15086, "upload_time": "2019-04-23T19:30:17", "url": "https://files.pythonhosted.org/packages/a1/e2/701f964729d6c7744f65680dd31389734f5c3e4f54d3bc20e955d229bcdc/wrapt_timeout_decorator-1.2.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e93795806e2b0d117c346dab28d5a0a5", "sha256": "f3e9e67ad35230e966c8b96c224231cd00808cf7370eba2b8a79b9a07eeb12f6" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.8.tar.gz", "has_sig": false, "md5_digest": "e93795806e2b0d117c346dab28d5a0a5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15822, "upload_time": "2019-04-23T19:30:18", "url": "https://files.pythonhosted.org/packages/11/22/f6b5dda47441cb532c62b1a2fd3b026c8bc43878b9b279830cfd6a6c3e82/wrapt_timeout_decorator-1.2.8.tar.gz" } ], "1.2.9": [ { "comment_text": "", "digests": { "md5": "547ba9a21fa3272c598c8bc16521ad5d", "sha256": "3ea0bd8fd7b7de1fadb0e8c24fddf4018fd11a42abd3a98880a7ebb7c85d670a" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.9-py3-none-any.whl", "has_sig": false, "md5_digest": "547ba9a21fa3272c598c8bc16521ad5d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16281, "upload_time": "2019-05-03T17:21:29", "url": "https://files.pythonhosted.org/packages/cd/bf/315222c3fd7409055d58f0290acfd50d2a448e33eec468014b137bc7fda2/wrapt_timeout_decorator-1.2.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1c28175e44f0444a0e3c7b8fde48356a", "sha256": "a8325c26db3d196adc3666ee58f55b3416de420e20174c542bf5becf5ec2625f" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.2.9.tar.gz", "has_sig": false, "md5_digest": "1c28175e44f0444a0e3c7b8fde48356a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22652, "upload_time": "2019-05-03T17:23:27", "url": "https://files.pythonhosted.org/packages/35/e5/62f51e9c2fbd3821f1270fdfc8ef01837f55a42b2a1c2bfe6a81a3acee50/wrapt_timeout_decorator-1.2.9.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "0816df8435877cc9114cea069676f175", "sha256": "df8654a52cc4db032d06ae3b0183a4fba9a6615afce9c030e62472db7f59230a" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0816df8435877cc9114cea069676f175", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17168, "upload_time": "2019-05-03T20:03:22", "url": "https://files.pythonhosted.org/packages/5a/c1/89e63afbb1407355205988424c190eb48a04b0cb08ac9e5a4f9227c197cd/wrapt_timeout_decorator-1.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a86043c538e78e5f643a4d5b4efc1810", "sha256": "be22bc8c14081be38d44ae56679d6fcf4e95826f37398dd358abcda3c1a5e7e3" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.0.tar.gz", "has_sig": false, "md5_digest": "a86043c538e78e5f643a4d5b4efc1810", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30744, "upload_time": "2019-05-03T20:03:23", "url": "https://files.pythonhosted.org/packages/de/07/f85a451f7bd0e591d551ecf794728fbad634e10db0aee3e324da9a753ff9/wrapt_timeout_decorator-1.3.0.tar.gz" } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "7ae4140cf65dc79766cca8581b9d38d5", "sha256": "1da30de7510e16c823bd17f020bd900ffc9959954f418f66c258073733c53bf7" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7ae4140cf65dc79766cca8581b9d38d5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17939, "upload_time": "2019-09-02T23:11:21", "url": "https://files.pythonhosted.org/packages/86/01/a749e2119a3b1917698de50ef9338b008dd3fe7f4dae0735fac73c155e2a/wrapt_timeout_decorator-1.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0f6948bb0ec670d924feeace5f3a7873", "sha256": "bf691d31b2fe147fc29d494c7aa31e604e3b1c17393667065bebcccd93d0daa3" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.1.tar.gz", "has_sig": false, "md5_digest": "0f6948bb0ec670d924feeace5f3a7873", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32498, "upload_time": "2019-09-02T23:11:23", "url": "https://files.pythonhosted.org/packages/e8/2e/808dea2df60f25f993214829fdb96cee2f43ad990fc9f514345016e2706f/wrapt_timeout_decorator-1.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7ae4140cf65dc79766cca8581b9d38d5", "sha256": "1da30de7510e16c823bd17f020bd900ffc9959954f418f66c258073733c53bf7" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7ae4140cf65dc79766cca8581b9d38d5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17939, "upload_time": "2019-09-02T23:11:21", "url": "https://files.pythonhosted.org/packages/86/01/a749e2119a3b1917698de50ef9338b008dd3fe7f4dae0735fac73c155e2a/wrapt_timeout_decorator-1.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0f6948bb0ec670d924feeace5f3a7873", "sha256": "bf691d31b2fe147fc29d494c7aa31e604e3b1c17393667065bebcccd93d0daa3" }, "downloads": -1, "filename": "wrapt_timeout_decorator-1.3.1.tar.gz", "has_sig": false, "md5_digest": "0f6948bb0ec670d924feeace5f3a7873", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32498, "upload_time": "2019-09-02T23:11:23", "url": "https://files.pythonhosted.org/packages/e8/2e/808dea2df60f25f993214829fdb96cee2f43ad990fc9f514345016e2706f/wrapt_timeout_decorator-1.3.1.tar.gz" } ] }