Skip to content

Commit 74a0033

Browse files
committed
feat: support task methods for exception and result
1 parent c277db5 commit 74a0033

File tree

2 files changed

+96
-10
lines changed

2 files changed

+96
-10
lines changed

asyncio/core.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,15 @@
2020

2121
# Import TaskQueue and Task, preferring built-in C code over Python code
2222
try:
23-
from _asyncio import TaskQueue, Task
23+
from _asyncio import TaskQueue, Task, CancelledError, InvalidStateError
2424
except:
25-
from .task import TaskQueue, Task
25+
from .task import TaskQueue, Task, CancelledError, InvalidStateError
2626

2727

2828
################################################################################
2929
# Exceptions
3030

3131

32-
class CancelledError(BaseException):
33-
"""Injected into a task when calling `Task.cancel()`"""
34-
35-
pass
36-
37-
3832
class TimeoutError(Exception):
3933
"""Raised when waiting for a task longer than the specified timeout."""
4034

asyncio/task.py

+94-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@
2121
from . import core
2222

2323

24+
class CancelledError(BaseException):
25+
"""Injected into a task when calling `Task.cancel()`"""
26+
27+
pass
28+
29+
30+
class InvalidStateError(Exception):
31+
"""Can be raised in situations like setting a result value for a task object that already has a result value set."""
32+
33+
pass
34+
35+
2436
# pairing-heap meld of 2 heaps; O(1)
2537
def ph_meld(h1, h2):
2638
if h1 is None:
@@ -188,7 +200,7 @@ def done(self):
188200

189201
return not self.state
190202

191-
def cancel(self):
203+
def cancel(self, msg=None):
192204
"""Cancel the task by injecting a ``CancelledError`` into it. The task
193205
may or may not ignore this exception.
194206
"""
@@ -211,5 +223,85 @@ def cancel(self):
211223
# On the main running queue but scheduled in the future, so bring it forward to now.
212224
core._task_queue.remove(self)
213225
core._task_queue.push(self)
214-
self.data = core.CancelledError
226+
self.data = CancelledError(msg) if msg else CancelledError()
215227
return True
228+
229+
def get_coro(self):
230+
return self.coro
231+
232+
def add_done_callback(self, callback):
233+
raise NotImplementedError()
234+
235+
def remove_done_callback(self, callback):
236+
raise NotImplementedError()
237+
238+
def set_result(self, result):
239+
raise RuntimeError('Task does not support set_result operation')
240+
241+
def result(self):
242+
"""
243+
Return the result of the Task.
244+
245+
If the Task is done, the result of the wrapped coroutine is returned (or if the coroutine raised an exception, that exception is re-raised.)
246+
247+
If the Task has been cancelled, this method raises a CancelledError exception.
248+
249+
If the Task’s result isn’t yet available, this method raises a InvalidStateError exception.
250+
251+
"""
252+
if not self.done():
253+
raise InvalidStateError()
254+
255+
exception = self.exception()
256+
257+
if exception is not None:
258+
raise exception
259+
260+
if not isinstance(self.data, StopIteration):
261+
# If this isn't the case then we're in an odd state.
262+
return None
263+
264+
return self.data.value
265+
266+
def set_exception(self, exception):
267+
raise RuntimeError('Task does not support set_exception operation')
268+
269+
def exception(self):
270+
"""
271+
Return the exception that was set on this Task.
272+
273+
The exception (or None if no exception was set) is returned only if the Task is done.
274+
275+
If the Task has been cancelled, this method raises a CancelledError exception.
276+
277+
If the Task isn’t done yet, this method raises an InvalidStateError exception.
278+
"""
279+
if not self.done():
280+
raise InvalidStateError()
281+
282+
if isinstance(self.data, core.CancelledError):
283+
raise self.data
284+
285+
if isinstance(self.data, StopIteration):
286+
# If the data is a stop iteration we can assume this
287+
# was a successful run rather than any possible exception
288+
return None
289+
290+
if not isinstance(self.data, BaseException):
291+
# If the data is not any type of exception we can treat it as
292+
# something else we don't understand but not an exception.
293+
return None
294+
295+
return self.data
296+
297+
def cancelled(self) -> bool:
298+
"""
299+
Return True if the Task is cancelled.
300+
301+
The Task is cancelled when the cancellation was requested with cancel() and
302+
the wrapped coroutine propagated the CancelledError exception thrown into it.
303+
"""
304+
if not self.done():
305+
return False
306+
307+
return isinstance(self.data, core.CancelledError)

0 commit comments

Comments
 (0)