Bonjour, Habr! J'ai publié une nouvelle version majeure de Dependency Injector .
La principale caractéristique de cette version est le câblage. Il vous permet d'injecter des fonctions et des méthodes sans les faire glisser dans un conteneur.
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() # <--
Lorsque la fonction est appelée, la
main()
dépendance Service
est collectée et transmise automatiquement.
Pendant le test, il est appelé
container.api_client.override()
pour remplacer le client API par un simulacre. Lorsqu'elle est appelée, la main()
dépendance Service
collectera des simulacres.
La nouvelle fonctionnalité simplifie l'utilisation de l'injecteur de dépendances avec d'autres frameworks Python.
Comment la liaison aide-t-elle à s'intégrer à d'autres cadres?
La liaison permet une injection précise quelle que soit la structure de l'application. Contrairement à la version 3, l'injection de dépendances ne nécessite pas l'extraction d'une fonction ou d'une classe dans un conteneur.
Exemple avec 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()
Autres exemples:
Comment fonctionne la reliure?
Pour appliquer la liaison, vous avez besoin:
- .
Provide[Container.bar]
. . - . container.wire(modules=[...], packages=[...]) , .
- . .
La reliure fonctionne sur la base de l'introspection. Lorsqu'il est appelé, le
container.wire(modules=[...], packages=[...])
framework passera en revue toutes les fonctions et méthodes de ces packages et modules et examinera leurs paramètres par défaut. Si le paramètre par défaut est un marqueur, une telle fonction ou méthode sera corrigée par le décorateur d'injection de dépendances. Ce décorateur, lorsqu'il est appelé, prépare et injecte des dépendances au lieu de marqueurs dans la fonction d'origine.
def foo(bar: Bar = Provide[Container.bar]):
...
container = Container()
container.wire(modules=[sys.modules[__name__]])
foo() # <--- "bar"
# :
foo(bar=container.bar())
En savoir plus sur les liens ici .
Compatibilité?
La version 4.0 est compatible avec les versions 3.x.
Les modules d'intégration
ext.flask
et sont ext.aiohttp
épinglés en faveur du regroupement.
Lorsqu'il est utilisé, le framework affichera un avertissement et recommandera de passer à la liaison.
Une liste complète des modifications peut être trouvée ici .
Et après?
- Découvrez le Github du projet
- Consultez la documentation