Async Property Decorator

0.2.2 · active · verified Thu Apr 09

The `async-property` library provides Python decorators (`@async_property`, `@async_cached_property`) that enable defining asynchronous properties in classes. It allows getter methods to be coroutines, which can then be awaited when accessed. It also includes `AwaitLoader` for concurrently loading multiple cached async properties. The current version is 0.2.2, with a release cadence that appears maintenance-driven, having had releases in 2019 and 2023.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates the basic usage of `@async_property` for a standard awaitable property, `@async_cached_property` for a property that computes its value only once, and `AwaitLoader` for classes with multiple concurrently loaded cached properties. Remember to `await` the property access.

import asyncio
from async_property import async_property, async_cached_property, AwaitLoader

async def fetch_data(delay: float, value: str):
    await asyncio.sleep(delay)
    return value

class MyClass:
    def __init__(self, initial_value: str):
        self._initial_value = initial_value

    @async_property
    async def regular_async_prop(self) -> str:
        print("Fetching regular_async_prop...")
        return await fetch_data(0.1, f"Regular: {self._initial_value}")

    @async_cached_property
    async def cached_async_prop(self) -> str:
        print("Fetching cached_async_prop (only once)...")
        return await fetch_data(0.2, f"Cached: {self._initial_value}")

class MyAwaitableClass(AwaitLoader):
    def __init__(self, initial_value: str):
        self._initial_value = initial_value

    async def load(self):
        print("AwaitLoader load method called.")

    @async_cached_property
    async def await_loader_prop1(self) -> str:
        print("Fetching await_loader_prop1...")
        return await fetch_data(0.05, f"AwaitLoader Prop1: {self._initial_value}")

    @async_cached_property
    async def await_loader_prop2(self) -> str:
        print("Fetching await_loader_prop2...")
        return await fetch_data(0.03, f"AwaitLoader Prop2: {self._initial_value}")

async def main():
    instance = MyClass("test")

    # Accessing regular async property
    print(f"-> {await instance.regular_async_prop}")
    print(f"-> {await instance.regular_async_prop}") # Fetches again

    # Accessing cached async property
    print(f"-> {await instance.cached_async_prop}")
    print(f"-> {await instance.cached_async_prop}") # Returns cached value

    # Using AwaitLoader
    awaitable_instance = await MyAwaitableClass("loader_data")
    print(f"-> {awaitable_instance.await_loader_prop1}")
    print(f"-> {awaitable_instance.await_loader_prop2}")

if __name__ == "__main__":
    asyncio.run(main())

view raw JSON →