Skip to main content

uncalled-for

Async dependency injection for Python functions.

Declare what your function needs as parameter defaults. They show up resolved when the function runs. No ceremony, no container, no configuration.

from uncalled_for import Depends

async def get_db():
    db = await connect()
    try:
        yield db
    finally:
        await db.close()

async def handle_request(db: Connection = Depends(get_db)):
    await db.execute("SELECT 1")

Features

  • Zero dependencies — standard library only
  • Async-native — built on AsyncExitStack and ContextVar
  • Context manager lifecycle — sync and async generators get proper cleanup
  • Nested dependencies — dependencies can depend on other dependencies
  • Caching — each dependency resolves once per call, even if referenced multiple times
  • Call arguments — a factory can reference the arguments of the call it serves

Annotated dependencies

Depends, Shared and CallArgument also work as Annotated metadata, so you can name a dependency once and reuse it:

DB = Annotated[Connection, Depends(get_db)]

async def handle_request(db: DB):
    await db.execute("SELECT 1")

This resolves like db: Connection = Depends(get_db), but to Python db is still a required parameter. A custom dependency supplies a value from metadata only if it subclasses Provider; other dependencies there wrap the call.

When something else calls the function with type-checked arguments, such as a task queue that schedules it, default the parameter to Provided so those callers can leave it out:

async def handle_request(db: DB = Provided): ...

A type alias works the same way: type DB = Annotated[Connection, Depends(get_db)].

Call arguments

A factory sometimes needs a value from the call itself, not from another dependency. CallArgument declares that reference:

from uncalled_for import CallArgument, Depends

def load_user(user_id: str = CallArgument()) -> User:
    return users[user_id]

async def handle_request(
    user_id: str,
    user: User = Depends(load_user),
):
    ...

The bare form takes the name of the parameter it is declared on. CallArgument("name") names a different parameter of the outer function. The reference sees the same value the outer function receives, whether the caller passed it or another dependency on the outer signature produced it. CallArgument(optional=True) yields None when the outer function has no such argument. References that form a cycle raise CycleError.

Bindings

Depends accepts keyword bindings, so you can wire up an ordinary function without changing it:

async def handle_request(
    user_id: str,
    user: User = Depends(load_user, user_id=CallArgument("user_id")),
):
    ...

A binding that is a Dependency, such as CallArgument(...) or another Depends(...), resolves first and the factory receives its value. Any other value passes through as it is. A binding replaces the factory parameter's own default, which is then never resolved. Two dependencies on the same factory share one cached result only when their bindings match.

Install

pip install uncalled-for

Metadata

Release files for uncalled-for 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for uncalled-for 0.6.0
File Size Uploaded Provenance Actions
uncalled_for-0.6.0.tar.gz 68.9 kB With provenance Details for uncalled_for-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for uncalled-for 0.6.0
File Interpreter ABI Platform Actions
uncalled_for-0.6.0-py3-none-any.whl Python 3 none any Details for uncalled_for-0.6.0-py3-none-any.whl

Total release size: 85.6 kB

Release files / uncalled_for-0.6.0.tar.gz

Download URL uncalled_for-0.6.0.tar.gz
Size 68.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5872701bf3b4eb0698930f87126d339d56a904c53f052eb0eadad64439fa9b11
BLAKE2b-256 checksum
How to use checksums
5849423c660a9b548ebe875562c4f47d3dcbc5807377e19eced0596b05894ca9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / uncalled_for-0.6.0-py3-none-any.whl

Download URL uncalled_for-0.6.0-py3-none-any.whl
Size 16.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5c6932836965b0e6b0a80f9962388922f3bb235431d8f5d3fedc2ad07b581189
BLAKE2b-256 checksum
How to use checksums
a6a7d819bc9c5ea3d0ccbedc9999e36efebe9dbae61b024f494afc423483909a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Security for uncalled-for 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for uncalled_for-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page