Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions tenacity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@
import sys
import threading
import typing as t
import warnings
from abc import ABCMeta, abstractmethod
from concurrent import futures


import six

from tenacity import _utils
Expand Down Expand Up @@ -209,6 +212,7 @@ def __exit__(self, exc_type, exc_value, traceback):


class BaseRetrying(object):
__metaclass__ = ABCMeta

def __init__(self,
sleep=sleep,
Expand Down Expand Up @@ -326,7 +330,7 @@ def wraps(self, f):
"""
@_utils.wraps(f)
def wrapped_f(*args, **kw):
return self.call(f, *args, **kw)
return self(f, *args, **kw)

def retry_with(*args, **kwargs):
return self.copy(*args, **kwargs).wraps(f)
Expand Down Expand Up @@ -396,11 +400,15 @@ def __iter__(self):
else:
break

@abstractmethod
def __call__(self, *args, **kwargs):
pass


class Retrying(BaseRetrying):
"""Retrying controller."""

def call(self, fn, *args, **kwargs):
def __call__(self, fn, *args, **kwargs):
Comment thread
jd marked this conversation as resolved.
self.begin(fn)

retry_state = RetryCallState(
Expand All @@ -420,7 +428,11 @@ def call(self, fn, *args, **kwargs):
else:
return do

__call__ = call
def call(self, *args, **kwargs):
"""Use ``__call__`` instead because this method is deprecated."""
warnings.warn("'Retrying.call()' method is deprecated. " +
"Use 'Retrying.__call__()' instead")
self.__call__(self, *args, **kwargs)


class Future(futures.Future):
Expand Down
2 changes: 1 addition & 1 deletion tenacity/_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self,
super(AsyncRetrying, self).__init__(**kwargs)
self.sleep = sleep

async def call(self, fn, *args, **kwargs):
async def __call__(self, fn, *args, **kwargs):
self.begin(fn)

retry_state = RetryCallState(
Expand Down
14 changes: 13 additions & 1 deletion tenacity/tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import six

from tenacity import RetryError
from tenacity import AsyncRetrying, RetryError
from tenacity import _asyncio as tasyncio
from tenacity import retry, stop_after_attempt
from tenacity.tests.test_tenacity import NoIOErrorAfterCount, current_time_ms
Expand All @@ -34,6 +34,11 @@ def wrapper(*a, **kw):
return wrapper


async def _async_function(thing):
await asyncio.sleep(0.00001)
return thing.go()


@retry
async def _retryable_coroutine(thing):
await asyncio.sleep(0.00001)
Expand All @@ -53,6 +58,13 @@ async def test_retry(self):
await _retryable_coroutine(thing)
assert thing.counter == thing.count

@asynctest
async def test_retry_using_async_retying(self):
thing = NoIOErrorAfterCount(5)
retrying = AsyncRetrying()
await retrying(_async_function, thing)
assert thing.counter == thing.count

@asynctest
async def test_stop_after_attempt(self):
thing = NoIOErrorAfterCount(2)
Expand Down
39 changes: 25 additions & 14 deletions tenacity/tests/test_tenacity.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@


class TestBase(unittest.TestCase):

def test_repr(self):
repr(tenacity.BaseRetrying())
class ConcreteRetrying(tenacity.BaseRetrying):
def __call__(self):
pass

repr(ConcreteRetrying())


class TestStopConditions(unittest.TestCase):
Expand Down Expand Up @@ -135,7 +140,7 @@ def __call__(self, attempt_number, seconds_since_start):
def failing():
raise NotImplementedError()
with pytest.raises(RetryError):
retrying.call(failing)
retrying(failing)

def test_stop_func_with_retry_state(self):
def stop_func(retry_state):
Expand Down Expand Up @@ -283,7 +288,7 @@ def dying():
stop=tenacity.stop_after_attempt(r_attempts),
reraise=True)
with reports_deprecation_warning():
self.assertRaises(Exception, r.call, dying)
self.assertRaises(Exception, r, dying)
self.assertEqual(r_attempts - 1, len(captures))
self.assertTrue(all([r.failed for r in captures]))

Expand Down Expand Up @@ -451,14 +456,14 @@ def dying():

retrying1 = Retrying(wait=wait1, stop=tenacity.stop_after_attempt(4))
with reports_deprecation_warning():
self.assertRaises(Exception, lambda: retrying1.call(dying))
self.assertRaises(Exception, lambda: retrying1(dying))
self.assertEqual([t[0] for t in wait1.calls], [1, 2, 3])
# This assumes that 3 iterations complete within 1 second.
self.assertTrue(all(t[1] < 1 for t in wait1.calls))

retrying2 = Retrying(wait=wait2, stop=tenacity.stop_after_attempt(4))
with reports_deprecation_warning():
self.assertRaises(Exception, lambda: retrying2.call(dying))
self.assertRaises(Exception, lambda: retrying2(dying))
self.assertEqual([t[0] for t in wait2.calls], [1, 2, 3])
# This assumes that 3 iterations complete within 1 second.
self.assertTrue(all(t[1] < 1 for t in wait2.calls))
Expand Down Expand Up @@ -494,7 +499,7 @@ def waitfunc(retry_state):
def returnval():
return 123
try:
retrying.call(returnval)
retrying(returnval)
except ExtractCallState as err:
retry_state = err.args[0]
self.assertIs(retry_state.fn, returnval)
Expand All @@ -508,7 +513,7 @@ def returnval():
def dying():
raise Exception("Broken")
try:
retrying.call(dying)
retrying(dying)
except ExtractCallState as err:
retry_state = err.args[0]
self.assertIs(retry_state.fn, dying)
Expand Down Expand Up @@ -598,7 +603,7 @@ def _raise_try_again(self):
def test_retry_try_again(self):
self._attempts = 0
Retrying(stop=tenacity.stop_after_attempt(5),
retry=tenacity.retry_never).call(self._raise_try_again)
retry=tenacity.retry_never)(self._raise_try_again)
self.assertEqual(3, self._attempts)

def test_retry_try_again_forever(self):
Expand All @@ -608,7 +613,7 @@ def _r():
r = Retrying(stop=tenacity.stop_after_attempt(5),
retry=tenacity.retry_never)
self.assertRaises(tenacity.RetryError,
r.call,
r,
_r)
self.assertEqual(5, r.statistics['attempt_number'])

Expand Down Expand Up @@ -1048,7 +1053,7 @@ def __call__(self, attempt):
def failing():
raise NotImplementedError()
with pytest.raises(RetryError):
retrying.call(failing)
retrying(failing)


class TestBeforeAfterAttempts(unittest.TestCase):
Expand Down Expand Up @@ -1143,7 +1148,7 @@ def _test_before_sleep():

self.assertEqual(self.slept, 2)

def test_before_sleep_log_raises(self):
def _before_sleep_log_raises(self, get_call_fn):
thing = NoIOErrorAfterCount(2)
logger = logging.getLogger(self.id())
logger.propagate = False
Expand All @@ -1155,7 +1160,7 @@ def test_before_sleep_log_raises(self):
retrying = Retrying(wait=tenacity.wait_fixed(0.01),
stop=tenacity.stop_after_attempt(3),
before_sleep=_before_sleep)
retrying.call(thing.go)
get_call_fn(retrying)(thing.go)
finally:
logger.removeHandler(handler)

Expand All @@ -1166,6 +1171,12 @@ def test_before_sleep_log_raises(self):
self.assertRegexpMatches(fmt(handler.records[0]), etalon_re)
self.assertRegexpMatches(fmt(handler.records[1]), etalon_re)

def test_before_sleep_log_raises(self):
self._before_sleep_log_raises(lambda x: x)

def test_before_sleep_log_raises_deprecated_call(self):
self._before_sleep_log_raises(lambda x: x.call)

def test_before_sleep_log_raises_with_exc_info(self):
thing = NoIOErrorAfterCount(2)
logger = logging.getLogger(self.id())
Expand All @@ -1180,7 +1191,7 @@ def test_before_sleep_log_raises_with_exc_info(self):
retrying = Retrying(wait=tenacity.wait_fixed(0.01),
stop=tenacity.stop_after_attempt(3),
before_sleep=_before_sleep)
retrying.call(thing.go)
retrying(thing.go)
finally:
logger.removeHandler(handler)

Expand Down Expand Up @@ -1209,7 +1220,7 @@ def test_before_sleep_log_returns(self, exc_info=False):
retrying = Retrying(wait=tenacity.wait_fixed(0.01),
stop=tenacity.stop_after_attempt(3),
retry=_retry, before_sleep=_before_sleep)
retrying.call(thing.go)
retrying(thing.go)
finally:
logger.removeHandler(handler)

Expand Down
2 changes: 1 addition & 1 deletion tenacity/tornadoweb.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self,
self.sleep = sleep

@gen.coroutine
def call(self, fn, *args, **kwargs):
def __call__(self, fn, *args, **kwargs):
self.begin(fn)

retry_state = RetryCallState(
Expand Down