Add container dependencies concept

This commit is contained in:
Roman Mogylatov 2017-12-20 12:25:46 +02:00
parent e4275c0f85
commit 6a64b6e297
11 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,45 @@
"""Containers module."""
import six
from dependency_injector import containers
from core import providers
class DeclarativeContainer(containers.DeclarativeContainer):
"""Declarative container."""
def __new__(cls, **dependencies):
"""Constructor.
:return: Dynamic container with copy of all providers.
:rtype: :py:class:`DynamicContainer`
"""
# Make copy of declarative container providers for container instance
container_providers = providers.deepcopy(cls.providers)
# Fetch container dependencies
container_dependencies = dict()
for name, provider in six.iteritems(container_providers):
if isinstance(provider, providers.Dependency):
container_dependencies[name] = provider
# Satisfy container dependencies
for name, dependency in six.iteritems(container_dependencies):
try:
dependency_provider = dependencies[name]
except KeyError:
raise Exception('Dependency {name} of container {container} '
'is not satisfied'.format(
name=name, container=cls))
else:
dependency.provided_by(dependency_provider)
# Create dynamic container
container = cls.instance_type()
container.provider_type = cls.provider_type
for name, provider in six.iteritems(container_providers):
setattr(container, name, provider)
return container

View File

@ -0,0 +1,18 @@
"""Providers module."""
from dependency_injector import providers
Factory = providers.Factory
Singleton = providers.Singleton
deepcopy = providers.deepcopy
class Dependency(providers.ExternalDependency):
"""Dependency provider."""
def __init__(self, type=object):
"""Initializer."""
super(Dependency, self).__init__(type)

View File

@ -0,0 +1,30 @@
"""Example applications."""
from core import containers, providers
from users import Users
from photos import Photos
class Core(containers.DeclarativeContainer):
"""Core container."""
pgsql = providers.Singleton(object)
s3 = providers.Singleton(object)
if __name__ == '__main__':
# Initializing containers
core = Core()
users = Users(database=core.pgsql)
photos = Photos(database=core.pgsql, 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.pgsql()

View File

@ -0,0 +1,20 @@
"""Photos package."""
from core import containers
from core import providers
from . import entities
from . import repositories
class Photos(containers.DeclarativeContainer):
"""Photos package 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

@ -0,0 +1,2 @@
class Photo(object):
pass

View File

@ -0,0 +1,6 @@
class PhotoRepository(object):
def __init__(self, object_factory, fs, db):
self.object_factory = object_factory
self.fs = fs
self.db = db

View File

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

View File

@ -0,0 +1,4 @@
class User(object):
def __init__(self, id):
self.id = id

View File

@ -0,0 +1,8 @@
class UserRepository(object):
def __init__(self, object_factory, db):
self.object_factory = object_factory
self.db = db
def get(self, id):
return self.object_factory(id=id)