wired
API
- class wired.ServiceContainer(factories, cache=None, context=None)[source]
A service container is used to create service instances.
Create a container via
wired.ServiceRegistry.create_container()
.A container controls creating services from the registered factories. Services are cached based on their registration constraints and re-used when possible based on the context and requested interface.
- get(iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=<default>, name='', default=<default>)[source]
Find a cached instance or create one from the registered factory.
The instance is found using the following algorithm:
Find an instance matching the criteria in the container. If one is found, return it directly.
Search for a factory, first in the container and second on the service registry. If one is not found, raise a
LookupError
or, if specified, returndefault
.Invoking the factory, cache the result in the container for later lookups, and return the result.
- Parameters:
iface_or_type – The registered service interface.
context – A context object. This object will be available as
container.context
in the invoked service factories and will influence which factories are matched. Defaults to the boundcontext
on the container.name (str) – The registered name of the service.
default – A service instance to return if lookup fails.
- register_factory(factory, iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=None, name='')[source]
Register a service factory.
This factory will override any lookups defined in the service registry. Otherwise the semantics are identical to
ServiceRegistry.register_factory()
.
- register_singleton(service, iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=None, name='')[source]
Register a singleton instance.
Functionally, the singleton is wrapped in a factory that always returns the same instance when invoked. See
ServiceRegistry.register_factory()
for information on the parameters.
- set(service, iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=<default>, name='')[source]
Add a service instance to the container.
Upon success,
service
will be returned for matching lookups on the same context.If this service registration would affect a previously-cached lookup then it will raise a
ValueError
.- Parameters:
service – A service instance to cache.
iface_or_type – A class or
zope.interface.Interface
object defining the interface of the service. Defaults tozope.interface.Interface
to match any requested interface.context – A context object. The
service
instance will be cached for any later lookups using this context. Defaults to the boundcontext
on the container.name (str) – An identifier for the service.
- class wired.ServiceRegistry(factory_registry=None)[source]
A service registry contains service factory definitions.
Define the tree of services your application needs once at config-time. Later, per operation, invoke
create_container()
to create a new service container which can be used to lazily instantiate service objects on-demand.Using this pattern, your code now depends on the container and your service interfaces. You are now programming to an interface, not to a specific implementation. It is now trivial to register a different factory to mock out, or replace, specific service implementations in tests or for any other purposes.
- create_container(*, context=None)[source]
Create a new
ServiceContainer
linked to the registry.A container will use all the registered service factories, independently of any other containers, in order to find and instantiate service objects.
Practically, a new container should be derived per logical “operation”. An operation is something like a web request, job, transaction, etc.
- Parameters:
context – The container will be bound to a different context object, affecting which factories are selected. By default, the container is bound to the
None
context.
- find_factory(iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=None, name='')[source]
Return the factory registered for the given parameters.
The arguments are the same as those used in
register_factory()
.- Returns:
The registered factory (or singleton wrapper) or
None
if a factory cannot be found satisfying the constraints.
- register_factory(factory, iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=None, name='')[source]
Register a service factory.
A factory should accept a single parameter which will be a
ServiceContainer
instance. The factory should not be bound to any particular container and should use the one passed in to find service dependencies.A factory can be registered for a particular type or interface, with more specific factories allowed per type of
context
or byname
string.It is recommended to register factories using types/interfaces instead of named strings, as they avoid naming clashes between independently defined components/features. Types are always unique and are better at expressing intent and contracts.
An example service factory:
def login_factory(container): dbsession = container.get(name='dbsession') return LoginService(dbsession)
Notice in the above example that the
login_factory
requires another service nameddbsession
to be registered which triggers a recursive lookup for that service in order to create theLoginService
instance.It is not required that the returned service actually implements, or is a subclass, of the defined
iface
.- Parameters:
factory – A factory is a callable that accepts a container argument and returns an instance of the service. Specifically,
factory(services: ServiceContainer) -> iface
.iface_or_type – A class or
zope.interface.Interface
object defining the interface of the service. Defaults tozope.interface.Interface
to match any requested interface.context – A class or
zope.interface.Interface
object defining the type ofcontext
required in order to use the factory. Defaults toNone
.name (str) – An identifier for the service. A factory can be registered for an
iface_or_type
or aname
or both, but aniface_or_type
is recommended for most services.
- register_singleton(service, iface_or_type=<InterfaceClass zope.interface.Interface>, *, context=None, name='')[source]
Register a singleton instance.
The singleton is global to all containers created from this registry. Any container created by this registry will receive the same instance.
Functionally, the singleton is wrapped in a factory that always returns the same instance when invoked. See
register_factory()
for information on the parameters.
- class wired.service_factory(for_=None, context=None, name: str = '')[source]
Register a factory for a class that can sniff dependencies.
The factory will be registered with a
wired.ServiceRegistry
when performing a venusian scan.
wired.dataclasses
API
- wired.dataclasses.register_dataclass(registry: ServiceRegistry, target, for_=None, context=None, name='')[source]
Register a factory for a dataclass that can sniff dependencies.
from sqlalchemy.orm import Session @dataclass class LoginService: db: Session registry = ServiceRegistry() register_dataclass(registry, LoginService) # ... later container = registry.create_container() svc = container.get(LoginService)
- Parameters:
for – By default,
target
is used as the service type. This can be used to override theiface_or_type
argument inwired.ServiceRegistry.register_factory()
to some other type.context – The
context
argument inwired.ServiceRegistry.register_factory()
.name (str) – The
name
argument inwired.ServiceRegistry.register_factory()
.
- wired.dataclasses.factory(for_=None, context=None, name: str = '')[source]
Register a factory for a dataclass that can sniff dependencies.
The factory will be registered with a
wired.ServiceRegistry
when performing a venusian scan.from sqlalchemy.orm import Session @factory @dataclass class LoginService: db: Session # ... later registry = ServiceRegistry() scanner = venusian.Scanner(registry=registry) scanner.scan() # ... later container = registry.create_container() svc = container.get(LoginService)
- wired.dataclasses.singleton(for_=None, context=None, name: str = '')[source]
Register an instance of a dataclass as a singleton.
The singleton will be registered with a
wired.ServiceRegistry
when performing a venusian scan.@singleton @dataclass class Settings: punctuation: str = ''
- wired.dataclasses.injected(iface_or_type=<InterfaceClass zope.interface.Interface>, *, name='', attr=None, **kwargs) Field [source]
Customize how the field is populated from the generated factory.
If just the field type is insufficient, this descriptor can be used to more explicitly define how the field in the dataclass should be populated from the
wired.ServiceContainer
.- Parameters:
iface_or_type – The
iface_or_type
argument inwired.ServiceContainer.get()
.name (str) – The
name
argument inwired.ServiceContainer.get()
.attr (str) – An attribute on the returned service object.
All other kwargs are forwarded directly into
dataclasses.field()
.