Use cases example

This example demonstrates a usage of the DependenciesContainer provider.

The source code is available on the Github.

Application structure

Example application has next structure:

./
└── example/
    ├── __init__.py
    ├── __main__.py
    ├── adapters.py
    ├── containers.py
    └── usecases.py

Containers

Listing of the example/containers.py:

"""Containers module."""

from dependency_injector import containers, providers

from . import adapters, usecases


class Adapters(containers.DeclarativeContainer):

    email_sender = providers.Singleton(adapters.SmtpEmailSender)


class TestAdapters(containers.DeclarativeContainer):

    email_sender = providers.Singleton(adapters.EchoEmailSender)


class UseCases(containers.DeclarativeContainer):

    adapters = providers.DependenciesContainer()

    signup = providers.Factory(
        usecases.SignupUseCase,
        email_sender=adapters.email_sender,
    )

Main module

Listing of the example/__main__.py:

"""Main module."""

import sys

from .containers import UseCases, Adapters, TestAdapters


def main(environment: str, email: str) -> None:
    if environment == "prod":
        adapters = Adapters()
    elif environment == "test":
        adapters = TestAdapters()
    else:
        raise RuntimeError("Unknown environment")

    use_cases = UseCases(adapters=adapters)

    use_case = use_cases.signup()
    use_case.execute(email)


if __name__ == "__main__":
    main(*sys.argv[1:])

Run the application

Instructions for running in the “test” mode:

python run.py test example@example.com

Instructions for running in the “prod” mode:

python run.py prod example@example.com

Adapters and use cases

Listing of the example/adapters.py:

"""Adapters module."""

import abc


class EmailSender(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def send(self, to: str, body: str) -> None:
        ...


class SmtpEmailSender:

    def send(self, to: str, body: str) -> None:
        print(f"Sending an email to {to} over SMTP, body=\"{body}\"")


class EchoEmailSender:

    def send(self, to: str, body: str) -> None:
        print(f"Fake sending an email to {to}, body=\"{body}\"")

Listing of the example/usecases.py:

"""Use cases module."""

import abc

from .adapters import EmailSender


class UseCase(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def execute(self) -> None:
        ...


class SignupUseCase:

    def __init__(self, email_sender: EmailSender) -> None:
        self.email_sender = email_sender

    def execute(self, email: str) -> None:
        print(f"Sign up user {email}")
        self.email_sender.send(email, f"Welcome, {email}")