Skip to content

Async Types#

# async_resource.py
# For reuse in subsequent examples
import asyncio
from dataclasses import dataclass


async def do_work():
    await asyncio.sleep(0.1)


@dataclass
class Resource:
    name: str

    @classmethod
    async def get(cls, name: str) -> Resource:
        await do_work()
        return cls(name=name)

    async def process(self) -> str:
        await do_work()
        return f"Completed: {self.name}"
# awaitable.py
import asyncio
from typing import Awaitable

from async_resource import Resource


def get_resource_awaitable() -> Awaitable[Resource]:
    return Resource.get("Awaitable")


async def get_async_resource_awaitable() -> None:
    resource = await get_resource_awaitable()
    print(await resource.process())


asyncio.run(get_async_resource_awaitable())
## Completed: Awaitable
# coroutine.py
import asyncio
from typing import Coroutine
from async_resource import Resource


def get_resource_coroutine() -> Coroutine[None, None, Resource]:
    return Resource.get("Coroutine")


async def get_async_resource_coroutine() -> None:
    resource = await get_resource_coroutine()
    print(await resource.process())


asyncio.run(get_async_resource_coroutine())
## Completed: Coroutine
# async_iterator_iterable.py
import asyncio
from typing import AsyncIterator, AsyncIterable

from async_resource import Resource, do_work


class ResourceStreamer:
    def __init__(self) -> None:
        self.count = 3

    def __aiter__(self) -> AsyncIterator[Resource]:
        return self

    async def __anext__(self) -> Resource:
        if self.count <= 0:
            raise StopAsyncIteration
        self.count -= 1
        await do_work()
        return Resource(f"Stream-{self.count}")


async def consume(stream: AsyncIterable[Resource]) -> None:
    async for resource in stream:
        print(await resource.process())


async def consumer() -> None:
    await consume(ResourceStreamer())


asyncio.run(consumer())
## Completed: Stream-2
## Completed: Stream-1
## Completed: Stream-0
# async_generator.py
import asyncio
from typing import AsyncGenerator

from async_resource import Resource, do_work


async def generate_resources() -> AsyncGenerator[Resource, None]:
    for i in range(3):
        await do_work()
        yield Resource(f"gen-{i}")


async def generate_resources_coroutine() -> None:
    async for r in generate_resources():
        print(await r.process())


asyncio.run(generate_resources_coroutine())
## Completed: gen-0
## Completed: gen-1
## Completed: gen-2
# callable_returning_awaitable.py
import asyncio
from typing import Awaitable, Callable

from async_resource import Resource, do_work


def resource_factory() -> Callable[[], Awaitable[Resource]]:
    async def make() -> Resource:
        await do_work()
        return Resource("Callable Returning Awaitable")

    return make


async def get_resource_factory() -> None:
    factory = resource_factory()
    resource = await factory()
    print(await resource.process())


asyncio.run(get_resource_factory())
## Completed: Callable Returning Awaitable
# async_context_manager.py
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncIterator

from async_resource import Resource


@asynccontextmanager
async def resource_context() -> AsyncIterator[Resource]:
    resource = Resource("Async Context Manager")
    print(f"Acquired {resource}")
    yield resource
    print(f"Releasing {resource}")


async def async_context_manager_async() -> None:
    async with resource_context() as res:
        print(await res.process())


asyncio.run(async_context_manager_async())
## Acquired Resource(name='Async Context Manager')
## Completed: Async Context Manager
## Releasing Resource(name='Async Context Manager')
# generic_async_context_manager.py
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncIterator

from async_resource import Resource


@asynccontextmanager
async def manage[T](value: T) -> AsyncIterator[T]:
    print(f"Acquired {value}")
    yield value
    print(f"Releasing {value}")


async def generic_async_context_manager() -> None:
    async with manage(Resource("Generic ACM")) as resource:
        print(await resource.process())


asyncio.run(generic_async_context_manager())
## Acquired Resource(name='Generic ACM')
## Completed: Generic ACM
## Releasing Resource(name='Generic ACM')