Skip to main content

Koin-like lightweight dependency injection container for Python with type inference support

Project description

KotInjection

image image image image image Unit Tests

Koin-like Dependency Injection Container for Python

KotInjection is a lightweight DI (Dependency Injection) container library for Python, inspired by Kotlin's Koin. It features type inference-based automatic dependency resolution and Koin-style DSL syntax.

Features

  • Simple API - Intuitive DSL similar to Koin
  • Type Inference Support - Automatic dependency resolution using Python type hints
  • Lifecycle Management - Supports singleton and factory patterns
  • Lazy Injection - Class attribute lazy dependency injection (like Koin's by inject())
  • Context Isolation - Independent container instances for isolated DI contexts
  • Lightweight - Pure Python implementation with no external dependencies
  • Type Safe - Safe dependency management through type hints

Installation

pip install kotinjection

Quick Start

Basic Usage

from kotinjection import KotInjection, KotInjectionModule


# Define dependencies
class Database:
    def __init__(self):
        self.connection = "db://localhost"


class UserRepository:
    def __init__(self, db: Database):
        self.db = db

    def get_users(self):
        return f"Users from {self.db.connection}"


# Create a module
module = KotInjectionModule()
with module:
    module.single[Database](lambda: Database())
    module.single[UserRepository](
        lambda: UserRepository(db=module.get())
    )

# Initialize the DI container
KotInjection.start(modules=[module])

# Retrieve dependencies
repo = KotInjection.get[UserRepository]()
print(repo.get_users())  # "Users from db://localhost"

# Stop when done
KotInjection.stop()

Lifecycle Management

# Singleton (same instance is reused)
module.single[Database](lambda: Database())

# Factory (new instance created each time)
module.factory[RequestHandler](
    lambda: RequestHandler(repo=module.get())
)

Lazy Injection (Class Attributes)

Similar to Koin's by inject(), you can define dependencies as class attributes that are resolved lazily on first access.

from kotinjection import KotInjection

class MyService:
    # Dependency is resolved on first access, not at class definition time
    repository = KotInjection.inject[UserRepository]

    def get_users(self):
        return self.repository.get_users()

# Initialize after class definition
KotInjection.start(modules=[module])

# Dependency is resolved when accessed
service = MyService()
service.get_users()  # repository is resolved here

Context Isolation

Context Isolation provides independent DI container instances that are completely separate from the global container. Ideal for library development, multi-tenant applications, and test isolation.

Basic Usage

from kotinjection import KotInjectionCore, KotInjectionModule

# Create an isolated container instance
module = KotInjectionModule()
with module:
    module.single[MyService](lambda: MyService())

app = KotInjectionCore(modules=[module])

# Retrieve dependencies from the instance
service = app.get[MyService]()

Use Case 1: Library Development

Create libraries that don't conflict with the host application's DI.

from kotinjection import (
    KotInjectionCore,
    IsolatedKotInjectionComponent,
    KotInjectionModule
)

# Define a library-specific container
library_module = KotInjectionModule()
with library_module:
    library_module.single[LibraryRepository](lambda: LibraryRepository())

library_app = KotInjectionCore(modules=[library_module])


# Base class for library components
class LibraryComponent(IsolatedKotInjectionComponent):
    def get_app(self):
        return library_app


# Actual service class
class MyLibraryService(LibraryComponent):
    def __init__(self):
        # Get dependencies from the isolated container
        self.repository = self.get[LibraryRepository]()

    def do_something(self):
        return self.repository.fetch_data()

Use Case 2: Multi-Tenant

Each tenant can have an independent DI environment.

# Tenant 1's container
tenant1_app = KotInjectionCore(modules=[tenant1_module])

# Tenant 2's container
tenant2_app = KotInjectionCore(modules=[tenant2_module])

# Use independent dependencies for each tenant
tenant1_service = tenant1_app.get[Service]()
tenant2_service = tenant2_app.get[Service]()

Use Case 3: Test Isolation

Use an independent DI container for each test case.

import unittest
from kotinjection import KotInjectionCore


class TestMyService(unittest.TestCase):
    def test_with_isolated_container(self):
        # Test-specific isolated container
        with KotInjectionCore(modules=[test_module]) as app:
            service = app.get[MyService]()
            # Run tests...
        # Automatically cleaned up when exiting the context

API Reference

For complete API documentation, see API Reference.

Quick Reference

Class Description
KotInjection Global DI container API
KotInjectionCore Isolated container instance
KotInjectionModule Dependency definitions container
IsolatedKotInjectionComponent Base class for isolated components
create_inject Create inject proxy for isolated containers

Key Methods

# Global API
KotInjection.start(modules=[...])  # Initialize
KotInjection.get[Type]()  # Retrieve dependency (eager)
KotInjection.inject[Type]  # Lazy injection (class attribute)
KotInjection.stop()  # Cleanup

# Module Definition
module.single[Type](factory)  # Singleton
module.factory[Type](factory)  # Factory
module.get()  # Type inference in factories

# Isolated Container
create_inject(app)  # Create inject proxy for isolated containers

Advanced Usage

Multiple Modules

# Database module
db_module = KotInjectionModule()
with db_module:
    db_module.single[Database](lambda: Database())
    db_module.single[CacheService](lambda: CacheService())

# Repository module
repo_module = KotInjectionModule()
with repo_module:
    repo_module.single[UserRepository](
        lambda: UserRepository(
            db=repo_module.get(),
            cache=repo_module.get()
        )
    )

# Initialize with all modules
KotInjection.start(modules=[db_module, repo_module])

Type Inference with Isolated Containers

# Create the app first
app = KotInjectionCore()

# Use module.get() in module definitions
module = KotInjectionModule()
with module:
    module.single[Repository](lambda: Repository())
    module.single[Service](lambda: Service(repo=module.get()))

# Load modules
app.load_modules([module])

# Retrieve dependencies
service = app.get[Service]()

Comparison with Koin

Feature Koin (Kotlin) KotInjection (Python)
DSL Syntax single { }, factory { } module.single[T], module.factory[T]
Type Inference get() module.get()
Lazy Injection by inject() KotInjection.inject[T]
Context Isolation koinApplication { } KotInjectionCore()
Scope Management Multiple scopes Singleton/Factory only
Context Manager N/A with statement support

Development Guidelines

Running Tests

python -m unittest discover tests

Type Hints

All type hints are required for dependency resolution.

class MyService:
    def __init__(self, repo: Repository):  # Type hint required
        self.repo = repo

License

MIT License

Acknowledgements

This project is inspired by Kotlin's Koin.

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

kotinjection-0.0.2.tar.gz (21.2 kB view details)

Uploaded Source

Built Distribution

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

kotinjection-0.0.2-py3-none-any.whl (28.9 kB view details)

Uploaded Python 3

File details

Details for the file kotinjection-0.0.2.tar.gz.

File metadata

  • Download URL: kotinjection-0.0.2.tar.gz
  • Upload date:
  • Size: 21.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.9 Linux/6.11.0-1018-azure

File hashes

Hashes for kotinjection-0.0.2.tar.gz
Algorithm Hash digest
SHA256 cd449da294aadcd886bc64e0d9adef894d7b329bf8efdddb7362a5ace9dae1ba
MD5 a041c57fa49a4b1a45135b9b506b057c
BLAKE2b-256 da00b7b8a9459601956e00f068e7cc30caeb1b097a46b1064f1936bdf594828d

See more details on using hashes here.

File details

Details for the file kotinjection-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: kotinjection-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 28.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.9 Linux/6.11.0-1018-azure

File hashes

Hashes for kotinjection-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 57aeec88d0a8e681cf95351883a9b8f6206b73c79ba72bcdd2eeb8f5a54e8e00
MD5 2aa39d4b0a008baa76ec1625e38f763a
BLAKE2b-256 cb83f2f09fd70d2a39492e5f414bba070fccbf6a82609ca0234655c94d7abeed

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