Skip to main content

Lightweight dependency injection container for Python.

Project description

philiprehberger-di

Tests PyPI version GitHub release Last updated License Bug Reports Feature Requests Sponsor

Lightweight dependency injection container for Python.

Installation

pip install philiprehberger-di

Usage

from philiprehberger_di import Container

container = Container()
container.register(Logger)
logger = container.resolve(Logger)

Singletons

container.register(Database, singleton=True)

a = container.resolve(Database)
b = container.resolve(Database)
assert a is b

Custom Factories

container.register(Cache, factory=lambda: Cache(max_size=256))
cache = container.resolve(Cache)

Recursive Resolution

class Service:
    def __init__(self, db: Database, logger: Logger) -> None:
        self.db = db
        self.logger = logger

container.register(Database)
container.register(Logger)
container.register(Service)
service = container.resolve(Service)  # db and logger are injected automatically

Inject Decorator

from philiprehberger_di import Container, inject

container = Container()
container.register(Logger, singleton=True)

@inject(container)
def handle_request(logger: Logger) -> str:
    logger.log("request handled")
    return "ok"

handle_request()  # logger is resolved and injected automatically

Lifecycle Hooks

container.register(
    Database,
    singleton=True,
    on_create=lambda db: db.connect(),
    on_destroy=lambda db: db.disconnect(),
)

db = container.resolve(Database)  # on_create called after creation
container.reset()                 # on_destroy called before clearing singletons

Circular Dependency Detection

The container detects circular dependencies during resolution and raises a CircularDependencyError with the full dependency chain:

from philiprehberger_di import CircularDependencyError

class A:
    def __init__(self, b: B) -> None: ...

class B:
    def __init__(self, a: A) -> None: ...

container.register(A)
container.register(B)

try:
    container.resolve(A)
except CircularDependencyError as e:
    print(e)  # Circular dependency detected: A -> B -> A
    print(e.chain)  # [A, B, A]

Scoped Lifetime

Services registered with Lifetime.SCOPED are singletons within a scope but differ across scopes:

from philiprehberger_di import Container, Lifetime

container = Container()
container.register(RequestContext, lifetime=Lifetime.SCOPED)
container.register(Logger, lifetime=Lifetime.SINGLETON)

with container.create_scope() as scope:
    ctx1 = scope.resolve(RequestContext)
    ctx2 = scope.resolve(RequestContext)
    assert ctx1 is ctx2  # same within the scope

# on_destroy hooks are called when the scope exits

API

Function / Class Description
Container() Create a new dependency injection container
container.register(cls, factory?, singleton?, lifetime?, on_create?, on_destroy?) Register a class with optional factory, lifetime, and lifecycle hooks
container.resolve(cls) Resolve an instance, recursively injecting dependencies
container.create_scope() Create a child scope for scoped lifetime management
container.reset() Call on_destroy for singletons with hooks, then clear the cache
inject(container) Decorator that resolves type-hinted params from the container
Lifetime.TRANSIENT New instance on every resolve (default)
Lifetime.SINGLETON Single shared instance across the container
Lifetime.SCOPED Single instance per scope, transient without a scope
CircularDependencyError Raised when a circular dependency chain is detected
Scope Child scope returned by create_scope(), used as a context manager

Development

pip install -e .
python -m pytest tests/ -v

Support

If you find this package useful, consider giving it a star on GitHub — it helps motivate continued maintenance and development.

LinkedIn More packages

License

MIT

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

philiprehberger_di-0.3.0.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

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

philiprehberger_di-0.3.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file philiprehberger_di-0.3.0.tar.gz.

File metadata

  • Download URL: philiprehberger_di-0.3.0.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for philiprehberger_di-0.3.0.tar.gz
Algorithm Hash digest
SHA256 6d76b2a0795a5b5fd29eb86e0608c76f7347d0c1490046b650d1ded7553541ad
MD5 0569af6cdf3366468c5365a576fc98f7
BLAKE2b-256 424a1a98155e1596a8a6ad8e10da3027a79ac2e4e548c9a2b9dccc29f1e7ef3d

See more details on using hashes here.

File details

Details for the file philiprehberger_di-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for philiprehberger_di-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c5410c9a96021371fa127cafe4530ba8185186c48217efc88fee62aeaa39c4f8
MD5 f24df2524fbf525fd6d17cd517464ec7
BLAKE2b-256 06ae7dccb6190fb135d80e42dfc9bb5527706ba019d404836a2f5d7d37a46fa0

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