2121from . 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)
2537def 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