{"id":16495655,"url":"https://github.com/bitranox/wrapt_timeout_decorator","last_synced_at":"2025-05-15T12:04:59.834Z","repository":{"id":29945384,"uuid":"110292653","full_name":"bitranox/wrapt_timeout_decorator","owner":"bitranox","description":"Python Powerful Timeout Decorator that can be used safely on classes, methods, class methods","archived":false,"fork":false,"pushed_at":"2025-01-24T23:21:54.000Z","size":711,"stargazers_count":158,"open_issues_count":9,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-15T01:19:40.008Z","etag":null,"topics":["cross-platform","crossplatform","decorated-functions","decorator","multiprocess","multiprocessing","pipe","pipes","python","python3","timeout","timeout-library","timeouts","wrapper","wrappers"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitranox.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGES.rst","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-10T21:06:19.000Z","updated_at":"2025-05-06T11:51:06.000Z","dependencies_parsed_at":"2024-01-10T18:56:02.955Z","dependency_job_id":"7f79401f-a20c-4868-9eac-a9b71e8de82b","html_url":"https://github.com/bitranox/wrapt_timeout_decorator","commit_stats":{"total_commits":704,"total_committers":5,"mean_commits":140.8,"dds":"0.20880681818181823","last_synced_commit":"f17c6b376df19854df903a1dcc00b3d1c4878db9"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitranox%2Fwrapt_timeout_decorator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitranox%2Fwrapt_timeout_decorator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitranox%2Fwrapt_timeout_decorator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitranox%2Fwrapt_timeout_decorator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitranox","download_url":"https://codeload.github.com/bitranox/wrapt_timeout_decorator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cross-platform","crossplatform","decorated-functions","decorator","multiprocess","multiprocessing","pipe","pipes","python","python3","timeout","timeout-library","timeouts","wrapper","wrappers"],"created_at":"2024-10-11T14:31:58.190Z","updated_at":"2025-05-15T12:04:54.817Z","avatar_url":"https://github.com/bitranox.png","language":"Python","readme":"wrapt_timeout_decorator\n=======================\n\n\nVersion v1.5.1 as of 2024-02-28 see `Changelog`_\n\n|build_badge| |codeql| |license| |jupyter| |pypi|\n|pypi-downloads| |black| |codecov| |cc_maintain| |cc_issues| |cc_coverage| |snyk|\n\n\n\n.. |build_badge| image:: https://github.com/bitranox/wrapt_timeout_decorator/actions/workflows/python-package.yml/badge.svg\n   :target: https://github.com/bitranox/wrapt_timeout_decorator/actions/workflows/python-package.yml\n\n\n.. |codeql| image:: https://github.com/bitranox/wrapt_timeout_decorator/actions/workflows/codeql-analysis.yml/badge.svg?event=push\n   :target: https://github.com//bitranox/wrapt_timeout_decorator/actions/workflows/codeql-analysis.yml\n\n.. |license| image:: https://img.shields.io/github/license/webcomics/pywine.svg\n   :target: http://en.wikipedia.org/wiki/MIT_License\n\n.. |jupyter| image:: https://mybinder.org/badge_logo.svg\n   :target: https://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=wrapt_timeout_decorator.ipynb\n\n.. for the pypi status link note the dashes, not the underscore !\n.. |pypi| image:: https://img.shields.io/pypi/status/wrapt-timeout-decorator?label=PyPI%20Package\n   :target: https://badge.fury.io/py/wrapt_timeout_decorator\n\n.. badge until 2023-10-08:\n.. https://img.shields.io/codecov/c/github/bitranox/wrapt_timeout_decorator\n.. badge from 2023-10-08:\n.. |codecov| image:: https://codecov.io/gh/bitranox/wrapt_timeout_decorator/graph/badge.svg\n   :target: https://codecov.io/gh/bitranox/wrapt_timeout_decorator\n\n.. |cc_maintain| image:: https://img.shields.io/codeclimate/maintainability-percentage/bitranox/wrapt_timeout_decorator?label=CC%20maintainability\n   :target: https://codeclimate.com/github/bitranox/wrapt_timeout_decorator/maintainability\n   :alt: Maintainability\n\n.. |cc_issues| image:: https://img.shields.io/codeclimate/issues/bitranox/wrapt_timeout_decorator?label=CC%20issues\n   :target: https://codeclimate.com/github/bitranox/wrapt_timeout_decorator/maintainability\n   :alt: Maintainability\n\n.. |cc_coverage| image:: https://img.shields.io/codeclimate/coverage/bitranox/wrapt_timeout_decorator?label=CC%20coverage\n   :target: https://codeclimate.com/github/bitranox/wrapt_timeout_decorator/test_coverage\n   :alt: Code Coverage\n\n.. |snyk| image:: https://snyk.io/test/github/bitranox/wrapt_timeout_decorator/badge.svg\n   :target: https://snyk.io/test/github/bitranox/wrapt_timeout_decorator\n\n.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg\n   :target: https://github.com/psf/black\n\n.. |pypi-downloads| image:: https://img.shields.io/pypi/dm/wrapt-timeout-decorator\n   :target: https://pypi.org/project/wrapt-timeout-decorator/\n   :alt: PyPI - Downloads\n\nThere are several timeout decorators available, but the one mentioned here\nfocuses on ensuring correctness when used with classes, methods, class methods,\nstatic methods, etc. It also preserves traceback information for PyCharm debugging.\n\nThe timeout can be dynamically adjusted, calculated from other parameters or methods accessible via an optional eval function.\n\nTwo timeout strategies have been implemented:\none using \"Signals\" and the other using \"Subprocess\".\n\nSignals Strategy\n----------------\n\nThe \"Signals\" strategy (for POSIX Systems) is elegant and efficient,\nbut it has some important caveats which should be reviewed\nin the `Considerations using Signals`_ section.\n\n\nSubprocess Strategy (the default)\n---------------------------------\n\nThe utilization of subprocesses serves as the default approach for executing timeouts:\n\n- **Windows Compatibility**:\n        Given the absence of signal support,\n        subprocesses become the sole method for implementing timeouts on Windows,\n        automatically applied to accommodate the platform's limitations.\n        On Windows the only available startmethod for subprocesses is ``spawn``\n- **POSIX Systems**:\n        On POSIX-compliant systems, signals cannot be employed within\n        subthreads, necessitating the use of subprocesses in these contexts as well.\n        On POSIX the available startmethods for subprocesses are ``fork``, ``forkserver``, ``spawn``\n\nTo ensure compatibility and functionality across subprocesses,\nit's essential that as many object types as possible are pickleable.\nTo this end, the ``dill`` library is preferred over Python's standard ``pickle`` module,\nand ``multiprocess`` is chosen instead of ``multiprocessing``.\n``dill`` enhances the pickle module's capabilities, extending support for\nserialization and deserialization of a broader array of Python object types.\n\nSubprocess communication is facilitated through ``multiprocess.pipe`` rather than ``queue``.\nThis choice not only boosts performance but also enhances compatibility,\npotentially offering better support for environments like Amazon AWS.\n\nSubprocesses can be initiated using various methods,\nincluding 'fork', 'forkserver', and 'spawn'.\nFor detailed information on these methods and their implications,\nplease refer to Section `Considerations using Subprocesses`_ of this manual.\n\n----\n\nautomated tests, Github Actions, Documentation, Badges, etc. are managed with `PizzaCutter \u003chttps://github\n.com/bitranox/PizzaCutter\u003e`_ (cookiecutter on steroids)\n\nPython version required: 3.8.0 or newer\n\ntested on recent linux with python 3.8, 3.9, 3.10, 3.11, 3.12, pypy-3.9, pypy-3.10 - architectures: amd64\n\n`100% code coverage \u003chttps://codeclimate.com/github/bitranox/wrapt_timeout_decorator/test_coverage\u003e`_, flake8 style checking ,mypy static type checking ,tested under `Linux, macOS, Windows \u003chttps://github.com/bitranox/wrapt_timeout_decorator/actions/workflows/python-package.yml\u003e`_, automatic daily builds and monitoring\n\n----\n\n- `Try it Online`_\n- `Usage`_\n- `Usage from Commandline`_\n- `Installation and Upgrade`_\n- `Requirements`_\n- `Acknowledgements`_\n- `Contribute`_\n- `Report Issues \u003chttps://github.com/bitranox/wrapt_timeout_decorator/blob/master/ISSUE_TEMPLATE.md\u003e`_\n- `Pull Request \u003chttps://github.com/bitranox/wrapt_timeout_decorator/blob/master/PULL_REQUEST_TEMPLATE.md\u003e`_\n- `Code of Conduct \u003chttps://github.com/bitranox/wrapt_timeout_decorator/blob/master/CODE_OF_CONDUCT.md\u003e`_\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 \u003chttps://mybinder.org/v2/gh/{{rst_include.\nrepository_slug}}/master?filepath=wrapt_timeout_decorator.ipynb\u003e`_\n\nUsage\n-----------\n\n- `Basic Usage`_\n- `General Recommendations`_\n- `use with Windows`_\n    - `Quick Guide for the Eager`_\n    - `In-Depth Explanation for the Curious`_\n    - `Windows Compatibility Issue`_\n    - `Timing Considerations`_\n- `Considerations using Signals`_\n- `Considerations using Subprocesses`_\n    - `Overview`_\n    - `Initialization`_\n    - `Process Execution and Communication`_\n    - `Subprocess Start Methods`_\n    - `Choosing the Right Start Method`_\n    - `Setting the Start Method`_\n    - `Special Considerations for Uvicorn, FastAPI, asyncio`_\n- `Handling Nested Timeouts`_\n- `Custom Timeout Exception`_\n- `Parameters`_\n- `Override Parameters`_\n- `Multithreading`_\n- `Subprocess Monitoring`_\n- `use as function not as decorator`_\n- `Dynamic Timeout Value Adjustment with eval`_\n- `Tools`_\n    - `detect pickle errors`_\n    - `set_subprocess_starting_method`_\n- `Logging Challenges with Subprocesses`_\n- `hard timeout`_\n- `Understanding Timeout Durations Across Platforms`_\n- `MYPY Testing`_\n\nBasic Usage\n-----------\n\n.. code-block:: python\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\nGeneral Recommendations\n-----------------------\n\nIt's recommended to minimize the utilization of timeouts in your programming, reserving them for truly essential instances.\n\nTimers should be applied at an appropriate level of detail, tailored specifically to the needs of your application.\nThis precision aids in circumventing unwanted outcomes, such as the mishandling of exceptions by unrelated code sections\nor complications with entities that cannot be pickled.\n\nConversely, it's prudent to refrain from embedding a Timeout Decorator within loops that execute multiple times.\nSuch an approach can induce notable delays, especially on Windows systems, owing to the additional burden of initiating subprocesses.\n\nWhere possible, opt for the timeout features natively available in the functions and libraries at your disposal.\nThese inherent capabilities are often adequate for the majority of use cases.\nThe implementation of a Timeout Decorator is best reserved as a measure of last resort,\nsubsequent to the exhaustive consideration of alternative strategies.\n\nAdditionally, be cognizant of the fact that the behavior and efficiency of subprocesses may vary significantly across platforms\n(Windows versus Linux) and depending on the chosen method for subprocess initiation.\nRefer to the documentation on `Subprocess Start Methods`_ for further details.\n\n\n    BAD EXAMPLE (Pseudocode) - lets assume the write to the database fails sometimes for unknown reasons, and \"hangs\"\n\n    .. code-block:: python\n\n        # module file_analyzer\n        import time\n        from wrapt_timeout_decorator import *\n\n        def read_the_file(filename):\n            ...\n\n        def analyze_the_file(filename):\n            ...\n\n        def write_to_database(file_content):\n            ...\n\n\n        @timeout(5)  # try to minimize the scope of the timeout\n        def import_file(filename):\n            file_content = read_the_file(filename)\n            structured_data = analyze_the_file(file_content)\n            write_to_database(structured_data)\n\n\n    BETTER EXAMPLE (Pseudocode)\n\n    .. code-block:: python\n\n        # module file_analyzer\n        import time\n        from wrapt_timeout_decorator import *\n\n        def read_the_file(filename):\n            ...\n\n        def analyze_the_file(filename):\n            ...\n\n        @timeout(5)     # better, because smaller scope\n        def write_to_database(file_content):\n            ...\n\n        def import_file(filename):\n            file_content = read_the_file(filename)\n            structured_data = analyze_the_file(file_content)\n            write_to_database(structured_data)\n\nuse with Windows\n----------------\n\nQuick Guide for the Eager\n-------------------------\nTo bypass complexities, simply place the decorated function within a separate module, rather than in the main script.\n\nIn-Depth Explanation for the Curious\n------------------------------------\nOn Windows, due to the absence of native forking support, Python attempts to emulate a forking environment.\nThis emulation involves re-importing the main module under a different name, not as '__main__'.\nThis behavior is part of Python's multiprocessing efforts to replicate the main process's environment as closely as possible.\nConsequently, it's crucial to protect the entry point of your application with the well-known conditional statement\n\"if __name__ == '__main__':\".\n\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\n\nWindows Compatibility Issue\n---------------------------\nThe challenge arises from Windows OS's lack of support for the \"fork\" process model, a limitation not present in Unix-based systems.\n\nFurther details can be explored through these resources:\n\n- [Stack Overflow discussion on multiprocessing and `__name__ == '__main__'`](https://stackoverflow.com/questions/45110287/workaround-for-using-name-main-in-python-multiprocessing)\n- [Python's multiprocessing documentation for Windows](https://docs.python.org/2/library/multiprocessing.html#windows)\n\nDue to this, when `main.py` is re-imported under a name different from `\"__main__\"`, references within decorated classes\nand functions become invalid. To circumvent this, it's advisable to house decorated entities in a separate module.\nGenerally, and particularly on Windows, the `main()` function should be streamlined to act merely as an entry point,\nwith the substantive logic residing in modules.\nAdditionally, storing settings or configurations in a distinct file is beneficial for centralized access and to leverage features\nlike type hints and auto-completion in your preferred IDE.\n\nThe `dill` serializer, chosen for its broader compatibility, successfully serializes the `__main__` context,\nenabling objects to be pickled to `\"__main__.lib_foo\"`, `\"__main__.some_module\"`, `\"__main__.main\"`, etc.\nThis overcomes the limitations faced when using `pickle`, which cannot serialize various types including functions\nwith yields, nested functions, and more.\n`Dill` enhances functionality by enabling the saving/loading of Python sessions, extraction of source code, and interactive debugging of serialization errors.\nHowever, it necessitates that decorated methods and classes not be defined in the `__main__` context but within a module.\n\nFor more insights on serialization with `pickle` or `dill`:\n- [Stack Overflow discussion on serializing objects in `__main__` with `pickle` or `dill`](https://stackoverflow.com/questions/45616584/serializing-an-object-in-main-with-pickle-or-dill)\n\nTiming Considerations\n---------------------\nGiven the variable duration of the spawning process (due to re-importing modules),\nthe `hard timeout`_ section provides guidance on configuring the commencement of timeouts.\n\n\nAn illustration highlights a scenario functional on Linux but problematic on Windows,\nwhere the variable `\"name\"` and the function `\"sleep\"` are not recognized in the spawned process:\n\n\n.. code-block:: python\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:: python\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:: python\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:: python\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\nConsiderations using Signals\n----------------------------\n\nABADGER1999 highlights in his `blog post \u003chttps://anonbadger.wordpress.com/2018/12/15/python-signal-handlers-and-exceptions/\u003e`_ the\npotential pitfalls of using signals alongside the TimeoutException.\nThis approach may not be advisable as the exception can be intercepted within the decorated function.\n\nWhile it's possible to implement a custom Exception derived from the Base Exception Class,\nthis doesn't guarantee the code will behave as anticipated.\nFor an illustrative example, you're encouraged to conduct an experiment using a\n`Jupyter notebook \u003chttps://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=jupyter_test_{repository}.ipynb\u003e`_.\n\n\n.. code-block:: python\n\n    import time\n    from wrapt_timeout_decorator import *\n\n    # Considerations for Signal Usage - Handling TimeoutError\n    # The TimeoutError triggered by a signal might be intercepted within the decorated function.\n    # Utilizing a custom Exception, derived from the base Exception Class, is a possible workaround.\n    # Within Python 3.7.1's standard library, there are over 300 instances where your custom timeout might be caught\n    # if it's based on Exception. Should you base your exception on BaseException,\n    # there still remain 231 potential catch points.\n    # To ensure proper timeout management, it's advisable to set `use_signals=False`.\n    # Consequently, `use_signals` defaults to `False` in this decorator to avoid these issues.\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\nConsiderations using Subprocesses\n---------------------------------\n\nOverview\n--------\nSubprocesses ares utilized by default to implement timeout functionality. This involves forking or spawning subprocesses, each with its own set of\nconsiderations and caveats.\n\nInitialization\n--------------\n- **Windows Considerations:** On Windows, the spawn method can significantly slow down the process initiation.\n- **Main Context Protection:** It is crucial to protect the ``__main__`` context for compatibility, especially on Windows. See the \"Usage with Windows\" section for more details.\n- **Pickle Requirements:** Function codes and arguments must be pickleable. To accommodate a wider range of types, `dill` is used for serialization.\n- **Global Variables:** Access to global variables from a child process might not reflect the parent process's state at the time of the fork. Module-level constants are generally unaffected.\n\nProcess Execution and Communication\n------------------------------------\n- **Subprocess Execution:** Functions run in a separate subprocess, whether forked or spawned.\n- **Data Transmission:** Parameters and results are communicated through pipes, with `dill` used for serialization.\n- **Timeout Management:** Absent a result within the specified timeout, the subprocess is terminated using `SIGTERM`. Ensuring subprocesses can terminate safely is essential; thus, disabling the `SIGTERM` handler is not advisable.\n\nSubprocess Start Methods\n------------------------\n- **Windows Limitation:** Only `spawn` is available on Windows.\n- **Linux/Unix Options:** Options include `fork`, `forkserver`, and `spawn`.\n    - **Fork:** Efficiently clones the parent process, including memory space, but may lead to issues with shared resources or in multi-threaded applications.\n    - **Forkserver:** Starts a server at program launch, creating new processes upon request for better isolation but at a slower pace due to the server communication requirement.\n    - **Spawn:** Initiates a fresh Python interpreter process, ensuring total independence at the cost of slower start-up due to the need for full initialization.\n\nChoosing the Right Start Method\n-------------------------------\n- **fork** offers speed but can encounter issues with resource sharing or threading.\n- **forkserver** enhances stability and isolation, ideal for applications requiring safety or managing unstable resources.\n- **spawn** provides the highest level of isolation, recommended for a clean start and avoiding shared state complications.\n\nSetting the Start Method\n------------------------\nConfigure the start method with ``multiprocessing.set_start_method(method, force=True)``. This should be done cautiously, ideally once, and within the ``if\n__name__ == '__main__'`` block to prevent unintended effects.\nSince we use ``multiprocess`` instead of ``multiprocessing``, we provide a method to set the starting method on both at the same time.\nsee : `set_subprocess_starting_method`_\n\nSpecial Considerations for Uvicorn, FastAPI, asyncio\n----------------------------------------------------\nFor Uvicorn or FastAPI applications, a specific approach to the `fork` method is recommended to ensure proper signal handling and isolation, facilitated by the ``dec_mp_reset_signals`` parameter.\nThis design aims to reset signal handlers and manage file descriptors in child processes effectively.\nYou can set that by passing the parameter ``dec_mp_reset_signals=True`` to the decorator.\n\nHandling Nested Timeouts\n------------------------\n\nDue to Unix's limitation of having just one ALARM signal per process, it's necessary to set `use_signals=False` for nested timeouts\nto function correctly. While the outermost decorator may utilize signals,\nall inner decorators must have `use_signals` set to `False`—which is the default setting.\nFor practical experimentation and to see this behavior in action,\nyou're encouraged to use a `Jupyter notebook \u003chttps://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=jupyter_test_{repository}.ipynb\u003e`_.\n\n\n.. code-block:: python\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:: python\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\nCustom Timeout Exception\n------------------------\n\nDefine a different exception to be raised upon timeout:\n\n.. code-block::  python\n\n    import time\n    from wrapt_timeout_decorator import *\n\n    # this will throw StopIteration Error instead of TimeoutError\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::  python\n\n    @timeout(dec_timeout, use_signals, timeout_exception, exception_message,\n             dec_allow_eval, dec_hard_timeout, dec_mp_reset_signals)\n    def decorated_function(*args, **kwargs):\n        # interesting things happens here ...\n        ...\n\n\n\n- dec_timeout\n    This parameter sets the timeout duration. It accepts a float, integer, or a string\n    that can be evaluated to a number if dec_allow_eval is enabled.\n    By default, there's no timeout (None). You can change the timeout dynamically\n    by passing a dec_timeout keyword argument to the decorated function.\n\n- use_signals\n    This boolean parameter controls whether to use UNIX signals for implementing timeouts.\n    It's the most accurate method but comes with certain limitations,\n    such as being available only on Linux and macOS, and only in the main thread.\n    By default, signals are not used (False). It's typically not necessary to modify\n    this setting manually, but you can override it by passing 'use_signals=True' to the decorated function.\n\n- timeout_exception\n    Specifies the exception to raise when a timeout occurs.\n    by default, it's set to TimeoutError\n    type: exception\n    default: TimeoutError\n\n- exception_message\n    You can customize the message of the timeout exception.\n    The default message includes the name of the function and the timeout duration.\n    This message gets formatted with the actual values when a timeout occurs.\n    type: str\n    default : 'Function {function_name} timed out after {dec_timeout} seconds' (will be formatted)\n\n- dec_allow_eval\n    When enabled (True), this boolean parameter allows the dec_timeout string to be evaluated dynamically.\n    It provides access\n\n    - to the decorated function (wrapped),\n    - the instance it belongs to (instance),\n    - the positional arguments (args),\n    - and keyword arguments (kwargs).\n\n    It's disabled (False) by default for safety reasons but can be enabled by passing a dec_allow_eval\n    keyword argument to the decorated function.\n\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                    see section \"Dynamic Timeout Value Adjustment with eval\" in the manual\n\n- dec_hard_timeout\n    This boolean parameter is relevant when signals cannot be used,\n    necessitating the creation of a new process for the timeout mechanism.\n    Setting it to True means the timeout strictly applies to the execution time of the function,\n    potentially not allowing enough time for process creation.\n    With False, the process creation time is not included in the timeout, giving the actual function\n    the full duration to execute.\n    You can override this setting by passing a dec_hard_timeout keyword argument to the decorated function.\n    type: bool\n    default: false\n    can be overridden by passing the kwarg dec_hard_timeout to the decorated function*\n\n- dec_mp_reset_signals\n    This parameter is relevant when using the \"fork\" start method for multiprocessing.\n    Setting it to True accomplishes two primary objectives:\n\n    - Restores Default Signal Handlers in Child Processes:\n        It ensures that child processes revert to the default signal handling behavior,\n        rather than inheriting signal handlers from the parent process.\n        This adjustment is crucial for applications utilizing frameworks like \"unicorn\" or \"FastAPI\",\n        facilitating the use of the efficient \"fork\" method while maintaining correct signal handling.\n        For more context, refer to the Discussion on\n        FastAPI GitHub page: https://github.com/tiangolo/fastapi/discussions/7442\n\n    - Avoids Inheritance of the File Descriptor (fd) for Wakeup Signals:\n        Typically, if the parent process utilizes a wakeup_fd, child processes inherit this descriptor.\n        Consequently, when a signal is sent to a child, it is also received by the parent process\n        via this shared socket, potentially leading to unintended termination or shutdown of the application.\n        By resetting signal handlers and not using the inherited fd, this parameter prevents such conflicts,\n        ensuring isolated and correct signal handling in child processes.\n\n    Note: This parameter exclusively affects processes initiated with the \"fork\" method\n    and is not applicable to other multiprocessing start methods.\n\n    For enhanced isolation of subprocesses, consider utilizing the \"forkserver\" or \"spawn\" start methods in multiprocessing.\n    These methods provide a greater degree of independence between the parent process and its children,\n    mitigating the risks associated with shared resources and ensuring a cleaner execution environment for each subprocess,\n    at the cost of slower startup times. This slowdown is due to the additional overhead involved in setting up a completely\n    new process environment for each child process, as opposed to directly duplicating the parent process's environment,\n    which occurs with the \"fork\" method.\n\n* that means the decorated_function must not use that kwarg itself, since this kwarg will be popped from the kwargs\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:: python\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\nSignals will not work if your function is not executed in the main thread.\n``use_signals`` is therefore automatically disabled (if set) when the function is not running in the main thread.\n\n\n.. code-block:: python\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 subprocess 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\nSubprocess Monitoring\n---------------------\n\nwhen using subprocesses, the subprocess is monitored if it is still alive.\nif the subprocess was terminated or killed (for instance by OOMKiller),\n``multiprocessing.context.ProcessError`` will be raised.\nBy default the subprocess is monitored every 5 seconds, but can be set with parameter\n``dec_poll_subprocess``. polling can be turned off by setting to 0.0 seconds\n\n.. code-block:: python\n\n    from wrapt_timeout_decorator import timeout\n\n\n    @timeout(10, use_signals=False, timeout_exception=TimeoutError, dec_poll_subprocess=1)\n    def slow_process() -\u003e None:\n        # should have enough time to finish\n        # but instead it gets terminated, and the\n        # poll the subprocess every second\n        logger.error(f\"Slow process started at {get_str_time()}\")\n        time.sleep(5)\n        logger.error(f\"Slow process done at {get_str_time()}\")\n\n\n    def fake_oom_killer() -\u003e None:\n        logger.error(f\"Fake OOMKiller started at {get_str_time()}\")\n        time.sleep(2)\n        # kill sibling slow_process\n        # hacky way to find it\n        target = psutil.Process().parent().children(recursive=True)[-1]\n        target.kill()\n        logger.error(f\"Killed {target.pid} at {get_str_time()}\")\n\n\n    def start_processes() -\u003e None:\n        \"\"\"\n        starts the 'fake_oom_killer' and 'slow_process' process -\n        and kill 'slow_process' after two seconds\n\n        \u003e\u003e\u003e start_processes()\n        Traceback (most recent call last):\n            ...\n        multiprocessing.context.ProcessError: Function slow_process was terminated or killed after ... seconds\n        \"\"\"\n        process_oom_killer = multiprocessing.Process(target=fake_oom_killer, args=())\n        process_oom_killer.start()\n        slow_process()\n        process_oom_killer.join()\n\n\n    def get_str_time() -\u003e str:\n        t = time.localtime()\n        current_time = time.strftime(\"%H:%M:%S\", t)\n        return current_time\n\n\n    if __name__ == '__main__':\n        start_processes()\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:: python\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\nDynamic Timeout Value Adjustment with eval\n------------------------------------------\n\nThe timeout value can be dynamically adjusted, calculated from other parameters or methods accessible via the eval function.\nThis capability is highly potent yet bears significant risks, especially when evaluating strings from UNTRUSTED sources.\n\n.. caution::\n\n   Utilizing eval with untrusted input is perilous.\n   For an in-depth understanding, refer to `this article by Ned Batchelder \u003chttps://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html\u003e`_.\n\nWhen activated, the ``dec_timeout`` function parameter,\nor the value passed through the ``dec_timeout`` keyword argument (kwarg), will undergo evaluation if it's a string type.\n\nAccessible objects within the eval context include:\n\n- **wrapped**: Represents the decorated function and its attributes.\n\n- **instance**: Accesses attributes of the class instance, e.g., ``'instance.x'`` refers to an attribute ``x`` of the instance.\n\n- **args**: Refers to positional arguments, e.g., ``'args[0]'`` might be used to indicate the first argument is the timeout.\n\n- **kwargs**: Accesses keyword arguments, e.g., ``'kwargs[\"max_time\"] * 2'`` doubles the value of ``max_time``.\n\nThese elements underscore the feature's versatility but also highlight its potential hazards.\nBy default, ``allow_eval`` is turned off to mitigate risks.\nHowever, it can be enabled to address specific use cases without altering the timeout decorator's core functionality.\n\n\n.. code-block:: python\n\n    # this example does NOT work on windows, please check the section\n    # \"use with Windows\" in the README.rst\n    def class FunnyMemes(object):\n        def __init__(self,x):\n            self.x=x\n\n        @timeout('instance.x', dec_allow_eval=True)\n        def swallow(self):\n            while True:\n                time.sleep(0.5)\n                print('swallow')\n\n        @timeout(1)\n        def parrot(self):\n            while True:\n                time.sleep(0.5)\n                print('parrot')\n\n        @timeout(dec_timeout='args[0] + kwargs.pop(\"more_time\",0)', dec_allow_eval=True)\n        def knight(self,base_delay):\n            while True:\n                time.sleep(base_delay)\n                print('knight')\n\n\n    def main():\n        my_memes = FunnyMemes(2)\n        my_memes.swallow()                                                      # this will time out after 2 seconds\n        my_memes.swallow(dec_timeout='instance.x * 2 + 1')                      # this will time out after 5 seconds\n        my_memes.parrot(dec_timeout='instance.x * 2 + 1', dec_allow_eval=True)  # this will time out after 5 seconds\n        my_memes.knight(1,more_time=4)                                          # this will time out after 5 seconds\n\n    if __name__ == '__main__':\n        main()\n\nTools\n-----\n\ndetect pickle errors\n--------------------\n\nKeep in mind that when employing subprocesses, both decorated functions and their return values must be pickleable.\nTo identify issues with pickling, you can utilize the ``detect_unpickable_objects`` function:\n\n.. code-block:: python\n\n    from wrapt_timeout_decorator import *\n    detect_unpickable_objects(object_to_pickle, dill_trace=True)\n\n\nset_subprocess_starting_method\n------------------------------\n\nSet the start Method for Subprocesses. Since we use multiprocess,\nwe set the starting method for multiprocess and multiprocessing to the same value.\nwe did not test what would happen if we set that to different values.\n\n    - Windows Limitation: Only `spawn` is available on Windows.\n    - Linux/Unix Options: Options include `fork`, `forkserver`, and `spawn`.\n        - fork:\n            Efficiently clones the parent process, including memory space,\n            but may lead to issues with shared resources or in multi-threaded applications.\n        - forkserver:\n            Starts a server at program launch, creating new processes upon request\n            for better isolation but at a slower pace due to the server communication requirement.\n        - spawn:\n            Initiates a fresh Python interpreter process, ensuring total independence\n            at the cost of slower start-up due to the need for full initialization.\n\n    - Choosing the Right Start Method\n        - fork\n            offers speed but can encounter issues with resource sharing or threading.\n        - forkserver\n            enhances stability and isolation, ideal for applications requiring safety or managing unstable resources.\n        - spawn\n            provides the highest level of isolation, recommended for a clean start and avoiding shared state complications.\n\n    - Setting the Start Method\n        Configure the start method with `set_subprocess_starting_method(method)`\n        This should be done cautiously, ideally once, and within the `if __name__ == '__main__'` block to prevent unintended effects.\n\n.. code-block:: python\n\n    from wrapt_timeout_decorator import *\n    set_subprocess_starting_method(\"forkserver\")\n\nLogging Challenges with Subprocesses\n------------------------------------\n\nWhen `signals=False` is set, implementing logging within a subprocess poses challenges.\nA new process does not inherit the main process's logger object, necessitating further development\nfor integration with the main process's logger via mechanisms like sockets or queues.\n\nUtilizing `logger=logging.getLogger()` within the wrapped function results in the instantiation of a new Logger Object.\nConfiguring this Logger, especially for file logging from concurrent processes, presents complications as direct file\nlogging from multiple processes is generally unsupported.\nA potential solution involves employing a SocketHandler coupled with a Receiver Thread to facilitate logging.\n\nIn the interim, it's necessary to initialize a separate logger within the decorated function for logging purposes.\nIt's crucial to remember that writing to the same logfile from multiple processes is not advisable.\nWhile certain logging modules may offer solutions for concurrent logging, they require specific setup and configuration.\n\nhard timeout\n------------\n\nWhen employing subprocesses (which is the default behavior), the timeout functionality is achieved by initiating\na new subprocess and terminating it once the specified timeout period elapses.\nThe process creation speed varies significantly between operating systems.\nOn Linux, the ``fork()`` method allows rapid creation of a new process.\nIn contrast, on Windows, the ``spawn()`` method can introduce a noticeable delay due to the necessity of reloading the main context,\nwith spawning a small module potentially taking upwards of 0.5 seconds.\n\nThe timeout duration commences subsequent to the creation of the new process.\nConsequently, the specified timeout reflects the period the decorated function is permitted to execute,\nexclusive of the process setup time. This distinction is particularly vital for scenarios utilizing brief timeout intervals:\n\n.. code-block:: py\n\n    @timeout(0.1)\n    def test():\n        time.sleep(0.2)\n\n\nUnderstanding Timeout Durations Across Platforms\n------------------------------------------------\n\nThe implementation of timeouts, yields different total timeout durations on Linux (fork, forkserver) compared to Windows (spawn).\nOn Linux, the timeout process may for instance complete in approximately 0.1 seconds with \"fork\".\nConversely, on Windows, the total time to reach timeout could extend for instance to about 0.6 seconds,\ncomprising a 0.5-second delay to spawn a new process and then allowing 0.1 seconds for the function ``test()`` to execute.\n\nTo enforce a decorated function to timeout strictly after the specified timeout period,\nyou may use the ``dec_hard_timeout=True`` parameter.\n\nWith this setting, the targeted function will timeout precisely after the designated duration after start,\nregardless of the process spawning time.\nHowever, setting a very short timeout with this option may prevent the process from running at all,\nresulting in an immediate timeout upon spawning.\n\n.. note::\n\n   The term \"precisely\" should be interpreted with a degree of flexibility.\n   There remains a negligible delay in returning from the spawned process, making it imperative to approach very short timeouts with caution.\n\nMYPY Testing\n------------\nfor local MYPY Testing please make sure that the stub file \"wrapt.pyi\" is in in the MYPY Path (once!), in order to preserve the decorated function signature.\n\nUsage from Commandline\n------------------------\n\n.. code-block::\n\n   Usage: wrapt_timeout_decorator [OPTIONS] COMMAND [ARGS]...\n\n     The better timout decorator\n\n   Options:\n     --version                     Show the version and exit.\n     --traceback / --no-traceback  return traceback information on cli\n     -h, --help                    Show this message and exit.\n\n   Commands:\n     info  get program informations\n\nInstallation and Upgrade\n------------------------\n\n- Before You start, its highly recommended to update pip:\n\n\n.. code-block::\n\n    python -m pip --upgrade pip\n\n- to install the latest release from PyPi via pip (recommended):\n\n.. code-block::\n\n    python -m pip install --upgrade wrapt_timeout_decorator\n\n\n- to install the latest release from PyPi via pip, including test dependencies:\n\n.. code-block::\n\n    python -m pip install --upgrade wrapt_timeout_decorator[test]\n\n- to install the latest version from github via pip:\n\n\n.. code-block::\n\n    python -m pip install --upgrade git+https://github.com/bitranox/wrapt_timeout_decorator.git\n\n\n- include it into Your requirements.txt:\n\n.. code-block::\n\n    # Insert following line in Your requirements.txt:\n    # for the latest Release on pypi:\n    wrapt_timeout_decorator\n\n    # for the latest development version :\n    wrapt_timeout_decorator @ git+https://github.com/bitranox/wrapt_timeout_decorator.git\n\n    # to install and upgrade all modules mentioned in requirements.txt:\n    python -m pip install --upgrade -r /\u003cpath\u003e/requirements.txt\n\n\n- to install the latest development version, including test dependencies from source code:\n\n.. code-block::\n\n    # cd ~\n    $ git clone https://github.com/bitranox/wrapt_timeout_decorator.git\n    $ cd wrapt_timeout_decorator\n    python -m pip install -e .[test]\n\n- via makefile:\n  makefiles are a very convenient way to install. Here we can do much more,\n  like installing virtual environments, clean caches and so on.\n\n.. code-block:: shell\n\n    # from Your shell's homedirectory:\n    $ git clone https://github.com/bitranox/wrapt_timeout_decorator.git\n    $ cd wrapt_timeout_decorator\n\n    # to run the tests:\n    $ make test\n\n    # to install the package\n    $ make install\n\n    # to clean the package\n    $ make clean\n\n    # uninstall the package\n    $ make uninstall\n\nRequirements\n------------\nfollowing modules will be automatically installed :\n\n.. code-block:: bash\n\n    ## Project Requirements\n    cli_exit_tools\n    lib_detect_testenv\n\n    # class decorators are failing on windows with dill 0.3.5, 0.3.5.1\n    dill\u003e0.3.0,!=0.3.5,!=0.3.5.1;sys_platform==\"win32\"\n    dill;sys_platform!=\"win32\"\n    multiprocess\n    psutil\n    wrapt\n\nAcknowledgements\n----------------\n\n- special 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 \u003chttps://github.com/bitranox/wrapt_timeout_decorator/blob/master/CONTRIBUTING.md\u003e`_\n\nLicense\n-------\n\nThis software is licensed under the `MIT license \u003chttp://en.wikipedia.org/wiki/MIT_License\u003e`_\n\n---\n\nChangelog\n=========\n\nv1.5.1\n---------\n2024-02-28:\n    - overhaul documentation\n    - github actions/checkout@v4\n    - github actions/setup-python@v5\n\nv1.5.0\n---------\n2024-02-27:\n    - thanks to `Alberto Ornaghi: \u003chttps://github.com/alor\u003e`_\n    - parameter ``dec_mp_reset_signals``\n    - restores the default behavior of signal handlers on multiprocessing ``fork``\n    - suitible especially for ``FastAPI`` and ``Uvicorn``\n\nv1.4.1\n---------\n2024-01-10:\n    - thanks to `fayak: \u003chttps://github.com/fayak\u003e`_\n    - omit mypy option --no-implicit-reexport\n    - explicitly export methods in ``__init__.py``\n\nv1.4.0\n---------\n2023-07-13:\n    - check for killed child processes (for instance by OOMKiller)\n    - change dill requirements for windows\n    - require minimum python 3.8\n    - remove python 3.7 tests\n    - introduce PEP517 packaging standard\n    - introduce pyproject.toml build-system\n    - remove mypy.ini\n    - remove pytest.ini\n    - remove setup.cfg\n    - remove setup.py\n    - remove .bettercodehub.yml\n    - remove .travis.yml\n    - update black config\n    - clean ./tests/test_cli.py\n    - add codeql badge\n    - move 3rd_party_stubs outside the src directory to ``./.3rd_party_stubs``\n    - add pypy 3.10 tests\n    - add python 3.12-dev tests\n\nv1.3.12.2\n---------\n2022-06-01: update to github actions checkout@v3 and setup-python@v3\n\nv1.3.12\n--------\n2022-05-23: update requirements.txt\n\nv1.3.11\n--------\n2022-05-23:\n    - set dill version \u003c 0.3.5 on windows, because decorating class methods fails with dill 0.3.5 upwards\n    - update tests to the latest python versions\n\nv1.3.10\n--------\n2022-04-26: add tests for thread lock\n\nv1.3.9\n--------\n2022-04-26: preserve Signature of the decorator\n\nv1.3.8\n--------\n2022-03-29: remedy mypy Untyped decorator makes function \"cli_info\" untyped\n\nv1.3.7\n--------\n2022-03-28: extend time on test_timeout_decorator_arg - github macos seems to be slow, so sometimes that test fails\n\nv1.3.6\n--------\n2022-03-25: fix github actions windows test\n\nv1.3.4\n-------\n2022-03-23: extend time on test_timeout_ok_timeout_as_kwarg - github macos seems to be slow, so sometimes that test fails\n\nv1.3.3\n-------\n2022-03-10: extend time on test_timeout_alternate_exception - github macos seems to be slow, so sometimes that test fails\n\nv1.3.2\n-------\n2022-03-01: github actions pipeline, codestyle black, fix requirements\n\nv1.3.1\n-------\n2019-09-02: strict mypy static type checking, housekeeping\n\nv1.3.0\n-------\n2019-05-03: pointing out caveats when using signals, the decorator defaults now to NOT using Signals !\n\nv1.2.9\n-------\n2019-05-03: support nested decorators, mypy static type checking\n\nv1.2.8\n-------\n2019-04-23: import multiprocess as multiprocess, not as multiprocessing - that might brake other packages\n\nv1.2.0\n------\n2019-04-09: initial PyPi release\n\nv1.1.0\n-------\n2019-04-03: added pickle analyze convenience function\n\nv1.0.9\n-------\n2019-03-27: added OsX and Windows tests, added parameter dec_hard_timeout for Windows, 100% Code Coverage\n\nv1.0.8\n-------\n2019-02-26: complete refractoring and code cleaning\n\nv1.0.7\n-------\n2019-02-25:  fix pickle detection, added some tests, codecov now correctly combining the coverage of all tests\n\nv1.0.6\n-------\n2019-02-24: fix pickle detection when use_signals = False, drop Python2.6 support since wrapt dropped it.\n\nv1.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\nv1.0.4\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\nv1.0.3\n-------\n2017-11-30: using dill and multiprocess to enhance windows functionality\n\nv1.0.0\n-------\n2017-11-10: Initial public release\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitranox%2Fwrapt_timeout_decorator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitranox%2Fwrapt_timeout_decorator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitranox%2Fwrapt_timeout_decorator/lists"}