a # raises: CircularDependency: Circular dependency encountered while injecting in ContextĬontexts provide implementations of dependencies. a = a class Dependent : a : AbstractA with Context ( A, B ): Dependent (). b = b class B ( AbstractB ): def _init_ ( self, a : AbstractA ): self. class AbstractA : pass class AbstractB : pass class A ( AbstractA ): def _init_ ( self, b : AbstractB ): self. Note that circular dependencies preventing instantiation of dependency decoratedĬlasses leads to an error. # InjectionError: Could not instantiate dependency # when injecting argument "dependency" in. f () # raises: # TypeError: _init_() missing 1 required positional argument: 'a' # The above exception was the direct cause of the following exception: # InjectionError Traceback (most recent call last) #. def f ( dependency : InvalidDependency ). class InvalidDependency : def _init_ ( self, a ). class AlsoValidDependency : # Also OK! def _init_ ( self, some_dependency : SomeDependency ). class SomeDependency : def method ( self ): pass class ValidDependency : # OK! some_dependency : SomeDependency def _init_ ( self ). This means that all arguments to _init_ of dependency decorated classes must be injected using inject. Of dependency decorated classes can be called without any arguments. To achieve this, serum assumes that the _init_ method Serum relies on being able to inject all dependencies for dependency decorated classes
from serum import dependency, inject class Log : def info ( self, message ): print ( message ) class NeedsLog : log : Log assert isinstance ( NeedsLog (). dependency = 'Overridden!' dependencyĬlasses decorated with dependency can be instantiated and injectedīy serum. Using key-word arguments to _init_ assert SomeClass ( dependency = 'Overridden!' ). _dependencyĭependencies that are specified as class level annotations can be overridden _dependency = dependency def dependency ( self ) -> MyDependency : return self. This is roughly equivalent to: class SomeClass : def _init_ ( self, dependency : MyDependency ): self. class SomeClass : dependency : MyDependency Inject can also be used to decorate classes. def f ( dependency : str ): assert dependency = 'a named dependency' with Context ( dependency = 'a named dependency' ): f () Injected using keyword arguments to Context. Instances of simple types and objects you want to instantiate yourself can be This way, your entire dependency graph can be specified using just inject and Inject will instantiate classes decorated with dependency. def f ( dependency : MyDependency ): print ( dependency ) f ( 'Overridden dependency' ) # outputs: Overridden dependency Not attempt to inject arguments given at call time. from serum import inject, dependency class MyDependency : pass def f ( dependency : MyDependency ): assert isinstance ( dependency, MyDependency ) f ()įunctions decorated with inject can be called as normal functions. Inject is used to decorate functions and classes in which you want to injectĭependencies. info ( 'Hello serum!' ) # doesn't output anything Documentation info ( 'Hello serum!' ) # doesn't output anything NeedsSimpleLog (). This allows you to change which # dependencies are injected.
named_dependency = 'this name is injected!' # Contexts will always provide the most specific # subtype of the requested type. log, SimpleLog ) assert NeedsNamedDependency (). log = log class NeedsNamedDependency : named_dependency : str # class level annotations annotated with a type that is not # decorated with 'dependency' will be treated as a named # dependency # Contexts provide dependencies with Context ( SimpleLog, named_dependency = 'this name is injected!' ): assert isinstance ( NeedsLog (). or using a function decorator def _init_ ( self, log : SimpleLog ): self. class Log : def info ( self, message : str ): raise NotImplementedError () class SimpleLog ( Log ): def info ( self, message : str ): print ( message ) class StubLog ( SimpleLog ): def info ( self, message : str ): pass # Dependencies are injected using a class decorator. Quickstart from serum import inject, dependency, Context # Classes decorated with 'dependency' are injectable types. Serum is pure python and has no dependencies. Serum is a fresh take on Dependency Injection in Python 3.