summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <p.f.moore@gmail.com>2023-04-02 14:43:48 +0100
committerPaul Moore <p.f.moore@gmail.com>2023-04-02 14:43:48 +0100
commitd2852d0ad2261880b25f7b137ae89c8e5bbeae65 (patch)
tree61ec5e63dc513ad0ccf749faed204c624b01e35a
parentd7e02483264703d6210e8c28937dcf1d9f547796 (diff)
downloadpip-d2852d0ad2261880b25f7b137ae89c8e5bbeae65.tar.gz
Upgrade tenacity to 8.2.2
-rw-r--r--news/tenacity.vendor.rst1
-rw-r--r--src/pip/_vendor/tenacity/__init__.py219
-rw-r--r--src/pip/_vendor/tenacity/_asyncio.py38
-rw-r--r--src/pip/_vendor/tenacity/_utils.py8
-rw-r--r--src/pip/_vendor/tenacity/after.py7
-rw-r--r--src/pip/_vendor/tenacity/before.py7
-rw-r--r--src/pip/_vendor/tenacity/before_sleep.py17
-rw-r--r--src/pip/_vendor/tenacity/retry.py38
-rw-r--r--src/pip/_vendor/tenacity/stop.py11
-rw-r--r--src/pip/_vendor/tenacity/tornadoweb.py6
-rw-r--r--src/pip/_vendor/tenacity/wait.py44
-rw-r--r--src/pip/_vendor/vendor.txt2
-rw-r--r--tools/vendoring/patches/tenacity.patch8
13 files changed, 282 insertions, 124 deletions
diff --git a/news/tenacity.vendor.rst b/news/tenacity.vendor.rst
new file mode 100644
index 000000000..493d38d01
--- /dev/null
+++ b/news/tenacity.vendor.rst
@@ -0,0 +1 @@
+Upgrade tenacity to 8.2.2
diff --git a/src/pip/_vendor/tenacity/__init__.py b/src/pip/_vendor/tenacity/__init__.py
index ab3be3bf6..4f1603ade 100644
--- a/src/pip/_vendor/tenacity/__init__.py
+++ b/src/pip/_vendor/tenacity/__init__.py
@@ -16,6 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
import functools
import sys
import threading
@@ -88,51 +89,13 @@ tornado = None # type: ignore
if t.TYPE_CHECKING:
import types
- from .wait import wait_base
- from .stop import stop_base
-
-
-WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable)
-_RetValT = t.TypeVar("_RetValT")
-
-
-@t.overload
-def retry(fn: WrappedFn) -> WrappedFn:
- pass
-
-
-@t.overload
-def retry(*dargs: t.Any, **dkw: t.Any) -> t.Callable[[WrappedFn], WrappedFn]: # noqa
- pass
-
-
-def retry(*dargs: t.Any, **dkw: t.Any) -> t.Union[WrappedFn, t.Callable[[WrappedFn], WrappedFn]]: # noqa
- """Wrap a function with a new `Retrying` object.
-
- :param dargs: positional arguments passed to Retrying object
- :param dkw: keyword arguments passed to the Retrying object
- """
- # support both @retry and @retry() as valid syntax
- if len(dargs) == 1 and callable(dargs[0]):
- return retry()(dargs[0])
- else:
-
- def wrap(f: WrappedFn) -> WrappedFn:
- if isinstance(f, retry_base):
- warnings.warn(
- f"Got retry_base instance ({f.__class__.__name__}) as callable argument, "
- f"this will probably hang indefinitely (did you mean retry={f.__class__.__name__}(...)?)"
- )
- if iscoroutinefunction(f):
- r: "BaseRetrying" = AsyncRetrying(*dargs, **dkw)
- elif tornado and hasattr(tornado.gen, "is_coroutine_function") and tornado.gen.is_coroutine_function(f):
- r = TornadoRetrying(*dargs, **dkw)
- else:
- r = Retrying(*dargs, **dkw)
+ from .retry import RetryBaseT
+ from .stop import StopBaseT
+ from .wait import WaitBaseT
- return r.wraps(f)
- return wrap
+WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
+WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Any])
class TryAgain(Exception):
@@ -216,7 +179,7 @@ class AttemptManager:
exc_value: t.Optional[BaseException],
traceback: t.Optional["types.TracebackType"],
) -> t.Optional[bool]:
- if isinstance(exc_value, BaseException):
+ if exc_type is not None and exc_value is not None:
self.retry_state.set_exception((exc_type, exc_value, traceback))
return True # Swallow exception.
else:
@@ -229,9 +192,9 @@ class BaseRetrying(ABC):
def __init__(
self,
sleep: t.Callable[[t.Union[int, float]], None] = sleep,
- stop: "stop_base" = stop_never,
- wait: "wait_base" = wait_none(),
- retry: retry_base = retry_if_exception_type(),
+ stop: "StopBaseT" = stop_never,
+ wait: "WaitBaseT" = wait_none(),
+ retry: "RetryBaseT" = retry_if_exception_type(),
before: t.Callable[["RetryCallState"], None] = before_nothing,
after: t.Callable[["RetryCallState"], None] = after_nothing,
before_sleep: t.Optional[t.Callable[["RetryCallState"], None]] = None,
@@ -254,8 +217,8 @@ class BaseRetrying(ABC):
def copy(
self,
sleep: t.Union[t.Callable[[t.Union[int, float]], None], object] = _unset,
- stop: t.Union["stop_base", object] = _unset,
- wait: t.Union["wait_base", object] = _unset,
+ stop: t.Union["StopBaseT", object] = _unset,
+ wait: t.Union["WaitBaseT", object] = _unset,
retry: t.Union[retry_base, object] = _unset,
before: t.Union[t.Callable[["RetryCallState"], None], object] = _unset,
after: t.Union[t.Callable[["RetryCallState"], None], object] = _unset,
@@ -312,9 +275,9 @@ class BaseRetrying(ABC):
statistics from each thread).
"""
try:
- return self._local.statistics
+ return self._local.statistics # type: ignore[no-any-return]
except AttributeError:
- self._local.statistics = {}
+ self._local.statistics = t.cast(t.Dict[str, t.Any], {})
return self._local.statistics
def wraps(self, f: WrappedFn) -> WrappedFn:
@@ -330,10 +293,10 @@ class BaseRetrying(ABC):
def retry_with(*args: t.Any, **kwargs: t.Any) -> WrappedFn:
return self.copy(*args, **kwargs).wraps(f)
- wrapped_f.retry = self
- wrapped_f.retry_with = retry_with
+ wrapped_f.retry = self # type: ignore[attr-defined]
+ wrapped_f.retry_with = retry_with # type: ignore[attr-defined]
- return wrapped_f
+ return wrapped_f # type: ignore[return-value]
def begin(self) -> None:
self.statistics.clear()
@@ -348,15 +311,15 @@ class BaseRetrying(ABC):
self.before(retry_state)
return DoAttempt()
- is_explicit_retry = retry_state.outcome.failed and isinstance(retry_state.outcome.exception(), TryAgain)
- if not (is_explicit_retry or self.retry(retry_state=retry_state)):
+ is_explicit_retry = fut.failed and isinstance(fut.exception(), TryAgain)
+ if not (is_explicit_retry or self.retry(retry_state)):
return fut.result()
if self.after is not None:
self.after(retry_state)
self.statistics["delay_since_first_attempt"] = retry_state.seconds_since_start
- if self.stop(retry_state=retry_state):
+ if self.stop(retry_state):
if self.retry_error_callback:
return self.retry_error_callback(retry_state)
retry_exc = self.retry_error_cls(fut)
@@ -365,7 +328,7 @@ class BaseRetrying(ABC):
raise retry_exc from fut.exception()
if self.wait:
- sleep = self.wait(retry_state=retry_state)
+ sleep = self.wait(retry_state)
else:
sleep = 0.0
retry_state.next_action = RetryAction(sleep)
@@ -393,14 +356,24 @@ class BaseRetrying(ABC):
break
@abstractmethod
- def __call__(self, fn: t.Callable[..., _RetValT], *args: t.Any, **kwargs: t.Any) -> _RetValT:
+ def __call__(
+ self,
+ fn: t.Callable[..., WrappedFnReturnT],
+ *args: t.Any,
+ **kwargs: t.Any,
+ ) -> WrappedFnReturnT:
pass
class Retrying(BaseRetrying):
"""Retrying controller."""
- def __call__(self, fn: t.Callable[..., _RetValT], *args: t.Any, **kwargs: t.Any) -> _RetValT:
+ def __call__(
+ self,
+ fn: t.Callable[..., WrappedFnReturnT],
+ *args: t.Any,
+ **kwargs: t.Any,
+ ) -> WrappedFnReturnT:
self.begin()
retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs)
@@ -410,17 +383,23 @@ class Retrying(BaseRetrying):
try:
result = fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type: ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
retry_state.prepare_for_next_attempt()
self.sleep(do)
else:
- return do
+ return do # type: ignore[no-any-return]
+
+
+if sys.version_info[1] >= 9:
+ FutureGenericT = futures.Future[t.Any]
+else:
+ FutureGenericT = futures.Future
-class Future(futures.Future):
+class Future(FutureGenericT):
"""Encapsulates a (future or past) attempted call to a target function."""
def __init__(self, attempt_number: int) -> None:
@@ -493,13 +472,15 @@ class RetryCallState:
fut.set_result(val)
self.outcome, self.outcome_timestamp = fut, ts
- def set_exception(self, exc_info: t.Tuple[t.Type[BaseException], BaseException, "types.TracebackType"]) -> None:
+ def set_exception(
+ self, exc_info: t.Tuple[t.Type[BaseException], BaseException, "types.TracebackType| None"]
+ ) -> None:
ts = time.monotonic()
fut = Future(self.attempt_number)
fut.set_exception(exc_info[1])
self.outcome, self.outcome_timestamp = fut, ts
- def __repr__(self):
+ def __repr__(self) -> str:
if self.outcome is None:
result = "none yet"
elif self.outcome.failed:
@@ -513,7 +494,115 @@ class RetryCallState:
return f"<{clsname} {id(self)}: attempt #{self.attempt_number}; slept for {slept}; last result: {result}>"
+@t.overload
+def retry(func: WrappedFn) -> WrappedFn:
+ ...
+
+
+@t.overload
+def retry(
+ sleep: t.Callable[[t.Union[int, float]], None] = sleep,
+ stop: "StopBaseT" = stop_never,
+ wait: "WaitBaseT" = wait_none(),
+ retry: "RetryBaseT" = retry_if_exception_type(),
+ before: t.Callable[["RetryCallState"], None] = before_nothing,
+ after: t.Callable[["RetryCallState"], None] = after_nothing,
+ before_sleep: t.Optional[t.Callable[["RetryCallState"], None]] = None,
+ reraise: bool = False,
+ retry_error_cls: t.Type["RetryError"] = RetryError,
+ retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Any]] = None,
+) -> t.Callable[[WrappedFn], WrappedFn]:
+ ...
+
+
+def retry(*dargs: t.Any, **dkw: t.Any) -> t.Any:
+ """Wrap a function with a new `Retrying` object.
+
+ :param dargs: positional arguments passed to Retrying object
+ :param dkw: keyword arguments passed to the Retrying object
+ """
+ # support both @retry and @retry() as valid syntax
+ if len(dargs) == 1 and callable(dargs[0]):
+ return retry()(dargs[0])
+ else:
+
+ def wrap(f: WrappedFn) -> WrappedFn:
+ if isinstance(f, retry_base):
+ warnings.warn(
+ f"Got retry_base instance ({f.__class__.__name__}) as callable argument, "
+ f"this will probably hang indefinitely (did you mean retry={f.__class__.__name__}(...)?)"
+ )
+ r: "BaseRetrying"
+ if iscoroutinefunction(f):
+ r = AsyncRetrying(*dargs, **dkw)
+ elif tornado and hasattr(tornado.gen, "is_coroutine_function") and tornado.gen.is_coroutine_function(f):
+ r = TornadoRetrying(*dargs, **dkw)
+ else:
+ r = Retrying(*dargs, **dkw)
+
+ return r.wraps(f)
+
+ return wrap
+
+
from pip._vendor.tenacity._asyncio import AsyncRetrying # noqa:E402,I100
if tornado:
from pip._vendor.tenacity.tornadoweb import TornadoRetrying
+
+
+__all__ = [
+ "retry_base",
+ "retry_all",
+ "retry_always",
+ "retry_any",
+ "retry_if_exception",
+ "retry_if_exception_type",
+ "retry_if_exception_cause_type",
+ "retry_if_not_exception_type",
+ "retry_if_not_result",
+ "retry_if_result",
+ "retry_never",
+ "retry_unless_exception_type",
+ "retry_if_exception_message",
+ "retry_if_not_exception_message",
+ "sleep",
+ "sleep_using_event",
+ "stop_after_attempt",
+ "stop_after_delay",
+ "stop_all",
+ "stop_any",
+ "stop_never",
+ "stop_when_event_set",
+ "wait_chain",
+ "wait_combine",
+ "wait_exponential",
+ "wait_fixed",
+ "wait_incrementing",
+ "wait_none",
+ "wait_random",
+ "wait_random_exponential",
+ "wait_full_jitter",
+ "wait_exponential_jitter",
+ "before_log",
+ "before_nothing",
+ "after_log",
+ "after_nothing",
+ "before_sleep_log",
+ "before_sleep_nothing",
+ "retry",
+ "WrappedFn",
+ "TryAgain",
+ "NO_RESULT",
+ "DoAttempt",
+ "DoSleep",
+ "BaseAction",
+ "RetryAction",
+ "RetryError",
+ "AttemptManager",
+ "BaseRetrying",
+ "Retrying",
+ "Future",
+ "RetryCallState",
+ "AsyncRetrying",
+]
diff --git a/src/pip/_vendor/tenacity/_asyncio.py b/src/pip/_vendor/tenacity/_asyncio.py
index 0f32b5f62..2e50cd7b4 100644
--- a/src/pip/_vendor/tenacity/_asyncio.py
+++ b/src/pip/_vendor/tenacity/_asyncio.py
@@ -17,7 +17,7 @@
import functools
import sys
-import typing
+import typing as t
from asyncio import sleep
from pip._vendor.tenacity import AttemptManager
@@ -26,21 +26,20 @@ from pip._vendor.tenacity import DoAttempt
from pip._vendor.tenacity import DoSleep
from pip._vendor.tenacity import RetryCallState
-WrappedFn = typing.TypeVar("WrappedFn", bound=typing.Callable)
-_RetValT = typing.TypeVar("_RetValT")
+WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
+WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Awaitable[t.Any]])
class AsyncRetrying(BaseRetrying):
- def __init__(self, sleep: typing.Callable[[float], typing.Awaitable] = sleep, **kwargs: typing.Any) -> None:
+ sleep: t.Callable[[float], t.Awaitable[t.Any]]
+
+ def __init__(self, sleep: t.Callable[[float], t.Awaitable[t.Any]] = sleep, **kwargs: t.Any) -> None:
super().__init__(**kwargs)
self.sleep = sleep
- async def __call__( # type: ignore # Change signature from supertype
- self,
- fn: typing.Callable[..., typing.Awaitable[_RetValT]],
- *args: typing.Any,
- **kwargs: typing.Any,
- ) -> _RetValT:
+ async def __call__( # type: ignore[override]
+ self, fn: WrappedFn, *args: t.Any, **kwargs: t.Any
+ ) -> WrappedFnReturnT:
self.begin()
retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs)
@@ -50,21 +49,24 @@ class AsyncRetrying(BaseRetrying):
try:
result = await fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type: ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
retry_state.prepare_for_next_attempt()
await self.sleep(do)
else:
- return do
+ return do # type: ignore[no-any-return]
+
+ def __iter__(self) -> t.Generator[AttemptManager, None, None]:
+ raise TypeError("AsyncRetrying object is not iterable")
def __aiter__(self) -> "AsyncRetrying":
self.begin()
self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={})
return self
- async def __anext__(self) -> typing.Union[AttemptManager, typing.Any]:
+ async def __anext__(self) -> AttemptManager:
while True:
do = self.iter(retry_state=self._retry_state)
if do is None:
@@ -75,18 +77,18 @@ class AsyncRetrying(BaseRetrying):
self._retry_state.prepare_for_next_attempt()
await self.sleep(do)
else:
- return do
+ raise StopAsyncIteration
def wraps(self, fn: WrappedFn) -> WrappedFn:
fn = super().wraps(fn)
# Ensure wrapper is recognized as a coroutine function.
@functools.wraps(fn)
- async def async_wrapped(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
+ async def async_wrapped(*args: t.Any, **kwargs: t.Any) -> t.Any:
return await fn(*args, **kwargs)
# Preserve attributes
- async_wrapped.retry = fn.retry
- async_wrapped.retry_with = fn.retry_with
+ async_wrapped.retry = fn.retry # type: ignore[attr-defined]
+ async_wrapped.retry_with = fn.retry_with # type: ignore[attr-defined]
- return async_wrapped
+ return async_wrapped # type: ignore[return-value]
diff --git a/src/pip/_vendor/tenacity/_utils.py b/src/pip/_vendor/tenacity/_utils.py
index d5c4c9de5..f14ff3209 100644
--- a/src/pip/_vendor/tenacity/_utils.py
+++ b/src/pip/_vendor/tenacity/_utils.py
@@ -16,6 +16,7 @@
import sys
import typing
+from datetime import timedelta
# sys.maxsize:
@@ -66,3 +67,10 @@ def get_callback_name(cb: typing.Callable[..., typing.Any]) -> str:
except AttributeError:
pass
return ".".join(segments)
+
+
+time_unit_type = typing.Union[int, float, timedelta]
+
+
+def to_seconds(time_unit: time_unit_type) -> float:
+ return float(time_unit.total_seconds() if isinstance(time_unit, timedelta) else time_unit)
diff --git a/src/pip/_vendor/tenacity/after.py b/src/pip/_vendor/tenacity/after.py
index c056700f9..574c9bcea 100644
--- a/src/pip/_vendor/tenacity/after.py
+++ b/src/pip/_vendor/tenacity/after.py
@@ -36,9 +36,14 @@ def after_log(
"""After call strategy that logs to some logger the finished attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
logger.log(
log_level,
- f"Finished call to '{_utils.get_callback_name(retry_state.fn)}' "
+ f"Finished call to '{fn_name}' "
f"after {sec_format % retry_state.seconds_since_start}(s), "
f"this was the {_utils.to_ordinal(retry_state.attempt_number)} time calling it.",
)
diff --git a/src/pip/_vendor/tenacity/before.py b/src/pip/_vendor/tenacity/before.py
index a72c2c5f7..cfd7dc72e 100644
--- a/src/pip/_vendor/tenacity/before.py
+++ b/src/pip/_vendor/tenacity/before.py
@@ -32,9 +32,14 @@ def before_log(logger: "logging.Logger", log_level: int) -> typing.Callable[["Re
"""Before call strategy that logs to some logger the attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
logger.log(
log_level,
- f"Starting call to '{_utils.get_callback_name(retry_state.fn)}', "
+ f"Starting call to '{fn_name}', "
f"this is the {_utils.to_ordinal(retry_state.attempt_number)} time calling it.",
)
diff --git a/src/pip/_vendor/tenacity/before_sleep.py b/src/pip/_vendor/tenacity/before_sleep.py
index b35564fba..8c6167fb3 100644
--- a/src/pip/_vendor/tenacity/before_sleep.py
+++ b/src/pip/_vendor/tenacity/before_sleep.py
@@ -36,6 +36,14 @@ def before_sleep_log(
"""Before call strategy that logs to some logger the attempt."""
def log_it(retry_state: "RetryCallState") -> None:
+ local_exc_info: BaseException | bool | None
+
+ if retry_state.outcome is None:
+ raise RuntimeError("log_it() called before outcome was set")
+
+ if retry_state.next_action is None:
+ raise RuntimeError("log_it() called before next_action was set")
+
if retry_state.outcome.failed:
ex = retry_state.outcome.exception()
verb, value = "raised", f"{ex.__class__.__name__}: {ex}"
@@ -48,10 +56,15 @@ def before_sleep_log(
verb, value = "returned", retry_state.outcome.result()
local_exc_info = False # exc_info does not apply when no exception
+ if retry_state.fn is None:
+ # NOTE(sileht): can't really happen, but we must please mypy
+ fn_name = "<unknown>"
+ else:
+ fn_name = _utils.get_callback_name(retry_state.fn)
+
logger.log(
log_level,
- f"Retrying {_utils.get_callback_name(retry_state.fn)} "
- f"in {retry_state.next_action.sleep} seconds as it {verb} {value}.",
+ f"Retrying {fn_name} " f"in {retry_state.next_action.sleep} seconds as it {verb} {value}.",
exc_info=local_exc_info,
)
diff --git a/src/pip/_vendor/tenacity/retry.py b/src/pip/_vendor/tenacity/retry.py
index 9ebeb62d5..38988739d 100644
--- a/src/pip/_vendor/tenacity/retry.py
+++ b/src/pip/_vendor/tenacity/retry.py
@@ -36,6 +36,9 @@ class retry_base(abc.ABC):
return retry_any(self, other)
+RetryBaseT = typing.Union[retry_base, typing.Callable[["RetryCallState"], bool]]
+
+
class _retry_never(retry_base):
"""Retry strategy that never rejects any result."""
@@ -63,8 +66,14 @@ class retry_if_exception(retry_base):
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if retry_state.outcome.failed:
- return self.predicate(retry_state.outcome.exception())
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
else:
return False
@@ -111,10 +120,17 @@ class retry_unless_exception_type(retry_if_exception):
super().__init__(lambda e: not isinstance(e, exception_types))
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
# always retry if no exception was raised
if not retry_state.outcome.failed:
return True
- return self.predicate(retry_state.outcome.exception())
+
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
class retry_if_exception_cause_type(retry_base):
@@ -134,6 +150,9 @@ class retry_if_exception_cause_type(retry_base):
self.exception_cause_types = exception_types
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__ called before outcome was set")
+
if retry_state.outcome.failed:
exc = retry_state.outcome.exception()
while exc is not None:
@@ -151,6 +170,9 @@ class retry_if_result(retry_base):
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return self.predicate(retry_state.outcome.result())
else:
@@ -164,6 +186,9 @@ class retry_if_not_result(retry_base):
self.predicate = predicate
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return not self.predicate(retry_state.outcome.result())
else:
@@ -215,9 +240,16 @@ class retry_if_not_exception_message(retry_if_exception_message):
self.predicate = lambda *args_, **kwargs_: not if_predicate(*args_, **kwargs_)
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
if not retry_state.outcome.failed:
return True
- return self.predicate(retry_state.outcome.exception())
+
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return self.predicate(exception)
class retry_any(retry_base):
diff --git a/src/pip/_vendor/tenacity/stop.py b/src/pip/_vendor/tenacity/stop.py
index faaae9a8d..bb23effdf 100644
--- a/src/pip/_vendor/tenacity/stop.py
+++ b/src/pip/_vendor/tenacity/stop.py
@@ -16,6 +16,8 @@
import abc
import typing
+from pip._vendor.tenacity import _utils
+
if typing.TYPE_CHECKING:
import threading
@@ -36,6 +38,9 @@ class stop_base(abc.ABC):
return stop_any(self, other)
+StopBaseT = typing.Union[stop_base, typing.Callable[["RetryCallState"], bool]]
+
+
class stop_any(stop_base):
"""Stop if any of the stop condition is valid."""
@@ -89,8 +94,10 @@ class stop_after_attempt(stop_base):
class stop_after_delay(stop_base):
"""Stop when the time from the first attempt >= limit."""
- def __init__(self, max_delay: float) -> None:
- self.max_delay = max_delay
+ def __init__(self, max_delay: _utils.time_unit_type) -> None:
+ self.max_delay = _utils.to_seconds(max_delay)
def __call__(self, retry_state: "RetryCallState") -> bool:
+ if retry_state.seconds_since_start is None:
+ raise RuntimeError("__call__() called but seconds_since_start is not set")
return retry_state.seconds_since_start >= self.max_delay
diff --git a/src/pip/_vendor/tenacity/tornadoweb.py b/src/pip/_vendor/tenacity/tornadoweb.py
index 8f7731af0..e19c30b18 100644
--- a/src/pip/_vendor/tenacity/tornadoweb.py
+++ b/src/pip/_vendor/tenacity/tornadoweb.py
@@ -33,8 +33,8 @@ class TornadoRetrying(BaseRetrying):
super().__init__(**kwargs)
self.sleep = sleep
- @gen.coroutine
- def __call__( # type: ignore # Change signature from supertype
+ @gen.coroutine # type: ignore[misc]
+ def __call__(
self,
fn: "typing.Callable[..., typing.Union[typing.Generator[typing.Any, typing.Any, _RetValT], Future[_RetValT]]]",
*args: typing.Any,
@@ -49,7 +49,7 @@ class TornadoRetrying(BaseRetrying):
try:
result = yield fn(*args, **kwargs)
except BaseException: # noqa: B902
- retry_state.set_exception(sys.exc_info())
+ retry_state.set_exception(sys.exc_info()) # type: ignore[arg-type]
else:
retry_state.set_result(result)
elif isinstance(do, DoSleep):
diff --git a/src/pip/_vendor/tenacity/wait.py b/src/pip/_vendor/tenacity/wait.py
index 8fdfc8f9d..f9349c028 100644
--- a/src/pip/_vendor/tenacity/wait.py
+++ b/src/pip/_vendor/tenacity/wait.py
@@ -17,19 +17,12 @@
import abc
import random
import typing
-from datetime import timedelta
from pip._vendor.tenacity import _utils
if typing.TYPE_CHECKING:
from pip._vendor.tenacity import RetryCallState
-wait_unit_type = typing.Union[int, float, timedelta]
-
-
-def to_seconds(wait_unit: wait_unit_type) -> float:
- return float(wait_unit.total_seconds() if isinstance(wait_unit, timedelta) else wait_unit)
-
class wait_base(abc.ABC):
"""Abstract base class for wait strategies."""
@@ -43,16 +36,19 @@ class wait_base(abc.ABC):
def __radd__(self, other: "wait_base") -> typing.Union["wait_combine", "wait_base"]:
# make it possible to use multiple waits with the built-in sum function
- if other == 0:
+ if other == 0: # type: ignore[comparison-overlap]
return self
return self.__add__(other)
+WaitBaseT = typing.Union[wait_base, typing.Callable[["RetryCallState"], typing.Union[float, int]]]
+
+
class wait_fixed(wait_base):
"""Wait strategy that waits a fixed amount of time between each retry."""
- def __init__(self, wait: wait_unit_type) -> None:
- self.wait_fixed = to_seconds(wait)
+ def __init__(self, wait: _utils.time_unit_type) -> None:
+ self.wait_fixed = _utils.to_seconds(wait)
def __call__(self, retry_state: "RetryCallState") -> float:
return self.wait_fixed
@@ -68,9 +64,9 @@ class wait_none(wait_fixed):
class wait_random(wait_base):
"""Wait strategy that waits a random amount of time between min/max."""
- def __init__(self, min: wait_unit_type = 0, max: wait_unit_type = 1) -> None: # noqa
- self.wait_random_min = to_seconds(min)
- self.wait_random_max = to_seconds(max)
+ def __init__(self, min: _utils.time_unit_type = 0, max: _utils.time_unit_type = 1) -> None: # noqa
+ self.wait_random_min = _utils.to_seconds(min)
+ self.wait_random_max = _utils.to_seconds(max)
def __call__(self, retry_state: "RetryCallState") -> float:
return self.wait_random_min + (random.random() * (self.wait_random_max - self.wait_random_min))
@@ -120,13 +116,13 @@ class wait_incrementing(wait_base):
def __init__(
self,
- start: wait_unit_type = 0,
- increment: wait_unit_type = 100,
- max: wait_unit_type = _utils.MAX_WAIT, # noqa
+ start: _utils.time_unit_type = 0,
+ increment: _utils.time_unit_type = 100,
+ max: _utils.time_unit_type = _utils.MAX_WAIT, # noqa
) -> None:
- self.start = to_seconds(start)
- self.increment = to_seconds(increment)
- self.max = to_seconds(max)
+ self.start = _utils.to_seconds(start)
+ self.increment = _utils.to_seconds(increment)
+ self.max = _utils.to_seconds(max)
def __call__(self, retry_state: "RetryCallState") -> float:
result = self.start + (self.increment * (retry_state.attempt_number - 1))
@@ -149,13 +145,13 @@ class wait_exponential(wait_base):
def __init__(
self,
multiplier: typing.Union[int, float] = 1,
- max: wait_unit_type = _utils.MAX_WAIT, # noqa
+ max: _utils.time_unit_type = _utils.MAX_WAIT, # noqa
exp_base: typing.Union[int, float] = 2,
- min: wait_unit_type = 0, # noqa
+ min: _utils.time_unit_type = 0, # noqa
) -> None:
self.multiplier = multiplier
- self.min = to_seconds(min)
- self.max = to_seconds(max)
+ self.min = _utils.to_seconds(min)
+ self.max = _utils.to_seconds(max)
self.exp_base = exp_base
def __call__(self, retry_state: "RetryCallState") -> float:
@@ -206,7 +202,7 @@ class wait_exponential_jitter(wait_base):
This implements the strategy described here:
https://cloud.google.com/storage/docs/retry-strategy
- The wait time is min(initial * (2**n + random.uniform(0, jitter)), maximum)
+ The wait time is min(initial * 2**n + random.uniform(0, jitter), maximum)
where n is the retry count.
"""
diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt
index 70a24f7bd..cfdf3dc44 100644
--- a/src/pip/_vendor/vendor.txt
+++ b/src/pip/_vendor/vendor.txt
@@ -18,6 +18,6 @@ rich==13.3.3
resolvelib==1.0.1
setuptools==67.6.1
six==1.16.0
-tenacity==8.1.0
+tenacity==8.2.2
tomli==2.0.1
webencodings==0.5.1
diff --git a/tools/vendoring/patches/tenacity.patch b/tools/vendoring/patches/tenacity.patch
index 85b29c60c..c87b1c5b2 100644
--- a/tools/vendoring/patches/tenacity.patch
+++ b/tools/vendoring/patches/tenacity.patch
@@ -2,14 +2,14 @@ diff --git a/src/pip/_vendor/tenacity/__init__.py b/src/pip/_vendor/tenacity/__i
index 88c28d2d6..086ad46e1 100644
--- a/src/pip/_vendor/tenacity/__init__.py
+++ b/src/pip/_vendor/tenacity/__init__.py
-@@ -76,10 +76,12 @@ from .after import after_nothing # noqa
+@@ -82,10 +82,12 @@ from .after import after_nothing # noqa
from .before_sleep import before_sleep_log # noqa
from .before_sleep import before_sleep_nothing # noqa
-try:
-- import tornado # type: ignore
+- import tornado
-except ImportError:
-- tornado = None # type: ignore
+- tornado = None
+# Replace a conditional import with a hard-coded None so that pip does
+# not attempt to use tornado even if it is present in the environment.
+# If tornado is non-None, tenacity will attempt to execute some code
@@ -22,7 +22,7 @@ index 88c28d2d6..086ad46e1 100644
--- a/src/pip/_vendor/tenacity/__init__.py
+++ b/src/pip/_vendor/tenacity/__init__.py
-@@ -190,7 +190,7 @@ class RetryError(Exception):
+@@ -153,7 +153,7 @@ class RetryError(Exception):
self.last_attempt = last_attempt
super().__init__(last_attempt)