Skip to content

Commit 74184c3

Browse files
Reject non-finite polling timing configuration
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent ccfaed7 commit 74184c3

File tree

2 files changed

+47
-18
lines changed

2 files changed

+47
-18
lines changed

hyperbrowser/client/polling.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import math
23
from numbers import Real
34
import time
45
from typing import Awaitable, Callable, Optional, TypeVar
@@ -12,6 +13,15 @@
1213
T = TypeVar("T")
1314

1415

16+
def _validate_non_negative_real(value: float, *, field_name: str) -> None:
17+
if isinstance(value, bool) or not isinstance(value, Real):
18+
raise HyperbrowserError(f"{field_name} must be a number")
19+
if not math.isfinite(float(value)):
20+
raise HyperbrowserError(f"{field_name} must be finite")
21+
if value < 0:
22+
raise HyperbrowserError(f"{field_name} must be non-negative")
23+
24+
1525
def _validate_operation_name(operation_name: str) -> None:
1626
if not isinstance(operation_name, str):
1727
raise HyperbrowserError("operation_name must be a string")
@@ -29,12 +39,7 @@ def _validate_retry_config(
2939
raise HyperbrowserError("max_attempts must be an integer")
3040
if max_attempts < 1:
3141
raise HyperbrowserError("max_attempts must be at least 1")
32-
if isinstance(retry_delay_seconds, bool) or not isinstance(
33-
retry_delay_seconds, Real
34-
):
35-
raise HyperbrowserError("retry_delay_seconds must be a number")
36-
if retry_delay_seconds < 0:
37-
raise HyperbrowserError("retry_delay_seconds must be non-negative")
42+
_validate_non_negative_real(retry_delay_seconds, field_name="retry_delay_seconds")
3843
if max_status_failures is not None:
3944
if isinstance(max_status_failures, bool) or not isinstance(
4045
max_status_failures, int
@@ -45,21 +50,15 @@ def _validate_retry_config(
4550

4651

4752
def _validate_poll_interval(poll_interval_seconds: float) -> None:
48-
if isinstance(poll_interval_seconds, bool) or not isinstance(
49-
poll_interval_seconds, Real
50-
):
51-
raise HyperbrowserError("poll_interval_seconds must be a number")
52-
if poll_interval_seconds < 0:
53-
raise HyperbrowserError("poll_interval_seconds must be non-negative")
53+
_validate_non_negative_real(
54+
poll_interval_seconds, field_name="poll_interval_seconds"
55+
)
5456

5557

5658
def _validate_max_wait_seconds(max_wait_seconds: Optional[float]) -> None:
57-
if max_wait_seconds is not None and (
58-
isinstance(max_wait_seconds, bool) or not isinstance(max_wait_seconds, Real)
59-
):
60-
raise HyperbrowserError("max_wait_seconds must be a number")
61-
if max_wait_seconds is not None and max_wait_seconds < 0:
62-
raise HyperbrowserError("max_wait_seconds must be non-negative")
59+
if max_wait_seconds is None:
60+
return
61+
_validate_non_negative_real(max_wait_seconds, field_name="max_wait_seconds")
6362

6463

6564
def _validate_page_batch_values(

tests/test_polling.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import math
23

34
import pytest
45

@@ -755,6 +756,35 @@ def test_polling_helpers_validate_retry_and_interval_configuration():
755756
retry_delay_seconds=0.0,
756757
)
757758

759+
with pytest.raises(HyperbrowserError, match="retry_delay_seconds must be finite"):
760+
retry_operation(
761+
operation_name="invalid-retry-delay-finite",
762+
operation=lambda: "ok",
763+
max_attempts=1,
764+
retry_delay_seconds=math.inf,
765+
)
766+
767+
with pytest.raises(HyperbrowserError, match="poll_interval_seconds must be finite"):
768+
poll_until_terminal_status(
769+
operation_name="invalid-poll-interval-finite",
770+
get_status=lambda: "completed",
771+
is_terminal_status=lambda value: value == "completed",
772+
poll_interval_seconds=math.nan,
773+
max_wait_seconds=1.0,
774+
)
775+
776+
with pytest.raises(HyperbrowserError, match="max_wait_seconds must be finite"):
777+
collect_paginated_results(
778+
operation_name="invalid-max-wait-finite",
779+
get_next_page=lambda page: {"current": 1, "total": 1, "items": []},
780+
get_current_page_batch=lambda response: response["current"],
781+
get_total_page_batches=lambda response: response["total"],
782+
on_page_success=lambda response: None,
783+
max_wait_seconds=math.inf,
784+
max_attempts=1,
785+
retry_delay_seconds=0.0,
786+
)
787+
758788
async def validate_async_operation_name() -> None:
759789
with pytest.raises(HyperbrowserError, match="operation_name must not be empty"):
760790
await poll_until_terminal_status_async(

0 commit comments

Comments
 (0)