Skip to main content

A simple dependency injection framework for Python 3 applications.

Project description

Welcome

PyPI version CodeFactor Shilds

Kanata is 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.

Requirements

The project currently targets Python version 3.11 or higher. Compatibility with older versions may be possible but isn't tested.

Getting started

First 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 kanata

Using the library is as simple as building a catalog of our injectables and resolving a root injectable:

from kanata import InjectableCatalog, 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:

from kanata.decorators import injectable

# Typically, you'll want to create an interface to be used as the contract:
class IMyInterface:
    pass

# And then register your type as an injectable with its contract:
@injectable(IMyInterface):
class MyClass(IMyInterface):
    ...

As constructor (or __init__(...) in Python) injection is used, you need to define the required dependencies in this method:

from kanata.decorators import injectable

@injectable(IMyInterface):
class MyClass(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, the structlog library is used instead of the built-in logging module of Python. Please, refer to the project's documentation for details.

Samples

In 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 the samples.py script and follow the on-screen instructions:

# Unix/MacOS
python3 ./samples.py

# Windows
py .\samples.py

The samples are full of comments to better explain what is happening.

Contribution

Contributions to the project are welcome in the form of creating an issue or forking the repository and creating a pull request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kanata-4.0.0.0.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kanata-4.0.0.0-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file kanata-4.0.0.0.tar.gz.

File metadata

  • Download URL: kanata-4.0.0.0.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.1

File hashes

Hashes for kanata-4.0.0.0.tar.gz
Algorithm Hash digest
SHA256 1f886075963622f58b5a0a3fbda6bd328e342b6e5d5ed3f341e7205e6e3ab097
MD5 70fcb2898370e334fc7632eedd6b3dcf
BLAKE2b-256 6f1a33c804209ba11e1793300091284a48b09be3f2463d6293d0202383501633

See more details on using hashes here.

File details

Details for the file kanata-4.0.0.0-py3-none-any.whl.

File metadata

  • Download URL: kanata-4.0.0.0-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.1

File hashes

Hashes for kanata-4.0.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2c7ba2405776f473c300458c593edac055ab3bf87af30c2d8e8cd7cd96504210
MD5 b04144ffd98bbded8deb5268d609b43d
BLAKE2b-256 e3448410cf2a19212807392dd50cfded3ddce368b312ed8131c5fdccceb1daa4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page