Skip to main content

Container for the Dependency Injection in Python.

Project description

Python Dependency Injection library

PyPI version PyPIDownloads CI

aiodi is a modern Python Dependency Injection library that allows you to standardize and centralize the way objects are constructed in your application highly inspired on PHP Symfony's DependencyInjection Component.

Key Features:

  • Native-based: Implements PEP 621 storing project metadata in pyproject.toml.
  • Dual mode: Setting dependencies using Python and using configuration files.
  • Clean: Wherever you want just use it, no more decorators and defaults everywhere.

Installation

Use the package manager pip to install aiodi.

pip install aiodi

Documentation

Usage

with Configuration Files

# sample/pyproject.toml

[tool.aiodi.variables]
name = "%env(str:APP_NAME, 'sample')%"
version = "%env(int:APP_VERSION, '1')%"
log_level = "%env(APP_LEVEL, 'INFO')%"
debug = "%env(bool:int:APP_DEBUG, '0')%"
text = "Hello World"

[tool.aiodi.services."_defaults"]
project_dir = "../../.."

[tool.aiodi.services."logging.Logger"]
class = "sample.libs.utils.get_simple_logger"
arguments = { name = "%var(name)%", level = "%var(log_level)%" }

[tool.aiodi.services."UserLogger"]
type = "sample.libs.users.infrastructure.in_memory_user_logger.InMemoryUserLogger"
arguments = { commands = "@logging.Logger" }

[tool.aiodi.services."*"]
_defaults = { autoregistration = { resource = "sample/libs/*", exclude = "sample/libs/users/{domain,infrastructure/in_memory_user_logger.py,infrastructure/*command.py}" } }
# sample/apps/settings.py

from typing import Optional
from aiodi import Container, ContainerBuilder

def container(filename: str, cwd: Optional[str] = None) -> Container:
    return ContainerBuilder(filenames=[filename], cwd=cwd).load()
# sample/apps/cli/main.py

from sample.apps.settings import container
from logging import Logger

def main() -> None:
    di = container(filename='../../pyproject.toml')

    di.get(Logger).info('Just simple call get with the type')
    di.get('UserLogger').logger().info('Just simple call get with the service name')

with Python

from abc import ABC, abstractmethod
from logging import Logger, getLogger, NOTSET, StreamHandler, Formatter
from os import getenv

from aiodi import Container
from typing import Optional, Union

_CONTAINER: Optional[Container] = None


def get_simple_logger(
        name: Optional[str] = None,
        level: Union[str, int] = NOTSET,
        fmt: str = '[%(asctime)s] - %(name)s - %(levelname)s - %(message)s',
) -> Logger:
    logger = getLogger(name)
    logger.setLevel(level)
    handler = StreamHandler()
    handler.setLevel(level)
    formatter = Formatter(fmt)
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    return logger


class GreetTo(ABC):
    @abstractmethod
    def __call__(self, who: str) -> None:
        pass


class GreetToWithPrint(GreetTo):
    def __call__(self, who: str) -> None:
        print('Hello ' + who)


class GreetToWithLogger(GreetTo):
    _logger: Logger

    def __init__(self, logger: Logger) -> None:
        self._logger = logger

    def __call__(self, who: str) -> None:
        self._logger.info('Hello ' + who)


def container() -> Container:
    global _CONTAINER
    if _CONTAINER:
        return _CONTAINER
    di = Container({'env': {
        'name': getenv('APP_NAME', 'aiodi'),
        'log_level': getenv('APP_LEVEL', 'INFO'),
    }})
    di.resolve([
        (
            Logger,
            get_simple_logger,
            {
                'name': di.resolve_parameter(lambda di_: di_.get('env.name', typ=str)),
                'level': di.resolve_parameter(lambda di_: di_.get('env.log_level', typ=str)),
            },
        ),
        (GreetTo, GreetToWithLogger),  # -> (GreetTo, GreetToWithLogger, {})
        GreetToWithPrint,  # -> (GreetToWithPrint, GreetToWithPrint, {})
    ])
    di.set('who', 'World!')
    # ...
    _CONTAINER = di
    return di


def main() -> None:
    di = container()

    di.get(Logger).info('Just simple call get with the type')

    for greet_to in di.get(GreetTo, instance_of=True):
        greet_to(di.get('who'))


if __name__ == '__main__':
    main()

Requirements

  • Python >= 3.9

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT

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

aiodi-1.2.0.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

aiodi-1.2.0-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file aiodi-1.2.0.tar.gz.

File metadata

  • Download URL: aiodi-1.2.0.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0rc2

File hashes

Hashes for aiodi-1.2.0.tar.gz
Algorithm Hash digest
SHA256 0624fcd581d36f1b300925f162401b18dc3cb3ef8300f0112be0dbf90413ef4a
MD5 7b1ec336e87d0ed1e913c29b6e74def6
BLAKE2b-256 8ae9c1597788cee91ce0104f3fe71e79d68260ed1fa143c6ebbf1a0802ce0c22

See more details on using hashes here.

File details

Details for the file aiodi-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: aiodi-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 19.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0rc2

File hashes

Hashes for aiodi-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a9b57612178ec13cf74ddd92c6125445bcfdc1aa588240535b7dcaa9e53bcc01
MD5 2017cceaf774a0388ddfa6e76298215c
BLAKE2b-256 613768a091f5d9c803b5a055b1124d48cbb9a6ce6aac55bf2628b0663ae4f528

See more details on using hashes here.

Supported by

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