Skip to content

Commit 8762dda

Browse files
authored
add waiters (#3)
1 parent 3ee87d7 commit 8762dda

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

pytest_test_utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from . import matchers
1+
from . import matchers, waiters
22
from .tmp_dir import TmpDir
33
from .tmp_dir_factory import TempDirFactory
44

55
__all__ = [
66
"matchers",
7+
"waiters",
78
"TmpDir",
89
"TempDirFactory",
910
]

pytest_test_utils/matchers.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
Optional,
1111
Pattern,
1212
Tuple,
13-
Type,
1413
Union,
1514
)
1615

@@ -124,7 +123,7 @@ def __eq__(self, other: object) -> bool:
124123
class instance_of:
125124
def __init__(
126125
self,
127-
expected_type: Union[Type[object], Tuple[Type[object], ...]],
126+
expected_type: Union[Any, Tuple[Any, ...]],
128127
) -> None:
129128
self.expected_type = expected_type
130129

@@ -198,9 +197,7 @@ def any_of(*items: Any) -> any_of:
198197
return any_of(*items)
199198

200199
@staticmethod
201-
def instance_of(
202-
expected_type: Union[Type[object], Tuple[Type[object], ...]]
203-
) -> instance_of:
200+
def instance_of(expected_type: Union[Any, Tuple[Any, ...]]) -> instance_of:
204201
return instance_of(expected_type)
205202

206203
@staticmethod

pytest_test_utils/waiters.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from time import perf_counter, sleep
2+
from typing import Callable, TypeVar
3+
4+
_T = TypeVar("_T")
5+
6+
7+
class TimedOutError(Exception):
8+
pass
9+
10+
11+
def wait_until(pred: Callable[[], _T], timeout: float, pause: float = 1) -> _T:
12+
start = perf_counter()
13+
while (perf_counter() - start) < timeout:
14+
value = pred()
15+
if value:
16+
return value
17+
sleep(pause)
18+
raise TimedOutError("Timeout reached while waiting")

tests.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import os
22
from datetime import datetime, timedelta
33
from pathlib import Path
4+
from time import perf_counter
45
from types import SimpleNamespace
56
from typing import TYPE_CHECKING, Type
7+
from unittest.mock import MagicMock
68

79
import pytest
810

911
from pytest_test_utils import TmpDir, matchers
1012
from pytest_test_utils.matchers import Matcher
1113
from pytest_test_utils.tmp_dir_factory import TempDirFactory
14+
from pytest_test_utils.waiters import TimedOutError, wait_until
1215

1316
if TYPE_CHECKING:
1417
from pytest import TempPathFactory
@@ -266,3 +269,24 @@ def test_matcher_alias( # pylint: disable=invalid-name
266269
M: Type[Matcher], matcher: Type[Matcher]
267270
) -> None:
268271
assert matcher is M is Matcher
272+
273+
274+
def test_wait_until() -> None:
275+
pred = MagicMock(side_effect=[False, False, True])
276+
277+
start = perf_counter()
278+
assert wait_until(pred, 0.01, pause=0.0001)
279+
assert perf_counter() == pytest.approx(start + 0.0002, rel=1e-3)
280+
assert len(pred.call_args_list) == 3
281+
282+
283+
def test_wait_until_raises_timedouterror() -> None:
284+
pred = MagicMock(return_value=False)
285+
286+
start = perf_counter()
287+
288+
with pytest.raises(TimedOutError):
289+
wait_until(pred, 0.01, pause=0.0001)
290+
291+
assert perf_counter() == pytest.approx(start + 0.01, rel=1e-3)
292+
assert len(pred.call_args_list) > 1

0 commit comments

Comments
 (0)