Skip to main content

Canteen

Lightweight dependency injection for Python. Zero dependencies, full type safety, async/sync compatible.

Canteen handles three common injection patterns:

  • Singleton — created once, cached forever
  • Factory — new instance every call
  • Resource — context manager with setup/teardown

The API is inspired by FastAPI's Depends, but works anywhere — no framework required.

Install

Requires Python 3.11+.

uv add canteen-di

The distribution is named canteen-di (the canteen name on PyPI belongs to an unrelated project abandoned in 2015), but you import it as canteen:

import canteen

Quick start

Decorate any function to turn it into a provider. Use Depends() in default parameter values to declare dependencies between them.

from canteen import singleton, factory, resource, Depends

@singleton
def get_config() -> Config:
    return Config.from_env()

@factory
def get_user_service(config: Config = Depends(get_config)) -> UserService:
    return UserService(config)

@resource
def get_db(config: Config = Depends(get_config)) -> Iterator[Session]:
    session = Session(config.db_url)
    try:
        yield session
    finally:
        session.close()

Call them like normal functions — dependencies resolve automatically:

config = get_config()        # cached after first call
service = get_user_service() # new instance, config injected

with get_db() as session:    # context manager, config injected
    session.query(...)

Async providers work identically; the decorator preserves the sync/async nature of the function, so you await them and use async with.

Group related providers into a Container to get auto-wiring by parameter name and per-instance singleton caches:

from canteen import Container

class AppContainer(Container):
    config = singleton(create_config)
    db = resource(create_db)
    user_service = factory(create_user_service)

app = AppContainer()
app.user_service()           # config auto-injected

Testing

Swap any provider with override(), or pass replacements to a container constructor:

with override(get_config, lambda: Config(env="test")):
    service = get_user_service()   # receives test config

app = AppContainer(config=singleton(lambda: Config(env="test")))

Overrides nest, and are safe across threads and asyncio tasks (backed by contextvars). Each container instance has independent state, so test isolation needs no cleanup.

Rules

  • Resources can depend on singletons, factories, and other resources. Nested resource lifetimes are managed automatically via ExitStack.
  • Singletons and factories cannot depend on resources — use a resource provider instead.
  • Sync providers cannot depend on async providers. Canteen raises rather than injecting an un-awaited coroutine.
  • @resource requires a generator function that yields exactly once.
  • Dependency cycles are rejected when a container is constructed.

Violations raise a subclass of CanteenError: ProviderError (also a TypeError), CircularDependencyError, or ResourceError (also a RuntimeError).

Documentation

Full guides — providers, dependencies, containers, async, and testing — live in docs/.

Development

uv sync
uv run pytest          # tests
uv run ruff check .    # lint
uv run mypy            # types

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

canteen_di-0.1.0.tar.gz (10.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

canteen_di-0.1.0-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

Details for the file canteen_di-0.1.0.tar.gz.

File metadata

  • Download URL: canteen_di-0.1.0.tar.gz
  • Upload date:
  • Size: 10.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for canteen_di-0.1.0.tar.gz
Algorithm Hash digest
SHA256 eac79fdce763440897362def362ea65684e15c688425afef3870e0b0755735da
MD5 9d19c5afc23c9ce057e21f8c04e87875
BLAKE2b-256 6db5932d129c269e1f28538c838cea81656b0d264c712e0b87775e446cf9c9b1

See more details on using hashes here.

File details

Details for the file canteen_di-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: canteen_di-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for canteen_di-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cf427a89750f318f3972e95b772e36632748c6f658a1c2f30d2a6dcf30cccb6d
MD5 8562e5ad7880ee16d449796c21590c1a
BLAKE2b-256 5ccc9af986f5a3214d128a331e71c30a5aaa1674f67c2ca0345711af73151c73

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page