Wait for a future, shielding it from cancellation. The statement task = asyncio.create_task(something()) res = await shield(task) is exactly equivalent to the statement res = await something() *except* that if the coroutine containing it is cancell
(arg)
| 849 | |
| 850 | |
| 851 | def shield(arg): |
| 852 | """Wait for a future, shielding it from cancellation. |
| 853 | |
| 854 | The statement |
| 855 | |
| 856 | task = asyncio.create_task(something()) |
| 857 | res = await shield(task) |
| 858 | |
| 859 | is exactly equivalent to the statement |
| 860 | |
| 861 | res = await something() |
| 862 | |
| 863 | *except* that if the coroutine containing it is cancelled, the |
| 864 | task running in something() is not cancelled. From the POV of |
| 865 | something(), the cancellation did not happen. But its caller is |
| 866 | still cancelled, so the yield-from expression still raises |
| 867 | CancelledError. Note: If something() is cancelled by other means |
| 868 | this will still cancel shield(). |
| 869 | |
| 870 | If you want to completely ignore cancellation (not recommended) |
| 871 | you can combine shield() with a try/except clause, as follows: |
| 872 | |
| 873 | task = asyncio.create_task(something()) |
| 874 | try: |
| 875 | res = await shield(task) |
| 876 | except CancelledError: |
| 877 | res = None |
| 878 | |
| 879 | Save a reference to tasks passed to this function, to avoid |
| 880 | a task disappearing mid-execution. The event loop only keeps |
| 881 | weak references to tasks. A task that isn't referenced elsewhere |
| 882 | may get garbage collected at any time, even before it's done. |
| 883 | """ |
| 884 | inner = _ensure_future(arg) |
| 885 | if inner.done(): |
| 886 | # Shortcut. |
| 887 | return inner |
| 888 | loop = futures._get_loop(inner) |
| 889 | outer = loop.create_future() |
| 890 | |
| 891 | def _inner_done_callback(inner): |
| 892 | if outer.cancelled(): |
| 893 | if not inner.cancelled(): |
| 894 | # Mark inner's result as retrieved. |
| 895 | inner.exception() |
| 896 | return |
| 897 | |
| 898 | if inner.cancelled(): |
| 899 | outer.cancel() |
| 900 | else: |
| 901 | exc = inner.exception() |
| 902 | if exc is not None: |
| 903 | outer.set_exception(exc) |
| 904 | else: |
| 905 | outer.set_result(inner.result()) |
| 906 | |
| 907 | |
| 908 | def _outer_done_callback(outer): |
nothing calls this directly
no test coverage detected