Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/anyio/_core/_futures.py: 38%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import annotations
3from collections.abc import Generator
4from enum import Enum, auto
5from typing import Any, Generic, TypeVar
7from ._exceptions import (
8 FutureAlreadyFinished,
9 FutureCancelled,
10 FutureFailed,
11 FutureNotFinished,
12)
13from ._synchronization import Event
15T = TypeVar("T")
18class Future(Generic[T]):
19 """
20 An awaitable object that works similar to a :class:`asyncio.Future` but
21 with similar characteristics to a :class:`.TaskHandle`.
22 """
24 class Status(Enum):
25 """
26 The status of a future handle.
28 .. attribute:: PENDING
30 The future has not finished yet.
31 .. attribute:: FINISHED
33 The future has finished with a return value.
34 .. attribute:: CANCELLED
36 The future was cancelled and has finished since.
37 .. attribute:: FAILED
39 The future raised an exception.
40 """
42 PENDING = auto()
43 FINISHED = auto()
44 CANCELLED = auto()
45 FAILED = auto()
47 __slots__ = (
48 "_cancelled",
49 "_exception",
50 "_finished_event",
51 "_name",
52 "_return_value",
53 )
54 _return_value: T
56 def __init__(self, *, name: str | None = None) -> None:
57 self._finished_event = Event()
58 self._exception: BaseException | None = None
59 self._cancelled: bool = False
60 self._name = name
62 def _check_pending(self) -> None:
63 """Shortcut for checking if a Future is pending
65 :raises FutureAlreadyFinished: if future was already given a result or exception.
66 :raises FutureCancelled: if future has been cancelled previously.
67 """
68 match self.status:
69 case Future.Status.PENDING:
70 return
71 case Future.Status.FINISHED:
72 raise FutureAlreadyFinished("future has already finished")
73 case Future.Status.FAILED:
74 raise FutureAlreadyFinished("future already failed")
75 case Future.Status.CANCELLED:
76 raise FutureCancelled("future was cancelled")
78 async def wait(self) -> None:
79 """
80 Waits for the future to finish.
82 This method will attempt to wait for a result or exception
83 """
84 await self._finished_event.wait()
86 def cancel(self) -> None:
87 """Cancels a pending `.Future` object
89 Does nothing if the Future was already finished.
90 """
91 if self.status is Future.Status.PENDING:
92 self._cancelled = True
93 self._finished_event.set()
95 @property
96 def exception(self) -> BaseException | None:
97 """
98 The exception value of a `.Future`
100 :raises FutureNotFinished: if future is still pending
101 :raises FutureCancelled: if future was cancelled
102 :returns: None if future succeeds with a result sent instead
103 otherwise this will be an exception
104 """
106 match self.status:
107 case Future.Status.PENDING:
108 raise FutureNotFinished("the future has not finished yet")
109 case Future.Status.FINISHED:
110 return None
111 case Future.Status.CANCELLED:
112 raise FutureCancelled("the future was cancelled")
113 case Future.Status.FAILED:
114 return self._exception
116 @exception.setter
117 def exception(self, exception: BaseException) -> None:
118 """Send exception for a `.Future` object
120 :raises FutureAlreadyFinished: if future was already given a result or exception.
121 :raises FutureCancelled: if future has been cancelled previously.
122 """
123 self._check_pending()
124 self._exception = exception
125 self._finished_event.set()
127 @property
128 def return_value(self) -> T:
129 """
130 The return value of the future.
132 :raises FutureNotFinished: if the future has not finished yet
133 :raises FutureCancelled: if the future was cancelled
134 :raises FutureFailed: if the future raised an exception
136 """
137 match self.status:
138 case Future.Status.PENDING:
139 raise FutureNotFinished("the future has not finished yet")
140 case Future.Status.FINISHED:
141 return self._return_value
142 case Future.Status.CANCELLED:
143 raise FutureCancelled("the future was cancelled")
144 case Future.Status.FAILED:
145 raise FutureFailed(
146 "the future raised an exception"
147 ) from self._exception
149 @return_value.setter
150 def return_value(self, value: T) -> None:
151 """
152 Send pending result for a `.Future` object
154 :raises FutureAlreadyFinished: if future was already given a result or exception.
155 :raises FutureCancelled: if future has been cancelled previously.
156 """
157 self._check_pending()
158 self._return_value = value
159 self._finished_event.set()
161 @property
162 def status(self) -> Future.Status:
163 """
164 The current status of a future.
166 Every future starts in the :attr:`~Future.Status.PENDING` state.
167 If a future is cancelled while in this state, it will transition to the
168 :attr:`Future.Status.CANCELLED` state. When the task finishes, it will
169 transition to one of the three final states (
170 :attr:`Future.Status.FINISHED`, :attr:`Future.Status.FAILED`, or
171 :attr:`Future.Status.CANCELLED`) depending on the exception the task
172 raised, if any. No other status transitions will happen.
173 """
174 if not self._finished_event.is_set():
175 return Future.Status.PENDING
176 elif self._cancelled:
177 return Future.Status.CANCELLED
178 elif self._exception is not None:
179 return Future.Status.FAILED
180 else:
181 return Future.Status.FINISHED
183 def __await__(self) -> Generator[Any, Any, T]:
184 yield from self.wait().__await__()
185 return self.return_value
187 def __repr__(self) -> str:
188 return (
189 f"<{self.__class__.__name__} {self.status.name.lower()} "
190 f"name={self._name!r}>"
191 )