Package: type-dep
type_deptype_dep is a dependency injection framework that uses type hints to inject dependencies (much like Angular, Dotnet and the like)Quick StartInstall the packagepipinstalltype_depInherit from the package'sDependencyclass to create an injectable dependency class.Use thedependencyinjecteddecorator to tag functions or methods that require dependency injection through their parameter type annotations.importosfromtype_depimportDependency,dependencyinjected,Contextcounter=0classA(Dependency):def__init__(self,name:str):self.name=name@classmethoddefinstantiate(cls):globalcountercounter+=1returnA(f"{counter}")classB(Dependency):def__init__(self,sex:str):self.sex=sex@classmethoddefinstantiate(cls):returnB(os.environ.get("SEX","female"))@dependencyinjecteddefget_detail(self,a:A):"""A method which uses dependency injection`a` will be instantiated and injected into this method at runtime.By default, these dependencies are stored in a global context.Subsequent method calls will use the instances of the dependencies that wereinstantiated on the first run.NOTE: The type hints on the parameters are a must"""return{"name":a.name,"sex":self.sex}@dependencyinjecteddefscoped_get_detail(self,a:A,context:Context):"""When a `Context` argument is passed,the dependencies are stored in a context that gets destroyed after every method call.NOTE: The type hints on the parameters are a must"""return{"name":a.name,"sex":self.sex}@dependencyinjecteddefrun(males:int,females:int,a:A,greeting:str,b:B):"""Just some function that is dependency injected.`a` and `b` will be instantiated and injected into the function at runtimeBy default, these dependencies are stored in a global context.Subsequent method calls will use the instances of the dependencies that wereinstantiated on the first run.NOTE: The type hints on the parameters are a must"""print(f"males:{males}, females:{females}, greeting:{greeting}, a.name:{a.name}, b.sex:{b.sex}")print(f'{b.get_detail()}\n')@dependencyinjecteddefscoped_run(males:int,females:int,a:A,greeting:str,b:B,context:Context):"""Just some function that is dependency injected.`a` and `b` will be instantiated and injected into the function at runtimeWhen a `Context` argument is passed,the dependencies are stored in a context that gets destroyed after every function call.NOTE: The type hints on the parameters are a must"""print(f"scoped: males:{males}, females:{females}, greeting:{greeting}, a.name:{a.name}, b.sex:{b.sex}")print(f'scoped:{b.scoped_get_detail()}\n')if__name__=='__main__':counter=0for_inrange(3):run(6,56,greeting="hey")# males: 6, females: 56, greeting: hey, a.name: 1, b.sex: female# {'name': '2', 'sex': 'female'}## males: 6, females: 56, greeting: hey, a.name: 1, b.sex: female# {'name': '2', 'sex': 'female'}## males: 6, females: 56, greeting: hey, a.name: 1, b.sex: female# {'name': '2', 'sex': 'female'}for_inrange(3):scoped_run(6,56,greeting="hey")# scoped: males: 6, females: 56, greeting: hey, a.name: 3, b.sex: female# scoped: {'name': '4', 'sex': 'female'}## scoped: males: 6, females: 56, greeting: hey, a.name: 5, b.sex: female# scoped: {'name': '6', 'sex': 'female'}## scoped: males: 6, females: 56, greeting: hey, a.name: 7, b.sex: female# scoped: {'name': '8', 'sex': 'female'}Why use type hintsPython type hints have matured alot. It is high time we used them to the maximum.
Apart from helping us avoid some logical errors, wouldn't be nice if type hints helped inject dependencies.Very little extra code is needed if you are already using typesIt is intuitiveHow to testClone the repositorygitclonegit@github.com:sopherapps/type_dep.gitcdtype_depCreate and activate the virtual environmentpython3-mvenvenvsourceenv/bin/activateRun the test commandpython-munittestLicenseCopyright (c) 2022Martin AhinduraLicensed under theMIT License