Package: pythondi
pythondipythondi is a lightweight dependency injection library for pythonSupport both sync and async functionsInstallationpip3installpythondiUsageFirst, you have to binding classes to provider.frompythondiimportProviderprovider=Provider()provider.bind(Repo,SQLRepo)provider.bind(Usecase,CreateUsecase)After binding, you need to configure it to containerfrompythondiimportconfigure,configure_after_clear# Inject with configureconfigure(provider=provider)# Or if you want to fresh inject, use `configure_after_clear`configure_after_clear(provider=provider)Import injectfrompythondiimportinjectAdd type annotations that you want to inject dependenciesclassUsecase:def__init__(self,repo:Repo):self.repo=repoAdd decoratorclassUsecase:@inject()def__init__(self,repo:Repo):self.repo=repoInitialize class with no argumentsusecase=Usecase()Or, you can also inject manually through decorator argumentsclassUsecase:@inject(repo=SQLRepo)def__init__(self,repo):self.repo=repoIn this case, do not have to configure providers and type annotation.Lazy initializingfrompythondiimportProviderprovider=Provider()provider.bind(Repo,SQLRepo,lazy=True)You can use lazy initializing throughlazyoption. (defaultFalse)For singleton, uselazy=False.classUsecase:@inject(repo=SQLRepo)def__init__(self,repo):self.repo=repoBy default, manual injection is lazy. If you want a singleton, instantiate it likerepo=SQLRepo().For testIn case of test codes, you probably want to use mock objects.In that case, you must use keyword arguments.classMockRepo:pass@inject()deftest(repo:Repo):returnrepoYes:test(repo=MockRepo())No:test(MockRepo())test(MockRepo)NoteAt the moment of inject, class is automatically initialized.So you don't have to initialize your class inside of code.Yes:@inject()def__init__(self,repo:Repo):self.repo=repoNo:@inject()def__init__(self,repo:Repo):self.repo=repo()General exampleimportabcfrompythondiimportProvider,configure,configure_after_clear,injectclassRepo:"""Interface class"""__metaclass__=abc.ABCMeta@abc.abstractmethoddefget(self):passclassSQLRepo(Repo):"""Impl class"""defget(self):print('SQLRepo')classUsecase:@inject()def__init__(self,repo:Repo):self.repo=repoif__name__=='__main__':# Init providerprovider=Provider()# Bind `Impl` class to `Interface` classprovider.bind(Repo,SQLRepo)# Inject with configureconfigure(provider=provider)# Or if you want to fresh injection, use `configure_after_clear`configure_after_clear(provider=provider)# Init class without argumentsu=Usecase()FastAPI examplefromfastapiimportFastAPI,APIRouterfrompythondiimportProvider,configure,injectimportabcrouter=APIRouter()classRepo:"""Interface class"""__metaclass__=abc.ABCMeta@abc.abstractmethoddefget(self):passclassSQLRepo(Repo):"""Impl class"""def__init__(self):passdefget(self):print('SQLRepo')@router.route('/')defhome():usecase=Usecase()usecase.repo.get()return{'hello':'world'}classUsecase:@inject()def__init__(self,repo:Repo):self.repo=repodefcreate_app():provider=Provider()provider.bind(Repo,SQLRepo)configure(provider=provider)app=FastAPI()app.include_router(router)returnappif__name__=='__main__':app=create_app()app.run(debug=True)Flask examplefromflaskimportFlask,Blueprint,jsonifyfrompythondiimportProvider,configure,injectimportabcbp=Blueprint('home',__name__)classRepo:"""Interface class"""__metaclass__=abc.ABCMeta@abc.abstractmethoddefget(self):passclassSQLRepo(Repo):"""Impl class"""def__init__(self):passdefget(self):print('SQLRepo')@bp.route('/')defhome():usecase=Usecase()usecase.repo.get()returnjsonify({'hello':'world'})classUsecase:@inject()def__init__(self,repo:Repo):self.repo=repodefcreate_app():provider=Provider()provider.bind(Repo,SQLRepo)configure(provider=provider)app=Flask(__name__)app.register_blueprint(bp)returnappif__name__=='__main__':app=create_app()app.run(debug=True)Sanic exampleimportabcfromsanicimportSanic,Blueprintfromsanic.responseimportjsonfrompythondiimportProvider,configure,injectclassRepo:"""Interface class"""__metaclass__=abc.ABCMeta@abc.abstractmethoddefget(self):passclassSQLRepo(Repo):"""Impl class"""def__init__(self):passdefget(self):print('SQLRepo')bp=Blueprint('home',url_prefix='/')@bp.route('/')asyncdefhome(request):usecase=Usecase()usecase.repo.get()returnjson({'hello':'world'})classUsecase:@inject()def__init__(self,repo:Repo):self.repo=repodefcreate_app():provider=Provider()provider.bind(Repo,SQLRepo)configure(provider=provider)app=Sanic(__name__)app.blueprint(bp)returnappif__name__=='__main__':app=create_app()app.run(debug=True)Django example"""In case of django, just put the initializing code inside of django startupYou can use project folder's __init__.py or urls.py"""