{"id":1914,"library":"async-property","title":"Async Property Decorator","description":"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.","status":"active","version":"0.2.2","language":"en","source_language":"en","source_url":"https://github.com/ryananguiano/async_property","tags":["asyncio","property","decorator","async","await","cached property"],"install":[{"cmd":"pip install async-property","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Used for ObjectProxy functionality, which is part of the decorator's implementation.","package":"wrapt","optional":false}],"imports":[{"symbol":"async_property","correct":"from async_property import async_property"},{"symbol":"async_cached_property","correct":"from async_property import async_cached_property"},{"note":"AwaitLoader is directly exposed from the top-level package for convenience in recent versions.","wrong":"from async_property.await_loader import AwaitLoader","symbol":"AwaitLoader","correct":"from async_property import AwaitLoader"}],"quickstart":{"code":"import asyncio\nfrom async_property import async_property, async_cached_property, AwaitLoader\n\nasync def fetch_data(delay: float, value: str):\n    await asyncio.sleep(delay)\n    return value\n\nclass MyClass:\n    def __init__(self, initial_value: str):\n        self._initial_value = initial_value\n\n    @async_property\n    async def regular_async_prop(self) -> str:\n        print(\"Fetching regular_async_prop...\")\n        return await fetch_data(0.1, f\"Regular: {self._initial_value}\")\n\n    @async_cached_property\n    async def cached_async_prop(self) -> str:\n        print(\"Fetching cached_async_prop (only once)...\")\n        return await fetch_data(0.2, f\"Cached: {self._initial_value}\")\n\nclass MyAwaitableClass(AwaitLoader):\n    def __init__(self, initial_value: str):\n        self._initial_value = initial_value\n\n    async def load(self):\n        print(\"AwaitLoader load method called.\")\n\n    @async_cached_property\n    async def await_loader_prop1(self) -> str:\n        print(\"Fetching await_loader_prop1...\")\n        return await fetch_data(0.05, f\"AwaitLoader Prop1: {self._initial_value}\")\n\n    @async_cached_property\n    async def await_loader_prop2(self) -> str:\n        print(\"Fetching await_loader_prop2...\")\n        return await fetch_data(0.03, f\"AwaitLoader Prop2: {self._initial_value}\")\n\nasync def main():\n    instance = MyClass(\"test\")\n\n    # Accessing regular async property\n    print(f\"-> {await instance.regular_async_prop}\")\n    print(f\"-> {await instance.regular_async_prop}\") # Fetches again\n\n    # Accessing cached async property\n    print(f\"-> {await instance.cached_async_prop}\")\n    print(f\"-> {await instance.cached_async_prop}\") # Returns cached value\n\n    # Using AwaitLoader\n    awaitable_instance = await MyAwaitableClass(\"loader_data\")\n    print(f\"-> {awaitable_instance.await_loader_prop1}\")\n    print(f\"-> {awaitable_instance.await_loader_prop2}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n","lang":"python","description":"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."},"warnings":[{"fix":"Use a regular async method for setting values that require asynchronous operations (e.g., `await instance.set_remote_value(new_value)`).","message":"Async properties do not support asynchronous setters. Python's `property` mechanism does not natively support async setters, and `async-property` only addresses async getters.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use `await` when accessing an `async_property` or `async_cached_property` (e.g., `await instance.my_async_property`).","message":"Forgetting to `await` the async property will result in getting a coroutine object instead of the property's computed value. This is a common pitfall in `asyncio` applications.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Evaluate whether an explicit `get_value()` async method might be more appropriate for highly expensive or complex I/O operations, reserving async properties for values that feel more like attributes.","message":"While `async-property` enables awaitable properties, the general Python community often advises against computationally expensive or I/O-bound operations in properties, as property access is semantically expected to be cheap and fast. Overusing async properties for heavy tasks might lead to less readable code or mask performance bottlenecks if not carefully designed.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure your `asyncio` environment is correctly set up for your Python version. In Jupyter/IPython with Python 3.14+, use `await` directly in cells instead of `asyncio.run()` for top-level execution. For `async-property`, ensure you always await its access.","message":"Python 3.14 includes significant changes to `asyncio`'s internal implementation, particularly affecting nested event loops and workarounds like `nest_asyncio`. While `async-property` itself doesn't use `nest_asyncio`, issues related to `asyncio.run()` in environments like Jupyter notebooks on Python 3.14+ can indirectly affect how async properties are tested or used in such contexts.","severity":"breaking","affected_versions":"Python 3.14+"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}