backon 3.2.0__tar.gz → 3.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {backon-3.2.0 → backon-3.4.0}/PKG-INFO +1 -1
  2. {backon-3.2.0 → backon-3.4.0}/backon/__init__.py +2 -1
  3. {backon-3.2.0 → backon-3.4.0}/backon/_common.py +10 -15
  4. {backon-3.2.0 → backon-3.4.0}/backon/_decorator.py +23 -5
  5. {backon-3.2.0 → backon-3.4.0}/backon/_retry.py +363 -116
  6. {backon-3.2.0 → backon-3.4.0}/backon/_state.py +42 -0
  7. {backon-3.2.0 → backon-3.4.0}/pyproject.toml +1 -1
  8. {backon-3.2.0 → backon-3.4.0}/tests/test_backon.py +1 -0
  9. backon-3.4.0/tests/test_retry_call_state.py +292 -0
  10. {backon-3.2.0 → backon-3.4.0}/LICENSE +0 -0
  11. {backon-3.2.0 → backon-3.4.0}/README.md +0 -0
  12. {backon-3.2.0 → backon-3.4.0}/backon/_async.py +0 -0
  13. {backon-3.2.0 → backon-3.4.0}/backon/_conditions.py +0 -0
  14. {backon-3.2.0 → backon-3.4.0}/backon/_jitter.py +0 -0
  15. {backon-3.2.0 → backon-3.4.0}/backon/_sync.py +0 -0
  16. {backon-3.2.0 → backon-3.4.0}/backon/_typing.py +0 -0
  17. {backon-3.2.0 → backon-3.4.0}/backon/_wait_gen.py +0 -0
  18. {backon-3.2.0 → backon-3.4.0}/backon/py.typed +0 -0
  19. {backon-3.2.0 → backon-3.4.0}/backon/types.py +0 -0
  20. {backon-3.2.0 → backon-3.4.0}/tests/__init__.py +0 -0
  21. {backon-3.2.0 → backon-3.4.0}/tests/test_advanced_features.py +0 -0
  22. {backon-3.2.0 → backon-3.4.0}/tests/test_backon_async.py +0 -0
  23. {backon-3.2.0 → backon-3.4.0}/tests/test_backon_predicate.py +0 -0
  24. {backon-3.2.0 → backon-3.4.0}/tests/test_backon_sync.py +0 -0
  25. {backon-3.2.0 → backon-3.4.0}/tests/test_features.py +0 -0
  26. {backon-3.2.0 → backon-3.4.0}/tests/test_jitter.py +0 -0
  27. {backon-3.2.0 → backon-3.4.0}/tests/test_retry.py +0 -0
  28. {backon-3.2.0 → backon-3.4.0}/tests/test_types.py +0 -0
  29. {backon-3.2.0 → backon-3.4.0}/tests/test_typing.py +0 -0
  30. {backon-3.2.0 → backon-3.4.0}/tests/test_wait_gen.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: backon
3
- Version: 3.2.0
3
+ Version: 3.4.0
4
4
  Summary: Function decoration for backoff and retry
5
5
  Keywords: retry,backoff,decorators
6
6
  Author-Email: Llucs <c307lucas@gmail.com>
@@ -25,7 +25,7 @@ from backon._conditions import (
25
25
  from backon._decorator import on_exception, on_predicate
26
26
  from backon._jitter import full_jitter, random_jitter
27
27
  from backon._retry import Retrying, retry, sleep_using_event
28
- from backon._state import RetryError, RetryState, TryAgain
28
+ from backon._state import RetryCallState, RetryError, RetryState, TryAgain
29
29
  from backon._wait_gen import (
30
30
  constant,
31
31
  decay,
@@ -66,6 +66,7 @@ __all__ = [
66
66
  "TryAgain",
67
67
  "RetryError",
68
68
  "RetryState",
69
+ "RetryCallState",
69
70
  "Stop",
70
71
  "RetryCondition",
71
72
  "stop_after_attempt",
@@ -1,8 +1,6 @@
1
1
  import functools
2
2
  import logging
3
- import sys
4
3
  import time as time_module
5
- import traceback
6
4
 
7
5
  _logger = logging.getLogger("backon")
8
6
  _logger.addHandler(logging.NullHandler())
@@ -63,6 +61,8 @@ def _prepare_logger(logger):
63
61
  def _config_handlers(
64
62
  user_handlers, *, default_handler=None, logger=None, log_level=None
65
63
  ):
64
+ if isinstance(user_handlers, list) and logger is None:
65
+ return user_handlers
66
66
  handlers = []
67
67
  if logger is not None:
68
68
  assert log_level is not None
@@ -84,28 +84,23 @@ def _config_handlers(
84
84
 
85
85
  def _log_backoff(details, logger, log_level):
86
86
  msg = "Backing off %s(...) for %.1fs (%s)"
87
- log_args = [details["target"].__name__, details["wait"]]
88
-
89
- exc_typ, exc, _ = sys.exc_info()
87
+ exc = details.get("exception")
90
88
  if exc is not None:
91
- exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
92
- log_args.append(exc_fmt.rstrip("\n"))
89
+ exc_fmt = f"{type(exc).__name__}: {exc}"
93
90
  else:
94
- log_args.append(details["value"])
91
+ exc_fmt = details.get("value", "unknown")
92
+ log_args = [details["target"].__name__, details["wait"], exc_fmt]
95
93
  logger.log(log_level, msg, *log_args)
96
94
 
97
95
 
98
96
  def _log_giveup(details, logger, log_level):
99
97
  msg = "Giving up %s(...) after %d tries (%s)"
100
- log_args = [details["target"].__name__, details["tries"]]
101
-
102
- exc_typ, exc, _ = sys.exc_info()
98
+ exc = details.get("exception")
103
99
  if exc is not None:
104
- exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
105
- log_args.append(exc_fmt.rstrip("\n"))
100
+ exc_fmt = f"{type(exc).__name__}: {exc}"
106
101
  else:
107
- log_args.append(details["value"])
108
-
102
+ exc_fmt = details.get("value", "unknown")
103
+ log_args = [details["target"].__name__, details["tries"], exc_fmt]
109
104
  logger.log(log_level, msg, *log_args)
110
105
 
111
106
 
@@ -21,7 +21,7 @@ from backon._conditions import (
21
21
  retry_if_result,
22
22
  )
23
23
  from backon._jitter import full_jitter
24
- from backon._retry import _retry_async, _retry_sync
24
+ from backon._retry import _retry_async_inner, _retry_sync_inner
25
25
  from backon._state import RetryState
26
26
  from backon._typing import (
27
27
  P,
@@ -54,10 +54,13 @@ def on_predicate(
54
54
  retry_error_callback: Callable[[dict], Any] | None = None,
55
55
  raise_on_giveup: bool = True,
56
56
  sleep: Callable[[float], Any] | None = None,
57
+ before: _Handler | Iterable[_Handler] | None = None,
58
+ after: _Handler | Iterable[_Handler] | None = None,
57
59
  **wait_gen_kwargs: Any,
58
60
  ) -> Callable[[Callable[P, R]], Callable[P, R]]:
59
61
  def decorate(target: Callable[P, R]) -> Callable[P, R]:
60
62
  nonlocal logger, on_success, on_backoff, on_giveup, on_attempt, before_sleep
63
+ nonlocal before, after
61
64
 
62
65
  logger = _prepare_logger(logger)
63
66
  on_success = _config_handlers(on_success)
@@ -75,6 +78,8 @@ def on_predicate(
75
78
  )
76
79
  on_attempt = _config_handlers(on_attempt)
77
80
  before_sleep = _config_handlers(before_sleep)
81
+ before = _config_handlers(before)
82
+ after = _config_handlers(after)
78
83
 
79
84
  condition: RetryCondition = retry_if_result(predicate)
80
85
 
@@ -91,7 +96,7 @@ def on_predicate(
91
96
 
92
97
  return cast(
93
98
  R,
94
- await _retry_async(
99
+ await _retry_async_inner(
95
100
  wrapped,
96
101
  wait_gen,
97
102
  condition=condition,
@@ -107,6 +112,8 @@ def on_predicate(
107
112
  retry_error_callback=retry_error_callback,
108
113
  raise_on_giveup=raise_on_giveup,
109
114
  wait_gen_kwargs=wait_gen_kwargs,
115
+ before=before,
116
+ after=after,
110
117
  ),
111
118
  )
112
119
 
@@ -121,7 +128,7 @@ def on_predicate(
121
128
 
122
129
  return cast(
123
130
  R,
124
- _retry_sync(
131
+ _retry_sync_inner(
125
132
  lambda: target(*args, **kwargs),
126
133
  wait_gen,
127
134
  condition=condition,
@@ -137,6 +144,8 @@ def on_predicate(
137
144
  retry_error_callback=retry_error_callback,
138
145
  raise_on_giveup=raise_on_giveup,
139
146
  wait_gen_kwargs=wait_gen_kwargs,
147
+ before=before,
148
+ after=after,
140
149
  ),
141
150
  )
142
151
 
@@ -164,10 +173,13 @@ def on_exception(
164
173
  backoff_log_level: int = logging.INFO,
165
174
  giveup_log_level: int = logging.ERROR,
166
175
  sleep: Callable[[float], Any] | None = None,
176
+ before: _Handler | Iterable[_Handler] | None = None,
177
+ after: _Handler | Iterable[_Handler] | None = None,
167
178
  **wait_gen_kwargs: Any,
168
179
  ) -> Callable[[Callable[P, R]], Callable[P, R]]:
169
180
  def decorate(target: Callable[P, R]) -> Callable[P, R]:
170
181
  nonlocal logger, on_success, on_backoff, on_giveup, on_attempt, before_sleep
182
+ nonlocal before, after
171
183
 
172
184
  logger = _prepare_logger(logger)
173
185
  on_success = _config_handlers(on_success)
@@ -185,6 +197,8 @@ def on_exception(
185
197
  )
186
198
  on_attempt = _config_handlers(on_attempt)
187
199
  before_sleep = _config_handlers(before_sleep)
200
+ before = _config_handlers(before)
201
+ after = _config_handlers(after)
188
202
 
189
203
  exc_types: tuple[type[Exception], ...]
190
204
  if isinstance(exception, type):
@@ -217,7 +231,7 @@ def on_exception(
217
231
 
218
232
  return cast(
219
233
  R,
220
- await _retry_async(
234
+ await _retry_async_inner(
221
235
  wrapped,
222
236
  wait_gen,
223
237
  condition=condition,
@@ -233,6 +247,8 @@ def on_exception(
233
247
  retry_error_callback=retry_error_callback,
234
248
  raise_on_giveup=raise_on_giveup,
235
249
  wait_gen_kwargs=wait_gen_kwargs,
250
+ before=before,
251
+ after=after,
236
252
  ),
237
253
  )
238
254
 
@@ -247,7 +263,7 @@ def on_exception(
247
263
 
248
264
  return cast(
249
265
  R,
250
- _retry_sync(
266
+ _retry_sync_inner(
251
267
  lambda: target(*args, **kwargs),
252
268
  wait_gen,
253
269
  condition=condition,
@@ -263,6 +279,8 @@ def on_exception(
263
279
  retry_error_callback=retry_error_callback,
264
280
  raise_on_giveup=raise_on_giveup,
265
281
  wait_gen_kwargs=wait_gen_kwargs,
282
+ before=before,
283
+ after=after,
266
284
  ),
267
285
  )
268
286