Skip to main content

Dependency injection package

Project description

depin — Small Dependency Injection container for Python

Simple, lightweight dependency injection for synchronous and asynchronous code, with request-scoped context useful for web frameworks such as FastAPI.

Features

  • Register classes and factories as SINGLETON, TRANSIENT or REQUEST scope.
  • Support for synchronous and asynchronous providers (functions / async functions).
  • Inject(...) helper for explicit provider parameters.
  • Container.inject decorator to auto-inject parameters into callables.
  • FastAPI integration: Container.Depends(...) and RequestScopeMiddleware.

Installation

Or install from a distribution package (if published):

# PIP
python -m pip install pydepin
# UV
uv add pydepin

Requirements: Python 3.9+.

Quickstart

Create a Container, register providers and resolve dependencies.

from depin import Container, Inject, Scope

DI = Container()

class Config:
    def __init__(self):
        self.value = 100


def config_provider():
    return Config()


def service(config: Config):
    return config.value * 2

# register providers
DI.bind(source=config_provider, scope=Scope.SINGLETON)
DI.bind(source=service, scope=Scope.SINGLETON)

result = DI.get(service)  # -> 200

Concepts

  • Container — main entry point. Use it to register providers and resolve values.
  • Scope — enumeration with SINGLETON, TRANSIENT and REQUEST.
    • SINGLETON: one instance shared during container lifetime.
    • TRANSIENT: a new instance produced on each resolution.
    • REQUEST: request-scoped lifecycle (requires RequestScopeService context).
  • Inject(provider) — used as a default value for function/constructor parameters to explicitly point to a provider.
  • Container.inject — decorator that wraps a function and automatically fills injectable parameters (by type-hint or Inject(...)). Works for sync and async.

Registration styles

You can register providers in a few different ways:

  • Using bind(...) with a class or function literal:
DI.bind(source=MyClass, scope=DI.Scope.SINGLETON)
DI.bind(source=my_factory_fn, scope=DI.Scope.SINGLETON)
  • Using the @register(...) decorator (convenient for modules):
@DI.register(DI.Scope.TRANSIENT)
def random_id():
    import uuid
    return uuid.uuid4().hex


@DI.register(DI.Scope.REQUEST)
class UserService:
    def __init__(self, repo: UserRepo, request: Request):
        ...

Explicit Inject parameter

Use Inject(provider) when you want to override the type hint and point to another provider directly:

from depin import Inject

def get_string():
    return 'from_provider'

class Service:
    def __init__(self, value: int = Inject(get_string)):
        self.value = value

DI.bind(source=get_string, scope=DI.Scope.SINGLETON)
DI.bind(source=Service, scope=DI.Scope.SINGLETON)

s = DI.get(Service)
assert s.value == 'from_provider'

Async providers and request-scoped resources

Request scope supports generator / async-generator providers which are entered when first resolved during a request and cleaned up when the request scope ends.

Example (from example/dependencies/database.py):

from contextlib import asynccontextmanager
from depin import Inject, Scope

@DI.register(Scope.SINGLETON)
async def db_engine():
    return Engine()


@DI.register(Scope.REQUEST)
async def db_session(engine: Engine = Inject(db_engine), session_id: str = Inject(random_id)):
    async with db_session_ctx(engine, session_id) as session:
        yield session

@asynccontextmanager
async def db_session_ctx(engine: Engine, session_id: str):
    session = Session(engine, session_id)
    try:
        yield session
    finally:
        # cleanup
        pass

The container will call __aenter__ / __enter__ for request-scoped generator providers and store the created resource in the current request store.

FastAPI integration

To use request scope with FastAPI, add the RequestScopeMiddleware from depin.extensions.fastapi before defining routes and use Container.Depends to get FastAPI-compatible dependencies that call into the container.

from fastapi import FastAPI
from depin import Container
from depin.extensions.fastapi import RequestScopeMiddleware

DI = Container()

app = FastAPI()
app.add_middleware(RequestScopeMiddleware)

@DI.register(DI.Scope.REQUEST)
class UserService:
    def __init__(self, request: Request):
        self.request = request

@app.get('/')
async def index(s: UserService = DI.Depends(UserService)):
    # `s` is resolved from the container using the request-scoped store
    return {'message': 'ok'}

Alternatively you can call RequestScopeService directly from providers to access the currently active Request instance.

Container helpers

  • Container.get(t) — synchronous resolution (raises when provider is async).
  • Container.get_async(t) — asynchronous resolution that awaits async providers.
  • Container.inject(func) — returns a wrapped callable that auto-injects dependencies by type hints and Inject(...) defaults.
  • Container.Depends(type_or_provider) — returns a FastAPI Depends wrapper.

Examples

  • See the example folder for a complete FastAPI example integrating request scope, async database sessions, and services.
  • See tests/ for unit tests showing usage patterns (provider functions, Inject param, decorators and scopes).

Running the example

From the repository root run:

python example/app.py

Open http://localhost:8001 to exercise the sample endpoints.

Project details


Download files

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

Source Distribution

pydepin-0.1.4.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

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

pydepin-0.1.4-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

File details

Details for the file pydepin-0.1.4.tar.gz.

File metadata

  • Download URL: pydepin-0.1.4.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for pydepin-0.1.4.tar.gz
Algorithm Hash digest
SHA256 121220757acf0555cd04db09448401b4c29f51b50d84dd049cbe982c15da0194
MD5 830d3e415844e45a356e57b018be6473
BLAKE2b-256 ec8ebdf1668179576aeb05ae5ed387a2a002f58aa2242e467a5c8b7663617fad

See more details on using hashes here.

File details

Details for the file pydepin-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: pydepin-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 10.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for pydepin-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 771a487f8d03af89970947b17525f923b5312a119e46f38fb6a35c19adb1d794
MD5 2b54ea54f7a1eabe2fd26d56ad677186
BLAKE2b-256 5de66cd779567561f2031ea2cf2fdf60b809bcab2a3a2779679115afa53da417

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 Pingdom Monitoring Sentry Error logging StatusPage Status page