You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

tenacity

Package Overview
Dependencies
Maintainers
2
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tenacity - pypi Package Compare versions

Comparing version
8.4.2
to
8.5.0
+6
releasenotes/notes...rapper-attributes-f7a3a45b8e90f257.yaml
---
fixes:
- |
Restore the value of the `retry` attribute for wrapped functions. Also,
clarify that those attributes are write-only and statistics should be
read from the function attribute directly.
+1
-1

@@ -37,3 +37,3 @@ name: Continuous Integration

- name: Checkout 🛎️
uses: actions/checkout@v4.1.6
uses: actions/checkout@v4.1.7
with:

@@ -40,0 +40,0 @@ fetch-depth: 0

@@ -14,3 +14,3 @@ name: Release deploy

- name: Checkout 🛎️
uses: actions/checkout@v4.1.6
uses: actions/checkout@v4.1.7
with:

@@ -17,0 +17,0 @@ fetch-depth: 0

@@ -127,4 +127,4 @@ Tenacity

If you're on a tight deadline, and exceeding your delay time isn't ok,
then you can give up on retries one attempt before you would exceed the delay.
If you're on a tight deadline, and exceeding your delay time isn't ok,
then you can give up on retries one attempt before you would exceed the delay.

@@ -366,3 +366,3 @@ .. testcode::

You can access the statistics about the retry made over a function by using the
`retry` attribute attached to the function and its `statistics` attribute:
`statistics` attribute attached to the function:

@@ -380,3 +380,3 @@ .. testcode::

print(raise_my_exception.retry.statistics)
print(raise_my_exception.statistics)

@@ -501,3 +501,3 @@ .. testoutput::

print(raise_my_exception.retry.statistics)
print(raise_my_exception.statistics)

@@ -521,2 +521,28 @@ .. testoutput::

You may also want to change the behaviour of a decorated function temporarily,
like in tests to avoid unnecessary wait times. You can modify/patch the `retry`
attribute attached to the function. Bear in mind this is a write-only attribute,
statistics should be read from the function `statistics` attribute.
.. testcode::
@retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
def raise_my_exception():
raise MyException("Fail")
from unittest import mock
with mock.patch.object(raise_my_exception.retry, "wait", wait_fixed(0)):
try:
raise_my_exception()
except Exception:
pass
print(raise_my_exception.statistics)
.. testoutput::
:hide:
...
Retrying code block

@@ -523,0 +549,0 @@ ~~~~~~~~~~~~~~~~~~~

Metadata-Version: 2.1
Name: tenacity
Version: 8.4.2
Version: 8.5.0
Summary: Retry code until it succeeds

@@ -5,0 +5,0 @@ Home-page: https://github.com/jd/tenacity

@@ -127,4 +127,4 @@ Tenacity

If you're on a tight deadline, and exceeding your delay time isn't ok,
then you can give up on retries one attempt before you would exceed the delay.
If you're on a tight deadline, and exceeding your delay time isn't ok,
then you can give up on retries one attempt before you would exceed the delay.

@@ -366,3 +366,3 @@ .. testcode::

You can access the statistics about the retry made over a function by using the
`retry` attribute attached to the function and its `statistics` attribute:
`statistics` attribute attached to the function:

@@ -380,3 +380,3 @@ .. testcode::

print(raise_my_exception.retry.statistics)
print(raise_my_exception.statistics)

@@ -501,3 +501,3 @@ .. testoutput::

print(raise_my_exception.retry.statistics)
print(raise_my_exception.statistics)

@@ -521,2 +521,28 @@ .. testoutput::

You may also want to change the behaviour of a decorated function temporarily,
like in tests to avoid unnecessary wait times. You can modify/patch the `retry`
attribute attached to the function. Bear in mind this is a write-only attribute,
statistics should be read from the function `statistics` attribute.
.. testcode::
@retry(stop=stop_after_attempt(3), wait=wait_fixed(3))
def raise_my_exception():
raise MyException("Fail")
from unittest import mock
with mock.patch.object(raise_my_exception.retry, "wait", wait_fixed(0)):
try:
raise_my_exception()
except Exception:
pass
print(raise_my_exception.statistics)
.. testoutput::
:hide:
...
Retrying code block

@@ -523,0 +549,0 @@ ~~~~~~~~~~~~~~~~~~~

Metadata-Version: 2.1
Name: tenacity
Version: 8.4.2
Version: 8.5.0
Summary: Retry code until it succeeds

@@ -5,0 +5,0 @@ Home-page: https://github.com/jd/tenacity

@@ -41,2 +41,3 @@ .editorconfig

releasenotes/notes/fix-local-context-overwrite-94190ba06a481631.yaml
releasenotes/notes/fix-retry-wrapper-attributes-f7a3a45b8e90f257.yaml
releasenotes/notes/fix-setuptools-config-3af71aa3592b6948.yaml

@@ -43,0 +44,0 @@ releasenotes/notes/fix-wait-typing-b26eecdb6cc0a1de.yaml

@@ -342,3 +342,3 @@ # Copyright 2016-2018 Julien Danjou

# Preserve attributes
wrapped_f.retry = wrapped_f # type: ignore[attr-defined]
wrapped_f.retry = self # type: ignore[attr-defined]
wrapped_f.retry_with = retry_with # type: ignore[attr-defined]

@@ -345,0 +345,0 @@ wrapped_f.statistics = {} # type: ignore[attr-defined]

@@ -192,3 +192,3 @@ # Copyright 2016 Étienne Bersac

# Preserve attributes
async_wrapped.retry = async_wrapped # type: ignore[attr-defined]
async_wrapped.retry = self # type: ignore[attr-defined]
async_wrapped.retry_with = wrapped.retry_with # type: ignore[attr-defined]

@@ -195,0 +195,0 @@ async_wrapped.statistics = {} # type: ignore[attr-defined]

@@ -20,2 +20,3 @@ # mypy: disable-error-code="no-untyped-def,no-untyped-call"

from functools import wraps
from unittest import mock

@@ -63,3 +64,3 @@ try:

await asyncio.sleep(0.00001)
thing.go()
return thing.go()

@@ -399,2 +400,60 @@

class TestDecoratorWrapper(unittest.TestCase):
@asynctest
async def test_retry_function_attributes(self):
"""Test that the wrapped function attributes are exposed as intended.
- statistics contains the value for the latest function run
- retry object can be modified to change its behaviour (useful to patch in tests)
- retry object statistics do not contain valid information
"""
self.assertTrue(
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(1))
)
expected_stats = {
"attempt_number": 2,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"start_time": mock.ANY,
}
self.assertEqual(
_retryable_coroutine_with_2_attempts.statistics, # type: ignore[attr-defined]
expected_stats,
)
self.assertEqual(
_retryable_coroutine_with_2_attempts.retry.statistics, # type: ignore[attr-defined]
{},
)
with mock.patch.object(
_retryable_coroutine_with_2_attempts.retry, # type: ignore[attr-defined]
"stop",
tenacity.stop_after_attempt(1),
):
try:
self.assertTrue(
await _retryable_coroutine_with_2_attempts(NoIOErrorAfterCount(2))
)
except RetryError as exc:
expected_stats = {
"attempt_number": 1,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"start_time": mock.ANY,
}
self.assertEqual(
_retryable_coroutine_with_2_attempts.statistics, # type: ignore[attr-defined]
expected_stats,
)
self.assertEqual(exc.last_attempt.attempt_number, 1)
self.assertEqual(
_retryable_coroutine_with_2_attempts.retry.statistics, # type: ignore[attr-defined]
{},
)
else:
self.fail("RetryError should have been raised after 1 attempt")
# make sure mypy accepts passing an async sleep function

@@ -401,0 +460,0 @@ # https://github.com/jd/tenacity/issues/399

@@ -28,2 +28,3 @@ # mypy: disable_error_code="no-untyped-def,no-untyped-call,attr-defined,arg-type,no-any-return,list-item,var-annotated,import,call-overload"

from fractions import Fraction
from unittest import mock

@@ -1077,3 +1078,3 @@ import pytest

except NameError as e:
s = _retryable_test_with_unless_exception_type_name.retry.statistics
s = _retryable_test_with_unless_exception_type_name.statistics
self.assertTrue(s["attempt_number"] == 6)

@@ -1093,3 +1094,3 @@ print(e)

except NameError as e:
s = _retryable_test_with_unless_exception_type_no_input.retry.statistics
s = _retryable_test_with_unless_exception_type_no_input.statistics
self.assertTrue(s["attempt_number"] == 6)

@@ -1117,3 +1118,3 @@ print(e)

except CustomError:
print(_retryable_test_if_exception_message_message.retry.statistics)
print(_retryable_test_if_exception_message_message.statistics)
self.fail("CustomError should've been retried from errormessage")

@@ -1129,3 +1130,3 @@

except CustomError:
s = _retryable_test_if_not_exception_message_message.retry.statistics
s = _retryable_test_if_not_exception_message_message.statistics
self.assertTrue(s["attempt_number"] == 1)

@@ -1139,3 +1140,3 @@

except NameError:
s = _retryable_test_not_exception_message_delay.retry.statistics
s = _retryable_test_not_exception_message_delay.statistics
print(s["attempt_number"])

@@ -1160,3 +1161,3 @@ self.assertTrue(s["attempt_number"] == 4)

except CustomError:
s = _retryable_test_if_not_exception_message_message.retry.statistics
s = _retryable_test_if_not_exception_message_message.statistics
self.assertTrue(s["attempt_number"] == 1)

@@ -1219,3 +1220,40 @@

def test_retry_function_attributes(self):
"""Test that the wrapped function attributes are exposed as intended.
- statistics contains the value for the latest function run
- retry object can be modified to change its behaviour (useful to patch in tests)
- retry object statistics do not contain valid information
"""
self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))
expected_stats = {
"attempt_number": 3,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"start_time": mock.ANY,
}
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
self.assertEqual(_retryable_test_with_stop.retry.statistics, {})
with mock.patch.object(
_retryable_test_with_stop.retry, "stop", tenacity.stop_after_attempt(1)
):
try:
self.assertTrue(_retryable_test_with_stop(NoneReturnUntilAfterCount(2)))
except RetryError as exc:
expected_stats = {
"attempt_number": 1,
"delay_since_first_attempt": mock.ANY,
"idle_for": mock.ANY,
"start_time": mock.ANY,
}
self.assertEqual(_retryable_test_with_stop.statistics, expected_stats)
self.assertEqual(exc.last_attempt.attempt_number, 1)
self.assertEqual(_retryable_test_with_stop.retry.statistics, {})
else:
self.fail("RetryError should have been raised after 1 attempt")
class TestRetryWith:

@@ -1490,5 +1528,5 @@ def test_redefine_wait(self):

self.assertEqual({}, _foobar.retry.statistics)
self.assertEqual({}, _foobar.statistics)
_foobar()
self.assertEqual(1, _foobar.retry.statistics["attempt_number"])
self.assertEqual(1, _foobar.statistics["attempt_number"])

@@ -1500,3 +1538,3 @@ def test_stats_failing(self):

self.assertEqual({}, _foobar.retry.statistics)
self.assertEqual({}, _foobar.statistics)
try:

@@ -1506,3 +1544,3 @@ _foobar()

pass
self.assertEqual(2, _foobar.retry.statistics["attempt_number"])
self.assertEqual(2, _foobar.statistics["attempt_number"])

@@ -1509,0 +1547,0 @@