mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-05 14:10:49 +03:00
Refactor multiple containers example
This commit is contained in:
parent
0f97fa4db8
commit
04f22e6152
29
examples/miniapps/services-multiple-containers/README.rst
Normal file
29
examples/miniapps/services-multiple-containers/README.rst
Normal file
|
@ -0,0 +1,29 @@
|
|||
Services mini application example (multiple containers)
|
||||
=======================================================
|
||||
|
||||
Create virtual env:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
|
||||
Install requirements:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
Run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python -m example user@example.com secret photo.jpg
|
||||
|
||||
You should see:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[2020-09-04 16:06:00,750] [DEBUG] [example.services.UserService]: User user@example.com has been found in database
|
||||
[2020-09-04 16:06:00,750] [DEBUG] [example.services.AuthService]: User user@example.com has been successfully authenticated
|
||||
[2020-09-04 16:06:00,750] [DEBUG] [example.services.PhotoService]: Photo photo.jpg has been successfully uploaded by user user@example.com
|
30
examples/miniapps/services-multiple-containers/config.yml
Normal file
30
examples/miniapps/services-multiple-containers/config.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
core:
|
||||
|
||||
logging:
|
||||
version: 1
|
||||
formatters:
|
||||
formatter:
|
||||
format: "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"
|
||||
handlers:
|
||||
console:
|
||||
class: "logging.StreamHandler"
|
||||
level: "DEBUG"
|
||||
formatter: "formatter"
|
||||
stream: "ext://sys.stderr"
|
||||
root:
|
||||
level: "DEBUG"
|
||||
handlers: ["console"]
|
||||
|
||||
gateways:
|
||||
|
||||
database:
|
||||
dsn: ":memory:"
|
||||
|
||||
aws:
|
||||
access_key_id: "KEY"
|
||||
secret_access_key: "SECRET"
|
||||
|
||||
services:
|
||||
|
||||
auth:
|
||||
token_ttl: 3600
|
|
@ -0,0 +1,24 @@
|
|||
"""Main module."""
|
||||
|
||||
import sys
|
||||
|
||||
from .containers import Application
|
||||
|
||||
|
||||
def main(email: str, password: str, photo: str) -> None:
|
||||
application = Application()
|
||||
|
||||
application.config.from_yaml('config.yml')
|
||||
application.core.configure_logging()
|
||||
|
||||
user_service = application.services.user()
|
||||
auth_service = application.services.auth()
|
||||
photo_service = application.services.photo()
|
||||
|
||||
user = user_service.get_user(email)
|
||||
auth_service.authenticate(user, password)
|
||||
photo_service.upload_photo(user, photo)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(*sys.argv[1:])
|
|
@ -0,0 +1,80 @@
|
|||
"""Containers module."""
|
||||
|
||||
import logging.config
|
||||
import sqlite3
|
||||
|
||||
import boto3
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
from . import services
|
||||
|
||||
|
||||
class Core(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
configure_logging = providers.Callable(
|
||||
logging.config.dictConfig,
|
||||
config=config.logging,
|
||||
)
|
||||
|
||||
|
||||
class Gateways(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
database_client = providers.Singleton(
|
||||
sqlite3.connect,
|
||||
config.database.dsn,
|
||||
)
|
||||
|
||||
s3_client = 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,
|
||||
)
|
||||
|
||||
|
||||
class Services(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
gateways = providers.DependenciesContainer()
|
||||
|
||||
user = providers.Factory(
|
||||
services.UserService,
|
||||
db=gateways.database_client,
|
||||
)
|
||||
|
||||
auth = providers.Factory(
|
||||
services.AuthService,
|
||||
db=gateways.database_client,
|
||||
token_ttl=config.auth.token_ttl.as_int(),
|
||||
)
|
||||
|
||||
photo = providers.Factory(
|
||||
services.PhotoService,
|
||||
db=gateways.database_client,
|
||||
s3=gateways.s3_client,
|
||||
)
|
||||
|
||||
|
||||
class Application(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
core = providers.Container(
|
||||
Core,
|
||||
config=config.core,
|
||||
)
|
||||
|
||||
gateways = providers.Container(
|
||||
Gateways,
|
||||
config=config.gateways,
|
||||
)
|
||||
|
||||
services = providers.Container(
|
||||
Services,
|
||||
config=config.services,
|
||||
gateways=gateways,
|
||||
)
|
|
@ -0,0 +1,56 @@
|
|||
"""Services module."""
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
from typing import Dict
|
||||
|
||||
from mypy_boto3_s3 import S3Client
|
||||
|
||||
|
||||
class BaseService:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.logger = logging.getLogger(
|
||||
f'{__name__}.{self.__class__.__name__}',
|
||||
)
|
||||
|
||||
|
||||
class UserService(BaseService):
|
||||
|
||||
def __init__(self, db: sqlite3.Connection) -> None:
|
||||
self.db = db
|
||||
super().__init__()
|
||||
|
||||
def get_user(self, email: str) -> Dict[str, str]:
|
||||
self.logger.debug('User %s has been found in database', email)
|
||||
return {'email': email, 'password_hash': '...'}
|
||||
|
||||
|
||||
class AuthService(BaseService):
|
||||
|
||||
def __init__(self, db: sqlite3.Connection, token_ttl: int) -> None:
|
||||
self.db = db
|
||||
self.token_ttl = token_ttl
|
||||
super().__init__()
|
||||
|
||||
def authenticate(self, user: Dict[str, str], password: str) -> None:
|
||||
assert password is not None
|
||||
self.logger.debug(
|
||||
'User %s has been successfully authenticated',
|
||||
user['email'],
|
||||
)
|
||||
|
||||
|
||||
class PhotoService(BaseService):
|
||||
|
||||
def __init__(self, db: sqlite3.Connection, s3: S3Client) -> None:
|
||||
self.db = db
|
||||
self.s3 = s3
|
||||
super().__init__()
|
||||
|
||||
def upload_photo(self, user: Dict[str, str], photo_path: str) -> None:
|
||||
self.logger.debug(
|
||||
'Photo %s has been successfully uploaded by user %s',
|
||||
photo_path,
|
||||
user['email'],
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
dependency-injector[yaml]
|
||||
boto3
|
||||
boto3-stubs[s3]
|
|
@ -1,8 +0,0 @@
|
|||
Dependency Injector IoC containers example
|
||||
==========================================
|
||||
|
||||
Instructions for running
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python run.py 1 secret photo.jpg
|
|
@ -1,58 +0,0 @@
|
|||
"""Example of dependency injection in Python."""
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
|
||||
import boto3
|
||||
|
||||
import example.main
|
||||
import example.services
|
||||
|
||||
import dependency_injector.containers as containers
|
||||
import dependency_injector.providers as providers
|
||||
|
||||
|
||||
class Core(containers.DeclarativeContainer):
|
||||
"""IoC container of core component providers."""
|
||||
|
||||
config = providers.Configuration('config')
|
||||
|
||||
logger = providers.Singleton(logging.Logger, name='example')
|
||||
|
||||
|
||||
class Gateways(containers.DeclarativeContainer):
|
||||
"""IoC container of gateway (API clients to remote services) providers."""
|
||||
|
||||
database = providers.Singleton(sqlite3.connect, Core.config.database.dsn)
|
||||
|
||||
s3 = providers.Singleton(
|
||||
boto3.client, 's3',
|
||||
aws_access_key_id=Core.config.aws.access_key_id,
|
||||
aws_secret_access_key=Core.config.aws.secret_access_key)
|
||||
|
||||
|
||||
class Services(containers.DeclarativeContainer):
|
||||
"""IoC container of business service providers."""
|
||||
|
||||
users = providers.Factory(example.services.UsersService,
|
||||
db=Gateways.database,
|
||||
logger=Core.logger)
|
||||
|
||||
auth = providers.Factory(example.services.AuthService,
|
||||
db=Gateways.database,
|
||||
logger=Core.logger,
|
||||
token_ttl=Core.config.auth.token_ttl)
|
||||
|
||||
photos = providers.Factory(example.services.PhotosService,
|
||||
db=Gateways.database,
|
||||
s3=Gateways.s3,
|
||||
logger=Core.logger)
|
||||
|
||||
|
||||
class Application(containers.DeclarativeContainer):
|
||||
"""IoC container of application component providers."""
|
||||
|
||||
main = providers.Callable(example.main.main,
|
||||
users_service=Services.users,
|
||||
auth_service=Services.auth,
|
||||
photos_service=Services.photos)
|
|
@ -1,8 +0,0 @@
|
|||
"""Example main module."""
|
||||
|
||||
|
||||
def main(uid, password, photo, users_service, auth_service, photos_service):
|
||||
"""Authenticate user and upload photo."""
|
||||
user = users_service.get_user_by_id(uid)
|
||||
auth_service.authenticate(user, password)
|
||||
photos_service.upload_photo(user['uid'], photo)
|
|
@ -1,50 +0,0 @@
|
|||
"""Example business services module."""
|
||||
|
||||
|
||||
class BaseService:
|
||||
"""Service base class."""
|
||||
|
||||
|
||||
class UsersService(BaseService):
|
||||
"""Users service."""
|
||||
|
||||
def __init__(self, logger, db):
|
||||
"""Initialize instance."""
|
||||
self.logger = logger
|
||||
self.db = db
|
||||
|
||||
def get_user_by_id(self, uid):
|
||||
"""Return user's data by identifier."""
|
||||
self.logger.debug('User %s has been found in database', uid)
|
||||
return dict(uid=uid, password_hash='secret_hash')
|
||||
|
||||
|
||||
class AuthService(BaseService):
|
||||
"""Authentication service."""
|
||||
|
||||
def __init__(self, logger, db, token_ttl):
|
||||
"""Initialize instance."""
|
||||
self.logger = logger
|
||||
self.db = db
|
||||
self.token_ttl = token_ttl
|
||||
|
||||
def authenticate(self, user, password):
|
||||
"""Authenticate user."""
|
||||
assert user['password_hash'] == '_'.join((password, 'hash'))
|
||||
self.logger.debug('User %s has been successfully authenticated',
|
||||
user['uid'])
|
||||
|
||||
|
||||
class PhotosService(BaseService):
|
||||
"""Photos service."""
|
||||
|
||||
def __init__(self, logger, db, s3):
|
||||
"""Initialize instance."""
|
||||
self.logger = logger
|
||||
self.db = db
|
||||
self.s3 = s3
|
||||
|
||||
def upload_photo(self, uid, photo_path):
|
||||
"""Upload user photo."""
|
||||
self.logger.debug('Photo %s has been successfully uploaded by user %s',
|
||||
photo_path, uid)
|
|
@ -1,20 +0,0 @@
|
|||
"""Run example application."""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from containers import Core, Application
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Configure platform:
|
||||
Core.config.override({'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'},
|
||||
'auth': {'token_ttl': 3600}})
|
||||
Core.logger().addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
# Run application:
|
||||
Application.main(uid=sys.argv[1],
|
||||
password=sys.argv[2],
|
||||
photo=sys.argv[3])
|
Loading…
Reference in New Issue
Block a user