1 27
from contextlib import contextmanager
2

3 27
import trio
4

5

6 27
def move_on_at(deadline):
7
    """Use as a context manager to create a cancel scope with the given
8
    absolute deadline.
9

10
    Args:
11
      deadline (float): The deadline.
12

13
    """
14 27
    return trio.CancelScope(deadline=deadline)
15

16

17 27
def move_on_after(seconds):
18
    """Use as a context manager to create a cancel scope whose deadline is
19
    set to now + *seconds*.
20

21
    Args:
22
      seconds (float): The timeout.
23

24
    Raises:
25
      ValueError: if timeout is less than zero.
26

27
    """
28

29 27
    if seconds < 0:
30 27
        raise ValueError("timeout must be non-negative")
31 27
    return move_on_at(trio.current_time() + seconds)
32

33

34 27
async def sleep_forever():
35
    """Pause execution of the current task forever (or until cancelled).
36

37
    Equivalent to calling ``await sleep(math.inf)``.
38

39
    """
40 27
    await trio.lowlevel.wait_task_rescheduled(lambda _: trio.lowlevel.Abort.SUCCEEDED)
41

42

43 27
async def sleep_until(deadline):
44
    """Pause execution of the current task until the given time.
45

46
    The difference between :func:`sleep` and :func:`sleep_until` is that the
47
    former takes a relative time and the latter takes an absolute time.
48

49
    Args:
50
        deadline (float): The time at which we should wake up again. May be in
51
            the past, in which case this function executes a checkpoint but
52
            does not block.
53

54
    """
55 27
    with move_on_at(deadline):
56 27
        await sleep_forever()
57

58

59 27
async def sleep(seconds):
60
    """Pause execution of the current task for the given number of seconds.
61

62
    Args:
63
        seconds (float): The number of seconds to sleep. May be zero to
64
            insert a checkpoint without actually blocking.
65

66
    Raises:
67
        ValueError: if *seconds* is negative.
68

69
    """
70 27
    if seconds < 0:
71 27
        raise ValueError("duration must be non-negative")
72 27
    if seconds == 0:
73 27
        await trio.lowlevel.checkpoint()
74
    else:
75 27
        await sleep_until(trio.current_time() + seconds)
76

77

78 27
class TooSlowError(Exception):
79
    """Raised by :func:`fail_after` and :func:`fail_at` if the timeout
80
    expires.
81

82
    """
83

84

85 27
@contextmanager
86 13
def fail_at(deadline):
87
    """Creates a cancel scope with the given deadline, and raises an error if it
88
    is actually cancelled.
89

90
    This function and :func:`move_on_at` are similar in that both create a
91
    cancel scope with a given absolute deadline, and if the deadline expires
92
    then both will cause :exc:`Cancelled` to be raised within the scope. The
93
    difference is that when the :exc:`Cancelled` exception reaches
94
    :func:`move_on_at`, it's caught and discarded. When it reaches
95
    :func:`fail_at`, then it's caught and :exc:`TooSlowError` is raised in its
96
    place.
97

98
    Raises:
99
      TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
100
        and caught by the context manager.
101

102
    """
103

104 27
    with move_on_at(deadline) as scope:
105 27
        yield scope
106 27
    if scope.cancelled_caught:
107 27
        raise TooSlowError
108

109

110 27
def fail_after(seconds):
111
    """Creates a cancel scope with the given timeout, and raises an error if
112
    it is actually cancelled.
113

114
    This function and :func:`move_on_after` are similar in that both create a
115
    cancel scope with a given timeout, and if the timeout expires then both
116
    will cause :exc:`Cancelled` to be raised within the scope. The difference
117
    is that when the :exc:`Cancelled` exception reaches :func:`move_on_after`,
118
    it's caught and discarded. When it reaches :func:`fail_after`, then it's
119
    caught and :exc:`TooSlowError` is raised in its place.
120

121
    Raises:
122
      TooSlowError: if a :exc:`Cancelled` exception is raised in this scope
123
        and caught by the context manager.
124
      ValueError: if *seconds* is less than zero.
125

126
    """
127 27
    if seconds < 0:
128 27
        raise ValueError("timeout must be non-negative")
129 27
    return fail_at(trio.current_time() + seconds)

Read our documentation on viewing source code .

Loading