|
20 | 20 | from .coroutines import coroutine |
21 | 21 |
|
22 | 22 |
|
| 23 | +def current_task(loop=None): |
| 24 | + """Return a currently executed task.""" |
| 25 | + if loop is None: |
| 26 | + loop = events.get_running_loop() |
| 27 | + return _current_tasks.get(loop) |
| 28 | + |
| 29 | + |
| 30 | +def all_tasks(loop=None): |
| 31 | + """Return a set of all tasks for the loop.""" |
| 32 | + if loop is None: |
| 33 | + loop = events.get_running_loop() |
| 34 | + return {t for t in _all_tasks |
| 35 | + if futures._get_loop(t) is loop and not t.done()} |
| 36 | + |
| 37 | + |
| 38 | +def _all_tasks_compat(loop=None): |
| 39 | + # Different from "all_task()" by returning *all* Tasks, including |
| 40 | + # the completed ones. Used to implement deprecated "Tasks.all_task()" |
| 41 | + # method. |
| 42 | + if loop is None: |
| 43 | + loop = events.get_event_loop() |
| 44 | + return {t for t in _all_tasks if futures._get_loop(t) is loop} |
| 45 | + |
| 46 | + |
23 | 47 | class Task(futures.Future): |
24 | 48 | """A coroutine wrapped in a Future.""" |
25 | 49 |
|
@@ -707,3 +731,56 @@ def callback(): |
707 | 731 |
|
708 | 732 | loop.call_soon_threadsafe(callback) |
709 | 733 | return future |
| 734 | + |
| 735 | + |
| 736 | +# WeakSet containing all alive tasks. |
| 737 | +_all_tasks = weakref.WeakSet() |
| 738 | + |
| 739 | +# Dictionary containing tasks that are currently active in |
| 740 | +# all running event loops. {EventLoop: Task} |
| 741 | +_current_tasks = {} |
| 742 | + |
| 743 | + |
| 744 | +def _register_task(task): |
| 745 | + """Register a new task in asyncio as executed by loop.""" |
| 746 | + _all_tasks.add(task) |
| 747 | + |
| 748 | + |
| 749 | +def _enter_task(loop, task): |
| 750 | + current_task = _current_tasks.get(loop) |
| 751 | + if current_task is not None: |
| 752 | + raise RuntimeError(f"Cannot enter into task {task!r} while another " |
| 753 | + f"task {current_task!r} is being executed.") |
| 754 | + _current_tasks[loop] = task |
| 755 | + |
| 756 | + |
| 757 | +def _leave_task(loop, task): |
| 758 | + current_task = _current_tasks.get(loop) |
| 759 | + if current_task is not task: |
| 760 | + raise RuntimeError(f"Leaving task {task!r} does not match " |
| 761 | + f"the current task {current_task!r}.") |
| 762 | + del _current_tasks[loop] |
| 763 | + |
| 764 | + |
| 765 | +def _unregister_task(task): |
| 766 | + """Unregister a task.""" |
| 767 | + _all_tasks.discard(task) |
| 768 | + |
| 769 | + |
| 770 | +_py_register_task = _register_task |
| 771 | +_py_unregister_task = _unregister_task |
| 772 | +_py_enter_task = _enter_task |
| 773 | +_py_leave_task = _leave_task |
| 774 | + |
| 775 | + |
| 776 | +try: |
| 777 | + from _asyncio import (_register_task, _unregister_task, |
| 778 | + _enter_task, _leave_task, |
| 779 | + _all_tasks, _current_tasks) |
| 780 | +except ImportError: |
| 781 | + pass |
| 782 | +else: |
| 783 | + _c_register_task = _register_task |
| 784 | + _c_unregister_task = _unregister_task |
| 785 | + _c_enter_task = _enter_task |
| 786 | + _c_leave_task = _leave_task |
0 commit comments