Skip to content

Commit 092bdc6

Browse files
committed
v1.5.1
--------- 2024-02-28: - overhaul documentation - github actions/checkout@v4 - github actions/setup-python@v5
1 parent e27fff2 commit 092bdc6

17 files changed

+248
-244
lines changed

.docs/description.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ There are several timeout decorators available, but the one mentioned here
22
focuses on ensuring correctness when used with classes, methods, class methods,
33
static methods, etc. It also preserves traceback information for PyCharm debugging.
44

5-
Additionally, there is a powerful eval function that allows reading
6-
the desired timeout value even from class attributes.
5+
The timeout can be dynamically adjusted, calculated from other parameters or methods accessible via an optional eval function.
76

87
Two timeout strategies have been implemented:
98
one using "Signals" and the other using "Subprocess".

.docs/installation.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
- Before You start, its highly recommended to update pip and setup tools:
1+
- Before You start, its highly recommended to update pip:
22

33

44
.. code-block::
55
66
python -m pip --upgrade pip
7-
python -m pip --upgrade setuptools
87
98
109
.. include:: ./installation_via_pypi.rst

.docs/parts/01_basic_usage.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Basic Usage
22
-----------
33

4-
.. code-block::
4+
.. code-block:: python
55
66
import time
77
from wrapt_timeout_decorator import *

.docs/parts/02_general_recommendations.rst

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
11
General Recommendations
22
-----------------------
3-
It is advised to limit the use of timeouts in your code, applying them only in critical situations.
4-
5-
Ensure that timeouts are implemented at the right granular level which is specific to Your application.
6-
7-
On one hand, this approach helps in avoiding undesired effects, such as exceptions being intercepted by unrelated segments of code,
8-
or issues with non-pickable entities.
9-
10-
On the other hand, incorporating a Timeout Decorator within a repetitive loop should be avoided.
11-
This practice can lead to significant delays, particularly on Windows platforms
12-
due to the overhead associated with spawning subprocesses.
13-
14-
Preferably, make use of the native timeouts provided by the functions and libraries you are working with.
15-
These built-in mechanisms typically suffice for most scenarios.
16-
The Timeout Decorator should only be considered as a fallback option, after all other possibilities have been thoroughly explored.
17-
18-
Be aware that the isolation and performance of subprocesses can be very different, depending on the Platform (Windows or Linux) and the selected subprecess
19-
start method. - see STARTMETHOD
20-
213

224
It's recommended to minimize the utilization of timeouts in your programming, reserving them for truly essential instances.
235

@@ -35,12 +17,12 @@ subsequent to the exhaustive consideration of alternative strategies.
3517

3618
Additionally, be cognizant of the fact that the behavior and efficiency of subprocesses may vary significantly across platforms
3719
(Windows versus Linux) and depending on the chosen method for subprocess initiation.
38-
Refer to the documentation on STARTMETHOD for further details.
20+
Refer to the documentation on `Subprocess Start Methods`_ for further details.
3921

4022

4123
BAD EXAMPLE (Pseudocode) - lets assume the write to the database fails sometimes for unknown reasons, and "hangs"
4224

43-
.. code-block:: py
25+
.. code-block:: python
4426
4527
# module file_analyzer
4628
import time
@@ -65,7 +47,7 @@ Refer to the documentation on STARTMETHOD for further details.
6547
6648
BETTER EXAMPLE (Pseudocode)
6749

68-
.. code-block:: py
50+
.. code-block:: python
6951
7052
# module file_analyzer
7153
import time

.docs/parts/03_use_with_windows.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ An illustration highlights a scenario functional on Linux but problematic on Win
6666
where the variable `"name"` and the function `"sleep"` are not recognized in the spawned process:
6767

6868

69-
.. code-block::
69+
.. code-block:: python
7070
7171
main.py:
7272
@@ -93,7 +93,7 @@ where the variable `"name"` and the function `"sleep"` are not recognized in the
9393
here the same example, which will work on Windows:
9494

9595

96-
.. code-block::
96+
.. code-block:: python
9797
9898
9999
# my_program_main.py:
@@ -107,7 +107,7 @@ here the same example, which will work on Windows:
107107
main()
108108
109109
110-
.. code-block::
110+
.. code-block:: python
111111
112112
113113
# conf_my_program.py:
@@ -119,7 +119,7 @@ here the same example, which will work on Windows:
119119
conf_my_program = ConfMyProgram()
120120
121121
122-
.. code-block::
122+
.. code-block:: python
123123
124124
# lib_test.py:
125125

.docs/parts/04_considerations_using_signals.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ For an illustrative example, you're encouraged to conduct an experiment using a
1111
`Jupyter notebook <https://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=jupyter_test_{repository}.ipynb>`_.
1212

1313

14-
.. code-block::
14+
.. code-block:: python
1515
1616
import time
1717
from wrapt_timeout_decorator import *

.docs/parts/05_considerations_using_subprocesses.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ Choosing the Right Start Method
3535

3636
Setting the Start Method
3737
------------------------
38-
Configure the start method with ``multiprocessing.set_start_method(method, force=False)``. This should be done cautiously, ideally once, and within the ``if __name__ == '__main__'`` block to prevent unintended effects.
38+
Configure the start method with ``multiprocessing.set_start_method(method, force=True)``. This should be done cautiously, ideally once, and within the ``if
39+
__name__ == '__main__'`` block to prevent unintended effects.
3940
Since we use ``multiprocess`` instead of ``multiprocessing``, we provide a method to set the starting method on both at the same time.
4041
see : `set_subprocess_starting_method`_
4142

4243
Special Considerations for Uvicorn, FastAPI, asyncio
4344
----------------------------------------------------
44-
For 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. This design aims to reset signal handlers and manage file descriptors in child processes effectively.
45-
You can set that by using the parameter `dec_mp_reset_signals`
45+
For 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.
46+
This design aims to reset signal handlers and manage file descriptors in child processes effectively.
47+
You can set that by passing the parameter ``dec_mp_reset_signals=True`` to the decorator.

.docs/parts/06_nested_timeouts.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ For practical experimentation and to see this behavior in action,
88
you're encouraged to use a `Jupyter notebook <https://mybinder.org/v2/gh/bitranox/wrapt_timeout_decorator/master?filepath=jupyter_test_{repository}.ipynb>`_.
99

1010

11-
.. code-block::
11+
.. code-block:: python
1212
1313
# main.py
1414
import mylib
@@ -20,7 +20,7 @@ you're encouraged to use a `Jupyter notebook <https://mybinder.org/v2/gh/bitrano
2020
mylib.outer()
2121
2222
23-
.. code-block::
23+
.. code-block:: python
2424
2525
# mylib.py
2626
from wrapt_timeout_decorator import *

.docs/parts/07_custom_timeout_exception.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ Custom Timeout Exception
33

44
Define a different exception to be raised upon timeout:
55

6-
.. code-block:: py
6+
.. code-block:: python
77
88
import time
99
from wrapt_timeout_decorator import *
1010
11+
# this will throw StopIteration Error instead of TimeoutError
1112
@timeout(5, timeout_exception=StopIteration)
1213
def mytest(message):
1314
# this example does NOT work on windows, please check the section

.docs/parts/08_parameters.rst

Lines changed: 84 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,94 @@
11
Parameters
22
----------
33

4-
.. code-block::
4+
.. code-block:: python
55
6-
@timeout(dec_timeout, use_signals, timeout_exception, exception_message, dec_allow_eval, dec_hard_timeout, dec_mp_reset_signals)
6+
@timeout(dec_timeout, use_signals, timeout_exception, exception_message,
7+
dec_allow_eval, dec_hard_timeout, dec_mp_reset_signals)
78
def decorated_function(*args, **kwargs):
89
# interesting things happens here ...
910
...
1011
11-
"""
12-
dec_timeout This parameter sets the timeout duration. It accepts a float, integer, or a string
13-
that can be evaluated to a number if dec_allow_eval is enabled.
14-
By default, there's no timeout (None). You can change the timeout dynamically
15-
by passing a dec_timeout keyword argument to the decorated function.
16-
17-
use_signals This boolean parameter controls whether to use UNIX signals for implementing timeouts.
18-
It's the most accurate method but comes with certain limitations,
19-
such as being available only on Linux and macOS, and only in the main thread.
20-
By default, signals are not used (False). It's typically not necessary to modify
21-
this setting manually, but you can override it by passing a use_signals keyword argument
22-
to the decorated function.
23-
24-
timeout_exception Specifies the exception to raise when a timeout occurs.
25-
by default, it's set to TimeoutError
26-
type: exception
27-
default: TimeoutError
28-
29-
exception_message You can customize the message of the timeout exception.
30-
The default message includes the name of the function and the timeout duration.
31-
This message gets formatted with the actual values when a timeout occurs.
32-
type: str
33-
default : 'Function {function_name} timed out after {dec_timeout} seconds' (will be formatted)
34-
35-
dec_allow_eval When enabled (True), this boolean parameter allows the dec_timeout string to be evaluated dynamically.
36-
It provides access to the decorated function (wrapped), the instance it belongs to (instance),
37-
the positional arguments (args), and keyword arguments (kwargs).
38-
It's disabled (False) by default for safety reasons but can be enabled by passing a dec_allow_eval
39-
keyword argument to the decorated function.
40-
41-
instance Example: 'instance.x' - see example above or doku
42-
args Example: 'args[0]' - the timeout is the first argument in args
43-
kwargs Example: 'kwargs["max_time"] * 2'
44-
type: bool
45-
default: false
46-
47-
dec_hard_timeout This boolean parameter is relevant when signals cannot be used,
48-
necessitating the creation of a new process for the timeout mechanism.
49-
Setting it to True means the timeout strictly applies to the execution time of the function,
50-
potentially not allowing enough time for process creation.
51-
With False, the process creation time is not included in the timeout, giving the actual function
52-
the full duration to execute.
53-
You can override this setting by passing a dec_hard_timeout keyword argument to the decorated function.
54-
type: bool
55-
default: false
56-
can be overridden by passing the kwarg dec_hard_timeout to the decorated function*
57-
58-
dec_mp_reset_signals This parameter is relevant when using the "fork" start method for multiprocessing.
59-
Setting it to True accomplishes two primary objectives:
60-
61-
- Restores Default Signal Handlers in Child Processes:
62-
It ensures that child processes revert to the default signal handling behavior,
63-
rather than inheriting signal handlers from the parent process.
64-
This adjustment is crucial for applications utilizing frameworks like "unicorn" or "FastAPI",
65-
facilitating the use of the efficient "fork" method while maintaining correct signal handling.
66-
For more context, refer to the Discussion on
67-
FastAPI GitHub page: https://github.com/tiangolo/fastapi/discussions/7442
68-
69-
- Avoids Inheritance of the File Descriptor (fd) for Wakeup Signals:
70-
Typically, if the parent process utilizes a wakeup_fd, child processes inherit this descriptor.
71-
Consequently, when a signal is sent to a child, it is also received by the parent process
72-
via this shared socket, potentially leading to unintended termination or shutdown of the application.
73-
By resetting signal handlers and not using the inherited fd, this parameter prevents such conflicts,
74-
ensuring isolated and correct signal handling in child processes.
75-
76-
Note: This parameter exclusively affects processes initiated with the "fork" method
77-
and is not applicable to other multiprocessing start methods.
12+
13+
14+
- dec_timeout
15+
This parameter sets the timeout duration. It accepts a float, integer, or a string
16+
that can be evaluated to a number if dec_allow_eval is enabled.
17+
By default, there's no timeout (None). You can change the timeout dynamically
18+
by passing a dec_timeout keyword argument to the decorated function.
19+
20+
- use_signals
21+
This boolean parameter controls whether to use UNIX signals for implementing timeouts.
22+
It's the most accurate method but comes with certain limitations,
23+
such as being available only on Linux and macOS, and only in the main thread.
24+
By default, signals are not used (False). It's typically not necessary to modify
25+
this setting manually, but you can override it by passing 'use_signals=True' to the decorated function.
26+
27+
- timeout_exception
28+
Specifies the exception to raise when a timeout occurs.
29+
by default, it's set to TimeoutError
30+
type: exception
31+
default: TimeoutError
32+
33+
- exception_message
34+
You can customize the message of the timeout exception.
35+
The default message includes the name of the function and the timeout duration.
36+
This message gets formatted with the actual values when a timeout occurs.
37+
type: str
38+
default : 'Function {function_name} timed out after {dec_timeout} seconds' (will be formatted)
39+
40+
- dec_allow_eval
41+
When enabled (True), this boolean parameter allows the dec_timeout string to be evaluated dynamically.
42+
It provides access
43+
44+
- to the decorated function (wrapped),
45+
- the instance it belongs to (instance),
46+
- the positional arguments (args),
47+
- and keyword arguments (kwargs).
48+
49+
It's disabled (False) by default for safety reasons but can be enabled by passing a dec_allow_eval
50+
keyword argument to the decorated function.
51+
52+
instance Example: 'instance.x' - see example above or doku
53+
args Example: 'args[0]' - the timeout is the first argument in args
54+
kwargs Example: 'kwargs["max_time"] * 2'
55+
type: bool
56+
default: false
57+
see section "Dynamic Timeout Value Adjustment with eval" in the manual
58+
59+
- dec_hard_timeout
60+
This boolean parameter is relevant when signals cannot be used,
61+
necessitating the creation of a new process for the timeout mechanism.
62+
Setting it to True means the timeout strictly applies to the execution time of the function,
63+
potentially not allowing enough time for process creation.
64+
With False, the process creation time is not included in the timeout, giving the actual function
65+
the full duration to execute.
66+
You can override this setting by passing a dec_hard_timeout keyword argument to the decorated function.
67+
type: bool
68+
default: false
69+
can be overridden by passing the kwarg dec_hard_timeout to the decorated function*
70+
71+
- dec_mp_reset_signals
72+
This parameter is relevant when using the "fork" start method for multiprocessing.
73+
Setting it to True accomplishes two primary objectives:
74+
75+
- Restores Default Signal Handlers in Child Processes:
76+
It ensures that child processes revert to the default signal handling behavior,
77+
rather than inheriting signal handlers from the parent process.
78+
This adjustment is crucial for applications utilizing frameworks like "unicorn" or "FastAPI",
79+
facilitating the use of the efficient "fork" method while maintaining correct signal handling.
80+
For more context, refer to the Discussion on
81+
FastAPI GitHub page: https://github.com/tiangolo/fastapi/discussions/7442
82+
83+
- Avoids Inheritance of the File Descriptor (fd) for Wakeup Signals:
84+
Typically, if the parent process utilizes a wakeup_fd, child processes inherit this descriptor.
85+
Consequently, when a signal is sent to a child, it is also received by the parent process
86+
via this shared socket, potentially leading to unintended termination or shutdown of the application.
87+
By resetting signal handlers and not using the inherited fd, this parameter prevents such conflicts,
88+
ensuring isolated and correct signal handling in child processes.
89+
90+
Note: This parameter exclusively affects processes initiated with the "fork" method
91+
and is not applicable to other multiprocessing start methods.
7892

7993
For enhanced isolation of subprocesses, consider utilizing the "forkserver" or "spawn" start methods in multiprocessing.
8094
These methods provide a greater degree of independence between the parent process and its children,
@@ -83,5 +97,4 @@ Parameters
8397
new process environment for each child process, as opposed to directly duplicating the parent process's environment,
8498
which occurs with the "fork" method.
8599

86-
* that means the decorated_function must not use that kwarg itself, since this kwarg will be popped from the kwargs
87-
"""
100+
* that means the decorated_function must not use that kwarg itself, since this kwarg will be popped from the kwargs

0 commit comments

Comments
 (0)