Olá, Habr! Eu lancei uma nova versão principal do Dependency Injector .
A principal característica desta versão é a fiação. Ele permite que você injete funções e métodos sem arrastá-los para um contêiner.
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() # <--
Quando a função é chamada, a
main()
dependência Service
é coletada e passada automaticamente.
Durante o teste, ele é chamado
container.api_client.override()
para substituir o cliente API por uma simulação. Quando chamada, a main()
dependência Service
coletará simulação.
O novo recurso simplifica o uso do Dependency Injector com outras estruturas Python.
Como a vinculação ajuda a se integrar a outras estruturas?
A vinculação permite a injeção precisa, independentemente da estrutura do aplicativo. Ao contrário da versão 3, a injeção de dependência não requer puxar uma função ou classe em um contêiner.
Exemplo com 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()
Outros exemplos:
- Django
- Frasco (exemplo expandido)
- Aiohttp
- Sanic
Como funciona a ligação?
Para aplicar a vinculação, você precisa:
- .
Provide[Container.bar]
. . - . container.wire(modules=[...], packages=[...]) , .
- . .
A vinculação funciona com base na introspecção. Quando chamado, o
container.wire(modules=[...], packages=[...])
framework percorrerá todas as funções e métodos nesses pacotes e módulos e examinará seus parâmetros padrão. Se o parâmetro padrão for um marcador, essa função ou método será corrigido pelo decorador de injeção de dependência. Este decorador, quando chamado, prepara e injeta dependências em vez de marcadores na função original.
def foo(bar: Bar = Provide[Container.bar]):
...
container = Container()
container.wire(modules=[sys.modules[__name__]])
foo() # <--- "bar"
# :
foo(bar=container.bar())
Saiba mais sobre vinculação aqui .
Compatibilidade?
A versão 4.0 é compatível com as versões 3.x.
Módulos de integração
ext.flask
e são ext.aiohttp
fixados em favor do empacotamento.
Quando usada, a estrutura exibirá um aviso e recomendará a mudança para a vinculação.
Uma lista completa de mudanças pode ser encontrada aqui .
Qual é o próximo?
- Confira o Github do projeto
- Confira a documentação