tenacity 8.4.1__tar.gz → 8.4.2__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.1/tenacity.egg-info → tenacity-8.4.2}/PKG-INFO +1 -1
- tenacity-8.4.2/releasenotes/notes/fix-local-context-overwrite-94190ba06a481631.yaml +4 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/__init__.py +8 -2
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/asyncio/__init__.py +9 -4
- {tenacity-8.4.1 → tenacity-8.4.2/tenacity.egg-info}/PKG-INFO +1 -1
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity.egg-info/SOURCES.txt +2 -0
- tenacity-8.4.2/tests/test_issue_478.py +118 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.editorconfig +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.github/dependabot.yml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.github/workflows/ci.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.github/workflows/deploy.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.gitignore +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.mergify.yml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/.readthedocs.yml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/LICENSE +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/README.rst +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/doc/source/api.rst +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/doc/source/changelog.rst +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/doc/source/conf.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/doc/source/index.rst +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/pyproject.toml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/Fix-tests-for-typeguard-3.x-6eebfea546b6207e.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/Use--for-formatting-and-validate-using-black-39ec9d57d4691778.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-async-actions-b249c527d99723bb.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-reno-d1ab5710f272650a.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-retry_except_exception_type-31b31da1924d55f4.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-stop-before-delay-a775f88ac872c923.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-test-extra-55e869261b03e56d.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add_omitted_modules_to_import_all-2ab282f20a2c22f7.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add_retry_if_exception_cause_type-d16b918ace4ae0ad.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/added_a_link_to_documentation-eefaf8f074b539f8.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/after_log-50f4d73b24ce9203.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/allow-mocking-of-nap-sleep-6679c50e702446f1.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/annotate_code-197b93130df14042.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/before_sleep_log-improvements-d8149274dfb37d7c.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/dependabot-for-github-actions-4d2464f3c0928463.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/do_not_package_tests-fe5ac61940b0a5ed.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/drop-deprecated-python-versions-69a05cb2e0f1034c.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/drop_deprecated-7ea90b212509b082.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/export-convenience-symbols-981d9611c8b754f3.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/fix-async-loop-with-result-f68e913ccb425aca.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/fix_async-52b6594c8e75c4bc.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/make-logger-more-compatible-5da1ddf1bab77047.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/no-async-iter-6132a42e52348a75.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/pr320-py3-only-wheel-tag.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/py36_plus-c425fb3aa17c6682.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/remove-py36-876c0416cf279d15.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/retrycallstate-repr-94947f7b00ee15e1.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/some-slug-for-preserve-defaults-86682846dfa18005.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/sphinx_define_error-642c9cd5c165d39a.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/support-timedelta-wait-unit-type-5ba1e9fc0fe45523.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/trio-support-retry-22bd544800cd1f36.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/wait_exponential_jitter-6ffc81dddcbaa6d3.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/reno.yaml +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/setup.cfg +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/setup.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/_utils.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/after.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/asyncio/retry.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/before.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/before_sleep.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/nap.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/py.typed +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/retry.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/stop.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/tornadoweb.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity/wait.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity.egg-info/dependency_links.txt +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity.egg-info/requires.txt +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tenacity.egg-info/top_level.txt +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/__init__.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/test_after.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/test_asyncio.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/test_tenacity.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/test_tornado.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tests/test_utils.py +0 -0
- {tenacity-8.4.1 → tenacity-8.4.2}/tox.ini +0 -0
|
@@ -329,13 +329,19 @@ class BaseRetrying(ABC):
|
|
|
329
329
|
f, functools.WRAPPER_ASSIGNMENTS + ("__defaults__", "__kwdefaults__")
|
|
330
330
|
)
|
|
331
331
|
def wrapped_f(*args: t.Any, **kw: t.Any) -> t.Any:
|
|
332
|
-
|
|
332
|
+
# Always create a copy to prevent overwriting the local contexts when
|
|
333
|
+
# calling the same wrapped functions multiple times in the same stack
|
|
334
|
+
copy = self.copy()
|
|
335
|
+
wrapped_f.statistics = copy.statistics # type: ignore[attr-defined]
|
|
336
|
+
return copy(f, *args, **kw)
|
|
333
337
|
|
|
334
338
|
def retry_with(*args: t.Any, **kwargs: t.Any) -> WrappedFn:
|
|
335
339
|
return self.copy(*args, **kwargs).wraps(f)
|
|
336
340
|
|
|
337
|
-
|
|
341
|
+
# Preserve attributes
|
|
342
|
+
wrapped_f.retry = wrapped_f # type: ignore[attr-defined]
|
|
338
343
|
wrapped_f.retry_with = retry_with # type: ignore[attr-defined]
|
|
344
|
+
wrapped_f.statistics = {} # type: ignore[attr-defined]
|
|
339
345
|
|
|
340
346
|
return wrapped_f # type: ignore[return-value]
|
|
341
347
|
|
|
@@ -175,18 +175,23 @@ class AsyncRetrying(BaseRetrying):
|
|
|
175
175
|
raise StopAsyncIteration
|
|
176
176
|
|
|
177
177
|
def wraps(self, fn: WrappedFn) -> WrappedFn:
|
|
178
|
-
|
|
178
|
+
wrapped = super().wraps(fn)
|
|
179
179
|
# Ensure wrapper is recognized as a coroutine function.
|
|
180
180
|
|
|
181
181
|
@functools.wraps(
|
|
182
182
|
fn, functools.WRAPPER_ASSIGNMENTS + ("__defaults__", "__kwdefaults__")
|
|
183
183
|
)
|
|
184
184
|
async def async_wrapped(*args: t.Any, **kwargs: t.Any) -> t.Any:
|
|
185
|
-
|
|
185
|
+
# Always create a copy to prevent overwriting the local contexts when
|
|
186
|
+
# calling the same wrapped functions multiple times in the same stack
|
|
187
|
+
copy = self.copy()
|
|
188
|
+
async_wrapped.statistics = copy.statistics # type: ignore[attr-defined]
|
|
189
|
+
return await copy(fn, *args, **kwargs)
|
|
186
190
|
|
|
187
191
|
# Preserve attributes
|
|
188
|
-
async_wrapped.retry =
|
|
189
|
-
async_wrapped.retry_with =
|
|
192
|
+
async_wrapped.retry = async_wrapped # type: ignore[attr-defined]
|
|
193
|
+
async_wrapped.retry_with = wrapped.retry_with # type: ignore[attr-defined]
|
|
194
|
+
async_wrapped.statistics = {} # type: ignore[attr-defined]
|
|
190
195
|
|
|
191
196
|
return async_wrapped # type: ignore[return-value]
|
|
192
197
|
|
|
@@ -37,6 +37,7 @@ releasenotes/notes/drop-deprecated-python-versions-69a05cb2e0f1034c.yaml
|
|
|
37
37
|
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
|
+
releasenotes/notes/fix-local-context-overwrite-94190ba06a481631.yaml
|
|
40
41
|
releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml
|
|
41
42
|
releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml
|
|
42
43
|
releasenotes/notes/fix_async-52b6594c8e75c4bc.yaml
|
|
@@ -73,6 +74,7 @@ tenacity/asyncio/retry.py
|
|
|
73
74
|
tests/__init__.py
|
|
74
75
|
tests/test_after.py
|
|
75
76
|
tests/test_asyncio.py
|
|
77
|
+
tests/test_issue_478.py
|
|
76
78
|
tests/test_tenacity.py
|
|
77
79
|
tests/test_tornado.py
|
|
78
80
|
tests/test_utils.py
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typing
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from functools import wraps
|
|
6
|
+
|
|
7
|
+
from tenacity import RetryCallState, retry
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def asynctest(
|
|
11
|
+
callable_: typing.Callable[..., typing.Any],
|
|
12
|
+
) -> typing.Callable[..., typing.Any]:
|
|
13
|
+
@wraps(callable_)
|
|
14
|
+
def wrapper(*a: typing.Any, **kw: typing.Any) -> typing.Any:
|
|
15
|
+
loop = asyncio.get_event_loop()
|
|
16
|
+
return loop.run_until_complete(callable_(*a, **kw))
|
|
17
|
+
|
|
18
|
+
return wrapper
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
MAX_RETRY_FIX_ATTEMPTS = 2
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestIssue478(unittest.TestCase):
|
|
25
|
+
def test_issue(self) -> None:
|
|
26
|
+
results = []
|
|
27
|
+
|
|
28
|
+
def do_retry(retry_state: RetryCallState) -> bool:
|
|
29
|
+
outcome = retry_state.outcome
|
|
30
|
+
assert outcome
|
|
31
|
+
ex = outcome.exception()
|
|
32
|
+
_subject_: str = retry_state.args[0]
|
|
33
|
+
|
|
34
|
+
if _subject_ == "Fix": # no retry on fix failure
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
if retry_state.attempt_number >= MAX_RETRY_FIX_ATTEMPTS:
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
if ex:
|
|
41
|
+
do_fix_work()
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
@retry(reraise=True, retry=do_retry)
|
|
47
|
+
def _do_work(subject: str) -> None:
|
|
48
|
+
if subject == "Error":
|
|
49
|
+
results.append(f"{subject} is not working")
|
|
50
|
+
raise Exception(f"{subject} is not working")
|
|
51
|
+
results.append(f"{subject} is working")
|
|
52
|
+
|
|
53
|
+
def do_any_work(subject: str) -> None:
|
|
54
|
+
_do_work(subject)
|
|
55
|
+
|
|
56
|
+
def do_fix_work() -> None:
|
|
57
|
+
_do_work("Fix")
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
do_any_work("Error")
|
|
61
|
+
except Exception as exc:
|
|
62
|
+
assert str(exc) == "Error is not working"
|
|
63
|
+
else:
|
|
64
|
+
assert False, "No exception caught"
|
|
65
|
+
|
|
66
|
+
assert results == [
|
|
67
|
+
"Error is not working",
|
|
68
|
+
"Fix is working",
|
|
69
|
+
"Error is not working",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
@asynctest
|
|
73
|
+
async def test_async(self) -> None:
|
|
74
|
+
results = []
|
|
75
|
+
|
|
76
|
+
async def do_retry(retry_state: RetryCallState) -> bool:
|
|
77
|
+
outcome = retry_state.outcome
|
|
78
|
+
assert outcome
|
|
79
|
+
ex = outcome.exception()
|
|
80
|
+
_subject_: str = retry_state.args[0]
|
|
81
|
+
|
|
82
|
+
if _subject_ == "Fix": # no retry on fix failure
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
if retry_state.attempt_number >= MAX_RETRY_FIX_ATTEMPTS:
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
if ex:
|
|
89
|
+
await do_fix_work()
|
|
90
|
+
return True
|
|
91
|
+
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
@retry(reraise=True, retry=do_retry)
|
|
95
|
+
async def _do_work(subject: str) -> None:
|
|
96
|
+
if subject == "Error":
|
|
97
|
+
results.append(f"{subject} is not working")
|
|
98
|
+
raise Exception(f"{subject} is not working")
|
|
99
|
+
results.append(f"{subject} is working")
|
|
100
|
+
|
|
101
|
+
async def do_any_work(subject: str) -> None:
|
|
102
|
+
await _do_work(subject)
|
|
103
|
+
|
|
104
|
+
async def do_fix_work() -> None:
|
|
105
|
+
await _do_work("Fix")
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
await do_any_work("Error")
|
|
109
|
+
except Exception as exc:
|
|
110
|
+
assert str(exc) == "Error is not working"
|
|
111
|
+
else:
|
|
112
|
+
assert False, "No exception caught"
|
|
113
|
+
|
|
114
|
+
assert results == [
|
|
115
|
+
"Error is not working",
|
|
116
|
+
"Fix is working",
|
|
117
|
+
"Error is not working",
|
|
118
|
+
]
|
|
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
|
{tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/add-async-actions-b249c527d99723bb.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/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.1 → tenacity-8.4.2}/releasenotes/notes/clarify-reraise-option-6829667eacf4f599.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/do_not_package_tests-fe5ac61940b0a5ed.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/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.1 → tenacity-8.4.2}/releasenotes/notes/retrycallstate-repr-94947f7b00ee15e1.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/sphinx_define_error-642c9cd5c165d39a.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/timedelta-for-stop-ef6bf71b88ce9988.yaml
RENAMED
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/releasenotes/notes/trio-support-retry-22bd544800cd1f36.yaml
RENAMED
|
File without changes
|
{tenacity-8.4.1 → tenacity-8.4.2}/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
|
|
File without changes
|