tenacity 9.1.2__py3-none-any.whl → 9.1.3__py3-none-any.whl
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/__init__.py +35 -23
- tenacity/_utils.py +12 -0
- tenacity/after.py +2 -4
- tenacity/asyncio/__init__.py +5 -1
- tenacity/before.py +1 -3
- tenacity/before_sleep.py +3 -4
- tenacity/tornadoweb.py +1 -1
- tenacity/wait.py +42 -3
- {tenacity-9.1.2.dist-info → tenacity-9.1.3.dist-info}/METADATA +3 -3
- tenacity-9.1.3.dist-info/RECORD +18 -0
- {tenacity-9.1.2.dist-info → tenacity-9.1.3.dist-info}/WHEEL +1 -1
- tenacity-9.1.2.dist-info/RECORD +0 -18
- {tenacity-9.1.2.dist-info → tenacity-9.1.3.dist-info}/licenses/LICENSE +0 -0
- {tenacity-9.1.2.dist-info → tenacity-9.1.3.dist-info}/top_level.txt +0 -0
tenacity/__init__.py
CHANGED
|
@@ -59,6 +59,7 @@ from .stop import stop_when_event_set # noqa
|
|
|
59
59
|
# Import all built-in wait strategies for easier usage.
|
|
60
60
|
from .wait import wait_chain # noqa
|
|
61
61
|
from .wait import wait_combine # noqa
|
|
62
|
+
from .wait import wait_exception # noqa
|
|
62
63
|
from .wait import wait_exponential # noqa
|
|
63
64
|
from .wait import wait_fixed # noqa
|
|
64
65
|
from .wait import wait_incrementing # noqa
|
|
@@ -98,14 +99,11 @@ if t.TYPE_CHECKING:
|
|
|
98
99
|
|
|
99
100
|
WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
|
|
100
101
|
WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Any])
|
|
102
|
+
P = t.ParamSpec("P")
|
|
103
|
+
R = t.TypeVar("R")
|
|
101
104
|
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
if sys.version_info >= (3, 10):
|
|
105
|
-
dataclass_kwargs.update({"slots": True})
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@dataclasses.dataclass(**dataclass_kwargs)
|
|
106
|
+
@dataclasses.dataclass(slots=True)
|
|
109
107
|
class IterState:
|
|
110
108
|
actions: t.List[t.Callable[["RetryCallState"], t.Any]] = dataclasses.field(
|
|
111
109
|
default_factory=list
|
|
@@ -307,19 +305,15 @@ class BaseRetrying(ABC):
|
|
|
307
305
|
future we may provide a way to aggregate the various
|
|
308
306
|
statistics from each thread).
|
|
309
307
|
"""
|
|
310
|
-
|
|
311
|
-
return self._local.statistics # type: ignore[no-any-return]
|
|
312
|
-
except AttributeError:
|
|
308
|
+
if not hasattr(self._local, "statistics"):
|
|
313
309
|
self._local.statistics = t.cast(t.Dict[str, t.Any], {})
|
|
314
|
-
|
|
310
|
+
return self._local.statistics # type: ignore[no-any-return]
|
|
315
311
|
|
|
316
312
|
@property
|
|
317
313
|
def iter_state(self) -> IterState:
|
|
318
|
-
|
|
319
|
-
return self._local.iter_state # type: ignore[no-any-return]
|
|
320
|
-
except AttributeError:
|
|
314
|
+
if not hasattr(self._local, "iter_state"):
|
|
321
315
|
self._local.iter_state = IterState()
|
|
322
|
-
|
|
316
|
+
return self._local.iter_state # type: ignore[no-any-return]
|
|
323
317
|
|
|
324
318
|
def wraps(self, f: WrappedFn) -> WrappedFn:
|
|
325
319
|
"""Wrap a function for retrying.
|
|
@@ -489,13 +483,7 @@ class Retrying(BaseRetrying):
|
|
|
489
483
|
return do # type: ignore[no-any-return]
|
|
490
484
|
|
|
491
485
|
|
|
492
|
-
|
|
493
|
-
FutureGenericT = futures.Future[t.Any]
|
|
494
|
-
else:
|
|
495
|
-
FutureGenericT = futures.Future
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
class Future(FutureGenericT):
|
|
486
|
+
class Future(futures.Future[t.Any]):
|
|
499
487
|
"""Encapsulates a (future or past) attempted call to a target function."""
|
|
500
488
|
|
|
501
489
|
def __init__(self, attempt_number: int) -> None:
|
|
@@ -603,7 +591,27 @@ def retry(func: WrappedFn) -> WrappedFn: ...
|
|
|
603
591
|
|
|
604
592
|
@t.overload
|
|
605
593
|
def retry(
|
|
606
|
-
|
|
594
|
+
*,
|
|
595
|
+
sleep: t.Callable[[t.Union[int, float]], t.Awaitable[None]],
|
|
596
|
+
stop: "StopBaseT" = ...,
|
|
597
|
+
wait: "WaitBaseT" = ...,
|
|
598
|
+
retry: "t.Union[RetryBaseT, tasyncio.retry.RetryBaseT]" = ...,
|
|
599
|
+
before: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = ...,
|
|
600
|
+
after: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = ...,
|
|
601
|
+
before_sleep: t.Optional[
|
|
602
|
+
t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]]
|
|
603
|
+
] = ...,
|
|
604
|
+
reraise: bool = ...,
|
|
605
|
+
retry_error_cls: t.Type["RetryError"] = ...,
|
|
606
|
+
retry_error_callback: t.Optional[
|
|
607
|
+
t.Callable[["RetryCallState"], t.Union[t.Any, t.Awaitable[t.Any]]]
|
|
608
|
+
] = ...,
|
|
609
|
+
) -> t.Callable[[t.Callable[P, R | t.Awaitable[R]]], t.Callable[P, t.Awaitable[R]]]: ...
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
@t.overload
|
|
613
|
+
def retry(
|
|
614
|
+
sleep: t.Callable[[t.Union[int, float]], None] = sleep,
|
|
607
615
|
stop: "StopBaseT" = stop_never,
|
|
608
616
|
wait: "WaitBaseT" = wait_none(),
|
|
609
617
|
retry: "t.Union[RetryBaseT, tasyncio.retry.RetryBaseT]" = retry_if_exception_type(),
|
|
@@ -642,7 +650,10 @@ def retry(*dargs: t.Any, **dkw: t.Any) -> t.Any:
|
|
|
642
650
|
f"this will probably hang indefinitely (did you mean retry={f.__class__.__name__}(...)?)"
|
|
643
651
|
)
|
|
644
652
|
r: "BaseRetrying"
|
|
645
|
-
|
|
653
|
+
sleep = dkw.get("sleep")
|
|
654
|
+
if _utils.is_coroutine_callable(f) or (
|
|
655
|
+
sleep is not None and _utils.is_coroutine_callable(sleep)
|
|
656
|
+
):
|
|
646
657
|
r = AsyncRetrying(*dargs, **dkw)
|
|
647
658
|
elif (
|
|
648
659
|
tornado
|
|
@@ -690,6 +701,7 @@ __all__ = [
|
|
|
690
701
|
"stop_when_event_set",
|
|
691
702
|
"wait_chain",
|
|
692
703
|
"wait_combine",
|
|
704
|
+
"wait_exception",
|
|
693
705
|
"wait_exponential",
|
|
694
706
|
"wait_fixed",
|
|
695
707
|
"wait_incrementing",
|
tenacity/_utils.py
CHANGED
|
@@ -25,6 +25,18 @@ from datetime import timedelta
|
|
|
25
25
|
MAX_WAIT = sys.maxsize / 2
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
class LoggerProtocol(typing.Protocol):
|
|
29
|
+
"""
|
|
30
|
+
Protocol used by utils expecting a logger (eg: before_log).
|
|
31
|
+
|
|
32
|
+
Compatible with logging, structlog, loguru, etc...
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def log(
|
|
36
|
+
self, level: int, msg: str, /, *args: typing.Any, **kwargs: typing.Any
|
|
37
|
+
) -> typing.Any: ...
|
|
38
|
+
|
|
39
|
+
|
|
28
40
|
def find_ordinal(pos_num: int) -> str:
|
|
29
41
|
# See: https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers
|
|
30
42
|
if pos_num == 0:
|
tenacity/after.py
CHANGED
|
@@ -19,8 +19,6 @@ import typing
|
|
|
19
19
|
from tenacity import _utils
|
|
20
20
|
|
|
21
21
|
if typing.TYPE_CHECKING:
|
|
22
|
-
import logging
|
|
23
|
-
|
|
24
22
|
from tenacity import RetryCallState
|
|
25
23
|
|
|
26
24
|
|
|
@@ -29,9 +27,9 @@ def after_nothing(retry_state: "RetryCallState") -> None:
|
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
def after_log(
|
|
32
|
-
logger:
|
|
30
|
+
logger: _utils.LoggerProtocol,
|
|
33
31
|
log_level: int,
|
|
34
|
-
sec_format: str = "
|
|
32
|
+
sec_format: str = "%.3g",
|
|
35
33
|
) -> typing.Callable[["RetryCallState"], None]:
|
|
36
34
|
"""After call strategy that logs to some logger the finished attempt."""
|
|
37
35
|
|
tenacity/asyncio/__init__.py
CHANGED
|
@@ -107,11 +107,15 @@ class AsyncRetrying(BaseRetrying):
|
|
|
107
107
|
self.begin()
|
|
108
108
|
|
|
109
109
|
retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs)
|
|
110
|
+
is_async = _utils.is_coroutine_callable(fn)
|
|
110
111
|
while True:
|
|
111
112
|
do = await self.iter(retry_state=retry_state)
|
|
112
113
|
if isinstance(do, DoAttempt):
|
|
113
114
|
try:
|
|
114
|
-
|
|
115
|
+
if is_async:
|
|
116
|
+
result = await fn(*args, **kwargs)
|
|
117
|
+
else:
|
|
118
|
+
result = fn(*args, **kwargs)
|
|
115
119
|
except BaseException: # noqa: B902
|
|
116
120
|
retry_state.set_exception(sys.exc_info()) # type: ignore[arg-type]
|
|
117
121
|
else:
|
tenacity/before.py
CHANGED
|
@@ -19,8 +19,6 @@ import typing
|
|
|
19
19
|
from tenacity import _utils
|
|
20
20
|
|
|
21
21
|
if typing.TYPE_CHECKING:
|
|
22
|
-
import logging
|
|
23
|
-
|
|
24
22
|
from tenacity import RetryCallState
|
|
25
23
|
|
|
26
24
|
|
|
@@ -29,7 +27,7 @@ def before_nothing(retry_state: "RetryCallState") -> None:
|
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
def before_log(
|
|
32
|
-
logger:
|
|
30
|
+
logger: _utils.LoggerProtocol, log_level: int
|
|
33
31
|
) -> typing.Callable[["RetryCallState"], None]:
|
|
34
32
|
"""Before call strategy that logs to some logger the attempt."""
|
|
35
33
|
|
tenacity/before_sleep.py
CHANGED
|
@@ -19,8 +19,6 @@ import typing
|
|
|
19
19
|
from tenacity import _utils
|
|
20
20
|
|
|
21
21
|
if typing.TYPE_CHECKING:
|
|
22
|
-
import logging
|
|
23
|
-
|
|
24
22
|
from tenacity import RetryCallState
|
|
25
23
|
|
|
26
24
|
|
|
@@ -29,9 +27,10 @@ def before_sleep_nothing(retry_state: "RetryCallState") -> None:
|
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
def before_sleep_log(
|
|
32
|
-
logger:
|
|
30
|
+
logger: _utils.LoggerProtocol,
|
|
33
31
|
log_level: int,
|
|
34
32
|
exc_info: bool = False,
|
|
33
|
+
sec_format: str = "%.3g",
|
|
35
34
|
) -> typing.Callable[["RetryCallState"], None]:
|
|
36
35
|
"""Before sleep strategy that logs to some logger the attempt."""
|
|
37
36
|
|
|
@@ -65,7 +64,7 @@ def before_sleep_log(
|
|
|
65
64
|
logger.log(
|
|
66
65
|
log_level,
|
|
67
66
|
f"Retrying {fn_name} "
|
|
68
|
-
f"in {retry_state.next_action.sleep} seconds as it {verb} {value}.",
|
|
67
|
+
f"in {sec_format % retry_state.next_action.sleep} seconds as it {verb} {value}.",
|
|
69
68
|
exc_info=local_exc_info,
|
|
70
69
|
)
|
|
71
70
|
|
tenacity/tornadoweb.py
CHANGED
|
@@ -37,7 +37,7 @@ class TornadoRetrying(BaseRetrying):
|
|
|
37
37
|
super().__init__(**kwargs)
|
|
38
38
|
self.sleep = sleep
|
|
39
39
|
|
|
40
|
-
@gen.coroutine # type: ignore[
|
|
40
|
+
@gen.coroutine # type: ignore[untyped-decorator]
|
|
41
41
|
def __call__(
|
|
42
42
|
self,
|
|
43
43
|
fn: "typing.Callable[..., typing.Union[typing.Generator[typing.Any, typing.Any, _RetValT], Future[_RetValT]]]",
|
tenacity/wait.py
CHANGED
|
@@ -98,10 +98,10 @@ class wait_chain(wait_base):
|
|
|
98
98
|
|
|
99
99
|
@retry(wait=wait_chain(*[wait_fixed(1) for i in range(3)] +
|
|
100
100
|
[wait_fixed(2) for j in range(5)] +
|
|
101
|
-
[wait_fixed(5) for k in range(4)))
|
|
101
|
+
[wait_fixed(5) for k in range(4)]))
|
|
102
102
|
def wait_chained():
|
|
103
|
-
print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s
|
|
104
|
-
|
|
103
|
+
print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s "
|
|
104
|
+
"thereafter.")
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
107
|
def __init__(self, *strategies: wait_base) -> None:
|
|
@@ -113,6 +113,45 @@ class wait_chain(wait_base):
|
|
|
113
113
|
return wait_func(retry_state=retry_state)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
class wait_exception(wait_base):
|
|
117
|
+
"""Wait strategy that waits the amount of time returned by the predicate.
|
|
118
|
+
|
|
119
|
+
The predicate is passed the exception object. Based on the exception, the
|
|
120
|
+
user can decide how much time to wait before retrying.
|
|
121
|
+
|
|
122
|
+
For example::
|
|
123
|
+
|
|
124
|
+
def http_error(exception: BaseException) -> float:
|
|
125
|
+
if (
|
|
126
|
+
isinstance(exception, requests.HTTPError)
|
|
127
|
+
and exception.response.status_code == requests.codes.too_many_requests
|
|
128
|
+
):
|
|
129
|
+
return float(exception.response.headers.get("Retry-After", "1"))
|
|
130
|
+
return 60.0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@retry(
|
|
134
|
+
stop=stop_after_attempt(3),
|
|
135
|
+
wait=wait_exception(http_error),
|
|
136
|
+
)
|
|
137
|
+
def http_get_request(url: str) -> None:
|
|
138
|
+
response = requests.get(url)
|
|
139
|
+
response.raise_for_status()
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def __init__(self, predicate: typing.Callable[[BaseException], float]) -> None:
|
|
143
|
+
self.predicate = predicate
|
|
144
|
+
|
|
145
|
+
def __call__(self, retry_state: "RetryCallState") -> float:
|
|
146
|
+
if retry_state.outcome is None:
|
|
147
|
+
raise RuntimeError("__call__() called before outcome was set")
|
|
148
|
+
|
|
149
|
+
exception = retry_state.outcome.exception()
|
|
150
|
+
if exception is None:
|
|
151
|
+
raise RuntimeError("outcome failed but the exception is None")
|
|
152
|
+
return self.predicate(exception)
|
|
153
|
+
|
|
154
|
+
|
|
116
155
|
class wait_incrementing(wait_base):
|
|
117
156
|
"""Wait an incremental amount of time after each attempt.
|
|
118
157
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tenacity
|
|
3
|
-
Version: 9.1.
|
|
3
|
+
Version: 9.1.3
|
|
4
4
|
Summary: Retry code until it succeeds
|
|
5
5
|
Home-page: https://github.com/jd/tenacity
|
|
6
6
|
Author: Julien Danjou
|
|
@@ -11,13 +11,13 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
19
|
Classifier: Topic :: Utilities
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Provides-Extra: doc
|
|
23
23
|
Requires-Dist: reno; extra == "doc"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
tenacity/__init__.py,sha256=4hlAUSM3kIMm_StxMCqLxPyqfU_JWHienwwi1VLWzS8,24761
|
|
2
|
+
tenacity/_utils.py,sha256=3t9RTQghqIA3bdFKfJFQJWigkNvmj2Kzwci6GM6SA_c,3211
|
|
3
|
+
tenacity/after.py,sha256=PIquwn3mfjqtjbLSWPFilMN9z03vAFBbNXa5No6I8F0,1642
|
|
4
|
+
tenacity/before.py,sha256=XfSkW2vxjZ0hnYq7zQm-5cuhP-cIeQngVC4xGrdECxU,1529
|
|
5
|
+
tenacity/before_sleep.py,sha256=KJrNnT2F6q5Ue4Ys52b71c8gmvuhYGyurfXOTy8rzrM,2390
|
|
6
|
+
tenacity/nap.py,sha256=fRWvnz1aIzbIq9Ap3gAkAZgDH6oo5zxMrU6ZOVByq0I,1383
|
|
7
|
+
tenacity/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
tenacity/retry.py,sha256=cZrAzWmMqAORKjmz9B1Pq2Kvn9GX2Znzs_3ybgvQwnE,9034
|
|
9
|
+
tenacity/stop.py,sha256=wQuwGfCLw8OH1C3x0G9lH9xtJCyhgviePQ40HRAUg54,4113
|
|
10
|
+
tenacity/tornadoweb.py,sha256=0oWRxWkJJijVoZT_nRJ2Id6YHmcZ0V6SUIaGHDcpwu8,2138
|
|
11
|
+
tenacity/wait.py,sha256=FLJG9wTFvDpkwMrK8QEW7Dhue22wHtOaoSZWN8k4sPk,9413
|
|
12
|
+
tenacity/asyncio/__init__.py,sha256=cgKuW91lVneg_3TBCJhWm6gqyl0GaWOSYHKq8yMbNlg,7941
|
|
13
|
+
tenacity/asyncio/retry.py,sha256=ymu8F1JfAerc5vDO0V4-2kCvHXqyce2jpO1Nlt6aKxI,4244
|
|
14
|
+
tenacity-9.1.3.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
15
|
+
tenacity-9.1.3.dist-info/METADATA,sha256=CnjNwf3FaryedkK6fGDnbHhsSMwCa3cn2LOF0vaBRvU,1174
|
|
16
|
+
tenacity-9.1.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
17
|
+
tenacity-9.1.3.dist-info/top_level.txt,sha256=Zf8AOZMN7hr1EEcUo9U5KzXsM4TOC1pBZ22D8913JYs,9
|
|
18
|
+
tenacity-9.1.3.dist-info/RECORD,,
|
tenacity-9.1.2.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
tenacity/__init__.py,sha256=LLTmuzCs-hqXeQSVlAig6GwSCj3V1PewC9-b3mTXn1g,24060
|
|
2
|
-
tenacity/_utils.py,sha256=5AwPoFrGOIfPkCtqeJdFBi7KKQNcJXJ3erbtGOXtn6w,2916
|
|
3
|
-
tenacity/after.py,sha256=NR4rGyslG7xF1hDJZb2Wf8wVApafX0HZwz2nFVLvaqE,1658
|
|
4
|
-
tenacity/before.py,sha256=7zDTpZ3b6rkY9sOdS-qbpjBgSjVr3xBqcIqdYAh9ZKM,1544
|
|
5
|
-
tenacity/before_sleep.py,sha256=J8emgLL-jkzbctXE7uzEUfCxWL4SKfGuOmilWowCP9c,2362
|
|
6
|
-
tenacity/nap.py,sha256=fRWvnz1aIzbIq9Ap3gAkAZgDH6oo5zxMrU6ZOVByq0I,1383
|
|
7
|
-
tenacity/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
tenacity/retry.py,sha256=cZrAzWmMqAORKjmz9B1Pq2Kvn9GX2Znzs_3ybgvQwnE,9034
|
|
9
|
-
tenacity/stop.py,sha256=wQuwGfCLw8OH1C3x0G9lH9xtJCyhgviePQ40HRAUg54,4113
|
|
10
|
-
tenacity/tornadoweb.py,sha256=vS1ONfPYoGzPx1asQaVbfoo6D9tPIzSysJipm61Yqw8,2125
|
|
11
|
-
tenacity/wait.py,sha256=1oye0erAqJkSIysEQIfgtZXHunv7t31BwI2gHL1FsSk,8049
|
|
12
|
-
tenacity/asyncio/__init__.py,sha256=PoDGzHN-neTr2GgA1Ti3ORMrSmUIEUblbiSiuyxKHTI,7773
|
|
13
|
-
tenacity/asyncio/retry.py,sha256=ymu8F1JfAerc5vDO0V4-2kCvHXqyce2jpO1Nlt6aKxI,4244
|
|
14
|
-
tenacity-9.1.2.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
15
|
-
tenacity-9.1.2.dist-info/METADATA,sha256=1vPK9y_B7kDK-RNa33tdRKRRABFbTqkrgPGe0YOxV6U,1172
|
|
16
|
-
tenacity-9.1.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
17
|
-
tenacity-9.1.2.dist-info/top_level.txt,sha256=Zf8AOZMN7hr1EEcUo9U5KzXsM4TOC1pBZ22D8913JYs,9
|
|
18
|
-
tenacity-9.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|