Skip to content

Basic example

This example shows how to build a simple application with AnyDI. The application has a User model, a UserRepository and UserService that depends on UserRepository instance and provides methods for creating and retrieving users.

Example application structure:

app/
  handlers.py
  main.py
  models.py
  modules.py
  repositories.py
  services.py

models.py

Defines the data model for the application - a simple User model with ID and email fields.

import uuid
from dataclasses import dataclass, field
from typing import NewType

UserId = NewType("UserId", uuid.UUID)


@dataclass(kw_only=True)
class User:
    id: UserId = field(default_factory=lambda: UserId(uuid.uuid4()))
    email: str

repositories.py

Defines the repository abstract class for User data access and manipulation. Includes an in-memory implementation of this class.

import abc

from app.models import User, UserId


class UserRepository(abc.ABC):
    @abc.abstractmethod
    def all(self) -> list[User]:
        pass

    @abc.abstractmethod
    def add(self, user: User) -> None:
        pass

    @abc.abstractmethod
    def get_by_email(self, email: str) -> User | None:
        pass


class InMemoryUserRepository(UserRepository):
    def __init__(self) -> None:
        self.data: dict[UserId, User] = {}

    def all(self) -> list[User]:
        return list(self.data.values())

    def add(self, user: User) -> None:
        self.data[user.id] = user

    def get_by_email(self, email: str) -> User | None:
        try:
            return [user for user in self.data.values() if user.email == email][0]
        except IndexError:
            return None

services.py

Defines the UserService class that provides business logic operations - retrieving all users, creating new users, and finding users by email.

from app.models import User
from app.repositories import UserRepository


class UserService:
    def __init__(self, user_repository: UserRepository) -> None:
        self.user_repository = user_repository

    def get_users(self) -> list[User]:
        return self.user_repository.all()

    def create_user(self, email: str) -> User:
        user = User(email=email)
        self.user_repository.add(user)
        return user

    def get_user(self, email: str) -> User | None:
        return self.user_repository.get_by_email(email)

modules.py

Defines dependency providers using the @provider decorator. The InMemoryUserRepository instance is registered and injected into UserService automatically.

from anydi import Module, provider

from app.repositories import InMemoryUserRepository, UserRepository
from app.services import UserService


class AppModule(Module):
    @provider(scope="singleton")
    def user_repository(self) -> UserRepository:
        return InMemoryUserRepository()

    @provider(scope="singleton")
    def user_service(self, user_repository: UserRepository) -> UserService:
        return UserService(user_repository=user_repository)

handlers.py

Defines handler functions that use injected UserService to perform operations - getting all users, creating users, and finding users by email.

from anydi import Inject, injectable

from app.models import User
from app.services import UserService


@injectable
def get_users(user_service: UserService = Inject()) -> list[User]:
    return user_service.get_users()


@injectable
def get_user(email: str, user_service: UserService = Inject()) -> User:
    user = user_service.get_user(email)
    if not user:
        raise Exception("User not found.")
    return user


@injectable
def create_user(email: str, user_service: UserService = Inject()) -> User:
    return user_service.create_user(email=email)

main.py

Creates the Container instance, scans for providers and handlers, starts the DI container, and runs tests to verify the application works correctly.

from anydi import Container

from app.modules import AppModule

container = Container(modules=[AppModule])
container.scan("app.handlers")
container.start()


def main() -> None:
    from app.handlers import create_user, get_user, get_users

    user = create_user(email="demo@mail.com")

    assert get_users() == [user]
    assert get_user(email="demo@mail.com") == user

    container.close()


if __name__ == "__main__":
    main()