Package: kanata
WelcomeKanatais a very simple dependency injection framework used for decoupling the services of your Python application's services from their dependencies. This may help with maintainability, testability and readability.Currently, the following lifetime scopes are supported:Transient:On each request, a new instance of the specific dependency is created. Typically, a transient injectable maintains its own state.Scoped:On the first request, a new instance is created for a particular lifetime scope and this same instance is returned on further requests. Typically, a scoped injectable is used for separating instances between incoming web requests.Singleton:On the first request, a new instance is created and this same instance is returned on further requests to any of the lifetime scopes in a tree.RequirementsThe project currently targetsPythonversion 3.11 or higher. Compatibility with older versions may be possible but isn't tested.Getting startedFirst of all, make sure that you install the library in your project. Using a default Python installation, the following will work:# Unix/MacOS
python3 -m pip install kanata

# Windows
py -m pip install kanataUsing the library is as simple as building a catalog of our injectables and resolving a root injectable:fromkanataimportInjectableCatalog,LifetimeScope,find_injectables# Find all types from a specific module that have been marked as injectables:registrations=find_injectables("my.module")# Construct a new catalog for these types:catalog=InjectableCatalog(registrations)# Create a scope that manages the resolved instances:scope=LifetimeScope(catalog)# And finally, resolve the injectable type you need:instance=scope.resolve(MyClass)For the above code to work, you need to mark the types you need as injectables. You can currently achieve this by using the@injectable(...)decorator as follows:fromkanata.decoratorsimportinjectable# Typically, you'll want to create an interface to be used as the contract:classIMyInterface:pass# And then register your type as an injectable with its contract:@injectable(IMyInterface):classMyClass(IMyInterface):...As constructor (or__init__(...)in Python) injection is used, you need to define the required dependencies in this method:fromkanata.decoratorsimportinjectable@injectable(IMyInterface):classMyClass(IMyInterface):# Type hints are required for the framework to identify the dependencies.# Where multiple dependencies are allowed, you can use a Tuple to specify it.def__init__(self,dependency1:IDependency1,dependency2:IDependency2,multiple_dependencies:tuple[IDependency3,...]):...The framework will then take care of resolving these dependencies.Below are some of the dependency resolution rules:If a single dependency is required but there is no matching registration, an exception is raised.If a single dependency is required and there are multiple candidates, it's unspecified which one will be injected. This is mainly because hash tables are used during dependency resolution.If multiple dependencies are required but there are no matching registrations, an empty tuple is injected. Otherwise, a tuple with all matching injectables is injected.For the ability to customize logging, thestructloglibrary is used instead of the built-inloggingmodule of Python. Please, refer to the project's documentation for details.SamplesIn case you would like to see more samples, clone the repository and run one of the bundled samples.First, make sure that Kanata is installed, preferably in editable mode (while standing in the root directory):# Unix/MacOS
python3 -m pip install -e .

# Windows
py -m pip install -e .Then, while standing in the root directory, execute thesamples.pyscript and follow the on-screen instructions:# Unix/MacOS
python3 ./samples.py

# Windows
py .\samples.pyThe samples are full of comments to better explain what is happening.ContributionContributions to the project are welcome in the form ofcreating an issueor forking the repository andcreating a pull request.