Minimal dependency injection container
Project description
Minimal dependency injection container for Python. Provides immutable rule definitions, singleton/transient lifetimes, scoped caching, nested attribute resolution, cycle detection, and optional validation, logging, and ordering layers.
How to use it
Installation
pip install doppy-di
Requires Python 3.10 or later.
Basic usage
from container import ContainerBuilder
builder = ContainerBuilder()
# Register a singleton service
builder.service("answer", lambda: 42, lifetime="singleton")
# Register a transient service with dependencies
builder.service("greeting", lambda name: f"Hello, {name}!", deps=["name"])
builder.value("name", "World")
container = builder.build()
print(container.get("answer")) # 42
print(container.get("greeting")) # Hello, World!
Scoped caching
with container.scope("request") as scope:
a = scope.get("greeting")
b = scope.get("greeting")
assert a is b # cached within scope
# scope cache is cleared on exit
Override for testing
with container.override("answer", 99):
print(container.get("answer")) # 99
print(container.get("answer")) # restored to 42
Use cases
Service registration with dependency injection
Register factories with explicit lifetime and dependency list. Container resolves the dependency graph on first access.
builder.service("db", lambda: Database("sqlite:///app.db"), lifetime="singleton")
builder.service("repo", lambda db: Repository(db), deps=["db"])
container = builder.build()
repo = container.get("repo")
Value objects and constants
Inject pre-computed values or configuration objects.
builder.value("config", {"debug": True, "port": 8080})
container.get("config") # {"debug": True, "port": 8080}
Aliasing
Create an alias that delegates resolution to another key.
builder.service("real_service", lambda: Service(), lifetime="singleton")
builder.alias("service", "real_service")
assert container.get("service") is container.get("real_service")
Nested attribute resolution
Access nested attributes of resolved services using tuple keys.
builder.service("db", lambda: Database("prod"), lifetime="singleton")
# resolve db.connection directly
container.get(("db", "connection")) # returns db.connection
Scoped request context
Use named scopes for per-request caching without polluting the global singleton cache.
def handle_request(request_id: str) -> dict:
with container.scope(request_id) as scope:
user = scope.get("current_user")
data = scope.get("request_data")
return process(user, data)
Validation at build time
Enable build-time validation to catch missing dependencies early.
builder.service("a", lambda b: A(b), deps=["b"])
try:
container = builder.build(validate=True)
except ContainerBuildError as e:
print(e.missing) # [("a", "b")]
Duplicate key policy
Control behaviour on duplicate registration.
from container import DuplicateKeyPolicy
strict = ContainerBuilder(duplicate_policy=DuplicateKeyPolicy.FAIL)
strict.service("x", lambda: 1)
strict.service("x", lambda: 2) # raises DuplicateKeyError
warning = ContainerBuilder(duplicate_policy=DuplicateKeyPolicy.WARN)
warning.service("x", lambda: 1)
warning.service("x", lambda: 2) # logs warning, overwrites
Optional runtime layers
The devkit package provides optional extensions:
from devkit import LoggingContainer, ValidatingContainer
container = LoggingContainer(container) # log all get operations
container = ValidatingContainer(container) # validate before resolving
from devkit.nested import NestedRules, SameValuePolicy
nested = NestedRules()
nested.add_rule("parent", "child", SameValuePolicy())
from devkit import ChildrenFirstPolicy, ParentFirstPolicy
from devkit.policy import OrderPolicy
# control the order of nested field resolution
policy = ChildrenFirstPolicy()
How to contribute
- Fork the repository.
- Create a feature branch (
git checkout -b feat/my-feature). - Install development dependencies:
uv sync --extra dev. - Make changes. Format and lint with:
uv run ruff format . && uv run ruff check --fix . - Type-check:
uv run mypy. - Run tests:
uv run pytest. - Commit messages must follow Conventional Commits (enforced via commitlint).
- Open a pull request against
main.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file doppy_di-2.0.0.tar.gz.
File metadata
- Download URL: doppy_di-2.0.0.tar.gz
- Upload date:
- Size: 273.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75e2ae15716db8b2a31f9e14409b499caaf739ba7bad441bfaa9d02a7f1221bf
|
|
| MD5 |
93ee7ea6928b1e6725121330c18de4cd
|
|
| BLAKE2b-256 |
1421cd7a7c6600695372c9e546b75afd5eb8ddbb1df37f479241ce9d8b82ea83
|
File details
Details for the file doppy_di-2.0.0-py3-none-any.whl.
File metadata
- Download URL: doppy_di-2.0.0-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27879ff0768267ed7643126e2bb3a5344a4da52daa5a5f7fe0b9e564e5c6c898
|
|
| MD5 |
0136e56816346d65b75b4f43692d67a9
|
|
| BLAKE2b-256 |
35ea0f2a6fd03c8c7ac8207ebfcfa17df6389a317e96c66233ce63dde6780c92
|