Package: auto-init
auto-initis a dependency injection tool that works in Python 3.6+ thanks to type hints.
If you write nice object oriented code and separate interfaces from implementations
then you could benefit from this.IntroductionDid you know that if you provide a type hint for an attribute in a class body and do not set a value then
the attribute isn’t actually initialised (neither in class, nor in instances)?classPoint:x:inty:intz:int=NoneForp, an instance ofPoint, onlyp.zis set. This is great because we can build a dependency
injection mechanism on top of this!Simple Examplefromauto_initimportAutoInitContextctx=AutoInitContext()p:Point=ctx.get_instance(Point)assertp.x==0assertp.y==0assertp.zisNoneNote that thePointclass could also be a dataclass and it would work too.Not So Simple Exampleimportloggingfromauto_initimportAutoInitContextclassWorker:enterprise:"Enterprise"log:logging.LoggerclassReporter:enterprise:"Enterprise"log:logging.LoggerclassEnterprise:worker:Workerreporter:Reporterctx=AutoInitContext()ctx.register_instance(logging.getLogger(__name__))ctx.register_singleton(Enterprise)enterprise:Enterprise=ctx.get_instance(Enterprise)assertenterprise.worker.logisenterprise.reporter.logassertenterprise.worker.enterpriseisenterpriseassertenterprise.reporter.enterpriseisenterpriseInstallationpipinstallauto-initAPIAutoInitContext()Create a new auto-initialisation context.register_singleton(instance_type: Type, factory: Callable=None)Register a singleton type. This is different fromregister_instancein that hereauto-initis responsible for the creation as well as initialisation of the singleton instance. This should
be used when the singleton itself has dependencies that need to be injected. See theenterprise.pyexample underauto_init/examples/.
Iffactoryis not supplied, theinstance_typeis used to create the instance.register_factory(instance_type: Type, factory: Callable)Register a callable which is called to create a new instance of the specified type when on is requested.register_instance(instance, instance_type: Type=None)Register an instance that should always be returned when an instance of the specified type is requested.get_instance(instance_type: Type)->AnyGet an instance of the specified type.init_instance(instance)Initialise any unitialised attributes of the instance.Changelogv0.0.5Supports initialising attributes annotated withtyping.Listandtyping.Dictas empty lists or dictionaries.
Othertyping.*-annotated attributes are initialised asNone.Do not attempt to get type hints fromtyping.*classes, it raises exceptions in Python 3.7 and does not return
anything useful in Python 3.6 anyway.Fixes dependencies for Python 3.6, removes unnecessarycontextvarsanddataclassesdependencies for Python 3.7.Travis CI setup.v0.0.4Complete rewrite to deal with circular references. Intrusive approach is no good.Forward references in type hints don’t really work in Python 3.7 even with futures. Let’s use Python 3.6.v0.0.3AddedAutoInitContext.explicit_only– allows marking the context as only initialising the types with specified
providers and leaving all othersuntouched.If a type hint includes a default value (declares a class attribute) then the corresponding instance attribute will
be a copy by reference of the class attribute unless there is an explicit provider specified in the context.
This means thatx: int = Nonewill be initialised asNone, not as0.v0.0.2Non-intrusive auto-init: functionauto_initand methodAutoInitContext.auto_initthat initialises instances
without making any changes to user’s classes.AddedAutoInitContext.singleton_types– allows to specify singleton types non-intrusively.