mirror of
https://github.com/astral-sh/ruff
synced 2026-01-22 22:10:48 -05:00
* origin/main: (67 commits) Move `Token`, `TokenKind` and `Tokens` to `ruff-python-ast` (#21760) [ty] Don't confuse multiple occurrences of `typing.Self` when binding bound methods (#21754) Use our org-wide Renovate preset (#21759) Delete `my-script.py` (#21751) [ty] Move `all_members`, and related types/routines, out of `ide_support.rs` (#21695) [ty] Fix find-references for import aliases (#21736) [ty] add tests for workspaces (#21741) [ty] Stop testing the (brittle) constraint set display implementation (#21743) [ty] Use generator over list comprehension to avoid cast (#21748) [ty] Add a diagnostic for prohibited `NamedTuple` attribute overrides (#21717) [ty] Fix subtyping with `type[T]` and unions (#21740) Use `npm ci --ignore-scripts` everywhere (#21742) [`flake8-simplify`] Fix truthiness assumption for non-iterable arguments in tuple/list/set calls (`SIM222`, `SIM223`) (#21479) [`flake8-use-pathlib`] Mark fixes unsafe for return type changes (`PTH104`, `PTH105`, `PTH109`, `PTH115`) (#21440) [ty] Fix auto-import code action to handle pre-existing import Enable PEP 740 attestations when publishing to PyPI (#21735) [ty] Fix find references for type defined in stub (#21732) Use OIDC instead of codspeed token (#21719) [ty] Exclude `typing_extensions` from completions unless it's really available [ty] Fix false positives for `class F(Generic[*Ts]): ...` (#21723) ...
120 lines
2.2 KiB
Markdown
120 lines
2.2 KiB
Markdown
# `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)
|
|
reveal_type(result) # revealed: int
|
|
```
|
|
|
|
### `asyncio.Task`
|
|
|
|
```py
|
|
import asyncio
|
|
|
|
async def f() -> int:
|
|
return 1
|
|
|
|
async def main():
|
|
task = asyncio.create_task(f())
|
|
|
|
result = await task
|
|
|
|
reveal_type(result) # revealed: int
|
|
```
|
|
|
|
### `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"),
|
|
)
|
|
|
|
reveal_type(a) # revealed: int
|
|
reveal_type(b) # revealed: int
|
|
```
|
|
|
|
## 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
|
|
```
|