Refactor bundles example app

This commit is contained in:
Roman Mogylatov 2020-09-06 14:12:34 -04:00
parent 94d500b0e2
commit 0754b38964
24 changed files with 200 additions and 122 deletions

View File

@ -1,8 +1,29 @@
Dependency Injector Bundles example
===================================
Bundles application example
===========================
Instructions for running
Create virtual env:
.. code-block:: bash
python run.py
python3 -m venv venv
. venv/bin/activate
Install requirements:
.. code-block:: bash
pip install -r requirements.txt
Run:
.. code-block:: bash
python -m bundles
You should see:
.. code-block:: bash
Retrieve user id=1, photos count=5
Retrieve user id=2, photos count=10
Aggregate analytics from user and photo bundles

View File

@ -1 +1 @@
"""Bundles package."""
"""Top-level package."""

View File

@ -0,0 +1,24 @@
"""Main module."""
from .containers import Application
if __name__ == '__main__':
application = Application()
application.config.from_ini('config.ini')
user_repository = application.user_bundle.user_repository()
photo_repository = application.photo_bundle.photo_repository()
user1 = user_repository.get(id=1)
user1_photos = photo_repository.get_photos(user1.id)
print(f'Retrieve user id={user1.id}, photos count={len(user1_photos)}')
user2 = user_repository.get(id=2)
user2_photos = photo_repository.get_photos(user2.id)
print(f'Retrieve user id={user2.id}, photos count={len(user2_photos)}')
aggregation_service = application.analytics_bundle.aggregation_service()
assert aggregation_service.user_repository is user_repository
assert aggregation_service.photo_repository is photo_repository
print('Aggregate analytics from user and photo bundles')

View File

@ -0,0 +1 @@
"""Analytics package."""

View File

@ -0,0 +1,17 @@
"""Analytics containers module."""
from dependency_injector import containers, providers
from . import services
class AnalyticsContainer(containers.DeclarativeContainer):
user_repository = providers.Dependency()
photo_repository = providers.Dependency()
aggregation_service = providers.Singleton(
services.AggregationService,
user_repository=user_repository,
photo_repository=photo_repository,
)

View File

@ -0,0 +1,8 @@
"""Analytics services module."""
class AggregationService:
def __init__(self, user_repository, photo_repository):
self.user_repository = user_repository
self.photo_repository = photo_repository

View File

@ -0,0 +1,41 @@
"""Containers module."""
import sqlite3
import boto3
from dependency_injector import containers, providers
from .user.containers import UserContainer
from .photo.containers import PhotoContainer
from .analytics.containers import AnalyticsContainer
class Application(containers.DeclarativeContainer):
config = providers.Configuration()
sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)
s3 = providers.Singleton(
boto3.client,
service_name='s3',
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key,
)
user_bundle = providers.Container(
UserContainer,
database=sqlite,
)
photo_bundle = providers.Container(
PhotoContainer,
database=sqlite,
file_storage=s3,
)
analytics_bundle = providers.Container(
AnalyticsContainer,
user_repository=user_bundle.user_repository,
photo_repository=photo_bundle.photo_repository,
)

View File

@ -0,0 +1 @@
"""Photo package."""

View File

@ -0,0 +1,20 @@
"""Photo containers module."""
from dependency_injector import containers, providers
from . import entities, repositories
class PhotoContainer(containers.DeclarativeContainer):
database = providers.Dependency()
file_storage = providers.Dependency()
photo = providers.Factory(entities.Photo)
photo_repository = providers.Singleton(
repositories.PhotoRepository,
entity_factory=photo.provider,
fs=file_storage,
db=database,
)

View File

@ -0,0 +1,5 @@
"""Photo entities module."""
class Photo:
...

View File

@ -0,0 +1,12 @@
"""Photo repositories module."""
class PhotoRepository:
def __init__(self, entity_factory, fs, db):
self.entity_factory = entity_factory
self.fs = fs
self.db = db
def get_photos(self, user_id):
return [self.entity_factory() for _ in range(user_id*5)]

View File

@ -1,20 +0,0 @@
"""Photos bundle."""
from dependency_injector import containers
from dependency_injector import providers
from . import entities
from . import repositories
class Photos(containers.DeclarativeContainer):
"""Photos bundle container."""
database = providers.Dependency()
file_storage = providers.Dependency()
photo = providers.Factory(entities.Photo)
photo_repository = providers.Singleton(repositories.PhotoRepository,
object_factory=photo.provider,
fs=file_storage,
db=database)

View File

@ -1,5 +0,0 @@
"""Photos bundle entities module."""
class Photo:
"""Photo entity."""

View File

@ -1,11 +0,0 @@
"""Photos bundle entity repositories module."""
class PhotoRepository:
"""Photo entity repository."""
def __init__(self, object_factory, fs, db):
"""Initialize instance."""
self.object_factory = object_factory
self.fs = fs
self.db = db

View File

@ -0,0 +1 @@
"""User package."""

View File

@ -0,0 +1,18 @@
"""User containers module."""
from dependency_injector import containers, providers
from . import entities, repositories
class UserContainer(containers.DeclarativeContainer):
database = providers.Dependency()
user = providers.Factory(entities.User)
user_repository = providers.Singleton(
repositories.UserRepository,
entity_factory=user.provider,
db=database,
)

View File

@ -0,0 +1,7 @@
"""User entities module."""
class User:
def __init__(self, id):
self.id = id

View File

@ -0,0 +1,11 @@
"""User repositories module."""
class UserRepository:
def __init__(self, entity_factory, db):
self.entity_factory = entity_factory
self.db = db
def get(self, id):
return self.entity_factory(id=id)

View File

@ -1,18 +0,0 @@
"""Users bundle."""
from dependency_injector import containers
from dependency_injector import providers
from . import entities
from . import repositories
class Users(containers.DeclarativeContainer):
"""Users bundle container."""
database = providers.Dependency()
user = providers.Factory(entities.User)
user_repository = providers.Singleton(repositories.UserRepository,
object_factory=user.provider,
db=database)

View File

@ -1,9 +0,0 @@
"""Users bundle entities module."""
class User:
"""User entity."""
def __init__(self, id):
"""Initialize instance."""
self.id = id

View File

@ -1,14 +0,0 @@
"""Users bundle entity repositories module."""
class UserRepository:
"""User entity repository."""
def __init__(self, object_factory, db):
"""Initialize instance."""
self.object_factory = object_factory
self.db = db
def get(self, id):
"""Return user entity with given identifier."""
return self.object_factory(id=id)

View File

@ -0,0 +1,6 @@
[database]
dsn=:memory:
[aws]
access_key_id=KEY
secret_access_key=SECRET

View File

@ -0,0 +1,2 @@
dependency-injector
boto3

View File

@ -1,40 +0,0 @@
"""Run 'Bundles' example application."""
import sqlite3
import boto3
from dependency_injector import containers
from dependency_injector import providers
from bundles.users import Users
from bundles.photos import Photos
class Core(containers.DeclarativeContainer):
"""Core container."""
config = providers.Configuration('config')
sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)
s3 = providers.Singleton(
boto3.client, 's3',
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key)
if __name__ == '__main__':
# Initializing containers
core = Core(config={'database': {'dsn': ':memory:'},
'aws': {'access_key_id': 'KEY',
'secret_access_key': 'SECRET'}})
users = Users(database=core.sqlite)
photos = Photos(database=core.sqlite, file_storage=core.s3)
# Fetching few users
user_repository = users.user_repository()
user1 = user_repository.get(id=1)
user2 = user_repository.get(id=2)
# Making some checks
assert user1.id == 1
assert user2.id == 2
assert user_repository.db is core.sqlite()