Dependency Injector 4.0-与其他Python框架的简化集成





哈Ha!我已经发布了依赖注入器的新的主要版本



此版本的主要功能是接线。它允许您注入函数和方法,而无需将其拖动到容器中。



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将收集模拟。



这项新功能使Dependency Injector与其他Python框架一起使用变得更加容易。



链接如何与其他框架集成?



不论应用程序的结构如何,绑定都能实现精确的注入。与版本3不同,依赖项注入不需要将函数或类拉入容器。



Flask示例:



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.flaskext.aiohttp倾向于捆绑。

使用时,框架将显示警告并建议切换到链接。



完整的更改列表可在此处找到



下一步是什么?






All Articles