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.

bind(*, context)[source]

Return a new container sharing the same cache but bound to context.

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:

  1. Find an instance matching the criteria in the container. If one is found, return it directly.

  2. 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, return default.

  3. 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 bound context 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 to zope.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 bound context 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 by name 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 named dbsession to be registered which triggers a recursive lookup for that service in order to create the LoginService 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 to zope.interface.Interface to match any requested interface.

  • context – A class or zope.interface.Interface object defining the type of context required in order to use the factory. Defaults to None.

  • name (str) – An identifier for the service. A factory can be registered for an iface_or_type or a name or both, but an iface_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:
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:

All other kwargs are forwarded directly into dataclasses.field().

class wired.dataclasses.Context[source]

Marker sentinel for telling injector to provide container.context.