Decorators¶
Use Container.decorate(...) when you want explicit cross-cutting wrappers
without changing consumer constructors.
DIWire keeps the current binding under an internal alias and rebinds the public
key to the decorator factory. This avoids A -> Decorator(A) circular
resolution errors.
Tracing Example¶
from typing import Protocol
from diwire import Container
class HttpClient(Protocol):
def get(self, url: str) -> bytes: ...
class RequestsHttpClient:
def __init__(self, base_url: str) -> None:
self.base_url = base_url
def get(self, url: str) -> bytes:
return b"ok"
class Tracer:
def span(self, name: str):
class _Span:
def __enter__(self) -> None:
return None
def __exit__(self, exc_type, exc_value, traceback) -> None:
return None
return _Span()
class TracedHttpClient:
def __init__(self, inner: HttpClient, tracer: Tracer) -> None:
self.inner = inner
self.tracer = tracer
def get(self, url: str) -> bytes:
with self.tracer.span("http.get"):
return self.inner.get(url)
container = Container()
container.add_instance("https://api.example.com", provides=str)
container.add(RequestsHttpClient, provides=HttpClient)
container.add_instance(Tracer(), provides=Tracer)
container.decorate(provides=HttpClient, decorator=TracedHttpClient)
Caching Example¶
class Repo:
...
class SqlRepo(Repo):
...
class CachedRepo(Repo):
def __init__(self, inner: Repo) -> None:
self.inner = inner
container.add(SqlRepo, provides=Repo)
container.decorate(provides=Repo, decorator=CachedRepo)
Decorator Rules¶
decorate(...)can run before or after the base registration.Multiple decorators stack in call order: last
decorate(...)call is outermost.Re-registering the same
provideskey replaces the base and rebuilds the decoration chain.For ambiguous inner-parameter inference, pass
inner_parameter=\"<parameter_name>\"explicitly.
This is explicit provider decoration, not method interception/AOP pointcuts.