Package: sinj
💉 sinjsinj(SimpleInject) is yet another IoC framework for python. If you try to avoid global variables and singletons you might end up with a complex graph of dependencies in your application. Withsinjeverything is just flat. If you are coming from Java or C# you might be more familiar with IoC frameworks where dependencies are resolved by interface. In python we do not have interfaces and strict types so here we resolve dependencies by constructor argument names or "inject labels".Basic usage and examplesimportsinjc=sinj.Container()# create dependencies containerc.register(SomeClass,"some_class")# add labeled class into containerc.resolve("some_class")# resolve instance by given labelc.inject(some_instance,"some_instance")# add resolved instance to an indexThe simplest example:importsinjclassA:defa(self):return"a"classB:def__init__(self,a):self._a=adefb(self):returnself._a()+" b"ioc_container=sinj.Container()ioc_container.register(A,"a")ioc_container.register(B,"b")b=ioc_container.resolve("b")print(b.b())# -> "a b"The same example with annotated classes:importsinjclassA:inject="a"# this label will be used to resolve instance of Adefa(self):return"a"classB:inject="b"# this label will be used to resolve instance of Bdef__init__(self,a):# instance of A is injected hereself._a=adefb(self):returnself._a()+" b"ioc_container=sinj.Container()ioc_container.register(A)# no need to specify label hereioc_container.register(B)# but you can overwrite it if you wantb=ioc_container.resolve("b")print(b.b())# -> "a b"More examples will be available in./examplesErrorssinj.DependencyNotFoundError- thrown onresolvewhen dependency is not found for a given label (and it is not optional).sinj.CircularDependencyError- thrown onresolvewhen circular dependency is detected.sinj.DependencyConflictError- thrown onregisterorinjectwhen the container already has something by the label.sinj.DependencyNotMappedError- thrown onregisterorinjectwhen the class is not annotated and the label is not provided in register method.Validating typesYou have an option to pass a validator intosinj.Containerto check injected types.sinjhas a simple built in validator which is able to log warnings or raise errors. You can create more complicated validators if you want, it is just a class withvalidate(self, instance, param: inspect.Parameter):method:classTypeValidator:def__init__(self,log_warning=True,raise_error=False):self._log_warning=log_warningself._raise_error=raise_errordefvalidate(self,instance,param:inspect.Parameter):err_msg=self._get_err_msg(instance,param)iferr_msgisNone:returnifself._log_warning:logger.warning(err_msg)ifself._raise_error:raiseTypeValidatorError(err_msg)def_get_err_msg(self,instance,param:inspect.Parameter):ifnothasattr(instance,"__class__"):returnf"could not determine class of instance for{param.name}"ifparam.annotation==param.empty:returnNoneifnotinspect.isclass(param.annotation):returnf"param annotated with a non-class for{param.name}"ifnotissubclass(instance.__class__,param.annotation):returnf"instance is not derived from annotated type for{param.name}"returnNoneioc_container=sinj.Container(validator=TypeValidator(True,True))InstallFrompypi.orgpipinstallsinjFromrepositorypipinstallgit+https://gitlab.com/mrsk/sinj