python-backoff 2.2.2rc1__tar.gz → 2.3.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 (25) hide show
  1. python_backoff-2.3.0/.gitignore +42 -0
  2. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/PKG-INFO +5 -6
  3. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/README.rst +3 -3
  4. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_async.py +7 -8
  5. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_common.py +2 -2
  6. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_decorator.py +5 -5
  7. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_sync.py +4 -6
  8. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_wait_gen.py +7 -7
  9. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/types.py +1 -1
  10. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/pyproject.toml +8 -6
  11. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_backoff.py +19 -26
  12. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_typing.py +1 -1
  13. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_wait_gen.py +8 -0
  14. python_backoff-2.2.2rc1/.gitignore +0 -15
  15. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/LICENSE +0 -0
  16. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/__init__.py +0 -0
  17. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_jitter.py +0 -0
  18. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/_typing.py +0 -0
  19. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/backoff/py.typed +0 -0
  20. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/__init__.py +0 -0
  21. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/common.py +0 -0
  22. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_backoff_async.py +0 -0
  23. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_integration.py +0 -0
  24. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_jitter.py +0 -0
  25. {python_backoff-2.2.2rc1 → python_backoff-2.3.0}/tests/test_types.py +0 -0
@@ -0,0 +1,42 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .coverage
4
+ virtualenv
5
+ MANIFEST
6
+ build/
7
+ dist/
8
+ .cache/
9
+ *.egg-info
10
+ .vscode
11
+ .tox/
12
+ coverage.xml
13
+
14
+ # mkdocs
15
+ site/
16
+
17
+ # General
18
+ .DS_Store
19
+ __MACOSX/
20
+ .AppleDouble
21
+ .LSOverride
22
+ Icon[
23
+ ]
24
+
25
+ # Thumbnails
26
+ ._*
27
+
28
+ # Files that might appear in the root of a volume
29
+ .DocumentRevisions-V100
30
+ .fseventsd
31
+ .Spotlight-V100
32
+ .TemporaryItems
33
+ .Trashes
34
+ .VolumeIcon.icns
35
+ .com.apple.timemachine.donotpresent
36
+
37
+ # Directories potentially created on remote AFP share
38
+ .AppleDB
39
+ .AppleDesktop
40
+ Network Trash Folder
41
+ Temporary Items
42
+ .apdisk
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-backoff
3
- Version: 2.2.2rc1
3
+ Version: 2.3.0
4
4
  Summary: Function decoration for backoff and retry
5
5
  Project-URL: Documentation, https://python-backoff.github.io/backoff
6
6
  Project-URL: Repository, https://github.com/python-backoff/backoff
@@ -16,7 +16,6 @@ Classifier: Natural Language :: English
16
16
  Classifier: Operating System :: OS Independent
17
17
  Classifier: Programming Language :: Python
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.7
20
19
  Classifier: Programming Language :: Python :: 3.8
21
20
  Classifier: Programming Language :: Python :: 3.9
22
21
  Classifier: Programming Language :: Python :: 3.10
@@ -28,7 +27,7 @@ Classifier: Programming Language :: Python :: 3.15
28
27
  Classifier: Topic :: Internet :: WWW/HTTP
29
28
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
30
29
  Classifier: Topic :: Utilities
31
- Requires-Python: >=3.7
30
+ Requires-Python: >=3.8
32
31
  Description-Content-Type: text/x-rst
33
32
 
34
33
  backoff
@@ -38,8 +37,8 @@ backoff
38
37
  :target: https://github.com/python-backoff/backoff/actions/workflows/ci.yaml
39
38
  .. image:: https://github.com/python-backoff/backoff/workflows/CodeQL/badge.svg
40
39
  :target: https://github.com/python-backoff/backoff/actions/workflows/codeql-analysis.yml
41
- .. image:: https://img.shields.io/pypi/v/backoff.svg
42
- :target: https://pypi.python.org/pypi/backoff
40
+ .. image:: https://img.shields.io/pypi/v/python-backoff.svg
41
+ :target: https://pypi.python.org/pypi/python-backoff
43
42
  .. image:: https://img.shields.io/github/license/python-backoff/backoff
44
43
  :target: https://github.com/python-backoff/backoff/blob/main/LICENSE
45
44
 
@@ -201,7 +200,7 @@ gets a non-falsey result could be defined like like this:
201
200
  def poll_for_message(queue):
202
201
  return queue.get()
203
202
 
204
- The jitter is disabled in order to keep the polling frequency fixed.
203
+ The jitter is disabled in order to keep the polling frequency fixed.
205
204
 
206
205
  @backoff.runtime
207
206
  ----------------
@@ -5,8 +5,8 @@ backoff
5
5
  :target: https://github.com/python-backoff/backoff/actions/workflows/ci.yaml
6
6
  .. image:: https://github.com/python-backoff/backoff/workflows/CodeQL/badge.svg
7
7
  :target: https://github.com/python-backoff/backoff/actions/workflows/codeql-analysis.yml
8
- .. image:: https://img.shields.io/pypi/v/backoff.svg
9
- :target: https://pypi.python.org/pypi/backoff
8
+ .. image:: https://img.shields.io/pypi/v/python-backoff.svg
9
+ :target: https://pypi.python.org/pypi/python-backoff
10
10
  .. image:: https://img.shields.io/github/license/python-backoff/backoff
11
11
  :target: https://github.com/python-backoff/backoff/blob/main/LICENSE
12
12
 
@@ -168,7 +168,7 @@ gets a non-falsey result could be defined like like this:
168
168
  def poll_for_message(queue):
169
169
  return queue.get()
170
170
 
171
- The jitter is disabled in order to keep the polling frequency fixed.
171
+ The jitter is disabled in order to keep the polling frequency fixed.
172
172
 
173
173
  @backoff.runtime
174
174
  ----------------
@@ -1,11 +1,10 @@
1
1
  # coding:utf-8
2
- import datetime
3
- import functools
4
2
  import asyncio
3
+ import functools
5
4
  import inspect
6
- from datetime import timedelta
5
+ import time
7
6
 
8
- from backoff._common import (_init_wait_gen, _maybe_call, _next_wait)
7
+ from backoff._common import _init_wait_gen, _maybe_call, _next_wait
9
8
 
10
9
 
11
10
  def _ensure_coroutine(coro_or_func):
@@ -61,11 +60,11 @@ def retry_predicate(target, wait_gen, predicate,
61
60
  max_time_value = _maybe_call(max_time)
62
61
 
63
62
  tries = 0
64
- start = datetime.datetime.now()
63
+ start = time.monotonic()
65
64
  wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
66
65
  while True:
67
66
  tries += 1
68
- elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
67
+ elapsed = time.monotonic() - start
69
68
  details = {
70
69
  "target": target,
71
70
  "args": args,
@@ -135,11 +134,11 @@ def retry_exception(target, wait_gen, exception,
135
134
  max_time_value = _maybe_call(max_time)
136
135
 
137
136
  tries = 0
138
- start = datetime.datetime.now()
137
+ start = time.monotonic()
139
138
  wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
140
139
  while True:
141
140
  tries += 1
142
- elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
141
+ elapsed = time.monotonic() - start
143
142
  details = {
144
143
  "target": target,
145
144
  "args": args,
@@ -65,14 +65,14 @@ def _prepare_logger(logger):
65
65
  # Configure handler list with user specified handler and optionally
66
66
  # with a default handler bound to the specified logger.
67
67
  def _config_handlers(
68
- user_handlers, *, default_handler=None, logger=None, log_level=None
68
+ user_handlers, *, default_handler=None, logger=None, log_level=None,
69
69
  ):
70
70
  handlers = []
71
71
  if logger is not None:
72
72
  assert log_level is not None, "Log level is not specified"
73
73
  # bind the specified logger to the default log handler
74
74
  log_handler = functools.partial(
75
- default_handler, logger=logger, log_level=log_level
75
+ default_handler, logger=logger, log_level=log_level,
76
76
  )
77
77
  handlers.append(log_handler)
78
78
 
@@ -8,7 +8,7 @@ from backoff._common import (
8
8
  _prepare_logger,
9
9
  _config_handlers,
10
10
  _log_backoff,
11
- _log_giveup
11
+ _log_giveup,
12
12
  )
13
13
  from backoff._jitter import full_jitter
14
14
  from backoff import _async, _sync
@@ -89,13 +89,13 @@ def on_predicate(wait_gen: _WaitGenerator,
89
89
  on_backoff,
90
90
  default_handler=_log_backoff,
91
91
  logger=logger,
92
- log_level=backoff_log_level
92
+ log_level=backoff_log_level,
93
93
  )
94
94
  on_giveup = _config_handlers(
95
95
  on_giveup,
96
96
  default_handler=_log_giveup,
97
97
  logger=logger,
98
- log_level=giveup_log_level
98
+ log_level=giveup_log_level,
99
99
  )
100
100
 
101
101
  if inspect.iscoroutinefunction(target):
@@ -113,7 +113,7 @@ def on_predicate(wait_gen: _WaitGenerator,
113
113
  on_success=on_success,
114
114
  on_backoff=on_backoff,
115
115
  on_giveup=on_giveup,
116
- wait_gen_kwargs=wait_gen_kwargs
116
+ wait_gen_kwargs=wait_gen_kwargs,
117
117
  )
118
118
 
119
119
  # Return a function which decorates a target with a retry loop.
@@ -215,7 +215,7 @@ def on_exception(wait_gen: _WaitGenerator,
215
215
  on_backoff=on_backoff,
216
216
  on_giveup=on_giveup,
217
217
  raise_on_giveup=raise_on_giveup,
218
- wait_gen_kwargs=wait_gen_kwargs
218
+ wait_gen_kwargs=wait_gen_kwargs,
219
219
  )
220
220
 
221
221
  # Return a function which decorates a target with a retry loop.
@@ -1,8 +1,6 @@
1
1
  # coding:utf-8
2
- import datetime
3
2
  import functools
4
3
  import time
5
- from datetime import timedelta
6
4
 
7
5
  from backoff._common import (_init_wait_gen, _maybe_call, _next_wait)
8
6
 
@@ -32,11 +30,11 @@ def retry_predicate(target, wait_gen, predicate,
32
30
  max_time_value = _maybe_call(max_time)
33
31
 
34
32
  tries = 0
35
- start = datetime.datetime.now()
33
+ start = time.monotonic()
36
34
  wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
37
35
  while True:
38
36
  tries += 1
39
- elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
37
+ elapsed = time.monotonic() - start
40
38
  details = {
41
39
  "target": target,
42
40
  "args": args,
@@ -88,11 +86,11 @@ def retry_exception(target, wait_gen, exception,
88
86
  max_time_value = _maybe_call(max_time)
89
87
 
90
88
  tries = 0
91
- start = datetime.datetime.now()
89
+ start = time.monotonic()
92
90
  wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
93
91
  while True:
94
92
  tries += 1
95
- elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
93
+ elapsed = time.monotonic() - start
96
94
  details = {
97
95
  "target": target,
98
96
  "args": args,
@@ -8,7 +8,7 @@ from typing import Any, Callable, Generator, Iterable, Optional, Union
8
8
  def expo(
9
9
  base: float = 2,
10
10
  factor: float = 1,
11
- max_value: Optional[float] = None
11
+ max_value: Optional[float] = None,
12
12
  ) -> Generator[float, Any, None]:
13
13
 
14
14
  """Generator for exponential decay.
@@ -22,12 +22,12 @@ def expo(
22
22
  """
23
23
  # Advance past initial .send() call
24
24
  yield # type: ignore[misc]
25
- n = 0
25
+ base_n: float = 1
26
26
  while True:
27
- a = factor * base ** n
27
+ a = factor * base_n
28
28
  if max_value is None or a < max_value:
29
29
  yield a
30
- n += 1
30
+ base_n *= base
31
31
  else:
32
32
  yield max_value
33
33
 
@@ -35,7 +35,7 @@ def expo(
35
35
  def decay(
36
36
  initial_value: float = 1,
37
37
  decay_factor: float = 1,
38
- min_value: Optional[float] = None
38
+ min_value: Optional[float] = None,
39
39
  ) -> Generator[float, Any, None]:
40
40
 
41
41
  """Generator for exponential decay[1]:
@@ -83,7 +83,7 @@ def fibo(max_value: Optional[int] = None) -> Generator[int, None, None]:
83
83
 
84
84
 
85
85
  def constant(
86
- interval: Union[int, Iterable[float]] = 1
86
+ interval: Union[int, Iterable[float]] = 1,
87
87
  ) -> Generator[float, None, None]:
88
88
  """Generator for constant intervals.
89
89
 
@@ -104,7 +104,7 @@ def constant(
104
104
 
105
105
  def runtime(
106
106
  *,
107
- value: Callable[[Any], float]
107
+ value: Callable[[Any], float],
108
108
  ) -> Generator[float, None, None]:
109
109
  """Generator that is based on parsing the return value or thrown
110
110
  exception of the decorated method
@@ -2,5 +2,5 @@
2
2
  from ._typing import Details
3
3
 
4
4
  __all__ = [
5
- 'Details'
5
+ 'Details',
6
6
  ]
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "python-backoff"
3
- version = "2.2.2rc1"
3
+ version = "2.3.0"
4
4
  description = "Function decoration for backoff and retry"
5
5
  authors = [{ name = "Bob Green", email = "rgreen@aquent.com" }]
6
6
  maintainers = [{ name = "Edgar Ramírez-Mondragón", email = "edgarrm358@gmail.com" }]
7
- requires-python = ">=3.7"
7
+ requires-python = ">=3.8"
8
8
  readme = "README.rst"
9
9
  license = "MIT"
10
10
  keywords = [
@@ -20,7 +20,6 @@ classifiers = [
20
20
  "Operating System :: OS Independent",
21
21
  "Programming Language :: Python",
22
22
  "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.7",
24
23
  "Programming Language :: Python :: 3.8",
25
24
  "Programming Language :: Python :: 3.9",
26
25
  "Programming Language :: Python :: 3.10",
@@ -77,7 +76,6 @@ min_version = "4.22"
77
76
  requires = [ "tox", "tox-gh", "tox-uv" ]
78
77
  env_list = [
79
78
  "format",
80
- "3.7",
81
79
  "3.8",
82
80
  "3.9",
83
81
  "3.10",
@@ -101,7 +99,6 @@ commands = [
101
99
  [tool.tox.env.coverage]
102
100
  description = "generate coverage report"
103
101
  depends = [
104
- "3.7",
105
102
  "3.8",
106
103
  "3.9",
107
104
  "3.10",
@@ -123,6 +120,7 @@ description = "format code"
123
120
  dependency_groups = [ "lint" ]
124
121
  commands = [
125
122
  [ "ruff", "check", "--fix", { replace = "posargs", default = [ "backoff", "tests" ], extend = true } ],
123
+ # [ "ruff", "format", { replace = "posargs", default = [ "backoff", "tests" ], extend = true } ],
126
124
  ]
127
125
 
128
126
  [tool.tox.env.lint]
@@ -155,7 +153,6 @@ commands = [
155
153
  "3.10" = ["3.10"]
156
154
  "3.9" = ["3.9"]
157
155
  "3.8" = ["3.8"]
158
- "3.7" = ["3.7"]
159
156
 
160
157
  [tool.pytest.ini_options]
161
158
  filterwarnings = [
@@ -183,6 +180,11 @@ source = [
183
180
  "backoff",
184
181
  ]
185
182
 
183
+ [tool.ruff.lint]
184
+ extend-select = [
185
+ "COM", # flake8-commas
186
+ ]
187
+
186
188
  [build-system]
187
189
  requires = ["hatchling"]
188
190
  build-backend = "hatchling.build"
@@ -1,5 +1,4 @@
1
1
  # coding:utf-8
2
- import datetime
3
2
  import itertools
4
3
  import logging
5
4
  import random
@@ -47,19 +46,17 @@ def test_on_predicate_max_tries(monkeypatch):
47
46
 
48
47
  def test_on_predicate_max_time(monkeypatch):
49
48
  nows = [
50
- datetime.datetime(2018, 1, 1, 12, 0, 10, 5),
51
- datetime.datetime(2018, 1, 1, 12, 0, 9, 0),
52
- datetime.datetime(2018, 1, 1, 12, 0, 1, 0),
53
- datetime.datetime(2018, 1, 1, 12, 0, 0, 0),
49
+ 10.000005,
50
+ 9,
51
+ 1,
52
+ 0,
54
53
  ]
55
54
 
56
- class Datetime:
57
- @staticmethod
58
- def now():
59
- return nows.pop()
55
+ def monotonic():
56
+ return nows.pop()
60
57
 
61
58
  monkeypatch.setattr('time.sleep', lambda x: None)
62
- monkeypatch.setattr('datetime.datetime', Datetime)
59
+ monkeypatch.setattr('time.monotonic', monotonic)
63
60
 
64
61
  def giveup(details):
65
62
  assert details['tries'] == 3
@@ -80,19 +77,17 @@ def test_on_predicate_max_time(monkeypatch):
80
77
 
81
78
  def test_on_predicate_max_time_callable(monkeypatch):
82
79
  nows = [
83
- datetime.datetime(2018, 1, 1, 12, 0, 10, 5),
84
- datetime.datetime(2018, 1, 1, 12, 0, 9, 0),
85
- datetime.datetime(2018, 1, 1, 12, 0, 1, 0),
86
- datetime.datetime(2018, 1, 1, 12, 0, 0, 0),
80
+ 10.000005,
81
+ 9,
82
+ 1,
83
+ 0,
87
84
  ]
88
85
 
89
- class Datetime:
90
- @staticmethod
91
- def now():
92
- return nows.pop()
86
+ def monotonic():
87
+ return nows.pop()
93
88
 
94
89
  monkeypatch.setattr('time.sleep', lambda x: None)
95
- monkeypatch.setattr('datetime.datetime', Datetime)
90
+ monkeypatch.setattr('time.monotonic', monotonic)
96
91
 
97
92
  def giveup(details):
98
93
  assert details['tries'] == 3
@@ -502,7 +497,6 @@ def test_on_predicate_iterable_handlers():
502
497
  assert len(logger.giveups) == 1
503
498
 
504
499
  details = dict(logger.giveups[0])
505
- print(details)
506
500
  elapsed = details.pop('elapsed')
507
501
  assert isinstance(elapsed, float)
508
502
  assert details == {'args': (1, 2, 3),
@@ -591,7 +585,6 @@ def test_on_predicate_success_0_arg_jitter(monkeypatch):
591
585
 
592
586
  for i in range(2):
593
587
  details = backoffs[i]
594
- print(details)
595
588
  elapsed = details.pop('elapsed')
596
589
  assert isinstance(elapsed, float)
597
590
  assert details == {'args': (1, 2, 3),
@@ -847,7 +840,7 @@ def test_on_exception_logger_user_str(monkeypatch, caplog):
847
840
 
848
841
 
849
842
  def _on_exception_factory(
850
- backoff_log_level, giveup_log_level, max_tries
843
+ backoff_log_level, giveup_log_level, max_tries,
851
844
  ):
852
845
  @backoff.on_exception(
853
846
  backoff.expo,
@@ -867,7 +860,7 @@ def _on_exception_factory(
867
860
 
868
861
 
869
862
  def _on_predicate_factory(
870
- backoff_log_level, giveup_log_level, max_tries
863
+ backoff_log_level, giveup_log_level, max_tries,
871
864
  ):
872
865
  @backoff.on_predicate(
873
866
  backoff.expo,
@@ -896,17 +889,17 @@ def _on_predicate_factory(
896
889
  repeat=2,
897
890
  )
898
891
  for factory in (_on_predicate_factory, _on_exception_factory)
899
- )
892
+ ),
900
893
  )
901
894
  def test_event_log_levels(
902
- caplog, func_factory, backoff_log_level, giveup_log_level
895
+ caplog, func_factory, backoff_log_level, giveup_log_level,
903
896
  ):
904
897
  max_tries = 3
905
898
  func = func_factory(backoff_log_level, giveup_log_level, max_tries)
906
899
 
907
900
  with unittest.mock.patch('time.sleep', return_value=None):
908
901
  with caplog.at_level(
909
- min(backoff_log_level, giveup_log_level), logger="backoff"
902
+ min(backoff_log_level, giveup_log_level), logger="backoff",
910
903
  ):
911
904
  func()
912
905
 
@@ -18,7 +18,7 @@ def foo():
18
18
  backoff.constant,
19
19
  ValueError,
20
20
  interval=1,
21
- max_tries=3
21
+ max_tries=3,
22
22
  )
23
23
  def bar():
24
24
  raise ValueError()
@@ -67,6 +67,14 @@ def test_expo_max_value():
67
67
  assert expect == next(gen)
68
68
 
69
69
 
70
+ def test_expo_max_value_factor():
71
+ gen = backoff.expo(factor=3, max_value=2 ** 4)
72
+ gen.send(None)
73
+ expected = [3 * 1, 3 * 2, 3 * 4, 16, 16, 16, 16]
74
+ for expect in expected:
75
+ assert expect == next(gen)
76
+
77
+
70
78
  def test_fibo():
71
79
  gen = backoff.fibo()
72
80
  gen.send(None)
@@ -1,15 +0,0 @@
1
- __pycache__/
2
- *.pyc
3
- .coverage
4
- virtualenv
5
- MANIFEST
6
- build/
7
- dist/
8
- .cache/
9
- *.egg-info
10
- .vscode
11
- .tox/
12
- coverage.xml
13
-
14
- # mkdocs
15
- site/