Package: hexdi
hexdiHighly extensible Dependency Injection framework for humansProject location:https://github.com/zibertscrem/hexdiInstallationpipinstallhexdiYoushouldhave python 3.5.* or higherUsageAll of that usages you can find inexamplesdirectoryQuick usage referenceimporthexdiclassSomeA:deffoo(self):pass# mark that class as injectable with permanent lifetime for class SomeA@hexdi.permanent(SomeA)classSomeAimplementation(SomeA):deffoo(self):return42# inject instance of SomeA as a first argument@hexdi.inject(SomeA)deftest_injection(a:SomeA):print('test_injection:',a.foo())classClassWithDependency:# constructor injection@hexdi.inject(SomeA)def__init__(self,a:SomeA):print('ClassWithDependency.__init__:',a.foo())# after that we can use property like an instance of SomeA class@property@hexdi.dependency(SomeA)defsome_a(self)->SomeA:passdeffoo(self):print('ClassWithDependency.foo:',self.some_a.foo())# method injection also works fine.# Because injection members are passing after all transmitted positional arguments@hexdi.inject(SomeA)deffoo_with_injection(self,a:SomeA):print('ClassWithDependency.foo_with_injection:',a.foo())if__name__=='__main__':# You don't need to provide any argument. DI container does it self# There also should not be cycle dependencies due to lazy loading of any injectionstest_injection()# prints: test_injection: 42cwd=ClassWithDependency()# prints: ClassWithDependency.__init__: 42cwd.foo()# prints: ClassWithDependency.foo: 42cwd.foo_with_injection()# prints: ClassWithDependency.foo_with_injection: 42Self-bindingimporthexdi@hexdi.permanent()classSomeA:deffoo(self):return42@hexdi.inject(SomeA)deftest(a):print(a.foo())if__name__=='__main__':test()# prints: 42Multiple injection argumentsimporthexdi@hexdi.permanent()classSomeA:deffoo(self):return42@hexdi.permanent()classSomeB:deffoo(self):return69@hexdi.inject(SomeA,SomeB)deftest(a,b):print(a.foo()+b.foo())if__name__=='__main__':test()# prints: 111Permanent lifetime and transient lifetimeimporthexdi@hexdi.permanent()classSomeA:NUMBER=0def__init__(self):self.num=SomeA.NUMBERSomeA.NUMBER+=1deffoo(self):print(self.__class__.__name__,self.num)@hexdi.transient()classSomeB:NUMBER=0def__init__(self):self.num=SomeB.NUMBERSomeB.NUMBER+=1deffoo(self):print(self.__class__.__name__,self.num)@hexdi.inject(SomeA)deftest_a(a):a.foo()@hexdi.inject(SomeB)deftest_b(b):b.foo()if__name__=='__main__':test_a()# prints: SomeA 0test_a()# prints: SomeA 0test_a()# prints: SomeA 0test_b()# prints: SomeB 0test_b()# prints: SomeB 1test_b()# prints: SomeB 2Usage of container. Demonstration of lazy injectionimporthexdiclassSomeA:deffoo(self):passclassSomeAImplementation(SomeA):deffoo(self):return42@hexdi.permanent()classSomeB:deffoo(self):return69classSomeC:deffoo(self):return100500@hexdi.inject(SomeC)deftest(c):print(c.foo())if__name__=='__main__':# getting of containercontainer=hexdi.get_root_container()# binding SomeAImplementation on SomeA type with permanent lifetimecontainer.bind_type(SomeAImplementation,SomeA,hexdi.lifetime.PermanentLifeTimeManager)instance=container.resolve(SomeA)print(instance.foo())# prints: 42# resolve decorator-binded SomeBinstance=container.resolve(SomeB)print(instance.foo())# prints: 69# bind SomeC on itself with permanent lifetimecontainer.bind_type(SomeC,SomeC,hexdi.lifetime.PermanentLifeTimeManager)# we mark SomeC for injection above in test func,# but all works fine, because it is lazy injectiontest()# prints: 100500Multifile projectIf you have a project with separated base objects(to registration) and
implementations(to injecting) there will be problematically to identify
these implementations if you import it nowhere. For that situation,
there is a class loading abstraction with a basic implementation that
gets a list ofspecificationobjects with implementation modules.
These specification object can be: - dot-separated module path as
string: ‘pack1.pack2.module1’ - a function/lambda without params that
returns aspecification- a tuple that contains a function as a
first argument and tuple of values as a second argument. Function should
return aspecificationimporthexdifromexamples.multifile.interfacesimportSomeAloader=hexdi.get_loader(['examples.multifile.implementations'])@hexdi.inject(SomeA)deftest(a:SomeA):print(a.foo())if__name__=='__main__':loader.load()test()# prints: 42You also able to use recursive module finder to find all local packages,
site-packages, dist-packages modules that contains type registering. Use
same rules as module loader hasimporthexdifromexamples.multifile.interfacesimportSomeA# That finder will find thatfinder=hexdi.get_finder(['examples.multifile-finder'])loader=hexdi.get_loader(finder.find())@hexdi.inject(SomeA)deftest(a:SomeA):print(a.foo())if__name__=='__main__':loader.load()test()# prints: 69