|
25 | 25 | Awaitable,
|
26 | 26 | Callable,
|
27 | 27 | Collection,
|
| 28 | + Coroutine, |
28 | 29 | Dict,
|
29 | 30 | Generic,
|
30 | 31 | Hashable,
|
@@ -701,27 +702,54 @@ def stop_cancellation(deferred: "defer.Deferred[T]") -> "defer.Deferred[T]":
|
701 | 702 | return new_deferred
|
702 | 703 |
|
703 | 704 |
|
704 |
| -def delay_cancellation(deferred: "defer.Deferred[T]") -> "defer.Deferred[T]": |
705 |
| - """Delay cancellation of a `Deferred` until it resolves. |
| 705 | +@overload |
| 706 | +def delay_cancellation(awaitable: "defer.Deferred[T]") -> "defer.Deferred[T]": |
| 707 | + ... |
| 708 | + |
| 709 | + |
| 710 | +@overload |
| 711 | +def delay_cancellation(awaitable: Coroutine[Any, Any, T]) -> "defer.Deferred[T]": |
| 712 | + ... |
| 713 | + |
| 714 | + |
| 715 | +@overload |
| 716 | +def delay_cancellation(awaitable: Awaitable[T]) -> Awaitable[T]: |
| 717 | + ... |
| 718 | + |
| 719 | + |
| 720 | +def delay_cancellation(awaitable: Awaitable[T]) -> Awaitable[T]: |
| 721 | + """Delay cancellation of a coroutine or `Deferred` awaitable until it resolves. |
706 | 722 |
|
707 | 723 | Has the same effect as `stop_cancellation`, but the returned `Deferred` will not
|
708 |
| - resolve with a `CancelledError` until the original `Deferred` resolves. |
| 724 | + resolve with a `CancelledError` until the original awaitable resolves. |
709 | 725 |
|
710 | 726 | Args:
|
711 |
| - deferred: The `Deferred` to protect against cancellation. May optionally follow |
712 |
| - the Synapse logcontext rules. |
| 727 | + deferred: The coroutine or `Deferred` to protect against cancellation. May |
| 728 | + optionally follow the Synapse logcontext rules. |
713 | 729 |
|
714 | 730 | Returns:
|
715 |
| - A new `Deferred`, which will contain the result of the original `Deferred`. |
716 |
| - The new `Deferred` will not propagate cancellation through to the original. |
717 |
| - When cancelled, the new `Deferred` will wait until the original `Deferred` |
718 |
| - resolves before failing with a `CancelledError`. |
| 731 | + A new `Deferred`, which will contain the result of the original coroutine or |
| 732 | + `Deferred`. The new `Deferred` will not propagate cancellation through to the |
| 733 | + original coroutine or `Deferred`. |
719 | 734 |
|
720 |
| - The new `Deferred` will follow the Synapse logcontext rules if `deferred` |
| 735 | + When cancelled, the new `Deferred` will wait until the original coroutine or |
| 736 | + `Deferred` resolves before failing with a `CancelledError`. |
| 737 | +
|
| 738 | + The new `Deferred` will follow the Synapse logcontext rules if `awaitable` |
721 | 739 | follows the Synapse logcontext rules. Otherwise the new `Deferred` should be
|
722 | 740 | wrapped with `make_deferred_yieldable`.
|
723 | 741 | """
|
724 | 742 |
|
| 743 | + # First, convert the awaitable into a `Deferred`. |
| 744 | + if isinstance(awaitable, defer.Deferred): |
| 745 | + deferred = awaitable |
| 746 | + elif isinstance(awaitable, Coroutine): |
| 747 | + deferred = defer.ensureDeferred(awaitable) |
| 748 | + else: |
| 749 | + # We have no idea what to do with this awaitable. |
| 750 | + # Let the caller `await` it normally. |
| 751 | + return awaitable |
| 752 | + |
725 | 753 | def handle_cancel(new_deferred: "defer.Deferred[T]") -> None:
|
726 | 754 | # before the new deferred is cancelled, we `pause` it to stop the cancellation
|
727 | 755 | # propagating. we then `unpause` it once the wrapped deferred completes, to
|
|
0 commit comments