Basic example
In this example, we are creating a simple application using AnyDI
. The application has a User
model, a UserRepository
and UserService
that takes an instance of UserRepository as a dependency and provides methods for creating and retrieving users.
Here an example app structure:
app/
handlers.py
main.py
models.py
modules.py
repositories.py
services.py
models.py
Defines the data model used in the application, in this case just a simple User model.
from typing import NewType
import uuid
from dataclasses import dataclass, field
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 interface for a UserRepository, which is responsible for accessing and manipulating the User data. It also provides an implementation of this interface using an in-memory data store.
import abc
from typing import Dict, List, Optional
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) -> Optional[User]:
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) -> Optional[User]:
try:
return [user for user in self.data.values() if user.email == email][0]
except IndexError:
return None
services.py
Defines a UserService class that provides higher-level operations on the User data, such as retrieving all users, creating new users, and retrieving a user by their email address.
from dataclasses import dataclass
from typing import List, Optional
from app.models import User
from app.repositories import UserRepository
@dataclass
class UserService:
user_repository: UserRepository
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) -> Optional[User]:
return self.user_repository.get_by_email(email)
modules.py
Defines two providers using AnyDI's @provider decorator. The first provider creates an instance of the InMemoryUserRepository class, which is then injected into the UserService provider when it is created.
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 several handlers that use the UserService instance to perform operations on the User data, such as retrieving all users, creating a new user, and retrieving a user by their email address.
from typing import List
from anydi import auto, injectable
from app.models import User
from app.services import UserService
@injectable
def get_users(user_service: UserService = auto) -> List[User]:
return user_service.get_users()
@injectable
def get_user(email: str, user_service: UserService = auto) -> 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 = auto) -> User:
return user_service.create_user(email=email)
main.py
Creates an instance of the AnyDI class, scans for providers and request handlers, starts the dependency injection container, and runs a small test suite to ensure that everything is working 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()