Async Key-Value Store - Pluggable Interface

raw JSON →
0.4.4 verified Tue May 12 auth: no python install: verified quickstart: stale

py-key-value-aio is an asynchronous Python library offering a pluggable interface for various Key-Value (KV) stores. It provides a backend-agnostic abstraction layer, allowing framework authors and applications to integrate KV storage without committing to a specific implementation like Redis, DynamoDB, or an in-memory solution. The library, currently at version 0.4.4, focuses exclusively on async/await patterns and requires Python >=3.10. It is actively maintained as part of a larger monorepo.

pip install py-key-value-aio
error ModuleNotFoundError: No module named 'key_value_aio'
cause The `py-key-value-aio` package is either not installed in your Python environment or the import statement uses an incorrect top-level module name.
fix
Install the library using pip: pip install py-key-value-aio.
error ImportError: cannot import name 'FernetEncryptionWrapper' from 'key_value.aio.wrappers.encryption'
cause The specific class or module path you are trying to import (`FernetEncryptionWrapper` from `key_value.aio.wrappers.encryption`) does not exist in your installed version of `py-key-value-aio`, potentially due to a version mismatch or a change in the library's structure.
fix
Ensure your py-key-value-aio version is compatible with the code you are using (e.g., pip install --upgrade py-key-value-aio to get the latest), and consult the official documentation for the correct import paths for your version.
error TypeError: object 'coroutine' is not awaitable
cause An asynchronous function (coroutine) from `py-key-value-aio` was called without the necessary `await` keyword within an `async` function. Python's `asyncio` requires coroutines to be explicitly awaited to execute.
fix
Prepend the call to the asynchronous function with await. For example, change store.get(...) to await store.get(...).
error RuntimeWarning: coroutine '...' was never awaited
cause You have created a coroutine object by calling an `async def` function, but you did not `await` it, `yield from` it, or schedule it with `asyncio.create_task()`, meaning its execution was never started or completed.
fix
If the coroutine should run, either await it, yield from it, or schedule it as a task, e.g., asyncio.create_task(my_coroutine()). If it's the entry point, use asyncio.run(my_coroutine()).
error KeyError: 'some_key'
cause Your application attempted to retrieve a value from the key-value store using a key that does not exist within that store or collection, or a dictionary returned by the store is missing an expected key.
fix
Before accessing a key, check for its existence (e.g., if key in await store.keys():) or use methods that provide a default value for missing keys (e.g., value = await store.get(key, default=None)), or implement a try-except KeyError block to handle the missing key gracefully.
breaking This library is strictly async-only. A synchronous wrapper is not planned, so ensure your application uses `async/await` patterns consistently when integrating `py-key-value-aio`.
fix Rewrite blocking code paths to use `async/await` and integrate with an `asyncio` event loop. Do not attempt to use this library in synchronous contexts directly.
gotcha Values retrieved from the store are 'managed entries' (often JSON-serialized) and are copies, not 'live' objects. Modifying the retrieved dictionary or Pydantic model will not affect the stored value until you explicitly `put` it back. The library ensures type safety but does not return the same in-memory instance.
fix Always assume retrieved values are copies. If modifications need to be persisted, explicitly call `await key_value_store.put(key, updated_value, ...)` after modifying the local copy.
gotcha The library utilizes `beartype` for runtime type checking on core protocol methods. Violations will raise `TypeError`. This can be unexpected if not accounted for during development or if data types are inconsistent.
fix Ensure that values passed to `put` and retrieved data conform to the expected types, especially when using Pydantic models. For debugging or specific scenarios, runtime type checks can be disabled by setting the environment variable `PY_KEY_VALUE_DISABLE_BEARTYPE=true`.
gotcha While `py-key-value-aio` provides many backend integrations, their maturity and specific limitations may vary. Relying on certain backends in production without thorough review of their specific documentation and caveats within the `py-key-value` monorepo can lead to unexpected behavior.
fix Always consult the official `py-key-value` GitHub monorepo documentation for details on individual backend implementations (e.g., DynamoDB, S3, Redis) before deploying them in production environments.
breaking The `py-key-value-aio` library requires Python version 3.10 or higher. Running it in environments with Python 3.9 or lower will result in installation failures due to `Requires-Python` metadata.
fix Ensure your project's Python interpreter is version 3.10 or newer before attempting to install and use `py-key-value-aio`.
pip install py-key-value-aio[memory]
pip install py-key-value-aio[redis]
python os / libc variant status wheel install import disk
3.10 alpine (musl) py-key-value-aio wheel - 0.40s 29.0M
3.10 alpine (musl) memory wheel - 0.39s 29.2M
3.10 alpine (musl) redis wheel - 0.39s 32.9M
3.10 alpine (musl) py-key-value-aio - - 0.40s 29.0M
3.10 alpine (musl) memory - - 0.41s 29.2M
3.10 alpine (musl) redis - - 0.41s 32.9M
3.10 slim (glibc) py-key-value-aio wheel 2.3s 0.30s 30M
3.10 slim (glibc) memory wheel 2.4s 0.28s 30M
3.10 slim (glibc) redis wheel 2.6s 0.29s 33M
3.10 slim (glibc) py-key-value-aio - - 0.27s 30M
3.10 slim (glibc) memory - - 0.27s 30M
3.10 slim (glibc) redis - - 0.27s 33M
3.11 alpine (musl) py-key-value-aio wheel - 0.50s 31.5M
3.11 alpine (musl) memory wheel - 0.51s 31.7M
3.11 alpine (musl) redis wheel - 0.48s 36.0M
3.11 alpine (musl) py-key-value-aio - - 0.56s 31.5M
3.11 alpine (musl) memory - - 0.55s 31.7M
3.11 alpine (musl) redis - - 0.54s 36.0M
3.11 slim (glibc) py-key-value-aio wheel 2.4s 0.49s 32M
3.11 slim (glibc) memory wheel 2.4s 0.44s 32M
3.11 slim (glibc) redis wheel 2.6s 0.44s 37M
3.11 slim (glibc) py-key-value-aio - - 0.42s 32M
3.11 slim (glibc) memory - - 0.42s 32M
3.11 slim (glibc) redis - - 0.42s 37M
3.12 alpine (musl) py-key-value-aio wheel - 0.43s 23.2M
3.12 alpine (musl) memory wheel - 0.43s 23.4M
3.12 alpine (musl) redis wheel - 0.42s 27.5M
3.12 alpine (musl) py-key-value-aio - - 0.45s 23.2M
3.12 alpine (musl) memory - - 0.45s 23.4M
3.12 alpine (musl) redis - - 0.45s 27.5M
3.12 slim (glibc) py-key-value-aio wheel 2.0s 0.46s 24M
3.12 slim (glibc) memory wheel 2.2s 0.44s 24M
3.12 slim (glibc) redis wheel 2.3s 0.45s 28M
3.12 slim (glibc) py-key-value-aio - - 0.44s 24M
3.12 slim (glibc) memory - - 0.44s 24M
3.12 slim (glibc) redis - - 0.48s 28M
3.13 alpine (musl) py-key-value-aio wheel - 0.45s 22.8M
3.13 alpine (musl) memory wheel - 0.47s 23.0M
3.13 alpine (musl) redis wheel - 0.41s 27.2M
3.13 alpine (musl) py-key-value-aio - - 0.41s 22.7M
3.13 alpine (musl) memory - - 0.41s 22.9M
3.13 alpine (musl) redis - - 0.43s 27.1M
3.13 slim (glibc) py-key-value-aio wheel 2.0s 0.41s 23M
3.13 slim (glibc) memory wheel 2.1s 0.41s 24M
3.13 slim (glibc) redis wheel 2.3s 0.42s 28M
3.13 slim (glibc) py-key-value-aio - - 0.42s 23M
3.13 slim (glibc) memory - - 0.42s 23M
3.13 slim (glibc) redis - - 0.42s 28M
3.9 alpine (musl) py-key-value-aio build_error - - - -
3.9 alpine (musl) memory build_error - - - -
3.9 alpine (musl) redis build_error - - - -
3.9 alpine (musl) py-key-value-aio - - - -
3.9 alpine (musl) memory - - - -
3.9 alpine (musl) redis - - - -
3.9 slim (glibc) py-key-value-aio build_error - 1.7s - -
3.9 slim (glibc) memory build_error - 1.7s - -
3.9 slim (glibc) redis build_error - 1.7s - -
3.9 slim (glibc) py-key-value-aio - - - -
3.9 slim (glibc) memory - - - -
3.9 slim (glibc) redis - - - -

This quickstart demonstrates the core `put`, `get`, and `delete` operations using the `AsyncKeyValue` protocol and an in-memory store. It highlights the asynchronous nature of the library and the common pattern of accepting the `AsyncKeyValue` protocol in your application logic, allowing the underlying store implementation to be swapped easily.

import asyncio
from key_value.aio.protocols.key_value import AsyncKeyValue
from key_value.aio.stores.memory import MemoryStore

async def example_usage(key_value_store: AsyncKeyValue):
    print(f"Putting key 'user:123' with value {{'name': 'Alice'}}")
    await key_value_store.put(key="user:123", value={"name": "Alice"}, collection="users", ttl=3600)
    
    print("Retrieving 'user:123'...")
    user_data = await key_value_store.get(key="user:123", collection="users")
    print(f"Retrieved: {user_data}")

    print("Deleting 'user:123'...")
    await key_value_store.delete(key="user:123", collection="users")

    print("Attempting to retrieve 'user:123' again...")
    deleted_user_data = await key_value_store.get(key="user:123", collection="users")
    print(f"Retrieved after deletion: {deleted_user_data}") # Should be None

async def main():
    # Example with MemoryStore
    memory_store = MemoryStore()
    await example_usage(memory_store)

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