af-di-core
A small, framework-agnostic dependency-injection framework for Python. Decorate your classes with @component, point the auto-discovery scanner at your package, and get a wired global container — no manual registration boilerplate. Works in a FastAPI app, a plain script, an AWS Lambda, or anywhere else.
Built on dependency-injector for the underlying provider machinery.
Installation
pip install af-di-core
# or with Poetry:
poetry add af-di-core
Quickstart
Mark the classes you want managed with @component (pairs naturally with @attrs.define):
import attrs
from allfly.di.core import component
@component
@attrs.define
class GreetingRepository:
def greeting(self) -> str:
return "hello"
@component
@attrs.define
class GreetingService:
_repo: GreetingRepository
def greet(self) -> str:
return self._repo.greeting()
At startup, scan your package once and then resolve anything:
from allfly.di.core import auto_discover_components, di_provide
auto_discover_components(base_package="myapp")
service = di_provide(GreetingService) # GreetingRepository injected automatically
service.greet()
Constructor dependencies are resolved from their type hints. Registration is multi-pass, so the order in which components are discovered does not matter. Parameters with default values are treated as optional and skipped, and an Optional[T] / T | None dependency is skipped when no provider for T exists.
How resolution works
auto_discover_components(base_package, registrars=None) runs in three steps:
@settingsfunctions are registered first as singletons (see below).registrars— optional callbacks for manual singletons that need special construction (e.g. third-party clients) — are invoked.@componentclasses are registered with multi-pass dependency resolution.
from allfly.di.core import auto_discover_components, di_register_singleton
def register_external_clients() -> None:
di_register_singleton(SomeClient, api_key="...")
auto_discover_components(base_package="myapp", registrars=[register_external_clients])
Settings providers
Use @settings on a function whose return type is the type to register. Combine with functools.lru_cache for single instantiation:
from functools import lru_cache
from allfly.di.core import settings
@settings
@lru_cache
def get_db_settings() -> DatabaseSettings:
return DatabaseSettings()
The returned instance is registered as a singleton keyed by the return annotation, so any @component depending on DatabaseSettings receives it.
Core providers (app-supplied)
af-di-core ships no opinionated providers — it is deliberately decoupled from databases, sessions, and web frameworks. Your application supplies its own "core" providers (things that must exist before anything is resolved, e.g. a DB session factory) by registering one or more callables on the container. They run once, lazily, the first time anything is provided:
from allfly.di.core import register_core_provider, di_register, di_provide
def register_db_providers() -> None:
di_register(DatabaseSettings, providers.Object(get_db_settings()))
di_register_singleton(SessionFactory, settings=get_provider(DatabaseSettings))
register_core_provider(register_db_providers)
# First di_provide(...) anywhere triggers ensure_core_providers() internally.
di_provide(SessionFactory)
You can also drive this explicitly via ensure_core_providers(). Initialization is guarded by a lock and a one-time flag, so it is safe to call repeatedly. Register core providers at startup, before the first di_provide.
Public API
from allfly.di.core import (
component, # class decorator → register for auto-discovery
settings, # function decorator → register a singleton by return type
auto_discover_components, # scan a package and wire the container
di_provide, # resolve an instance by type
di_register, # register a raw dependency-injector provider
di_register_factory, # register a Factory provider
di_register_singleton, # register a Singleton provider
get_provider, # get the provider (not the instance) for chaining
provider_exists, # check whether a type is registered
register_core_provider, # add an app-supplied core provider callable
ensure_core_providers, # run core providers once (called lazily by di_provide)
get_global_container, # the GlobalDependencyContainer singleton
dependency_container, # alias for the same singleton
GlobalDependencyContainer, # the container type
get_component_registry, # introspection: everything @component/@settings collected
analyze_component_dependencies, # introspection: a class's required constructor deps
providers, # re-export of dependency_injector.providers (Object/Factory/Singleton/Callable)
containers, # re-export of dependency_injector.containers
)
providers and containers are re-exported so consumers can build custom providers (e.g. providers.Object(instance)) without importing dependency-injector directly — this library is the single DI surface.
FastAPI
The framework intentionally does not import FastAPI. To expose a component to routes, write the small glue in your app:
from typing import Annotated
from fastapi import Depends, Request
from allfly.di.core import get_global_container
# Make the container available on app.state at startup:
# application.state.provide = get_global_container().provide
def build(request: Request) -> GreetingService:
return request.app.state.provide(GreetingService)
GreetingServiceDI = Annotated[GreetingService, Depends(build)]
Logging
The library logs through loguru (mostly at trace/debug). If your app does not configure loguru, these messages are simply silent by default at higher levels.
Metadata
Release files for af-di-core 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| af_di_core-0.0.3.tar.gz | 7.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| af_di_core-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 15.9 kB
Release files / af_di_core-0.0.3.tar.gz
| Download URL | af_di_core-0.0.3.tar.gz |
|---|---|
| Size | 7.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4a80df561dcddd30cd537801b0b0d0ef7430454dbec50674c710c674ac052672
|
|
BLAKE2b-256 checksum How to use checksums |
f14c33e1f06e0ca9ffb5a49fba73f032fdddbf5293b629ae8b781a197c9f02c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.
Transparency logRelease files / af_di_core-0.0.3-py3-none-any.whl
| Download URL | af_di_core-0.0.3-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dc812ca2b100cb9388ef15677291dee5f1bab8a4013ce28aa0ce898b379a43d6
|
|
BLAKE2b-256 checksum How to use checksums |
314982c4138e4b237b37bbf99aeba0559defc97e768a4d5d5f4c979a5b333aec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.
Transparency logSecurity for af-di-core 0.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for af_di_core-0.0.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.