Dioxide v1.0.0 is Here! π
After months of development, I'm thrilled to announce Dioxide v1.0.0 my opinionated, ergonomic dependency injection framework for Python backed by Rust.
What is Dioxide?
Dioxide makes the Dependency Inversion Principle feel inevitable. It's designed to make depending on abstractions (ports) instead of implementations (adapters) trivially easy.
from dioxide import service, adapter, Container, Profile
from typing import Protocol
# Define your port (interface)
class EmailPort(Protocol):
def send(self, to: str, body: str) -> None: ...
# Business logic depends on abstractions, not infrastructure
@service
class NotificationService:
def __init__(self, email: EmailPort) -> None:
self.email = email
def notify_user(self, user_id: str, message: str) -> None:
self.email.send(f"{user_id}@example.com", message)
# Production adapter - the only place with real infrastructure
@adapter.for_(EmailPort, profile=Profile.PRODUCTION)
class SendGridAdapter:
def send(self, to: str, body: str) -> None:
# Real SendGrid implementation
pass
# Test adapter - fast, in-memory
@adapter.for_(EmailPort, profile=Profile.TEST)
class FakeEmailAdapter:
sent: list[tuple[str, str]] = []
def send(self, to: str, body: str) -> None:
self.sent.append((to, body))
Why Dioxide?
π¦ Rust-Backed Core
The container internals are written in Rust via PyO3. Why? Because dependency graphs and cycle detection are a perfect fit for Rust's strong type system. The Python API stays Pythonic; Rust handles the graph theory.
π Pythonic API
No XML. No YAML. No Java patterns. Just decorators, type hints, and Protocols β the Python way.
π§ͺ Testing is Architecture
Dioxide's profile system makes testing a first-class citizen. Swap implementations with a single parameter:
# Production
container = Container(profile=Profile.PRODUCTION)
container.scan(packages=["myapp"])
# Tests - same code, different adapters
container = Container(profile=Profile.TEST)
container.scan(packages=["myapp"])
π Framework Integrations
v1.0.0 ships with integrations for the most popular Python frameworks:
| Framework | Install | Features |
|---|---|---|
| FastAPI | pip install dioxide[fastapi] |
Middleware, Inject() helper |
| Django | pip install dioxide[django] |
Middleware, inject() in views |
| Django REST Framework | pip install dioxide[drf] |
Works with APIView, ViewSet, @api_view |
| Django Ninja | pip install dioxide[ninja] |
Sync and async endpoints |
| Flask | pip install dioxide[flask] |
Request hooks, inject() helper |
| Celery | pip install dioxide[celery] |
Task scoping with scoped_task
|
| Click | pip install dioxide[click] |
CLI command scoping |
Quick Start with Django
# settings.py
MIDDLEWARE = [
"dioxide.django.DioxideMiddleware",
# ... other middleware
]
# apps.py
from dioxide.django import configure_dioxide
from dioxide import Profile
class MyAppConfig(AppConfig):
def ready(self):
configure_dioxide(
packages=["myapp.services"],
profile=Profile.PRODUCTION,
)
# views.py
from dioxide.django import inject
def my_view(request):
service = inject(MyService)
return JsonResponse({"result": service.do_work()})
The Philosophy: Fakes Over Mocks
Dioxide encourages fakes over mocks for testing. Instead of complex mock configurations that test mock behavior, use simple in-memory implementations that test real behavior:
@adapter.for_(UserRepository, profile=Profile.TEST)
class FakeUserRepository:
def __init__(self):
self.users: dict[str, User] = {}
def save(self, user: User) -> None:
self.users[user.id] = user
def find(self, user_id: str) -> User | None:
return self.users.get(user_id)
Your tests become simpler, more reliable, and actually test your business logic.
Installation
# Core only
pip install dioxide
# With your framework of choice
pip install dioxide[fastapi]
pip install dioxide[django]
pip install dioxide[flask]
# Multiple frameworks
pip install dioxide[fastapi,celery]
What's Next?
v1.0.0 marks the completion of our Minimum Lovable Product. The API is now stable β no breaking changes until v2.0.
We're exploring:
- Multi-binding / collection injection for plugin patterns
- Enhanced async support
- More framework integrations
Get Involved
- π¦ PyPI: pypi.org/project/dioxide
- π Docs: dioxide.readthedocs.io
- π GitHub: github.com/mikelane/dioxide
- β Star us if you find Dioxide useful!
Dioxide is open source under the MIT license. Contributions welcome!
Top comments (0)