Skip to main content

No project description provided

Project description

Async-first dependency injection library based on python type hints

Quickstart

First let's create a class we would be injecting:

class Service:
    pass

Then we should create instance of container and register Service class in it using a provider:

from aioinject import Container, providers

container = Container()
container.register(providers.Callable(Service))

Then we can create a context and resolve our Service class from it:

with container.sync_context() as ctx:
    service = ctx.resolve(Service)

If you need to inject something into a function just annotate it with inject:

from aioinject import inject


@inject
def awesome_function(service: Service):
    print(service)

And call it within an active context:

with container.sync_conext() as ctx:
    awesome_function()

Complete example (should run as-is):

from typing import Annotated

from aioinject import Container, Inject, inject, providers


class Service:
    pass


container = Container()
container.register(providers.Callable(Service))


@inject
def awesome_function(
    service: Service,
):
    print(service)


with container.sync_context() as ctx:
    service = ctx.resolve(Service)
    awesome_function()

Specifying Dependencies

To mark parameters for injection we can use typing.Annotated and Inject marker

from typing import Annotated
from aioinject import Callable, Container, Inject


class Session:
    pass


class Service:
    def __init__(self, session: Session):
        self.session = session


container = Container()
container.register(Callable(Session))
container.register(Callable(Service))

with container.sync_context() as ctx:
    service = ctx.resolve(Service)

If you have multiple dependencies with same type you can specify concrete implementation in Inject:

import dataclasses
from typing import Annotated

from aioinject import Container, providers, inject, Inject


@dataclasses.dataclass
class Client:
    name: str


def get_github_client() -> Client:
    return Client(name="GitHub Client")


def get_gitlab_client() -> Client:
    return Client(name="GitLab Client")


container = Container()
container.register(providers.Callable(get_github_client))
container.register(providers.Callable(get_gitlab_client))


@inject
def injectee(
    github_client: Annotated[Client, Inject(get_github_client)],
    gitlab_client: Annotated[Client, Inject(get_gitlab_client)],
):
    print(github_client, gitlab_client)


with container.sync_context() as ctx:
    # Manually resolving client
    client = ctx.resolve(Client, impl=get_github_client)
    print(client)
    injectee()

Working with Resources

Often you need to initialize and close a resource (file, database session, etc...), you can do that by using a contextmanager that would return your resource.
We would use custom Session class that defines __exit__ and __enter__ methods:

import contextlib

from aioinject import Container, providers


class Session:
    def __init__(self):
        self.closed = False

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.closed = True


@contextlib.contextmanager
def get_session() -> Session:
    with Session() as session:
        yield session


container = Container()
container.register(providers.Callable(get_session))

with container.sync_context() as ctx:
    session = ctx.resolve(Session)
    print(session.closed)
print(session.closed)  # <- Session.__exit__ would be called when context closes

Async Dependencies

You can register async resolvers the same way as you do with other dependencies, all you need to change is to use Container.context instead of Container.sync_context:

import asyncio

from aioinject import Container, providers


class Service:
    pass


async def get_service() -> Service:
    await asyncio.sleep(1)
    return Service()


async def main():
    container = Container()
    container.register(providers.Callable(get_service))

    async with container.context() as ctx:
        service = await ctx.resolve(Service)
        print(service)


if __name__ == '__main__':
    asyncio.run(main())

Providers

When creating a provider you should specify the type it returns, but it can be inferred from class type or function return type:

Callable

Callable provider would create instance of a class each time:

from aioinject import Callable


class Service:
    pass


provider = Callable(Service)
service_one = provider.provide_sync()
service_two = provider.provide_sync()
print(service_one is service_two)
# False

Singleton

Singleton works the same way as Callable but it caches first created object:

from aioinject import Singleton


class Service:
    pass


provider = Singleton(Service)
first = provider.provide_sync()
second = provider.provide_sync()
print(first is second)
# True

Object

Object provider just returns an object provided to it:

from aioinject import Object


class Service:
    pass


provider = Object(Service())
service = provider.provide_sync()
print(service)
# <__main__.Service>

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

aioinject-0.11.1.tar.gz (17.1 kB view details)

Uploaded Source

Built Distribution

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

aioinject-0.11.1-py3-none-any.whl (12.2 kB view details)

Uploaded Python 3

File details

Details for the file aioinject-0.11.1.tar.gz.

File metadata

  • Download URL: aioinject-0.11.1.tar.gz
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.8.2 CPython/3.10.7

File hashes

Hashes for aioinject-0.11.1.tar.gz
Algorithm Hash digest
SHA256 71c1970a94babf1bb51714d64aca9545641b03322040123858443cda06e48700
MD5 3079d08ccb5b42abd908b20391883890
BLAKE2b-256 89aca2a9fd5069e1af6b6b6994cf526c0a76ef7638c5254a9f6ea610d48e694b

See more details on using hashes here.

File details

Details for the file aioinject-0.11.1-py3-none-any.whl.

File metadata

  • Download URL: aioinject-0.11.1-py3-none-any.whl
  • Upload date:
  • Size: 12.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.8.2 CPython/3.10.7

File hashes

Hashes for aioinject-0.11.1-py3-none-any.whl
Algorithm Hash digest
SHA256 92b1039239f9ee050760556b3e68416ab024d220e3e0db4eaa00222d29cec714
MD5 23fd0215ea324656420bc1f1aa6e6092
BLAKE2b-256 76c18963184da781c18a1cb63fa1721de63c644128daa2ebf7d442bc4275d3fa

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