Skip to content

Commit 3d8cc46

Browse files
emar-karbusunkim96
authored andcommitted
API Core: Retry.__init__ add on_error (#8892)
1 parent 92840f1 commit 3d8cc46

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

google/api_core/retry.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,14 @@ def __init__(
237237
maximum=_DEFAULT_MAXIMUM_DELAY,
238238
multiplier=_DEFAULT_DELAY_MULTIPLIER,
239239
deadline=_DEFAULT_DEADLINE,
240+
on_error=None
240241
):
241242
self._predicate = predicate
242243
self._initial = initial
243244
self._multiplier = multiplier
244245
self._maximum = maximum
245246
self._deadline = deadline
247+
self._on_error = on_error
246248

247249
def __call__(self, func, on_error=None):
248250
"""Wrap a callable with retry behavior.
@@ -257,6 +259,8 @@ def __call__(self, func, on_error=None):
257259
Callable: A callable that will invoke ``func`` with retry
258260
behavior.
259261
"""
262+
if self._on_error is not None:
263+
on_error = self._on_error
260264

261265
@general_helpers.wraps(func)
262266
def retry_wrapped_func(*args, **kwargs):
@@ -290,6 +294,7 @@ def with_deadline(self, deadline):
290294
maximum=self._maximum,
291295
multiplier=self._multiplier,
292296
deadline=deadline,
297+
on_error=self._on_error,
293298
)
294299

295300
def with_predicate(self, predicate):
@@ -308,6 +313,7 @@ def with_predicate(self, predicate):
308313
maximum=self._maximum,
309314
multiplier=self._multiplier,
310315
deadline=self._deadline,
316+
on_error=self._on_error,
311317
)
312318

313319
def with_delay(self, initial=None, maximum=None, multiplier=None):
@@ -328,16 +334,18 @@ def with_delay(self, initial=None, maximum=None, multiplier=None):
328334
maximum=maximum if maximum is not None else self._maximum,
329335
multiplier=multiplier if maximum is not None else self._multiplier,
330336
deadline=self._deadline,
337+
on_error=self._on_error,
331338
)
332339

333340
def __str__(self):
334341
return (
335342
"<Retry predicate={}, initial={:.1f}, maximum={:.1f}, "
336-
"multiplier={:.1f}, deadline={:.1f}>".format(
343+
"multiplier={:.1f}, deadline={:.1f}, on_error={}>".format(
337344
self._predicate,
338345
self._initial,
339346
self._maximum,
340347
self._multiplier,
341348
self._deadline,
349+
self._on_error,
342350
)
343351
)

tests/unit/test_retry.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,20 +161,25 @@ def test_constructor_defaults(self):
161161
assert retry_._maximum == 60
162162
assert retry_._multiplier == 2
163163
assert retry_._deadline == 120
164+
assert retry_._on_error is None
164165

165166
def test_constructor_options(self):
167+
_some_function = mock.Mock()
168+
166169
retry_ = retry.Retry(
167170
predicate=mock.sentinel.predicate,
168171
initial=1,
169172
maximum=2,
170173
multiplier=3,
171174
deadline=4,
175+
on_error=_some_function,
172176
)
173177
assert retry_._predicate == mock.sentinel.predicate
174178
assert retry_._initial == 1
175179
assert retry_._maximum == 2
176180
assert retry_._multiplier == 3
177181
assert retry_._deadline == 4
182+
assert retry_._on_error is _some_function
178183

179184
def test_with_deadline(self):
180185
retry_ = retry.Retry()
@@ -209,7 +214,8 @@ def test___str__(self):
209214
assert re.match(
210215
(
211216
r"<Retry predicate=<function.*?if_exception_type.*?>, "
212-
r"initial=1.0, maximum=60.0, multiplier=2.0, deadline=120.0>"
217+
r"initial=1.0, maximum=60.0, multiplier=2.0, deadline=120.0, "
218+
r"on_error=None>"
213219
),
214220
str(retry_),
215221
)
@@ -230,8 +236,7 @@ def test___call___and_execute_success(self, sleep):
230236
target.assert_called_once_with("meep")
231237
sleep.assert_not_called()
232238

233-
# Make uniform return half of its maximum, which will be the calculated
234-
# sleep time.
239+
# Make uniform return half of its maximum, which is the calculated sleep time.
235240
@mock.patch("random.uniform", autospec=True, side_effect=lambda m, n: n / 2.0)
236241
@mock.patch("time.sleep", autospec=True)
237242
def test___call___and_execute_retry(self, sleep, uniform):
@@ -253,3 +258,55 @@ def test___call___and_execute_retry(self, sleep, uniform):
253258
target.assert_has_calls([mock.call("meep"), mock.call("meep")])
254259
sleep.assert_called_once_with(retry_._initial)
255260
assert on_error.call_count == 1
261+
262+
@mock.patch("time.sleep", autospec=True)
263+
def test___init___without_retry_executed(self, sleep):
264+
_some_function = mock.Mock()
265+
266+
retry_ = retry.Retry(
267+
predicate=retry.if_exception_type(ValueError), on_error=_some_function
268+
)
269+
# check the proper creation of the class
270+
assert retry_._on_error is _some_function
271+
272+
target = mock.Mock(spec=["__call__"], side_effect=[42])
273+
# __name__ is needed by functools.partial.
274+
target.__name__ = "target"
275+
276+
wrapped = retry_(target)
277+
278+
result = wrapped("meep")
279+
280+
assert result == 42
281+
target.assert_called_once_with("meep")
282+
sleep.assert_not_called()
283+
_some_function.assert_not_called()
284+
285+
# Make uniform return half of its maximum, which is the calculated sleep time.
286+
@mock.patch("random.uniform", autospec=True, side_effect=lambda m, n: n / 2.0)
287+
@mock.patch("time.sleep", autospec=True)
288+
def test___init___when_retry_is_executed(self, sleep, uniform):
289+
_some_function = mock.Mock()
290+
291+
retry_ = retry.Retry(
292+
predicate=retry.if_exception_type(ValueError), on_error=_some_function
293+
)
294+
# check the proper creation of the class
295+
assert retry_._on_error is _some_function
296+
297+
target = mock.Mock(
298+
spec=["__call__"], side_effect=[ValueError(), ValueError(), 42]
299+
)
300+
# __name__ is needed by functools.partial.
301+
target.__name__ = "target"
302+
303+
wrapped = retry_(target)
304+
target.assert_not_called()
305+
306+
result = wrapped("meep")
307+
308+
assert result == 42
309+
assert target.call_count == 3
310+
assert _some_function.call_count == 2
311+
target.assert_has_calls([mock.call("meep"), mock.call("meep")])
312+
sleep.assert_any_call(retry_._initial)

0 commit comments

Comments
 (0)