Soupape
Soupape is a dependency injection and inversion of control library in pure Python. It allows you to manage the dependencies of your services in your application in a clean and efficient way. Soupape is a standalone library that does not rely on any framework and can be used in any Python project.
Synchronous and asynchronous applications get the same API: SyncInjector and AsyncInjector register, resolve and dispose services the same way.
Installation
$ pip install soupape # or use your preferred package manager
Soupape requires Python 3.13 or later.
Quick start
Write your services as plain classes. The dependencies are declared as type hints in the constructor, and the injector will resolve them automatically.
from typing import Any
from my_app.models import User
class HttpService:
async def get(self, url: str) -> dict[str, Any]: ...
class UserService:
async def get_user(self, user_id: int) -> User: ...
class AuthService:
def __init__(self, http: HttpService, user_service: UserService) -> None:
self.http = http
self.user_service = user_service
async def authenticate(self, token: str) -> User: ...
Register them in a ServiceCollection, then resolve them from an injector.
from soupape import AsyncInjector, ServiceCollection
from my_app.services import AuthService, HttpService, UserService
def define_services() -> ServiceCollection:
services = ServiceCollection()
services.add_singleton(HttpService)
services.add_scoped(UserService)
services.add_scoped(AuthService)
return services
async def main() -> None:
async with AsyncInjector(define_services()) as injector:
async with injector.get_scoped_injector() as scoped_injector:
auth_service = await scoped_injector.require(AuthService)
token = ... # obtain token from somewhere
user = await auth_service.authenticate(token)
HttpService is a singleton: a single instance shared for the lifetime of the main injector.
UserService and AuthService are scoped: a new instance per scoped injector, disposed of when that injection session closes.
The same registrations run on a SyncInjector, as long as no service requires asynchronous initialization.
What Soupape does
- Service lifetimes — singleton, scoped and transient. Each service can define its own lifetime, the nested injectors will manage their instances accordingly.
- Injection sessions — scoped injectors, nested or not. Scoped services will be created once per session, and disposed of when the session they belong to closes. Child sessions will inherit the parent session's scoped services.
- Initialization and teardown — services can implement the sync or async context manager protocol, or declare
@post_inithooks. The injector will enter them as it builds them, and exit them in reverse order, the dependents before their dependencies. - Resolver functions — register a function instead of a class, synchronous, asynchronous, or a generator that cleans up on teardown. Its return type hint is the registration.
- Function calls —
injector.call(func)will inject the parameters of any function and call it. Some parameters can be given aspositional_argsornamed_args, the injector will resolve the others. - Per-call fallbacks —
requireandcallaccept a list of fallback resolvers. They will serve the parameters no registered service matches, by name or by anything else the resolution context knows about. - Custom and annotated resolvers —
soupape.extensionis the extension surface. AServiceResolverwill take over a whole type, anAnnotatedmarker with a__resolve__method will build a single parameter. - Collection and context injection — a
list[T]or adict[str, T]parameter will receive every registered service assignable toT. The injector itself, the resolution context and the caller context can be injected the same way. - Generic services — generic services are registered and resolved by specialization.
Repository[User]andRepository[Order]are two different services. - Registration helpers — the
@injectabledecorators will register your services from a cache.depends_ondeclares a service that must be resolved first, typically one that registers other services. - Errors — every failure raises a
SoupapeErrorwith its own error code. Unknown services, missing type hints, captive dependencies and circular dependencies are all detected before any instance is created.
Soupape is fully typed and checked in Pyright's strict mode.
License
Soupape is released under the MIT license, see LICENSE.txt.
Metadata
Release files for soupape 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| soupape-0.10.0.tar.gz | 18.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| soupape-0.10.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.8 kB
Release files / soupape-0.10.0.tar.gz
| Download URL | soupape-0.10.0.tar.gz |
|---|---|
| Size | 18.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
66677491a78858e5ea4e5d32345b279e5774b3e0f24ef4472b76a38a66bd47d9
|
|
BLAKE2b-256 checksum How to use checksums |
50c75a54ddfcc91f832874378fec3c82295439db74bd16153f5a89a302c1b83c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / soupape-0.10.0-py3-none-any.whl
| Download URL | soupape-0.10.0-py3-none-any.whl |
|---|---|
| Size | 31.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f2c2e366d80978681df9e1a729ca3ac5fc5521e3766948ba94d859826888bbd2
|
|
BLAKE2b-256 checksum How to use checksums |
48548d918d8de372c3378478b1ad19f0275d24cf879062dc84cd0b1c4674a25d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|