Skip to content

Commit

Permalink
timeout functions now raise ValueError on NaN inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
jakkdl committed Jun 23, 2023
1 parent 493c915 commit 0c5f45e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
36 changes: 26 additions & 10 deletions trio/_tests/test_timeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ async def sleep_2():

await check_takes_about(sleep_2, TARGET)

with pytest.raises(ValueError):
await sleep(-1)

with assert_checkpoints():
await sleep(0)
# This also serves as a test of the trivial move_on_at
Expand All @@ -66,10 +63,6 @@ async def sleep_2():

@slow
async def test_move_on_after():
with pytest.raises(ValueError):
with move_on_after(-1):
pass # pragma: no cover

async def sleep_3():
with move_on_after(TARGET):
await sleep(100)
Expand Down Expand Up @@ -99,6 +92,29 @@ async def sleep_5():
with fail_after(100):
await sleep(0)

with pytest.raises(ValueError):
with fail_after(-1):
pass # pragma: no cover

async def test_timeout_value_error():
# deadlines are allowed to be negative, but not delays.
# neither delays nor deadlines are allowed to be NaN

nan = float("nan")

for fun, val in (
(sleep, -1),
(sleep, nan),
(sleep_until, nan),
):
with pytest.raises(ValueError):
await fun(val)

for cm, val in (
(fail_after, -1),
(fail_after, nan),
(fail_at, nan),
(move_on_after, -1),
(move_on_after, nan),
(move_on_at, nan),
):
with pytest.raises(ValueError):
with cm(val):
pass # pragma: no cover
23 changes: 19 additions & 4 deletions trio/_timeouts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import math
from contextlib import contextmanager

import trio
Expand All @@ -10,7 +11,12 @@ def move_on_at(deadline):
Args:
deadline (float): The deadline.
Raises:
ValueError: if deadline is NaN.
"""
if math.isnan(deadline):
raise ValueError("deadline must not be NaN")
return trio.CancelScope(deadline=deadline)


Expand All @@ -22,10 +28,9 @@ def move_on_after(seconds):
seconds (float): The timeout.
Raises:
ValueError: if timeout is less than zero.
ValueError: if timeout is less than zero or NaN.
"""

if seconds < 0:
raise ValueError("timeout must be non-negative")
return move_on_at(trio.current_time() + seconds)
Expand All @@ -52,6 +57,9 @@ async def sleep_until(deadline):
the past, in which case this function executes a checkpoint but
does not block.
Raises:
ValueError: if deadline is NaN.
"""
with move_on_at(deadline):
await sleep_forever()
Expand All @@ -65,7 +73,7 @@ async def sleep(seconds):
insert a checkpoint without actually blocking.
Raises:
ValueError: if *seconds* is negative.
ValueError: if *seconds* is negative or NaN.
"""
if seconds < 0:
Expand Down Expand Up @@ -96,9 +104,13 @@ def fail_at(deadline):
:func:`fail_at`, then it's caught and :exc:`TooSlowError` is raised in its
place.
Args:
deadline (float): The deadline.
Raises:
TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
and caught by the context manager.
ValueError: if deadline is NaN.
"""

Expand All @@ -119,10 +131,13 @@ def fail_after(seconds):
it's caught and discarded. When it reaches :func:`fail_after`, then it's
caught and :exc:`TooSlowError` is raised in its place.
Args:
seconds (float): The timeout.
Raises:
TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
and caught by the context manager.
ValueError: if *seconds* is less than zero.
ValueError: if *seconds* is less than zero or NaN.
"""
if seconds < 0:
Expand Down

0 comments on commit 0c5f45e

Please sign in to comment.