tenacity 8.4.2__tar.gz → 8.5.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.
- {tenacity-8.4.2 → tenacity-8.5.0}/.github/workflows/ci.yaml +1 -1
- {tenacity-8.4.2 → tenacity-8.5.0}/.github/workflows/deploy.yaml +1 -1
- {tenacity-8.4.2/tenacity.egg-info → tenacity-8.5.0}/PKG-INFO +1 -1
- {tenacity-8.4.2 → tenacity-8.5.0}/README.rst +31 -5
- {tenacity-8.4.2 → tenacity-8.5.0}/doc/source/index.rst +31 -5
- tenacity-8.5.0/releasenotes/notes/fix-retry-wrapper-attributes-f7a3a45b8e90f257.yaml +6 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/__init__.py +1 -1
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/asyncio/__init__.py +1 -1
- {tenacity-8.4.2 → tenacity-8.5.0/tenacity.egg-info}/PKG-INFO +1 -1
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity.egg-info/SOURCES.txt +1 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_asyncio.py +60 -1
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_tenacity.py +48 -10
- {tenacity-8.4.2 → tenacity-8.5.0}/.editorconfig +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/.github/dependabot.yml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/.gitignore +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/.mergify.yml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/.readthedocs.yml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/LICENSE +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/doc/source/api.rst +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/doc/source/changelog.rst +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/doc/source/conf.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/pyproject.toml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/Fix-tests-for-typeguard-3.x-6eebfea546b6207e.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/Use--for-formatting-and-validate-using-black-39ec9d57d4691778.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-async-actions-b249c527d99723bb.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-reno-d1ab5710f272650a.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-retry_except_exception_type-31b31da1924d55f4.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-stop-before-delay-a775f88ac872c923.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-test-extra-55e869261b03e56d.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add_retry_if_exception_cause_type-d16b918ace4ae0ad.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/added_a_link_to_documentation-eefaf8f074b539f8.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/after_log-50f4d73b24ce9203.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/allow-mocking-of-nap-sleep-6679c50e702446f1.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/annotate_code-197b93130df14042.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/before_sleep_log-improvements-d8149274dfb37d7c.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/dependabot-for-github-actions-4d2464f3c0928463.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/do_not_package_tests-fe5ac61940b0a5ed.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/drop-deprecated-python-versions-69a05cb2e0f1034c.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/drop_deprecated-7ea90b212509b082.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix-local-context-overwrite-94190ba06a481631.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix_async-52b6594c8e75c4bc.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/make-logger-more-compatible-5da1ddf1bab77047.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/pr320-py3-only-wheel-tag.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/py36_plus-c425fb3aa17c6682.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/remove-py36-876c0416cf279d15.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/retrycallstate-repr-94947f7b00ee15e1.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/some-slug-for-preserve-defaults-86682846dfa18005.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/sphinx_define_error-642c9cd5c165d39a.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/support-timedelta-wait-unit-type-5ba1e9fc0fe45523.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/trio-support-retry-22bd544800cd1f36.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/wait_exponential_jitter-6ffc81dddcbaa6d3.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/reno.yaml +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/setup.cfg +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/setup.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/_utils.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/after.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/asyncio/retry.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/before.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/before_sleep.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/nap.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/py.typed +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/retry.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/stop.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/tornadoweb.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity/wait.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity.egg-info/dependency_links.txt +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity.egg-info/requires.txt +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tenacity.egg-info/top_level.txt +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/__init__.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_after.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_issue_478.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_tornado.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tests/test_utils.py +0 -0
- {tenacity-8.4.2 → tenacity-8.5.0}/tox.ini +0 -0
|
@@ -124,8 +124,8 @@ retrying stuff.
|
|
|
124
124
|
print("Stopping after 10 seconds")
|
|
125
125
|
raise Exception
|
|
126
126
|
|
|
127
|
-
If you're on a tight deadline, and exceeding your delay time isn't ok,
|
|
128
|
-
then you can give up on retries one attempt before you would exceed the delay.
|
|
127
|
+
If you're on a tight deadline, and exceeding your delay time isn't ok,
|
|
128
|
+
then you can give up on retries one attempt before you would exceed the delay.
|
|
129
129
|
|
|
130
130
|
.. testcode::
|
|
131
131
|
|
|
@@ -362,7 +362,7 @@ Statistics
|
|
|
362
362
|
~~~~~~~~~~
|
|
363
363
|
|
|
364
364
|
You can access the statistics about the retry made over a function by using the
|
|
365
|
-
`
|
|
365
|
+
`statistics` attribute attached to the function:
|
|
366
366
|
|
|
367
367
|
.. testcode::
|
|
368
368
|
|
|
@@ -375,7 +375,7 @@ You can access the statistics about the retry made over a function by using the
|
|
|
375
375
|
except Exception:
|
|
376
376
|
pass
|
|
377
377
|
|
|
378
|
-
print(raise_my_exception.
|
|
378
|
+
print(raise_my_exception.statistics)
|
|
379
379
|
|
|
380
380
|
.. testoutput::
|
|
381
381
|
:hide:
|
|
@@ -495,7 +495,7 @@ using the `retry_with` function attached to the wrapped function:
|
|
|
495
495
|
except Exception:
|
|
496
496
|
pass
|
|
497
497
|
|
|
498
|
-
print(raise_my_exception.
|
|
498
|
+
print(raise_my_exception.statistics)
|
|
499
499
|
|
|
500
500
|
.. testoutput::
|
|
501
501
|
:hide:
|
|
@@ -514,6 +514,32 @@ to use the `retry` decorator - you can instead use `Retrying` directly:
|
|
|
514
514
|
retryer = Retrying(stop=stop_after_attempt(max_attempts), reraise=True)
|
|
515
515
|
retryer(never_good_enough, 'I really do try')
|
|
516
516
|
|
|
517
|
+
You may also want to change the behaviour of a decorated function temporarily,
|
|
518
|
+
like in tests to avoid unnecessary wait times. You can modify/patch the `retry`
|
|
519
|
+
attribute attached to the function. Bear in mind this is a write-only attribute,
|
|
520
|
+
statistics should be read from the function `statistics` attribute.
|
|
521
|
+
|
|
522
|
+
.. testcode::
|
|
523
|
+
|
|
524
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
|
|
525
|
+
def raise_my_exception():
|
|
526
|
+
raise MyException("Fail")
|
|
527
|
+
|
|
528
|
+
from unittest import mock
|
|
529
|
+
|
|
530
|
+
with mock.patch.object(raise_my_exception.retry, "wait", wait_fixed(0)):
|
|
531
|
+
try:
|
|
532
|
+
raise_my_exception()
|
|
533
|
+
except Exception:
|
|
534
|
+
pass
|
|
535
|
+
|
|
536
|
+
print(raise_my_exception.statistics)
|
|
537
|
+
|
|
538
|
+
.. testoutput::
|
|
539
|
+
:hide:
|
|
540
|
+
|
|
541
|
+
...
|
|
542
|
+
|
|
517
543
|
Retrying code block
|
|
518
544
|
~~~~~~~~~~~~~~~~~~~
|
|
519
545
|
|
|
@@ -124,8 +124,8 @@ retrying stuff.
|
|
|
124
124
|
print("Stopping after 10 seconds")
|
|
125
125
|
raise Exception
|
|
126
126
|
|
|
127
|
-
If you're on a tight deadline, and exceeding your delay time isn't ok,
|
|
128
|
-
then you can give up on retries one attempt before you would exceed the delay.
|
|
127
|
+
If you're on a tight deadline, and exceeding your delay time isn't ok,
|
|
128
|
+
then you can give up on retries one attempt before you would exceed the delay.
|
|
129
129
|
|
|
130
130
|
.. testcode::
|
|
131
131
|
|
|
@@ -362,7 +362,7 @@ Statistics
|
|
|
362
362
|
~~~~~~~~~~
|
|
363
363
|
|
|
364
364
|
You can access the statistics about the retry made over a function by using the
|
|
365
|
-
`
|
|
365
|
+
`statistics` attribute attached to the function:
|
|
366
366
|
|
|
367
367
|
.. testcode::
|
|
368
368
|
|
|
@@ -375,7 +375,7 @@ You can access the statistics about the retry made over a function by using the
|
|
|
375
375
|
except Exception:
|
|
376
376
|
pass
|
|
377
377
|
|
|
378
|
-
print(raise_my_exception.
|
|
378
|
+
print(raise_my_exception.statistics)
|
|
379
379
|
|
|
380
380
|
.. testoutput::
|
|
381
381
|
:hide:
|
|
@@ -495,7 +495,7 @@ using the `retry_with` function attached to the wrapped function:
|
|
|
495
495
|
except Exception:
|
|
496
496
|
pass
|
|
497
497
|
|
|
498
|
-
print(raise_my_exception.
|
|
498
|
+
print(raise_my_exception.statistics)
|
|
499
499
|
|
|
500
500
|
.. testoutput::
|
|
501
501
|
:hide:
|
|
@@ -514,6 +514,32 @@ to use the `retry` decorator - you can instead use `Retrying` directly:
|
|
|
514
514
|
retryer = Retrying(stop=stop_after_attempt(max_attempts), reraise=True)
|
|
515
515
|
retryer(never_good_enough, 'I really do try')
|
|
516
516
|
|
|
517
|
+
You may also want to change the behaviour of a decorated function temporarily,
|
|
518
|
+
like in tests to avoid unnecessary wait times. You can modify/patch the `retry`
|
|
519
|
+
attribute attached to the function. Bear in mind this is a write-only attribute,
|
|
520
|
+
statistics should be read from the function `statistics` attribute.
|
|
521
|
+
|
|
522
|
+
.. testcode::
|
|
523
|
+
|
|
524
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
|
|
525
|
+
def raise_my_exception():
|
|
526
|
+
raise MyException("Fail")
|
|
527
|
+
|
|
528
|
+
from unittest import mock
|
|
529
|
+
|
|
530
|
+
with mock.patch.object(raise_my_exception.retry, "wait", wait_fixed(0)):
|
|
531
|
+
try:
|
|
532
|
+
raise_my_exception()
|
|
533
|
+
except Exception:
|
|
534
|
+
pass
|
|
535
|
+
|
|
536
|
+
print(raise_my_exception.statistics)
|
|
537
|
+
|
|
538
|
+
.. testoutput::
|
|
539
|
+
:hide:
|
|
540
|
+
|
|
541
|
+
...
|
|
542
|
+
|
|
517
543
|
Retrying code block
|
|
518
544
|
~~~~~~~~~~~~~~~~~~~
|
|
519
545
|
|
|
@@ -339,7 +339,7 @@ class BaseRetrying(ABC):
|
|
|
339
339
|
return self.copy(*args, **kwargs).wraps(f)
|
|
340
340
|
|
|
341
341
|
# Preserve attributes
|
|
342
|
-
wrapped_f.retry =
|
|
342
|
+
wrapped_f.retry = self # type: ignore[attr-defined]
|
|
343
343
|
wrapped_f.retry_with = retry_with # type: ignore[attr-defined]
|
|
344
344
|
wrapped_f.statistics = {} # type: ignore[attr-defined]
|
|
345
345
|
|
|
@@ -189,7 +189,7 @@ class AsyncRetrying(BaseRetrying):
|
|
|
189
189
|
return await copy(fn, *args, **kwargs)
|
|
190
190
|
|
|
191
191
|
# Preserve attributes
|
|
192
|
-
async_wrapped.retry =
|
|
192
|
+
async_wrapped.retry = self # type: ignore[attr-defined]
|
|
193
193
|
async_wrapped.retry_with = wrapped.retry_with # type: ignore[attr-defined]
|
|
194
194
|
async_wrapped.statistics = {} # type: ignore[attr-defined]
|
|
195
195
|
|
|
@@ -38,6 +38,7 @@ releasenotes/notes/drop_deprecated-7ea90b212509b082.yaml
|
|
|
38
38
|
releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml
|
|
39
39
|
releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml
|
|
40
40
|
releasenotes/notes/fix-local-context-overwrite-94190ba06a481631.yaml
|
|
41
|
+
releasenotes/notes/fix-retry-wrapper-attributes-f7a3a45b8e90f257.yaml
|
|
41
42
|
releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml
|
|
42
43
|
releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
|
|
43
44
|
releasenotes/notes/fix_async-52b6594c8e75c4bc.yaml
|
|
@@ -17,6 +17,7 @@ import asyncio
|
|
|
17
17
|
import inspect
|
|
18
18
|
import unittest
|
|
19
19
|
from functools import wraps
|
|
20
|
+
from unittest import mock
|
|
20
21
|
|
|
21
22
|
try:
|
|
22
23
|
import trio
|
|
@@ -59,7 +60,7 @@ async def _retryable_coroutine(thing):
|
|
|
59
60
|
@retry(stop=stop_after_attempt(2))
|
|
60
61
|
async def _retryable_coroutine_with_2_attempts(thing):
|
|
61
62
|
await asyncio.sleep(0.00001)
|
|
62
|
-
thing.go()
|
|
63
|
+
return thing.go()
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
class TestAsyncio(unittest.TestCase):
|
|
@@ -394,6 +395,64 @@ class TestContextManager(unittest.TestCase):
|
|
|
394
395
|
await _async_function(thing)
|
|
395
396
|
|
|
396
397
|
|
|
398
|
+
class TestDecoratorWrapper(unittest.TestCase):
|
|
399
|
+
@asynctest
|
|
400
|
+
async def test_retry_function_attributes(self):
|
|
401
|
+
"""Test that the wrapped function attributes are exposed as intended.
|
|
402
|
+
|
|
403
|
+
- statistics contains the value for the latest function run
|
|
404
|
+
- retry object can be modified to change its behaviour (useful to patch in tests)
|
|
405
|
+
- retry object statistics do not contain valid information
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
self.assertTrue(
|
|
409
|
+
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(1))
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
expected_stats = {
|
|
413
|
+
"attempt_number": 2,
|
|
414
|
+
"delay_since_first_attempt": mock.ANY,
|
|
415
|
+
"idle_for": mock.ANY,
|
|
416
|
+
"start_time": mock.ANY,
|
|
417
|
+
}
|
|
418
|
+
self.assertEqual(
|
|
419
|
+
_retryable_coroutine_with_2_attempts.statistics, # type: ignore[attr-defined]
|
|
420
|
+
expected_stats,
|
|
421
|
+
)
|
|
422
|
+
self.assertEqual(
|
|
423
|
+
_retryable_coroutine_with_2_attempts.retry.statistics, # type: ignore[attr-defined]
|
|
424
|
+
{},
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
with mock.patch.object(
|
|
428
|
+
_retryable_coroutine_with_2_attempts.retry, # type: ignore[attr-defined]
|
|
429
|
+
"stop",
|
|
430
|
+
tenacity.stop_after_attempt(1),
|
|
431
|
+
):
|
|
432
|
+
try:
|
|
433
|
+
self.assertTrue(
|
|
434
|
+
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(2))
|
|
435
|
+
)
|
|
436
|
+
except RetryError as exc:
|
|
437
|
+
expected_stats = {
|
|
438
|
+
"attempt_number": 1,
|
|
439
|
+
"delay_since_first_attempt": mock.ANY,
|
|
440
|
+
"idle_for": mock.ANY,
|
|
441
|
+
"start_time": mock.ANY,
|
|
442
|
+
}
|
|
443
|
+
self.assertEqual(
|
|
444
|
+
_retryable_coroutine_with_2_attempts.statistics, # type: ignore[attr-defined]
|
|
445
|
+
expected_stats,
|
|
446
|
+
)
|
|
447
|
+
self.assertEqual(exc.last_attempt.attempt_number, 1)
|
|
448
|
+
self.assertEqual(
|
|
449
|
+
_retryable_coroutine_with_2_attempts.retry.statistics, # type: ignore[attr-defined]
|
|
450
|
+
{},
|
|
451
|
+
)
|
|
452
|
+
else:
|
|
453
|
+
self.fail("RetryError should have been raised after 1 attempt")
|
|
454
|
+
|
|
455
|
+
|
|
397
456
|
# make sure mypy accepts passing an async sleep function
|
|
398
457
|
# https://github.com/jd/tenacity/issues/399
|
|
399
458
|
async def my_async_sleep(x: float) -> None:
|
|
@@ -25,6 +25,7 @@ import warnings
|
|
|
25
25
|
from contextlib import contextmanager
|
|
26
26
|
from copy import copy
|
|
27
27
|
from fractions import Fraction
|
|
28
|
+
from unittest import mock
|
|
28
29
|
|
|
29
30
|
import pytest
|
|
30
31
|
|
|
@@ -1073,7 +1074,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1073
1074
|
_retryable_test_with_unless_exception_type_name(NameErrorUntilCount(5))
|
|
1074
1075
|
)
|
|
1075
1076
|
except NameError as e:
|
|
1076
|
-
s = _retryable_test_with_unless_exception_type_name.
|
|
1077
|
+
s = _retryable_test_with_unless_exception_type_name.statistics
|
|
1077
1078
|
self.assertTrue(s["attempt_number"] == 6)
|
|
1078
1079
|
print(e)
|
|
1079
1080
|
else:
|
|
@@ -1088,7 +1089,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1088
1089
|
)
|
|
1089
1090
|
)
|
|
1090
1091
|
except NameError as e:
|
|
1091
|
-
s = _retryable_test_with_unless_exception_type_no_input.
|
|
1092
|
+
s = _retryable_test_with_unless_exception_type_no_input.statistics
|
|
1092
1093
|
self.assertTrue(s["attempt_number"] == 6)
|
|
1093
1094
|
print(e)
|
|
1094
1095
|
else:
|
|
@@ -1111,7 +1112,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1111
1112
|
_retryable_test_if_exception_message_message(NoCustomErrorAfterCount(3))
|
|
1112
1113
|
)
|
|
1113
1114
|
except CustomError:
|
|
1114
|
-
print(_retryable_test_if_exception_message_message.
|
|
1115
|
+
print(_retryable_test_if_exception_message_message.statistics)
|
|
1115
1116
|
self.fail("CustomError should've been retried from errormessage")
|
|
1116
1117
|
|
|
1117
1118
|
def test_retry_if_not_exception_message(self):
|
|
@@ -1122,7 +1123,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1122
1123
|
)
|
|
1123
1124
|
)
|
|
1124
1125
|
except CustomError:
|
|
1125
|
-
s = _retryable_test_if_not_exception_message_message.
|
|
1126
|
+
s = _retryable_test_if_not_exception_message_message.statistics
|
|
1126
1127
|
self.assertTrue(s["attempt_number"] == 1)
|
|
1127
1128
|
|
|
1128
1129
|
def test_retry_if_not_exception_message_delay(self):
|
|
@@ -1131,7 +1132,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1131
1132
|
_retryable_test_not_exception_message_delay(NameErrorUntilCount(3))
|
|
1132
1133
|
)
|
|
1133
1134
|
except NameError:
|
|
1134
|
-
s = _retryable_test_not_exception_message_delay.
|
|
1135
|
+
s = _retryable_test_not_exception_message_delay.statistics
|
|
1135
1136
|
print(s["attempt_number"])
|
|
1136
1137
|
self.assertTrue(s["attempt_number"] == 4)
|
|
1137
1138
|
|
|
@@ -1151,7 +1152,7 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1151
1152
|
)
|
|
1152
1153
|
)
|
|
1153
1154
|
except CustomError:
|
|
1154
|
-
s = _retryable_test_if_not_exception_message_message.
|
|
1155
|
+
s = _retryable_test_if_not_exception_message_message.statistics
|
|
1155
1156
|
self.assertTrue(s["attempt_number"] == 1)
|
|
1156
1157
|
|
|
1157
1158
|
def test_retry_if_exception_cause_type(self):
|
|
@@ -1209,6 +1210,43 @@ class TestDecoratorWrapper(unittest.TestCase):
|
|
|
1209
1210
|
h = retrying.wraps(Hello())
|
|
1210
1211
|
self.assertEqual(h(), "Hello")
|
|
1211
1212
|
|
|
1213
|
+
def test_retry_function_attributes(self):
|
|
1214
|
+
"""Test that the wrapped function attributes are exposed as intended.
|
|
1215
|
+
|
|
1216
|
+
- statistics contains the value for the latest function run
|
|
1217
|
+
- retry object can be modified to change its behaviour (useful to patch in tests)
|
|
1218
|
+
- retry object statistics do not contain valid information
|
|
1219
|
+
"""
|
|
1220
|
+
|
|
1221
|
+
self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))
|
|
1222
|
+
|
|
1223
|
+
expected_stats = {
|
|
1224
|
+
"attempt_number": 3,
|
|
1225
|
+
"delay_since_first_attempt": mock.ANY,
|
|
1226
|
+
"idle_for": mock.ANY,
|
|
1227
|
+
"start_time": mock.ANY,
|
|
1228
|
+
}
|
|
1229
|
+
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
|
|
1230
|
+
self.assertEqual(_retryable_test_with_stop.retry.statistics, {})
|
|
1231
|
+
|
|
1232
|
+
with mock.patch.object(
|
|
1233
|
+
_retryable_test_with_stop.retry, "stop", tenacity.stop_after_attempt(1)
|
|
1234
|
+
):
|
|
1235
|
+
try:
|
|
1236
|
+
self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))
|
|
1237
|
+
except RetryError as exc:
|
|
1238
|
+
expected_stats = {
|
|
1239
|
+
"attempt_number": 1,
|
|
1240
|
+
"delay_since_first_attempt": mock.ANY,
|
|
1241
|
+
"idle_for": mock.ANY,
|
|
1242
|
+
"start_time": mock.ANY,
|
|
1243
|
+
}
|
|
1244
|
+
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
|
|
1245
|
+
self.assertEqual(exc.last_attempt.attempt_number, 1)
|
|
1246
|
+
self.assertEqual(_retryable_test_with_stop.retry.statistics, {})
|
|
1247
|
+
else:
|
|
1248
|
+
self.fail("RetryError should have been raised after 1 attempt")
|
|
1249
|
+
|
|
1212
1250
|
|
|
1213
1251
|
class TestRetryWith:
|
|
1214
1252
|
def test_redefine_wait(self):
|
|
@@ -1479,21 +1517,21 @@ class TestStatistics(unittest.TestCase):
|
|
|
1479
1517
|
def _foobar():
|
|
1480
1518
|
return 42
|
|
1481
1519
|
|
|
1482
|
-
self.assertEqual({}, _foobar.
|
|
1520
|
+
self.assertEqual({}, _foobar.statistics)
|
|
1483
1521
|
_foobar()
|
|
1484
|
-
self.assertEqual(1, _foobar.
|
|
1522
|
+
self.assertEqual(1, _foobar.statistics["attempt_number"])
|
|
1485
1523
|
|
|
1486
1524
|
def test_stats_failing(self):
|
|
1487
1525
|
@retry(stop=tenacity.stop_after_attempt(2))
|
|
1488
1526
|
def _foobar():
|
|
1489
1527
|
raise ValueError(42)
|
|
1490
1528
|
|
|
1491
|
-
self.assertEqual({}, _foobar.
|
|
1529
|
+
self.assertEqual({}, _foobar.statistics)
|
|
1492
1530
|
try:
|
|
1493
1531
|
_foobar()
|
|
1494
1532
|
except Exception: # noqa: B902
|
|
1495
1533
|
pass
|
|
1496
|
-
self.assertEqual(2, _foobar.
|
|
1534
|
+
self.assertEqual(2, _foobar.statistics["attempt_number"])
|
|
1497
1535
|
|
|
1498
1536
|
|
|
1499
1537
|
class TestRetryErrorCallback(unittest.TestCase):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-async-actions-b249c527d99723bb.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/add-stop-before-delay-a775f88ac872c923.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/do_not_package_tests-fe5ac61940b0a5ed.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/retrycallstate-repr-94947f7b00ee15e1.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/sphinx_define_error-642c9cd5c165d39a.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
RENAMED
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/trio-support-retry-22bd544800cd1f36.yaml
RENAMED
|
File without changes
|
{tenacity-8.4.2 → tenacity-8.5.0}/releasenotes/notes/wait_exponential_jitter-6ffc81dddcbaa6d3.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|