Catalog PyPI
PACKAGE EXPLORERView in registry

aeterna-di

PyPI

Explicit async dependency injection for aeterna

aeternaasyncdependencyframeworkinjection
Versions collected1
Direct dependencies0From release 1.0.0.dev1
Last observed20 Oct, 20:53 UTC

README

Version 1.0.0.dev1 documentation

Aeterna DI

aeterna-di is an explicit, annotation-driven asynchronous dependency-injection container. Applications compose a ServiceCollection, build a provider, and resolve services through that provider or an explicit scope.

Features

  • Register existing instances, implementation types, and synchronous or asynchronous factories.
  • Resolve constructor dependencies from type annotations.
  • Choose singleton, scoped, or transient lifetimes.
  • Validate duplicate registrations, missing services, dependency cycles, constructor annotations, and singleton graphs that capture scoped services.
  • Opt into ownership and close supported resources in reverse acquisition order.
  • Detect cross-task singleton cycles and report cleanup cancellation as a framework error.

Requirements

  • Python 3.12 or later.
  • No runtime dependencies outside the Python standard library.

Installation

With pip:

pip install aeterna-di

With uv:

uv add aeterna-di

Basic usage

Constructor dependencies must have resolvable type annotations. Resolution and provider cleanup are asynchronous.

import asyncio

from aeterna.di import ServiceCollection, ServiceLifetime


class Clock:
    def now(self) -> str:
        return "12:00"


class GreetingService:
    def __init__(self, clock: Clock) -> None:
        self._clock = clock

    def greet(self) -> str:
        return f"Hello at {self._clock.now()}"


async def main() -> None:
    services = ServiceCollection()
    services.add_type(Clock, lifetime=ServiceLifetime.SINGLETON)
    services.add_type(GreetingService)

    async with services.build_provider() as provider:
        greeting = await provider.get(GreetingService)
        print(greeting.greet())  # Hello at 12:00


asyncio.run(main())

Registration, scopes, and ownership

add_type() creates instances from annotated constructor dependencies. add_factory() and add_async_factory() receive a ServiceResolver; their optional dependencies=(...) sequence enables build-time validation of services the factory will resolve. Without that declaration, factory resolution failures are deferred until first use.

add_instance() registers an existing singleton. add_type() and factory registrations accept lifetime and owns_instance; ownership is opt-in. Owned singleton resources belong to the provider, owned scoped resources belong to their scope, and transient services may not be owned. Supported cleanup includes sync/async context management, close(), and aclose().

Scoped services require an explicit scope:

async with provider.create_scope() as scope:
    service = await scope.get(RequestService)

ServiceCollection is immutable after build_provider(). Provider and scope closing is idempotent and prevents new resolutions.

Public API

Classes, protocol, and enum:

  • ServiceCollection: mutable registration builder.
  • ServiceDescriptor: immutable description of one registration.
  • ServiceLifetime: SINGLETON, SCOPED, and TRANSIENT lifetime policies.
  • ServiceProvider: root resolver and singleton ownership boundary.
  • ServiceScope: scoped resolver and scoped ownership boundary.
  • ServiceResolver: protocol providing asynchronous get() and try_get() methods.

Exceptions:

  • ResolutionError: base class for service-resolution failures.
  • RegistrationError: an invalid registration or mutation after build.
  • MissingRegistrationError: no registration exists for a required service.
  • AmbiguousRegistrationError: more than one registration uses the same key.
  • CircularDependencyError: the dependency graph contains a cycle.
  • CaptiveDependencyError: a singleton graph depends on a scoped service.
  • ActivationError: a registered service could not be created.
  • ScopeClosedError: a provider or scope was used after it closed.
  • ServiceCancellationError: cleanup could not complete normally after cancellation.

Tests

From the repository root:

uv sync --locked
uv run pytest tests/test_di.py

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.0.0.dev120 Sept 20260

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
aochoae/aeterna

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 20:53 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:b307f469ab427434dbc5585bda9fb30030e4997fca40e664639be87be8cdd3e2