svcs: A Flexible Service Locator#

Release 24.1.0 (What’s new?)

svcs (pronounced services) is a dependency container for Python. It gives you a central place to register factories for types/interfaces and then imperatively acquire instances of those types with automatic cleanup and health checks.

It’s suitable for implementing Inversion of Control using either dependency injection or service location while not requiring global state, decorators, or mangling of function signatures.

Benefits:

  • Eliminates tons of repetitive boilerplate code,

  • unifies acquisition and cleanups of services,

  • provides full static type safety for them,

  • simplifies testing through loose coupling,

  • improves live introspection and monitoring with health checks.

The goal is to minimize the code for acquiring pluggable services to:

import svcs

async def view(request):
    db, api, cache = await svcs.aiohttp.aget(request, Database, WebAPIClient, Cache)

    ...
import svcs

@app.get("/")
async def view(services: svcs.fastapi.DepContainer):
    db, api, cache = await services.aget(Database, WebAPIClient, Cache)

    ...
import svcs

@app.route("/")
def view():
    db, api, cache = svcs.flask.get(Database, WebAPIClient, Cache)

    ...
import svcs

@view_config(route_name="index")
def view(request):
    db, api, cache = svcs.pyramid.get(request, Database, WebAPIClient, Cache)

    ...
import svcs

async def view(request):
    db, api, cache = await svcs.starlette.aget(request, Database, WebAPIClient, Cache)

    ...

To a type checker like Mypy, db has the type Database, api has the type WebAPIClient, and cache has the type Cache. db, api, and cache will be automatically cleaned up when the request ends – it’s context managers all the way down.

Read on in Why? if you’re intrigued!