python-retrying: upgrade to 1.2.4 (#8104)
This commit is contained in:
Родитель
5a3b7756a5
Коммит
7ea69dad85
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"Signatures": {
|
||||
"retrying-1.3.3.tar.gz": "6a73d0210bf515e5cc5c5eadc8f2ee9dfb805b638d8b8514086128d3f411a49a"
|
||||
"retrying-1.3.4.tar.gz": "345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e",
|
||||
"test_retrying.py": "c409009a8aef577373d7c3b9fa803aaa21eb6ea3b976b30be60149913633152b"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,18 @@ written in Python, to simplify the task of adding retry behavior to\
|
|||
just about anything.\
|
||||
|
||||
Name: python-%{pypi_name}
|
||||
Version: 1.3.3
|
||||
Release: 6%{?dist}
|
||||
Version: 1.3.4
|
||||
Release: 1%{?dist}
|
||||
Summary: General-purpose retrying library in Python
|
||||
License: ASL 2.0
|
||||
Vendor: Microsoft Corporation
|
||||
Distribution: Azure Linux
|
||||
URL: https://github.com/rholder/retrying
|
||||
Source0: %{url}/archive/refs/tags/v%{version}.tar.gz#/%{pypi_name}-%{version}.tar.gz
|
||||
URL: https://pypi.org/project/retrying
|
||||
Source0: https://files.pythonhosted.org/packages/ce/70/15ce8551d65b324e18c5aa6ef6998880f21ead51ebe5ed743c0950d7d9dd/retrying-1.3.4.tar.gz
|
||||
|
||||
# The tarball does not contain the tests, so add them here
|
||||
Source1: test_retrying.py
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
%description %{_description}
|
||||
|
@ -26,12 +30,14 @@ Requires: python3-six
|
|||
|
||||
%if 0%{?with_check}
|
||||
BuildRequires: python3-six
|
||||
BuildRequires: python3-pip
|
||||
%endif
|
||||
|
||||
%description -n python3-%{pypi_name} %{_description}
|
||||
|
||||
%prep
|
||||
%autosetup -n %{pypi_name}-%{version}
|
||||
cp -p %{SOURCE1} .
|
||||
|
||||
%build
|
||||
%py3_build
|
||||
|
@ -50,6 +56,9 @@ BuildRequires: python3-six
|
|||
%{python3_sitelib}/%{pypi_name}-%{version}-py%{python3_version}.egg-info
|
||||
|
||||
%changelog
|
||||
* Mon Feb 26 2024 Yash Panchal <yashpanchal@microsoft.com> - 1.3.4-1
|
||||
- Upgrade to 1.3.4
|
||||
|
||||
* Wed Jul 06 2022 Sumedh Sharma <sumsharma@microsoft.com> - 1.3.3-6
|
||||
- Initial CBL-Mariner import from Fedora 36 (license: MIT)
|
||||
- Adding as run dependency for package cassandra medusa
|
||||
|
|
|
@ -0,0 +1,485 @@
|
|||
# Copyright 2013 Ray Holder
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from retrying import RetryError
|
||||
from retrying import Retrying
|
||||
from retrying import retry
|
||||
|
||||
|
||||
class TestStopConditions(unittest.TestCase):
|
||||
def test_never_stop(self):
|
||||
r = Retrying()
|
||||
self.assertFalse(r.stop(3, 6546))
|
||||
|
||||
def test_stop_after_attempt(self):
|
||||
r = Retrying(stop_max_attempt_number=3)
|
||||
self.assertFalse(r.stop(2, 6546))
|
||||
self.assertTrue(r.stop(3, 6546))
|
||||
self.assertTrue(r.stop(4, 6546))
|
||||
|
||||
def test_stop_after_delay(self):
|
||||
r = Retrying(stop_max_delay=1000)
|
||||
self.assertFalse(r.stop(2, 999))
|
||||
self.assertTrue(r.stop(2, 1000))
|
||||
self.assertTrue(r.stop(2, 1001))
|
||||
|
||||
def test_legacy_explicit_stop_type(self):
|
||||
Retrying(stop="stop_after_attempt")
|
||||
|
||||
def test_stop_func(self):
|
||||
r = Retrying(stop_func=lambda attempt, delay: attempt == delay)
|
||||
self.assertFalse(r.stop(1, 3))
|
||||
self.assertFalse(r.stop(100, 99))
|
||||
self.assertTrue(r.stop(101, 101))
|
||||
|
||||
|
||||
class TestWaitConditions(unittest.TestCase):
|
||||
def test_no_sleep(self):
|
||||
r = Retrying()
|
||||
self.assertEqual(0, r.wait(18, 9879))
|
||||
|
||||
def test_fixed_sleep(self):
|
||||
r = Retrying(wait_fixed=1000)
|
||||
self.assertEqual(1000, r.wait(12, 6546))
|
||||
|
||||
def test_incrementing_sleep(self):
|
||||
r = Retrying(wait_incrementing_start=500, wait_incrementing_increment=100)
|
||||
self.assertEqual(500, r.wait(1, 6546))
|
||||
self.assertEqual(600, r.wait(2, 6546))
|
||||
self.assertEqual(700, r.wait(3, 6546))
|
||||
|
||||
def test_random_sleep(self):
|
||||
r = Retrying(wait_random_min=1000, wait_random_max=2000)
|
||||
times = set()
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
|
||||
# this is kind of non-deterministic...
|
||||
self.assertTrue(len(times) > 1)
|
||||
for t in times:
|
||||
self.assertTrue(t >= 1000)
|
||||
self.assertTrue(t <= 2000)
|
||||
|
||||
def test_random_sleep_without_min(self):
|
||||
r = Retrying(wait_random_max=2000)
|
||||
times = set()
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
times.add(r.wait(1, 6546))
|
||||
|
||||
# this is kind of non-deterministic...
|
||||
self.assertTrue(len(times) > 1)
|
||||
for t in times:
|
||||
self.assertTrue(t >= 0)
|
||||
self.assertTrue(t <= 2000)
|
||||
|
||||
def test_exponential(self):
|
||||
r = Retrying(wait_exponential_max=100000)
|
||||
self.assertEqual(r.wait(1, 0), 2)
|
||||
self.assertEqual(r.wait(2, 0), 4)
|
||||
self.assertEqual(r.wait(3, 0), 8)
|
||||
self.assertEqual(r.wait(4, 0), 16)
|
||||
self.assertEqual(r.wait(5, 0), 32)
|
||||
self.assertEqual(r.wait(6, 0), 64)
|
||||
|
||||
def test_exponential_with_max_wait(self):
|
||||
r = Retrying(wait_exponential_max=40)
|
||||
self.assertEqual(r.wait(1, 0), 2)
|
||||
self.assertEqual(r.wait(2, 0), 4)
|
||||
self.assertEqual(r.wait(3, 0), 8)
|
||||
self.assertEqual(r.wait(4, 0), 16)
|
||||
self.assertEqual(r.wait(5, 0), 32)
|
||||
self.assertEqual(r.wait(6, 0), 40)
|
||||
self.assertEqual(r.wait(7, 0), 40)
|
||||
self.assertEqual(r.wait(50, 0), 40)
|
||||
|
||||
def test_exponential_with_max_wait_and_multiplier(self):
|
||||
r = Retrying(wait_exponential_max=50000, wait_exponential_multiplier=1000)
|
||||
self.assertEqual(r.wait(1, 0), 2000)
|
||||
self.assertEqual(r.wait(2, 0), 4000)
|
||||
self.assertEqual(r.wait(3, 0), 8000)
|
||||
self.assertEqual(r.wait(4, 0), 16000)
|
||||
self.assertEqual(r.wait(5, 0), 32000)
|
||||
self.assertEqual(r.wait(6, 0), 50000)
|
||||
self.assertEqual(r.wait(7, 0), 50000)
|
||||
self.assertEqual(r.wait(50, 0), 50000)
|
||||
|
||||
def test_legacy_explicit_wait_type(self):
|
||||
Retrying(wait="exponential_sleep")
|
||||
|
||||
def test_wait_func(self):
|
||||
r = Retrying(wait_func=lambda attempt, delay: attempt * delay)
|
||||
self.assertEqual(r.wait(1, 5), 5)
|
||||
self.assertEqual(r.wait(2, 11), 22)
|
||||
self.assertEqual(r.wait(10, 100), 1000)
|
||||
|
||||
|
||||
class NoneReturnUntilAfterCount:
|
||||
"""
|
||||
This class holds counter state for invoking a method several times in a row.
|
||||
"""
|
||||
|
||||
def __init__(self, count):
|
||||
self.counter = 0
|
||||
self.count = count
|
||||
|
||||
def go(self):
|
||||
"""
|
||||
Return None until after count threshold has been crossed, then return True.
|
||||
"""
|
||||
if self.counter < self.count:
|
||||
self.counter += 1
|
||||
return None
|
||||
return True
|
||||
|
||||
|
||||
class NoIOErrorAfterCount:
|
||||
"""
|
||||
This class holds counter state for invoking a method several times in a row.
|
||||
"""
|
||||
|
||||
def __init__(self, count):
|
||||
self.counter = 0
|
||||
self.count = count
|
||||
|
||||
def go(self):
|
||||
"""
|
||||
Raise an IOError until after count threshold has been crossed, then return True.
|
||||
"""
|
||||
if self.counter < self.count:
|
||||
self.counter += 1
|
||||
raise IOError("Hi there, I'm an IOError")
|
||||
return True
|
||||
|
||||
|
||||
class NoNameErrorAfterCount:
|
||||
"""
|
||||
This class holds counter state for invoking a method several times in a row.
|
||||
"""
|
||||
|
||||
def __init__(self, count):
|
||||
self.counter = 0
|
||||
self.count = count
|
||||
|
||||
def go(self):
|
||||
"""
|
||||
Raise a NameError until after count threshold has been crossed, then return True.
|
||||
"""
|
||||
if self.counter < self.count:
|
||||
self.counter += 1
|
||||
raise NameError("Hi there, I'm a NameError")
|
||||
return True
|
||||
|
||||
|
||||
class CustomError(Exception):
|
||||
"""
|
||||
This is a custom exception class. Note that For Python 2.x, we don't
|
||||
strictly need to extend BaseException, however, Python 3.x will complain.
|
||||
While this test suite won't run correctly under Python 3.x without
|
||||
extending from the Python exception hierarchy, the actual module code is
|
||||
backwards compatible Python 2.x and will allow for cases where exception
|
||||
classes don't extend from the hierarchy.
|
||||
"""
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
class NoCustomErrorAfterCount:
|
||||
"""
|
||||
This class holds counter state for invoking a method several times in a row.
|
||||
"""
|
||||
|
||||
def __init__(self, count):
|
||||
self.counter = 0
|
||||
self.count = count
|
||||
|
||||
def go(self):
|
||||
"""
|
||||
Raise a CustomError until after count threshold has been crossed, then return True.
|
||||
"""
|
||||
if self.counter < self.count:
|
||||
self.counter += 1
|
||||
derived_message = "This is a Custom exception class"
|
||||
raise CustomError(derived_message)
|
||||
return True
|
||||
|
||||
|
||||
def retry_if_result_none(result):
|
||||
return result is None
|
||||
|
||||
|
||||
def retry_if_exception_of_type(retryable_types):
|
||||
def retry_if_exception_these_types(exception):
|
||||
print("Detected Exception of type: {0}".format(str(type(exception))))
|
||||
return isinstance(exception, retryable_types)
|
||||
|
||||
return retry_if_exception_these_types
|
||||
|
||||
|
||||
def current_time_ms():
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
|
||||
@retry(wait_fixed=50, retry_on_result=retry_if_result_none)
|
||||
def _retryable_test_with_wait(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(stop_max_attempt_number=3, retry_on_result=retry_if_result_none)
|
||||
def _retryable_test_with_stop(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(retry_on_exception=(IOError,))
|
||||
def _retryable_test_with_exception_type_io(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(retry_on_exception=retry_if_exception_of_type(IOError), wrap_exception=True)
|
||||
def _retryable_test_with_exception_type_io_wrap(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(stop_max_attempt_number=3, retry_on_exception=(IOError,))
|
||||
def _retryable_test_with_exception_type_io_attempt_limit(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(stop_max_attempt_number=3, retry_on_exception=(IOError,), wrap_exception=True)
|
||||
def _retryable_test_with_exception_type_io_attempt_limit_wrap(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry
|
||||
def _retryable_default(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry()
|
||||
def _retryable_default_f(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(retry_on_exception=retry_if_exception_of_type(CustomError))
|
||||
def _retryable_test_with_exception_type_custom(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(retry_on_exception=retry_if_exception_of_type(CustomError), wrap_exception=True)
|
||||
def _retryable_test_with_exception_type_custom_wrap(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(
|
||||
stop_max_attempt_number=3,
|
||||
retry_on_exception=retry_if_exception_of_type(CustomError),
|
||||
)
|
||||
def _retryable_test_with_exception_type_custom_attempt_limit(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
@retry(
|
||||
stop_max_attempt_number=3,
|
||||
retry_on_exception=retry_if_exception_of_type(CustomError),
|
||||
wrap_exception=True,
|
||||
)
|
||||
def _retryable_test_with_exception_type_custom_attempt_limit_wrap(thing):
|
||||
return thing.go()
|
||||
|
||||
|
||||
class TestDecoratorWrapper(unittest.TestCase):
|
||||
def test_with_wait(self):
|
||||
start = current_time_ms()
|
||||
result = _retryable_test_with_wait(NoneReturnUntilAfterCount(5))
|
||||
t = current_time_ms() - start
|
||||
self.assertTrue(t >= 250)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_with_stop_on_return_value(self):
|
||||
try:
|
||||
_retryable_test_with_stop(NoneReturnUntilAfterCount(5))
|
||||
self.fail("Expected RetryError after 3 attempts")
|
||||
except RetryError as re:
|
||||
self.assertFalse(re.last_attempt.has_exception)
|
||||
self.assertEqual(3, re.last_attempt.attempt_number)
|
||||
self.assertTrue(re.last_attempt.value is None)
|
||||
print(re)
|
||||
|
||||
def test_with_stop_on_exception(self):
|
||||
try:
|
||||
_retryable_test_with_stop(NoIOErrorAfterCount(5))
|
||||
self.fail("Expected IOError")
|
||||
except IOError as re:
|
||||
self.assertTrue(isinstance(re, IOError))
|
||||
print(re)
|
||||
|
||||
def test_retry_if_exception_of_type(self):
|
||||
self.assertTrue(_retryable_test_with_exception_type_io(NoIOErrorAfterCount(5)))
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_io(NoNameErrorAfterCount(5))
|
||||
self.fail("Expected NameError")
|
||||
except NameError as n:
|
||||
self.assertTrue(isinstance(n, NameError))
|
||||
print(n)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_io_attempt_limit_wrap(
|
||||
NoIOErrorAfterCount(5)
|
||||
)
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertEqual(3, re.last_attempt.attempt_number)
|
||||
self.assertTrue(re.last_attempt.has_exception)
|
||||
self.assertTrue(re.last_attempt.value[0] is not None)
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], IOError))
|
||||
self.assertTrue(re.last_attempt.value[2] is not None)
|
||||
print(re)
|
||||
|
||||
self.assertTrue(
|
||||
_retryable_test_with_exception_type_custom(NoCustomErrorAfterCount(5))
|
||||
)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_custom(NoNameErrorAfterCount(5))
|
||||
self.fail("Expected NameError")
|
||||
except NameError as n:
|
||||
self.assertTrue(isinstance(n, NameError))
|
||||
print(n)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_custom_attempt_limit_wrap(
|
||||
NoCustomErrorAfterCount(5)
|
||||
)
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertEqual(3, re.last_attempt.attempt_number)
|
||||
self.assertTrue(re.last_attempt.has_exception)
|
||||
self.assertTrue(re.last_attempt.value[0] is not None)
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], CustomError))
|
||||
self.assertTrue(re.last_attempt.value[2] is not None)
|
||||
print(re)
|
||||
|
||||
def test_wrapped_exception(self):
|
||||
|
||||
# base exception cases
|
||||
self.assertTrue(
|
||||
_retryable_test_with_exception_type_io_wrap(NoIOErrorAfterCount(5))
|
||||
)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_io_wrap(NoNameErrorAfterCount(5))
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], NameError))
|
||||
print(re)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_io_attempt_limit_wrap(
|
||||
NoIOErrorAfterCount(5)
|
||||
)
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertEqual(3, re.last_attempt.attempt_number)
|
||||
self.assertTrue(re.last_attempt.has_exception)
|
||||
self.assertTrue(re.last_attempt.value[0] is not None)
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], IOError))
|
||||
self.assertTrue(re.last_attempt.value[2] is not None)
|
||||
print(re)
|
||||
|
||||
# custom error cases
|
||||
self.assertTrue(
|
||||
_retryable_test_with_exception_type_custom_wrap(NoCustomErrorAfterCount(5))
|
||||
)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_custom_wrap(NoNameErrorAfterCount(5))
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertTrue(re.last_attempt.value[0] is not None)
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], NameError))
|
||||
self.assertTrue(re.last_attempt.value[2] is not None)
|
||||
print(re)
|
||||
|
||||
try:
|
||||
_retryable_test_with_exception_type_custom_attempt_limit_wrap(
|
||||
NoCustomErrorAfterCount(5)
|
||||
)
|
||||
self.fail("Expected RetryError")
|
||||
except RetryError as re:
|
||||
self.assertEqual(3, re.last_attempt.attempt_number)
|
||||
self.assertTrue(re.last_attempt.has_exception)
|
||||
self.assertTrue(re.last_attempt.value[0] is not None)
|
||||
self.assertTrue(isinstance(re.last_attempt.value[1], CustomError))
|
||||
self.assertTrue(re.last_attempt.value[2] is not None)
|
||||
|
||||
self.assertTrue(
|
||||
"This is a Custom exception class" in str(re.last_attempt.value[1])
|
||||
)
|
||||
print(re)
|
||||
|
||||
def test_defaults(self):
|
||||
self.assertTrue(_retryable_default(NoNameErrorAfterCount(5)))
|
||||
self.assertTrue(_retryable_default_f(NoNameErrorAfterCount(5)))
|
||||
self.assertTrue(_retryable_default(NoCustomErrorAfterCount(5)))
|
||||
self.assertTrue(_retryable_default_f(NoCustomErrorAfterCount(5)))
|
||||
|
||||
|
||||
class TestBeforeAfterAttempts(unittest.TestCase):
|
||||
_attempt_number = 0
|
||||
|
||||
def test_before_attempts(self):
|
||||
TestBeforeAfterAttempts._attempt_number = 0
|
||||
|
||||
def _before(attempt_number):
|
||||
TestBeforeAfterAttempts._attempt_number = attempt_number
|
||||
|
||||
@retry(wait_fixed=1000, stop_max_attempt_number=1, before_attempts=_before)
|
||||
def _test_before():
|
||||
pass
|
||||
|
||||
_test_before()
|
||||
|
||||
self.assertTrue(TestBeforeAfterAttempts._attempt_number is 1)
|
||||
|
||||
def test_after_attempts(self):
|
||||
TestBeforeAfterAttempts._attempt_number = 0
|
||||
|
||||
def _after(attempt_number):
|
||||
TestBeforeAfterAttempts._attempt_number = attempt_number
|
||||
|
||||
@retry(wait_fixed=100, stop_max_attempt_number=3, after_attempts=_after)
|
||||
def _test_after():
|
||||
if TestBeforeAfterAttempts._attempt_number < 2:
|
||||
raise Exception("testing after_attempts handler")
|
||||
else:
|
||||
pass
|
||||
|
||||
_test_after()
|
||||
|
||||
self.assertTrue(TestBeforeAfterAttempts._attempt_number is 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -23943,8 +23943,8 @@
|
|||
"type": "other",
|
||||
"other": {
|
||||
"name": "python-retrying",
|
||||
"version": "1.3.3",
|
||||
"downloadUrl": "https://github.com/rholder/retrying/archive/refs/tags/v1.3.3.tar.gz"
|
||||
"version": "1.3.4",
|
||||
"downloadUrl": "https://files.pythonhosted.org/packages/ce/70/15ce8551d65b324e18c5aa6ef6998880f21ead51ebe5ed743c0950d7d9dd/retrying-1.3.4.tar.gz"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче