こんにちは、Habr!DependencyInjectorの新しいメジャーバージョンをリリースしました。
このバージョンの主な機能は配線です。これにより、関数とメソッドをコンテナーにドラッグせずに挿入できます。
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
api_client = providers.Singleton(
ApiClient,
api_key=config.api_key,
timeout=config.timeout.as_int(),
)
service = providers.Factory(
Service,
api_client=api_client,
)
def main(service: Service = Provide[Container.service]):
...
if __name__ == '__main__':
container = Container()
container.config.api_key.from_env('API_KEY')
container.config.timeout.from_env('TIMEOUT')
container.wire(modules=[sys.modules[__name__]])
main() # <--
with container.api_client.override(mock.Mock()):
main() # <--
関数が呼び出されると、
main()依存関係Serviceが収集され、自動的に渡されます。
テスト中に
container.api_client.override()、APIクライアントをモックに置き換えるために呼び出されます。呼び出されると、main()依存関係Serviceはモックを収集します。
この新機能により、他のPythonフレームワークでDependencyInjectorを簡単に使用できるようになります。
リンクは他のフレームワークとの統合にどのように役立ちますか?
バインディングにより、アプリケーションの構造に関係なく、正確な注入が可能になります。バージョン3とは異なり、依存関係の挿入では、関数またはクラスをコンテナーにプルする必要はありません。
フラスコの例:
import sys
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide
from flask import Flask, json
class Service:
...
class Container(containers.DeclarativeContainer):
service = providers.Factory(Service)
def index_view(service: Service = Provide[Container.service]) -> str:
return json.dumps({'service_id': id(service)})
if __name__ == '__main__':
container = Container()
container.wire(modules=[sys.modules[__name__]])
app = Flask(__name__)
app.add_url_rule('/', 'index', index_view)
app.run()
その他の例:
バインディングはどのように機能しますか?
バインディングを適用するには、次のものが必要です。
- コードにマーカーを配置します。ビューマーカーは
Provide[Container.bar]、関数またはメソッド引数のデフォルト値として指定されます。何をどこに埋め込むかを示すためにマーカーが必要です。 - コンテナをコード内のマーカーに関連付けます。これを行うには、container.wire(modules = [...]、packages = [...])メソッドを呼び出して、マーカーを持つモジュールまたはパッケージを指定する必要があります。
- 通常どおり関数とメソッドを使用します。フレームワークは、必要な依存関係を自動的に準備して挿入します。
バインディングは、イントロスペクションに基づいて機能します。呼び出されると、
container.wire(modules=[...], packages=[...])フレームワークはこれらのパッケージとモジュールのすべての関数とメソッドを調べ、それらのデフォルトのパラメーターを調べます。デフォルトのパラメータがマーカーの場合、そのような関数またはメソッドは、依存関係インジェクションデコレータによってパッチが適用されます。このデコレータは、呼び出されると、マーカーの代わりに依存関係を準備して元の関数に挿入します。
def foo(bar: Bar = Provide[Container.bar]):
...
container = Container()
container.wire(modules=[sys.modules[__name__]])
foo() # <--- "bar"
# :
foo(bar=container.bar())
リンクの詳細については、こちらをご覧ください。
互換性?
バージョン4.0はバージョン3.xと互換性があります。
統合モジュール
ext.flaskとはext.aiohttp、バンドルを優先して固定されています。
フレームワークを使用すると、警告が表示され、リンクへの切り替えが推奨されます。
変更の完全なリストはここにあります。
次は何ですか?
- プロジェクトのGithubをチェックしてください
- ドキュメントをチェックしてください