You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP β†’
Socket
Book a DemoInstallSign in
Socket

duckdi

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

duckdi

πŸ¦† A minimal dependency injection library for Python

0.1.10
pipPyPI
Maintainers
1

DuckDI Logo

πŸ¦† DuckDI

DuckDI is a minimal, type-safe, and architecture-friendly dependency injection library for Python.

It provides a clean interface to register and resolve dependencies at runtime using a TOML-based configuration, following the duck typing principle: "if it implements the expected methods, it’s good enough."
Ideal for developers who want clarity, zero magic, and full control over dependency resolution.

πŸš€ Features

  • βœ… Clean and lightweight API
  • βœ… Zero runtime dependencies
  • βœ… Fully type-safe (no introspection magic)
  • βœ… Supports singleton and transient resolution
  • βœ… Uses TOML to bind interfaces to adapters
  • βœ… Works with ABC and regular classes (no need for Protocols)
  • βœ… Clear and informative error messages
  • βœ… Environment-based configuration (INJECTIONS_PATH)

πŸ“¦ Installation

With Poetry:

poetry add duckdi

Or using pip:

pip install duckdi

πŸ› οΈ Usage

1. Define an interface

from duckdi import Interface
from abc import ABC, abstractmethod

@Interface
class IUserRepository(ABC):
    @abstractmethod
    def get_user(self, user_id: str) -> dict: ...

2. Register an adapter

from duckdi import register

class PostgresUserRepository(IUserRepository):
    def get_user(self, user_id: str) -> dict:
        return {"id": user_id, "name": "John Doe"}

register(PostgresUserRepository)

You can also register it as a singleton:

register(PostgresUserRepository, is_singleton=True)

3. Create your injection payload

Create a file called injections.toml:

[injections]
"i_user_repository" = "postgres_user_repository"

4. Set the environment variable

Set the injection file path using the INJECTIONS_PATH environment variable:

export INJECTIONS_PATH=./injections.toml

5. Resolve your dependencies

from duckdi import Get

repo = Get(IUserRepository)
user = repo.get_user("123")
print(user)  # {'id': '123', 'name': 'John Doe'}

πŸ’₯ Error Handling

MissingInjectionPayloadError

Raised when no injection payload file is found at the specified path.

InvalidAdapterImplementationError

Raised when the adapter registered does not implement the expected interface.

InterfaceAlreadyRegisteredError

Raised when trying to register the same interface twice.

AdapterAlreadyRegisteredError

Raised when the same adapter is registered more than once.

πŸ“ Project Structure

duckdi/
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ README.md
β”œβ”€β”€ src/
β”‚   └── duckdi/
β”‚       β”œβ”€β”€ __init__.py
β”‚       β”œβ”€β”€ cli.py
β”‚       β”œβ”€β”€ duck.py
β”‚       β”œβ”€β”€ errors/
β”‚       β”‚   β”œβ”€β”€ __init__.py
β”‚       β”‚   β”œβ”€β”€ invalid_adapter_implementation_error.py
β”‚       β”‚   β”œβ”€β”€ interface_already_registered_error.py
β”‚       β”‚   β”œβ”€β”€ adapter_already_registered_error.py
β”‚       β”‚   └── missing_injection_payload_error.py
β”‚       β”œβ”€β”€ utils/
β”‚       β”‚   β”œβ”€β”€ __init__.py
β”‚       β”‚   β”œβ”€β”€ buffer_readers.py
β”‚       β”‚   └── to_snake.py
β”‚       └── injections/
β”‚           β”œβ”€β”€ injections_container.py
β”‚           └── injections_payload.py
└── tests/
    β”œβ”€β”€ test_interface.py
    β”œβ”€β”€ test_register.py
    └── test_get.py

🧩 Advanced Example

You can register multiple adapters and resolve them dynamically based on the TOML mapping:

from duckdi import Interface, register, Get

@Interface
class INotifier:
    def send(self, msg: str): ...

class EmailNotifier(INotifier):
    def send(self, msg: str):
        print(f"Sending email: {msg}")

register(EmailNotifier)

# injections.toml
# [injections]
# "i_notifier" = "email_notifier"

notifier = Get(INotifier)
notifier.send("Hello from DuckDI!")

πŸ§ͺ Testing

To run tests:

pytest

Or via Makefile:

make test

To check static typing:

make check

πŸ“„ License

Licensed under the MIT License.
See the LICENSE file for more information.

πŸ‘€ Author

Made with ❀️ by PhePato
Pull requests, issues and ideas are always welcome!

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts