python-backoff 2.3.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_backoff-2.3.0 → python_backoff-2.4.0}/.gitignore +1 -3
- {python_backoff-2.3.0 → python_backoff-2.4.0}/PKG-INFO +108 -59
- {python_backoff-2.3.0 → python_backoff-2.4.0}/README.rst +106 -55
- {python_backoff-2.3.0 → python_backoff-2.4.0}/backoff/__init__.py +15 -13
- python_backoff-2.4.0/backoff/_async.py +301 -0
- python_backoff-2.4.0/backoff/_common.py +291 -0
- python_backoff-2.4.0/backoff/_decorator.py +398 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/backoff/_jitter.py +0 -2
- python_backoff-2.4.0/backoff/_sync.py +238 -0
- python_backoff-2.4.0/backoff/_typing.py +68 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/backoff/_wait_gen.py +36 -42
- {python_backoff-2.3.0 → python_backoff-2.4.0}/backoff/types.py +1 -2
- python_backoff-2.4.0/pyproject.toml +262 -0
- python_backoff-2.4.0/tests/common.py +45 -0
- python_backoff-2.4.0/tests/test_backoff.py +1021 -0
- python_backoff-2.4.0/tests/test_backoff_async.py +772 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/test_integration.py +6 -8
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/test_jitter.py +2 -3
- python_backoff-2.4.0/tests/test_package.py +31 -0
- python_backoff-2.4.0/tests/test_retry_context.py +348 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/test_types.py +0 -3
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/test_wait_gen.py +37 -28
- python_backoff-2.3.0/backoff/_async.py +0 -188
- python_backoff-2.3.0/backoff/_common.py +0 -120
- python_backoff-2.3.0/backoff/_decorator.py +0 -222
- python_backoff-2.3.0/backoff/_sync.py +0 -130
- python_backoff-2.3.0/backoff/_typing.py +0 -45
- python_backoff-2.3.0/pyproject.toml +0 -190
- python_backoff-2.3.0/tests/common.py +0 -24
- python_backoff-2.3.0/tests/test_backoff.py +0 -918
- python_backoff-2.3.0/tests/test_backoff_async.py +0 -688
- {python_backoff-2.3.0 → python_backoff-2.4.0}/LICENSE +0 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/backoff/py.typed +0 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/__init__.py +0 -0
- {python_backoff-2.3.0 → python_backoff-2.4.0}/tests/test_typing.py +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-backoff
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Function decoration for backoff and retry
|
|
5
5
|
Project-URL: Documentation, https://python-backoff.github.io/backoff
|
|
6
6
|
Project-URL: Repository, https://github.com/python-backoff/backoff
|
|
@@ -11,12 +11,10 @@ License-File: LICENSE
|
|
|
11
11
|
Keywords: backoff,decorators,retry
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Natural Language :: English
|
|
16
15
|
Classifier: Operating System :: OS Independent
|
|
17
16
|
Classifier: Programming Language :: Python
|
|
18
17
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -27,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.15
|
|
|
27
25
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
28
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
27
|
Classifier: Topic :: Utilities
|
|
30
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.9
|
|
31
29
|
Description-Content-Type: text/x-rst
|
|
32
30
|
|
|
33
31
|
backoff
|
|
@@ -58,7 +56,7 @@ for asynchronous code.
|
|
|
58
56
|
Examples
|
|
59
57
|
========
|
|
60
58
|
|
|
61
|
-
Since Kenneth Reitz's `requests <
|
|
59
|
+
Since Kenneth Reitz's `requests <https://requests.readthedocs.io>`_ module
|
|
62
60
|
has become a defacto standard for synchronous HTTP clients in Python,
|
|
63
61
|
networking examples below are written using it, but it is in no way required
|
|
64
62
|
by the backoff module.
|
|
@@ -72,8 +70,10 @@ is raised. Here's an example using exponential backoff when any
|
|
|
72
70
|
|
|
73
71
|
.. code-block:: python
|
|
74
72
|
|
|
75
|
-
@backoff.on_exception(
|
|
76
|
-
|
|
73
|
+
@backoff.on_exception(
|
|
74
|
+
backoff.expo,
|
|
75
|
+
requests.exceptions.RequestException,
|
|
76
|
+
)
|
|
77
77
|
def get_url(url):
|
|
78
78
|
return requests.get(url)
|
|
79
79
|
|
|
@@ -82,9 +82,13 @@ the same backoff behavior is desired for more than one exception type:
|
|
|
82
82
|
|
|
83
83
|
.. code-block:: python
|
|
84
84
|
|
|
85
|
-
@backoff.on_exception(
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
@backoff.on_exception(
|
|
86
|
+
backoff.expo,
|
|
87
|
+
(
|
|
88
|
+
requests.exceptions.Timeout,
|
|
89
|
+
requests.exceptions.ConnectionError,
|
|
90
|
+
),
|
|
91
|
+
)
|
|
88
92
|
def get_url(url):
|
|
89
93
|
return requests.get(url)
|
|
90
94
|
|
|
@@ -98,9 +102,11 @@ of total time in seconds that can elapse before giving up.
|
|
|
98
102
|
|
|
99
103
|
.. code-block:: python
|
|
100
104
|
|
|
101
|
-
@backoff.on_exception(
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
@backoff.on_exception(
|
|
106
|
+
backoff.expo,
|
|
107
|
+
requests.exceptions.RequestException,
|
|
108
|
+
max_time=60,
|
|
109
|
+
)
|
|
104
110
|
def get_url(url):
|
|
105
111
|
return requests.get(url)
|
|
106
112
|
|
|
@@ -110,10 +116,12 @@ to make to the target function before giving up.
|
|
|
110
116
|
|
|
111
117
|
.. code-block:: python
|
|
112
118
|
|
|
113
|
-
@backoff.on_exception(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
@backoff.on_exception(
|
|
120
|
+
backoff.expo,
|
|
121
|
+
requests.exceptions.RequestException,
|
|
122
|
+
max_tries=8,
|
|
123
|
+
jitter=None,
|
|
124
|
+
)
|
|
117
125
|
def get_url(url):
|
|
118
126
|
return requests.get(url)
|
|
119
127
|
|
|
@@ -129,10 +137,13 @@ be retried:
|
|
|
129
137
|
def fatal_code(e):
|
|
130
138
|
return 400 <= e.response.status_code < 500
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
|
|
141
|
+
@backoff.on_exception(
|
|
142
|
+
backoff.expo,
|
|
143
|
+
requests.exceptions.RequestException,
|
|
144
|
+
max_time=300,
|
|
145
|
+
giveup=fatal_code,
|
|
146
|
+
)
|
|
136
147
|
def get_url(url):
|
|
137
148
|
return requests.get(url)
|
|
138
149
|
|
|
@@ -150,11 +161,14 @@ case, regardless of the logic in the `on_exception` handler.
|
|
|
150
161
|
def fatal_code(e):
|
|
151
162
|
return 400 <= e.response.status_code < 500
|
|
152
163
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
164
|
+
|
|
165
|
+
@backoff.on_exception(
|
|
166
|
+
backoff.expo,
|
|
167
|
+
requests.exceptions.RequestException,
|
|
168
|
+
max_time=300,
|
|
169
|
+
raise_on_giveup=False,
|
|
170
|
+
giveup=fatal_code,
|
|
171
|
+
)
|
|
158
172
|
def get_url(url):
|
|
159
173
|
return requests.get(url)
|
|
160
174
|
|
|
@@ -174,7 +188,11 @@ return value of the target function is the empty list:
|
|
|
174
188
|
|
|
175
189
|
.. code-block:: python
|
|
176
190
|
|
|
177
|
-
@backoff.on_predicate(
|
|
191
|
+
@backoff.on_predicate(
|
|
192
|
+
backoff.fibo,
|
|
193
|
+
lambda x: x == [],
|
|
194
|
+
max_value=13,
|
|
195
|
+
)
|
|
178
196
|
def poll_for_messages(queue):
|
|
179
197
|
return queue.get()
|
|
180
198
|
|
|
@@ -196,7 +214,11 @@ gets a non-falsey result could be defined like like this:
|
|
|
196
214
|
|
|
197
215
|
.. code-block:: python
|
|
198
216
|
|
|
199
|
-
@backoff.on_predicate(
|
|
217
|
+
@backoff.on_predicate(
|
|
218
|
+
backoff.constant,
|
|
219
|
+
jitter=None,
|
|
220
|
+
interval=1,
|
|
221
|
+
)
|
|
200
222
|
def poll_for_message(queue):
|
|
201
223
|
return queue.get()
|
|
202
224
|
|
|
@@ -249,12 +271,16 @@ backoff behavior for different cases:
|
|
|
249
271
|
.. code-block:: python
|
|
250
272
|
|
|
251
273
|
@backoff.on_predicate(backoff.fibo, max_value=13)
|
|
252
|
-
@backoff.on_exception(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
@backoff.on_exception(
|
|
275
|
+
backoff.expo,
|
|
276
|
+
requests.exceptions.HTTPError,
|
|
277
|
+
max_time=60,
|
|
278
|
+
)
|
|
279
|
+
@backoff.on_exception(
|
|
280
|
+
backoff.expo,
|
|
281
|
+
requests.exceptions.Timeout,
|
|
282
|
+
max_time=300,
|
|
283
|
+
)
|
|
258
284
|
def poll_for_message(queue):
|
|
259
285
|
return queue.get()
|
|
260
286
|
|
|
@@ -277,9 +303,13 @@ runtime to obtain the value:
|
|
|
277
303
|
# and that it has a dictionary-like 'config' property
|
|
278
304
|
return app.config["BACKOFF_MAX_TIME"]
|
|
279
305
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
306
|
+
|
|
307
|
+
@backoff.on_exception(
|
|
308
|
+
backoff.expo,
|
|
309
|
+
ValueError,
|
|
310
|
+
max_time=lookup_max_time,
|
|
311
|
+
)
|
|
312
|
+
def my_function(): ...
|
|
283
313
|
|
|
284
314
|
Event handlers
|
|
285
315
|
--------------
|
|
@@ -307,13 +337,18 @@ implemented like so:
|
|
|
307
337
|
.. code-block:: python
|
|
308
338
|
|
|
309
339
|
def backoff_hdlr(details):
|
|
310
|
-
print
|
|
311
|
-
|
|
312
|
-
|
|
340
|
+
print(
|
|
341
|
+
"Backing off {wait:0.1f} seconds after {tries} tries "
|
|
342
|
+
"calling function {target} with args {args} and kwargs "
|
|
343
|
+
"{kwargs}".format(**details)
|
|
344
|
+
)
|
|
345
|
+
|
|
313
346
|
|
|
314
|
-
@backoff.on_exception(
|
|
315
|
-
|
|
316
|
-
|
|
347
|
+
@backoff.on_exception(
|
|
348
|
+
backoff.expo,
|
|
349
|
+
requests.exceptions.RequestException,
|
|
350
|
+
on_backoff=backoff_hdlr,
|
|
351
|
+
)
|
|
317
352
|
def get_url(url):
|
|
318
353
|
return requests.get(url)
|
|
319
354
|
|
|
@@ -325,9 +360,14 @@ handler functions as the value of the ``on_backoff`` keyword arg:
|
|
|
325
360
|
|
|
326
361
|
.. code-block:: python
|
|
327
362
|
|
|
328
|
-
@backoff.on_exception(
|
|
329
|
-
|
|
330
|
-
|
|
363
|
+
@backoff.on_exception(
|
|
364
|
+
backoff.expo,
|
|
365
|
+
requests.exceptions.RequestException,
|
|
366
|
+
on_backoff=[
|
|
367
|
+
backoff_hdlr1,
|
|
368
|
+
backoff_hdlr2,
|
|
369
|
+
],
|
|
370
|
+
)
|
|
331
371
|
def get_url(url):
|
|
332
372
|
return requests.get(url)
|
|
333
373
|
|
|
@@ -358,9 +398,13 @@ asynchronous HTTP client/server library.
|
|
|
358
398
|
|
|
359
399
|
.. code-block:: python
|
|
360
400
|
|
|
361
|
-
@backoff.on_exception(
|
|
401
|
+
@backoff.on_exception(
|
|
402
|
+
backoff.expo,
|
|
403
|
+
aiohttp.ClientError,
|
|
404
|
+
max_time=60,
|
|
405
|
+
)
|
|
362
406
|
async def get_url(url):
|
|
363
|
-
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
|
407
|
+
async with aiohttp.ClientSession(raise_for_status=True) as session: # ruff:ignore[multiple-with-statements]
|
|
364
408
|
async with session.get(url) as response:
|
|
365
409
|
return await response.text()
|
|
366
410
|
|
|
@@ -375,7 +419,7 @@ as:
|
|
|
375
419
|
|
|
376
420
|
.. code-block:: python
|
|
377
421
|
|
|
378
|
-
logging.getLogger(
|
|
422
|
+
logging.getLogger("backoff").addHandler(logging.StreamHandler())
|
|
379
423
|
|
|
380
424
|
The default logging level is INFO, which corresponds to logging
|
|
381
425
|
anytime a retry event occurs. If you would instead like to log
|
|
@@ -383,7 +427,7 @@ only when a giveup event occurs, set the logger level to ERROR.
|
|
|
383
427
|
|
|
384
428
|
.. code-block:: python
|
|
385
429
|
|
|
386
|
-
logging.getLogger(
|
|
430
|
+
logging.getLogger("backoff").setLevel(logging.ERROR)
|
|
387
431
|
|
|
388
432
|
It is also possible to specify an alternate logger with the ``logger``
|
|
389
433
|
keyword argument. If a string value is specified the logger will be
|
|
@@ -391,25 +435,30 @@ looked up by name.
|
|
|
391
435
|
|
|
392
436
|
.. code-block:: python
|
|
393
437
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
438
|
+
@backoff.on_exception(
|
|
439
|
+
backoff.expo,
|
|
440
|
+
requests.exceptions.RequestException,
|
|
441
|
+
logger="my_logger",
|
|
442
|
+
)
|
|
443
|
+
def my_function(): ...
|
|
398
444
|
|
|
399
445
|
It is also supported to specify a Logger (or LoggerAdapter) object
|
|
400
446
|
directly.
|
|
401
447
|
|
|
402
448
|
.. code-block:: python
|
|
403
449
|
|
|
404
|
-
my_logger = logging.getLogger(
|
|
450
|
+
my_logger = logging.getLogger("my_logger")
|
|
405
451
|
my_handler = logging.StreamHandler()
|
|
406
452
|
my_logger.addHandler(my_handler)
|
|
407
453
|
my_logger.setLevel(logging.ERROR)
|
|
408
454
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
455
|
+
|
|
456
|
+
@backoff.on_exception(
|
|
457
|
+
backoff.expo,
|
|
458
|
+
requests.exceptions.RequestException,
|
|
459
|
+
logger=my_logger,
|
|
460
|
+
)
|
|
461
|
+
def my_function(): ...
|
|
413
462
|
|
|
414
463
|
Default logging can be disabled all together by specifying
|
|
415
464
|
``logger=None``. In this case, if desired alternative logging behavior
|
|
@@ -26,7 +26,7 @@ for asynchronous code.
|
|
|
26
26
|
Examples
|
|
27
27
|
========
|
|
28
28
|
|
|
29
|
-
Since Kenneth Reitz's `requests <
|
|
29
|
+
Since Kenneth Reitz's `requests <https://requests.readthedocs.io>`_ module
|
|
30
30
|
has become a defacto standard for synchronous HTTP clients in Python,
|
|
31
31
|
networking examples below are written using it, but it is in no way required
|
|
32
32
|
by the backoff module.
|
|
@@ -40,8 +40,10 @@ is raised. Here's an example using exponential backoff when any
|
|
|
40
40
|
|
|
41
41
|
.. code-block:: python
|
|
42
42
|
|
|
43
|
-
@backoff.on_exception(
|
|
44
|
-
|
|
43
|
+
@backoff.on_exception(
|
|
44
|
+
backoff.expo,
|
|
45
|
+
requests.exceptions.RequestException,
|
|
46
|
+
)
|
|
45
47
|
def get_url(url):
|
|
46
48
|
return requests.get(url)
|
|
47
49
|
|
|
@@ -50,9 +52,13 @@ the same backoff behavior is desired for more than one exception type:
|
|
|
50
52
|
|
|
51
53
|
.. code-block:: python
|
|
52
54
|
|
|
53
|
-
@backoff.on_exception(
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
@backoff.on_exception(
|
|
56
|
+
backoff.expo,
|
|
57
|
+
(
|
|
58
|
+
requests.exceptions.Timeout,
|
|
59
|
+
requests.exceptions.ConnectionError,
|
|
60
|
+
),
|
|
61
|
+
)
|
|
56
62
|
def get_url(url):
|
|
57
63
|
return requests.get(url)
|
|
58
64
|
|
|
@@ -66,9 +72,11 @@ of total time in seconds that can elapse before giving up.
|
|
|
66
72
|
|
|
67
73
|
.. code-block:: python
|
|
68
74
|
|
|
69
|
-
@backoff.on_exception(
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
@backoff.on_exception(
|
|
76
|
+
backoff.expo,
|
|
77
|
+
requests.exceptions.RequestException,
|
|
78
|
+
max_time=60,
|
|
79
|
+
)
|
|
72
80
|
def get_url(url):
|
|
73
81
|
return requests.get(url)
|
|
74
82
|
|
|
@@ -78,10 +86,12 @@ to make to the target function before giving up.
|
|
|
78
86
|
|
|
79
87
|
.. code-block:: python
|
|
80
88
|
|
|
81
|
-
@backoff.on_exception(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
@backoff.on_exception(
|
|
90
|
+
backoff.expo,
|
|
91
|
+
requests.exceptions.RequestException,
|
|
92
|
+
max_tries=8,
|
|
93
|
+
jitter=None,
|
|
94
|
+
)
|
|
85
95
|
def get_url(url):
|
|
86
96
|
return requests.get(url)
|
|
87
97
|
|
|
@@ -97,10 +107,13 @@ be retried:
|
|
|
97
107
|
def fatal_code(e):
|
|
98
108
|
return 400 <= e.response.status_code < 500
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
|
|
111
|
+
@backoff.on_exception(
|
|
112
|
+
backoff.expo,
|
|
113
|
+
requests.exceptions.RequestException,
|
|
114
|
+
max_time=300,
|
|
115
|
+
giveup=fatal_code,
|
|
116
|
+
)
|
|
104
117
|
def get_url(url):
|
|
105
118
|
return requests.get(url)
|
|
106
119
|
|
|
@@ -118,11 +131,14 @@ case, regardless of the logic in the `on_exception` handler.
|
|
|
118
131
|
def fatal_code(e):
|
|
119
132
|
return 400 <= e.response.status_code < 500
|
|
120
133
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
|
|
135
|
+
@backoff.on_exception(
|
|
136
|
+
backoff.expo,
|
|
137
|
+
requests.exceptions.RequestException,
|
|
138
|
+
max_time=300,
|
|
139
|
+
raise_on_giveup=False,
|
|
140
|
+
giveup=fatal_code,
|
|
141
|
+
)
|
|
126
142
|
def get_url(url):
|
|
127
143
|
return requests.get(url)
|
|
128
144
|
|
|
@@ -142,7 +158,11 @@ return value of the target function is the empty list:
|
|
|
142
158
|
|
|
143
159
|
.. code-block:: python
|
|
144
160
|
|
|
145
|
-
@backoff.on_predicate(
|
|
161
|
+
@backoff.on_predicate(
|
|
162
|
+
backoff.fibo,
|
|
163
|
+
lambda x: x == [],
|
|
164
|
+
max_value=13,
|
|
165
|
+
)
|
|
146
166
|
def poll_for_messages(queue):
|
|
147
167
|
return queue.get()
|
|
148
168
|
|
|
@@ -164,7 +184,11 @@ gets a non-falsey result could be defined like like this:
|
|
|
164
184
|
|
|
165
185
|
.. code-block:: python
|
|
166
186
|
|
|
167
|
-
@backoff.on_predicate(
|
|
187
|
+
@backoff.on_predicate(
|
|
188
|
+
backoff.constant,
|
|
189
|
+
jitter=None,
|
|
190
|
+
interval=1,
|
|
191
|
+
)
|
|
168
192
|
def poll_for_message(queue):
|
|
169
193
|
return queue.get()
|
|
170
194
|
|
|
@@ -217,12 +241,16 @@ backoff behavior for different cases:
|
|
|
217
241
|
.. code-block:: python
|
|
218
242
|
|
|
219
243
|
@backoff.on_predicate(backoff.fibo, max_value=13)
|
|
220
|
-
@backoff.on_exception(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
244
|
+
@backoff.on_exception(
|
|
245
|
+
backoff.expo,
|
|
246
|
+
requests.exceptions.HTTPError,
|
|
247
|
+
max_time=60,
|
|
248
|
+
)
|
|
249
|
+
@backoff.on_exception(
|
|
250
|
+
backoff.expo,
|
|
251
|
+
requests.exceptions.Timeout,
|
|
252
|
+
max_time=300,
|
|
253
|
+
)
|
|
226
254
|
def poll_for_message(queue):
|
|
227
255
|
return queue.get()
|
|
228
256
|
|
|
@@ -245,9 +273,13 @@ runtime to obtain the value:
|
|
|
245
273
|
# and that it has a dictionary-like 'config' property
|
|
246
274
|
return app.config["BACKOFF_MAX_TIME"]
|
|
247
275
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
276
|
+
|
|
277
|
+
@backoff.on_exception(
|
|
278
|
+
backoff.expo,
|
|
279
|
+
ValueError,
|
|
280
|
+
max_time=lookup_max_time,
|
|
281
|
+
)
|
|
282
|
+
def my_function(): ...
|
|
251
283
|
|
|
252
284
|
Event handlers
|
|
253
285
|
--------------
|
|
@@ -275,13 +307,18 @@ implemented like so:
|
|
|
275
307
|
.. code-block:: python
|
|
276
308
|
|
|
277
309
|
def backoff_hdlr(details):
|
|
278
|
-
print
|
|
279
|
-
|
|
280
|
-
|
|
310
|
+
print(
|
|
311
|
+
"Backing off {wait:0.1f} seconds after {tries} tries "
|
|
312
|
+
"calling function {target} with args {args} and kwargs "
|
|
313
|
+
"{kwargs}".format(**details)
|
|
314
|
+
)
|
|
315
|
+
|
|
281
316
|
|
|
282
|
-
@backoff.on_exception(
|
|
283
|
-
|
|
284
|
-
|
|
317
|
+
@backoff.on_exception(
|
|
318
|
+
backoff.expo,
|
|
319
|
+
requests.exceptions.RequestException,
|
|
320
|
+
on_backoff=backoff_hdlr,
|
|
321
|
+
)
|
|
285
322
|
def get_url(url):
|
|
286
323
|
return requests.get(url)
|
|
287
324
|
|
|
@@ -293,9 +330,14 @@ handler functions as the value of the ``on_backoff`` keyword arg:
|
|
|
293
330
|
|
|
294
331
|
.. code-block:: python
|
|
295
332
|
|
|
296
|
-
@backoff.on_exception(
|
|
297
|
-
|
|
298
|
-
|
|
333
|
+
@backoff.on_exception(
|
|
334
|
+
backoff.expo,
|
|
335
|
+
requests.exceptions.RequestException,
|
|
336
|
+
on_backoff=[
|
|
337
|
+
backoff_hdlr1,
|
|
338
|
+
backoff_hdlr2,
|
|
339
|
+
],
|
|
340
|
+
)
|
|
299
341
|
def get_url(url):
|
|
300
342
|
return requests.get(url)
|
|
301
343
|
|
|
@@ -326,9 +368,13 @@ asynchronous HTTP client/server library.
|
|
|
326
368
|
|
|
327
369
|
.. code-block:: python
|
|
328
370
|
|
|
329
|
-
@backoff.on_exception(
|
|
371
|
+
@backoff.on_exception(
|
|
372
|
+
backoff.expo,
|
|
373
|
+
aiohttp.ClientError,
|
|
374
|
+
max_time=60,
|
|
375
|
+
)
|
|
330
376
|
async def get_url(url):
|
|
331
|
-
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
|
377
|
+
async with aiohttp.ClientSession(raise_for_status=True) as session: # ruff:ignore[multiple-with-statements]
|
|
332
378
|
async with session.get(url) as response:
|
|
333
379
|
return await response.text()
|
|
334
380
|
|
|
@@ -343,7 +389,7 @@ as:
|
|
|
343
389
|
|
|
344
390
|
.. code-block:: python
|
|
345
391
|
|
|
346
|
-
logging.getLogger(
|
|
392
|
+
logging.getLogger("backoff").addHandler(logging.StreamHandler())
|
|
347
393
|
|
|
348
394
|
The default logging level is INFO, which corresponds to logging
|
|
349
395
|
anytime a retry event occurs. If you would instead like to log
|
|
@@ -351,7 +397,7 @@ only when a giveup event occurs, set the logger level to ERROR.
|
|
|
351
397
|
|
|
352
398
|
.. code-block:: python
|
|
353
399
|
|
|
354
|
-
logging.getLogger(
|
|
400
|
+
logging.getLogger("backoff").setLevel(logging.ERROR)
|
|
355
401
|
|
|
356
402
|
It is also possible to specify an alternate logger with the ``logger``
|
|
357
403
|
keyword argument. If a string value is specified the logger will be
|
|
@@ -359,25 +405,30 @@ looked up by name.
|
|
|
359
405
|
|
|
360
406
|
.. code-block:: python
|
|
361
407
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
408
|
+
@backoff.on_exception(
|
|
409
|
+
backoff.expo,
|
|
410
|
+
requests.exceptions.RequestException,
|
|
411
|
+
logger="my_logger",
|
|
412
|
+
)
|
|
413
|
+
def my_function(): ...
|
|
366
414
|
|
|
367
415
|
It is also supported to specify a Logger (or LoggerAdapter) object
|
|
368
416
|
directly.
|
|
369
417
|
|
|
370
418
|
.. code-block:: python
|
|
371
419
|
|
|
372
|
-
my_logger = logging.getLogger(
|
|
420
|
+
my_logger = logging.getLogger("my_logger")
|
|
373
421
|
my_handler = logging.StreamHandler()
|
|
374
422
|
my_logger.addHandler(my_handler)
|
|
375
423
|
my_logger.setLevel(logging.ERROR)
|
|
376
424
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
425
|
+
|
|
426
|
+
@backoff.on_exception(
|
|
427
|
+
backoff.expo,
|
|
428
|
+
requests.exceptions.RequestException,
|
|
429
|
+
logger=my_logger,
|
|
430
|
+
)
|
|
431
|
+
def my_function(): ...
|
|
381
432
|
|
|
382
433
|
Default logging can be disabled all together by specifying
|
|
383
434
|
``logger=None``. In this case, if desired alternative logging behavior
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# coding:utf-8
|
|
2
1
|
"""
|
|
3
2
|
Function decoration for backoff and retry
|
|
4
3
|
|
|
@@ -12,20 +11,23 @@ polling resources for externally generated content.
|
|
|
12
11
|
For examples and full documentation see the README at
|
|
13
12
|
https://github.com/python-backoff/backoff
|
|
14
13
|
"""
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
from backoff._decorator import aretry_context, on_exception, on_predicate, retry_context
|
|
16
16
|
from backoff._jitter import full_jitter, random_jitter
|
|
17
|
-
from backoff._wait_gen import constant, expo, fibo, runtime
|
|
17
|
+
from backoff._wait_gen import constant, decay, expo, fibo, runtime
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
"aretry_context",
|
|
21
|
+
"constant",
|
|
22
|
+
"decay",
|
|
23
|
+
"expo",
|
|
24
|
+
"fibo",
|
|
25
|
+
"full_jitter",
|
|
26
|
+
"on_exception",
|
|
27
|
+
"on_predicate",
|
|
28
|
+
"random_jitter",
|
|
29
|
+
"retry_context",
|
|
30
|
+
"runtime",
|
|
29
31
|
]
|
|
30
32
|
|
|
31
|
-
__version__ = "2.
|
|
33
|
+
__version__ = "2.4.0"
|