Skip to main content

Simple dependency injection tool

Project description

yggsdrasyl

Simplistic, but totally explicit dependency injection tool. Main goal is to provide simple, but powerful API for registering dependencies by type and their extensible resolution mechanism in functions.

Why yggdrasyl? This is misspelling of yggdrasil - the ancient tree of life in Nordic / Scandinavian mythologies, that connects all the worlds, like DI Framework connects dependencies.

Usage

Main entry point to dependency management is class Dependencies. You can create your own instance, or use predefined global one - deps.

Dependency Registration

To register a dependency invoke method Dependencies.register:

from yggdrasyl import deps


deps.register(UserServiceConfig, lambda d: UserServiceConfig())
deps.register(UserService, lambda d: UserService(config=d.resolve(UserServiceConfig)))

Dependencies.register accepts accepts 2 required arguments:

  1. dependency type - identifier for dependency resolution
  2. factory function - function that accepts Dependencies object and returns dependency instance

Also there are multiple optional keyword-only arguments:

  1. cached - if True than dependency object is reused across all resolutions, True by default
  2. managed - if True than dependency object is managed by context manager and can be initialized with all the other dependencies
  3. override - if True than existing dependency with same type is overridden, False by default

For simplification of registering objects from instances one can use from_instance utility function. If one has factory function (for example class constructor) use from_factory.

from yggdrasyl import deps, from_instance, from_factory


deps.register(int, from_instance(1))
deps.register(IService, from_factory(Service))

If dependency type is already registered, then TypeAlreadyRegisteredError is raised.

Dependency Resolution

To resolve dependency invoke Dependencies.resolve method with single desired type argument:

from yggdrasyl import deps

user_service = deps.resolve(UserService)

If type is not registered, then TypeNotRegisteredError is raised.

Context Manager Dependencies

Some dependencies require being initialized on application startup. In order not to forget one and rule management from single place there is a managed parameter, that indicates that this dependency should be resolved on startup and is sync or async context manager, that should be initialized. By default it takes False meaning, that one must explicitly tell, that dependency is managed.

After marking only dependencies as managed just open Dependencies.initialize context and all the dependencies will be initialized at once. Basically this method should be used as lifespan for ASGI applications (for example).

from contextlib import asynccontextmanager

from fastapi import FastAPI
from yggdrasyl import deps


@asynccontextmanager
async def _lifespan(app: FastAPI):
    async with deps.initialize():
        yield

Dependency Wiring

In order not to call Dependencies.resolve manually for each dependency, there is a way to tell that some callable requires some dependencies via Dependencies.wire decorator:

from yggdrasyl import deps, Injected


@deps.wire
async def _handle_register_user(
    action: RegisterUser,
    user_service: UserService = Injected[UserService]
) -> UserID:
    ...

To mark argument to be injected from DI container one should use Injected object with wanted type in [].

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yggdrasyl-0.1.0.tar.gz (24.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yggdrasyl-0.1.0-py3-none-any.whl (5.1 kB view details)

Uploaded Python 3

File details

Details for the file yggdrasyl-0.1.0.tar.gz.

File metadata

  • Download URL: yggdrasyl-0.1.0.tar.gz
  • Upload date:
  • Size: 24.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","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}

File hashes

Hashes for yggdrasyl-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9139948d81523700a5a9bf244eeb512539d968b312a889b81d2d9436ad16ab0a
MD5 32f094ee120144db5ddf6b760a2a8038
BLAKE2b-256 0928f51ed86191a5643f7912d7f0196101b2ea433323b641b8a66b9e81e651fb

See more details on using hashes here.

File details

Details for the file yggdrasyl-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: yggdrasyl-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 5.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","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}

File hashes

Hashes for yggdrasyl-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a10e0642e9c30b52fff35e214a84ae57fb5b6be7c8b19c3f42a93912490abd9b
MD5 dc31b873bf3aa016c9be1dd3a059f389
BLAKE2b-256 435cacc2e216eb33aa97914e970724ef89fee6ab1a6a62c72175884b0be89bdd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page