WD-DI
.NET Style Dependency Injection for Python
WD-DI brings the robust and flexible dependency injection patterns of .NET to your Python applications, with no external library dependencies, just Python's standard library.
Full documentation can be found at https://whiteducksoftware.github.io/wd-di/ (or in the /docs directory).
For beginners, the Core Concepts and Tutorials sections in the documentation are a great place to start to understand not just how to use DI, but why it's beneficial!
Why WD-DI? 🤔
- Simplified Dependency Management: Effortlessly manage object creation and lifecycles.
- Enhanced Testability: Easily mock dependencies for robust unit tests.
- Modular Architecture: Build loosely coupled, maintainable, and scalable applications.
- Familiar Patterns: Leverage .NET-inspired DI concepts like service lifetimes (Singleton, Scoped, Transient), constructor injection, and the Options pattern for configuration.
- Pythonic and Lightweight: Clean, intuitive API that integrates smoothly into your Python projects.
| ✅ Feature | WD-DI | Typical alternatives |
|---|---|---|
| Pure-stdlib (zero runtime deps) | ✔ | ✘ pull in pydantic / C-extensions |
| .NET-style lifetimes Transient • Singleton • Scoped (+ auto-dispose) |
✔ | ✘ Scoped rarely supported |
| Strongly-typed Options binding from dict/JSON/env → dataclass | ✔ | ✘ Dicts or manual parsing |
| Decorator Pattern Built-in "wrap this service with that decorator" API? | ✔ | ✘ Only by manual implementation |
| Middleware pipeline bundled & DI-aware (async-first) | ✔ | ✘ None ship a generic pipeline |
Decorator-based registration tied to your ServiceCollection (no globals) |
✔ | ✘ Global singletons or meta-classes |
Thread-safe circular-dependency detection via ContextVar |
✔ | ✘ Simple set → race-prone |
Full IDE type inference for get_service() |
✔ | ✘ Returns Any / needs cast() |
| Lean & readable (~1.4 k LOC + robust test suite) | ✔ | ✘ wtf am I reading |
Installation 📦
pip install wd-di
Quick Example: The Power of WD-DI 🚀
Experience clean, decoupled code with intuitive type-hinted dependency resolution:
from wd.di import ServiceCollection
services = ServiceCollection()
# Define interfaces and implementations
class IEmailService:
def send_email(self, to: str, subject: str, body: str) -> None:
pass
class EmailService(IEmailService):
def send_email(self, to: str, subject: str, body: str) -> None:
print(f"\nSending email to {to}")
print(f"Subject: {subject}")
print(f"Body: {body}")
print("Email sent successfully\n")
# UserService depends on IEmailService
class UserService:
def __init__(self, email_service: IEmailService):
self.email_service = email_service
def notify_user(self, user_id: str, message: str) -> None:
self.email_service.send_email(f"user{user_id}@example.com", "Notification", message)
# Register services
services.add_singleton(IEmailService, EmailService)
services.add_singleton(UserService)
# Build provider
# Services will be resolved and injected into services
# like EmailService into UserService
provider = services.build_service_provider()
# Get services with proper type hints
email_service = provider.get_service(IEmailService)
user_service = provider.get_service(UserService)
# IDE will provide code completion for these methods
# No need to cast or use Any
email_service.send_email("test@example.com", "Test", "Hello")
user_service.notify_user("123", "Welcome!")
Dive into the full documentation to explore service lifetimes, configuration, middleware, and more!
Contributing 🤝
Contributions are welcome! Please see the main documentation site for details on how to contribute, report issues, or request features.
License 📜
This project is licensed under the MIT License. See the LICENSE file for details.
Metadata
Release files for wd-di 0.2.14
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| wd_di-0.2.14.tar.gz | 1.0 MB | Without provenance | Details for wd_di-0.2.14.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| wd_di-0.2.14-py3-none-any.whl | Python 3 | none | any | Details for wd_di-0.2.14-py3-none-any.whl |
Total release size: 1.0 MB
Release files / wd_di-0.2.14.tar.gz
| Download URL | wd_di-0.2.14.tar.gz |
|---|---|
| Size | 1.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d81b23dadd480df607202b152bbbdb60b9224722d8aeb2e9867d153e16757a3
|
|
BLAKE2b-256 checksum How to use checksums |
9b42a07cabcdd8e4cdf95bf26a1a125b0d54df9d8c24721b47feca20631c5a45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.4
|
Release files / wd_di-0.2.14-py3-none-any.whl
| Download URL | wd_di-0.2.14-py3-none-any.whl |
|---|---|
| Size | 30.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cfe1ce957d8cb7624f3517029117cae8f81319746652523e82e996ece16f8857
|
|
BLAKE2b-256 checksum How to use checksums |
8fc3888e7a3d787a56a09e2abce1f867c06f261a51d6ba015758db7ec5a02ba4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.4
|
Security for wd-di 0.2.14
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.