Skip to content

Commit 036642e

Browse files
categulariotony
authored andcommitted
Add retry_until() to take a callable and enforce the timeout
1 parent 8fd0cee commit 036642e

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

libtmux/test.py

+49
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
import tempfile
66
import time
77

8+
from .exc import WaitTimeout
9+
810
logger = logging.getLogger(__name__)
911

1012
TEST_SESSION_PREFIX = "libtmux_"
1113
RETRY_TIMEOUT_SECONDS = int(os.getenv("RETRY_TIMEOUT_SECONDS", 8))
14+
RETRY_INTERVAL_SECONDS = float(os.getenv("RETRY_INTERVAL_SECONDS", 0.05))
1215

1316
namer = tempfile._RandomNameSequence()
1417
current_dir = os.path.abspath(os.path.dirname(__file__))
@@ -43,6 +46,52 @@ def retry(seconds=RETRY_TIMEOUT_SECONDS):
4346
return (lambda: time.time() < time.time() + seconds)()
4447

4548

49+
def retry_until(
50+
fun,
51+
seconds=RETRY_TIMEOUT_SECONDS,
52+
*,
53+
interval=RETRY_INTERVAL_SECONDS,
54+
raises=True,
55+
):
56+
"""
57+
Retry a function until a condition meets or the specified time passes.
58+
59+
Parameters
60+
----------
61+
fun : callable
62+
A function that will be called repeatedly until it returns ``True`` or
63+
the specified time passes.
64+
seconds : int
65+
Seconds to retry. Defaults to ``8``, which is configurable via
66+
``RETRY_TIMEOUT_SECONDS`` environment variables.
67+
interval : float
68+
Time in seconds to wait between calls. Defaults to ``0.05`` and is
69+
configurable via ``RETRY_INTERVAL_SECONDS`` environment variable.
70+
raises : bool
71+
Wether or not to raise an exception on timeout. Defaults to ``True``.
72+
73+
Examples
74+
--------
75+
76+
>>> def f():
77+
... p = w.attached_pane
78+
... p.server._update_panes()
79+
... return p.current_path == pane_path
80+
...
81+
... retry(f)
82+
"""
83+
ini = time.time()
84+
85+
while not fun():
86+
end = time.time()
87+
if end - ini >= seconds:
88+
if raises:
89+
raise WaitTimeout()
90+
else:
91+
break
92+
time.sleep(interval)
93+
94+
4695
def get_test_session_name(server, prefix=TEST_SESSION_PREFIX):
4796
"""
4897
Faker to create a session name that doesn't exist.

tests/test_test.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from time import time
2+
3+
import pytest
4+
5+
from libtmux.test import WaitTimeout, retry_until
6+
7+
8+
def test_retry_three_times():
9+
ini = time()
10+
value = 0
11+
12+
def call_me_three_times():
13+
nonlocal value
14+
15+
if value == 2:
16+
return True
17+
18+
value += 1
19+
20+
return False
21+
22+
retry_until(call_me_three_times, 1)
23+
24+
end = time()
25+
26+
assert abs((end - ini) - 0.1) < 0.01
27+
28+
29+
def test_function_times_out():
30+
ini = time()
31+
32+
def never_true():
33+
return False
34+
35+
with pytest.raises(WaitTimeout):
36+
retry_until(never_true, 1)
37+
38+
end = time()
39+
40+
assert abs((end - ini) - 1.0) < 0.01
41+
42+
43+
def test_function_times_out_no_rise():
44+
ini = time()
45+
46+
def never_true():
47+
return False
48+
49+
retry_until(never_true, 1, raises=False)
50+
51+
end = time()
52+
53+
assert abs((end - ini) - 1.0) < 0.01

0 commit comments

Comments
 (0)