前提・実現したいこと
Flask-Injectorを使用してDIをしたいんですが、うまくDIされていなくて困っています。誰かお助けください(python初心者なので、もしかしたら超初歩的なミスをしてるかもしれません)
発生している問題・エラーメッセージ
TypeError: __init__() missing 1 required positional argument: 'make_answer_usecase'
ディレクトリ構成
$ tree . . ├── README.md ├── __init__.py ├── __pycache__ │ └── __init__.cpython-38.pyc ├── adopter │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-38.pyc │ ├── controller │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ ├── controller_interface.cpython-38.pyc │ │ │ └── line_webhook_controller.cpython-38.pyc │ │ ├── controller_interface.py │ │ └── line_webhook_controller.py │ ├── gateway │ │ ├── __init__.py │ │ └── __pycache__ │ │ └── __init__.cpython-38.pyc │ └── presenter │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── line_presenter.cpython-38.pyc │ └── line_presenter.py ├── app.yaml ├── domain │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── corona_data.cpython-38.pyc │ └── corona_data.py ├── drivers │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-38.pyc │ └── repositories │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── datastore.cpython-38.pyc │ └── datastore.py ├── helper │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ ├── config.cpython-38.pyc │ │ ├── di_container.cpython-38.pyc │ │ ├── logging.cpython-38.pyc │ │ └── singleton.cpython-38.pyc │ ├── config.py │ ├── di_container.py │ ├── logging.py │ └── singleton.py ├── main.py ├── make_env.sh ├── requirements.txt └── usecase ├── __init__.py ├── __pycache__ │ └── __init__.cpython-38.pyc ├── impl │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── make_answer_usecase.cpython-38.pyc │ └── make_answer_usecase.py └── interfaces ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-38.pyc │ ├── corona_data_repository.cpython-38.pyc │ ├── make_answer_input_port.cpython-38.pyc │ └── make_answer_presenter.cpython-38.pyc ├── corona_data_repository.py ├── make_answer_input_port.py └── make_answer_presenter.py
該当のソースコード
main.py
python
1import logging 2 3from flask import Flask, request 4from flask_injector import FlaskInjector 5from flask.views import View 6from injector import inject 7from linebot import ( 8 LineBotApi, 9 WebhookHandler 10) 11from linebot.exceptions import ( 12 InvalidSignatureError 13) 14from linebot.models import ( 15 MessageEvent, TextMessage 16) 17 18from helper import logging 19from helper import di_container 20from helper.config import Config 21from usecase.impl import make_answer_usecase 22from adopter.controller import line_webhook_controller 23 24 25 26app = Flask(__name__) 27 28logging.logging_config() 29c = Config() 30 31line_bot_api = LineBotApi(c.LINE_ACCESS_TOKEN) 32handler = WebhookHandler(c.LINE_CHANNEL_SECRET) 33 34 35@app.route("/callback", methods=['POST']) 36def callback(): 37 38 # get X-Line-Signature header value 39 signature = request.headers['X-Line-Signature'] 40 41 # get request body as text 42 body = request.get_data(as_text=True) 43 44 # handle webhook body 45 try: 46 handler.handle(body, signature) 47 except InvalidSignatureError: 48 print("Invalid signature. Please check your channel access token/channel secret.") 49 abort(400) 50 51 return 'OK' 52 53 54@handler.add(MessageEvent, message=TextMessage) 55def handle_message(event): 56 FlaskInjector(app=app, modules=[di_container.configure]) 57 lwc = line_webhook_controller.LineWebhookController() 58 c.REPLY_TOKEN = event.reply_token 59 lwc.serve(message=event.message.text) 60 61 62if __name__ == "__main__": 63 app.run(debug=c.DEBUG) 64
adopter.controller.line_webhook_controller.py
python
1from injector import inject 2from flask.views import View 3 4import sys 5sys.path.append('../../') 6from usecase.interfaces.make_answer_input_port import MakeAnswerInputPortInterface 7from helper.config import Config 8from adopter.controller.controller_interface import ControllerInterface 9 10class LineWebhookController(View, ControllerInterface): 11 @inject 12 def __init__(self, make_answer_usecase: MakeAnswerInputPortInterface): 13 self.make_answer_usecase = make_answer_usecase 14 15 def serve(self, message) -> str: 16 self.make_answer_usecase.make_answer(message)
usecase.impl.make_answer_usecase
python
1from datetime import datetime 2 3from injector import inject 4from jp_pref import prefecture 5from flask.views import View 6 7import sys 8sys.path.append('../../') 9from usecase.interfaces.corona_data_repository import CoronaDataRepositoryInterface 10from usecase.interfaces.make_answer_presenter import MakeAnswerPresenterInterface 11from domain import corona_data 12 13 14class MakeAnswerUseCase(View): 15 @inject 16 def __init__(self, repo: CoronaDataRepositoryInterface, presenter: MakeAnswerPresenterInterface): 17 """ 18 :param repo: 19 repoはコロナのデータが格納されているレポジトリ。 20 """ 21 self.repo = repo 22 self.presenter = presenter 23
helper.di_container.py
import sys sys.path.append("../") from usecase.interfaces.make_answer_input_port import MakeAnswerInputPortInterface from usecase.interfaces.make_answer_presenter import MakeAnswerPresenterInterface from usecase.interfaces.corona_data_repository import CoronaDataRepositoryInterface from usecase.impl.make_answer_usecase import MakeAnswerUseCase from drivers.repositories.datastore import DatastoreRepository from adopter.presenter.line_presenter import LinePresenter from adopter.controller.controller_interface import ControllerInterface from adopter.controller.line_webhook_controller import LineWebhookController from adopter.controller.line_webhook_controller import MockController # DIの設定はここに集約している。使用する実装クラスを変更する場合はここを変える。 def configure(binder) -> None: # Controllerが持つUsecaseの設定 binder.bind(MakeAnswerInputPortInterface, to=MakeAnswerUseCase, scope=request) # Usecaseが持つPresenterの設定 binder.bind(MakeAnswerPresenterInterface, to=LinePresenter) # Usecaseが持つRepositoryの設定 binder.bind(CoronaDataRepositoryInterface, to=DatastoreRepository)
試したこと
Flask-Injectorのドキュメント(https://pypi.org/project/Flask-Injector/)に、
# Initialize Flask-Injector. This needs to be run *after* you attached all # views, handlers, context processors and template globals. FlaskInjector(app=app, modules=[configure])
とあったので、inject
したいクラスが入ってるパッケージを全てmain.py
のなかでインポートして、FlaskInjector(...)
より先に持ってきました。でも無理でした。
補足情報(FW/ツールのバージョンなど)
Flask-Injector == 0.12.3
python == 3.8.5
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。