|
__all__ = 'run', |
|
|
|
from . import coroutines |
|
from . import events |
|
from . import tasks |
|
|
|
|
|
def run(main, *, debug=None): |
|
"""Execute the coroutine and return the result. |
|
|
|
This function runs the passed coroutine, taking care of |
|
managing the asyncio event loop and finalizing asynchronous |
|
generators. |
|
|
|
This function cannot be called when another asyncio event loop is |
|
running in the same thread. |
|
|
|
If debug is True, the event loop will be run in debug mode. |
|
|
|
This function always creates a new event loop and closes it at the end. |
|
It should be used as a main entry point for asyncio programs, and should |
|
ideally only be called once. |
|
|
|
Example: |
|
|
|
async def main(): |
|
await asyncio.sleep(1) |
|
print('hello') |
|
|
|
asyncio.run(main()) |
|
""" |
|
if events._get_running_loop() is not None: |
|
raise RuntimeError( |
|
"asyncio.run() cannot be called from a running event loop") |
|
|
|
if not coroutines.iscoroutine(main): |
|
raise ValueError("a coroutine was expected, got {!r}".format(main)) |
|
|
|
loop = events.new_event_loop() |
|
try: |
|
events.set_event_loop(loop) |
|
if debug is not None: |
|
loop.set_debug(debug) |
|
return loop.run_until_complete(main) |
|
finally: |
|
try: |
|
_cancel_all_tasks(loop) |
|
loop.run_until_complete(loop.shutdown_asyncgens()) |
|
loop.run_until_complete(loop.shutdown_default_executor()) |
|
finally: |
|
events.set_event_loop(None) |
|
loop.close() |
|
|
|
|
|
def _cancel_all_tasks(loop): |
|
to_cancel = tasks.all_tasks(loop) |
|
if not to_cancel: |
|
return |
|
|
|
for task in to_cancel: |
|
task.cancel() |
|
|
|
loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True)) |
|
|
|
for task in to_cancel: |
|
if task.cancelled(): |
|
continue |
|
if task.exception() is not None: |
|
loop.call_exception_handler({ |
|
'message': 'unhandled exception during asyncio.run() shutdown', |
|
'exception': task.exception(), |
|
'task': task, |
|
}) |
|
|