DIとは
- Dependency Injectionの略称
- 日本語:依存性注入
- DIとは、プログラミングにおけるデザインパターン(設計思想)の一種で、オブジェクトを成立させるために必要となるコードを実行時に注入(Inject)してゆくという概念のことである。
python用DIライブラリ
-
python-dependency-injector Public
- ライセンス: BSD-3
- 最新バージョン: v4.41.0(2022.12)
-
- ライセンス: BSD-3
- 最新バージョン: v0.20.1(2022.08.17)
-
更新頻度より、今回はpython-dependency-injector Publicを利用する
導入してみる
コンポーネント構成
ファイル構成
./
├── example/
│ ├── __init__.py
│ ├── containers.py
│ ├── controller.py
│ └── api_view.py
├── datalayer.py
├── awslayer.py
├── config.ini
└── requirements.txt
コンテナー作成
"""Containers module."""
import logging.config
import sqlite3
import boto3
from dependency_injector import containers, providers
from . import Controller
class Container(containers.DeclarativeContainer):
config = providers.Configuration(ini_files=["config.ini"])
# Gateways
database_client = providers.Singleton(
sqlite3.connect,
config.database.dsn,
)
aws_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,
)
controller = providers.Factory(
Controller,
db = database_client,
s3 = aws_s3_client
)
コンテナー利用
api_view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from containers.py import Container
class Contents(APIView):
def get(self, request, **kwargs):
user = kwargs["user"]
container = Container()
content_controller = container.controller()
# userのコンテンツを取得
contents = content_controller.get_contents(user)
return Response(contents)
DI導入後の構成図
単体テストを書く
api_view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from controller.py import Controller
class Contents(APIView):
def get(self, request, **kwargs):
user = kwargs["user"]
content_controller = controller()
# userのコンテンツを取得
contents = content_controller.get_contents(user)
return Response(contents)
- DI導入前のコードに対して、content_controller = controller()をmockすることがとても難しい
- DI導入後は、controllerをoverrideしてmockすることが簡単
test_api_view.py
def test_view_get():
container = Container()
with container.controller.override(controller_mock):
api_view = Contents()
api_view.get()
課題
- container作成する時に、全てのconfig導入
- AWS Parameter Storeと環境変数と合わせて、config導入
- マルチコンテナー構成