# `async` / `await` ## Basic ```py async def retrieve() -> int: return 42 async def main(): result = await retrieve() reveal_type(result) # revealed: int ``` ## Generic `async` functions ```py from typing import TypeVar T = TypeVar("T") async def persist(x: T) -> T: return x async def f(x: int): result = await persist(x) reveal_type(result) # revealed: int ``` ## Use cases ### `Future` ```py import asyncio import concurrent.futures def blocking_function() -> int: return 42 async def main(): loop = asyncio.get_event_loop() with concurrent.futures.ThreadPoolExecutor() as pool: result = await loop.run_in_executor(pool, blocking_function) # TODO: should be `int` reveal_type(result) # revealed: Unknown ``` ### `asyncio.Task` ```py import asyncio async def f() -> int: return 1 async def main(): task = asyncio.create_task(f()) result = await task # TODO: this should be `int` reveal_type(result) # revealed: Unknown ``` ### `asyncio.gather` ```py import asyncio async def task(name: str) -> int: return len(name) async def main(): (a, b) = await asyncio.gather( task("A"), task("B"), ) # TODO: these should be `int` reveal_type(a) # revealed: Unknown reveal_type(b) # revealed: Unknown ``` ## Under the hood ```toml [environment] python-version = "3.12" # Use 3.12 to be able to use PEP 695 generics ``` Let's look at the example from the beginning again: ```py async def retrieve() -> int: return 42 ``` When we look at the signature of this function, we see that it actually returns a `CoroutineType`: ```py reveal_type(retrieve) # revealed: def retrieve() -> CoroutineType[Any, Any, int] ``` The expression `await retrieve()` desugars into a call to the `__await__` dunder method on the `CoroutineType` object, followed by a `yield from`. Let's first see the return type of `__await__`: ```py reveal_type(retrieve().__await__()) # revealed: Generator[Any, None, int] ``` We can see that this returns a `Generator` that yields `Any`, and eventually returns `int`. For the final type of the `await` expression, we retrieve that third argument of the `Generator` type: ```py from typing import Generator def _(): result = yield from retrieve().__await__() reveal_type(result) # revealed: int ```