Uncalled-for

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

Async dependency injection for Python functions. It allows declaring function dependencies as parameter defaults, which are then resolved when the function runs, offering a zero-ceremony, container-less, and configuration-free approach. The library is async-native and built on standard library features like `AsyncExitStack` and `ContextVar`. It supports context manager lifecycle for generators and nested dependencies, with caching to ensure each dependency resolves once per call. Current version is 0.2.0, with an active release cadence as seen from recent GitHub releases.

pip install uncalled-for
breaking The `__aexit__` signature for custom `Dependency` classes changed between versions 0.1.0 and 0.1.1. If you implemented custom asynchronous dependencies, ensure their `__aexit__` method matches the full expected signature.
fix Update the `__aexit__` method signature in your custom asynchronous `Dependency` implementations to `async def __aexit__(self, exc_type, exc_val, exc_tb):`.
gotcha As of version 0.1.2, the library reports concrete types for duplicate single dependencies. This change might alter behavior or error reporting if your application previously had ambiguously defined duplicate dependencies that were implicitly resolved.
fix Review your dependency definitions to ensure uniqueness where intended or explicitly define how duplicate dependencies should be resolved.
gotcha The library explicitly requires Python 3.10 or newer. Using it with older Python versions will result in `SyntaxError` or `ImportError` due to modern language features utilized.
fix Ensure your project's Python interpreter is version 3.10 or higher. You may need to upgrade your Python environment or use a tool like `pyenv` or `conda` to manage different Python versions.
gotcha As an async-native library built on `AsyncExitStack` and `ContextVar`, proper asynchronous context management is crucial. Misunderstanding `await` usage or resource lifecycle in async generators can lead to unclosed resources or unexpected behavior.
fix Always `await` calls to functions decorated or managed by `uncalled-for` if they involve async dependencies. Ensure any custom async generators used as dependencies properly `yield` and handle their `finally` blocks for resource cleanup.
breaking The `call` function is no longer available for direct import from the `uncalled_for` package's top level. This indicates a breaking API change where the function has either been removed, renamed, or moved to a different module.
fix Update your import statements and code to reflect the library's current API for its primary callable functionality. Refer to the library's changelog or documentation to identify the new entry point or alternative method for the `call` functionality.
python os / libc status wheel install import disk mem side effects
3.10 alpine (musl) wheel - - 17.9M - broken
3.10 alpine (musl) - - - - - -
3.10 slim (glibc) wheel 1.5s - 18M - broken
3.10 slim (glibc) - - - - - -
3.11 alpine (musl) wheel - - 19.7M - broken
3.11 alpine (musl) - - - - - -
3.11 slim (glibc) wheel 1.6s - 20M - broken
3.11 slim (glibc) - - - - - -
3.12 alpine (musl) wheel - - 11.6M - broken
3.12 alpine (musl) - - - - - -
3.12 slim (glibc) wheel 1.4s - 12M - broken
3.12 slim (glibc) - - - - - -
3.13 alpine (musl) wheel - - 11.3M - broken
3.13 alpine (musl) - - - - - -
3.13 slim (glibc) wheel 1.5s - 12M - broken
3.13 slim (glibc) - - - - - -
3.9 alpine (musl) build_error - - - - - -
3.9 alpine (musl) - - - - - -
3.9 slim (glibc) build_error - 1.6s - - - -
3.9 slim (glibc) - - - - - -

This example demonstrates how to define an asynchronous dependency using an async generator, and then use `uncalled_for.call` to automatically resolve and inject this dependency into another asynchronous function. The `get_db_connection` acts as a context manager, ensuring resource cleanup.

import asyncio
from uncalled_for import call

# Define an async generator for a mock database connection
async def get_db_connection():
    print("Connecting to DB...")
    try:
        # Simulate a connection object
        yield "mock_db_connection_obj"
    finally:
        print("Closing DB connection...")

# Define a function that depends on the database connection
async def get_user_data(db_connection: str):
    print(f"Fetching user data using: {db_connection}")
    await asyncio.sleep(0.1) # Simulate async I/O
    return f"User data fetched with {db_connection}"

# Define the main application function
async def main_app_logic():
    # 'call' resolves get_db_connection and injects its yielded value into get_user_data
    data = await call(get_user_data, db_connection=get_db_connection)
    print(f"Received: {data}")

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