Skip to main content

InjectQ

PyPI version Python versions License Coverage

InjectQ is a modern, lightweight Python dependency injection library focused on clarity, type-safety, and seamless framework integration.

Documentation

Full documentation is hosted at Documentation and the repository docs/ contains the source.

Key features

  • Simplicity-first dict-like API for quick starts
  • Flexible decorator- and type-based injection (@inject, Inject[T])
  • Type-friendly: designed to work with static type checkers
  • Built-in integrations for frameworks (FastAPI, Taskiq) as optional extras
  • Factory and async factory support
  • 🆕 Hybrid factory methods combining DI with manual arguments (invoke(), ainvoke())
  • Scope management and testing utilities

Quick Start (recommended pattern)

Prefer the exported global InjectQ.get_instance() container in examples and application code. It uses the active context container when present, otherwise falls back to a global singleton.

from injectq import InjectQ, inject, singleton

container = InjectQ.get_instance()

# Basic value binding
container[str] = "Hello, World!"

@singleton
class UserService:
    def __init__(self, message: str):
        self.message = message

    def greet(self) -> str:
        return f"Service says: {self.message}"

@inject
def main(service: UserService) -> None:
    print(service.greet())

if __name__ == "__main__":
    main()  # Prints: Service says: Hello, World!

Notes:

  • Use container[...] for simple bindings and values.
  • Use @inject and Inject[T] for function/class injection.

Enhanced Features

Nullable Dependencies

InjectQ supports binding None values for optional dependencies using the allow_none parameter:

from injectq import InjectQ

container = InjectQ()

# Optional service - can be None
class EmailService:
    def send_email(self, to: str, message: str) -> str:
        return f"Email sent to {to}: {message}"

class NotificationService:
    def __init__(self, email_service: EmailService | None = None):
        self.email_service = email_service

    def notify(self, message: str) -> str:
        if self.email_service:
            return self.email_service.send_email("user", message)
        return f"Basic notification: {message}"

# Bind None for optional dependency
container.bind(EmailService, None, allow_none=True)
container.bind(NotificationService, NotificationService)

service = container.get(NotificationService)
print(service.notify("Hello"))  # Prints: Basic notification: Hello

Abstract Class Validation

InjectQ automatically prevents binding abstract classes and raises a BindingError during binding (not at resolution time):

from abc import ABC, abstractmethod
from injectq import InjectQ
from injectq.utils.exceptions import BindingError

class PaymentProcessor(ABC):  # Abstract class
    @abstractmethod
    def process_payment(self, amount: float) -> str:
        pass

class CreditCardProcessor(PaymentProcessor):  # Concrete implementation
    def process_payment(self, amount: float) -> str:
        return f"Processing ${amount} via credit card"

container = InjectQ()

# This will raise BindingError immediately
try:
    container.bind(PaymentProcessor, PaymentProcessor)  # Error!
except BindingError:
    print("Cannot bind abstract class")

# This works fine
container.bind(PaymentProcessor, CreditCardProcessor)  # OK

See examples/enhanced_features_demo.py for a complete demonstration.

🆕 Hybrid Factory Methods

The new invoke() and ainvoke() methods combine dependency injection with manual arguments:

from injectq import InjectQ

container = InjectQ()
container.bind(Database, Database)
container.bind(Cache, Cache)

# Factory that needs both DI dependencies and runtime arguments
def create_user_service(db: Database, cache: Cache, user_id: str):
    return UserService(db, cache, user_id)

container.bind_factory("user_service", create_user_service)

# ❌ Old way - verbose
db = container[Database]
cache = container[Cache]
service = container.call_factory("user_service", db, cache, "user123")

# ✅ New way - automatic DI + manual args
service = container.invoke("user_service", user_id="user123")
# Database and Cache auto-injected, only provide user_id!

# Also works with async
service = await container.ainvoke("async_service", batch_size=100)

When to use invoke():

  • Factory needs some DI dependencies + some runtime arguments
  • You want cleaner code without manual resolution
  • Mix configuration from container with user input

See examples/factory_api_showcase.py and docs/injection-patterns/factory-methods.md for details.

Installation

Install from PyPI:

pip install injectq

Optional framework integrations (install only what you need):

pip install injectq[fastapi]   # FastAPI integration (optional)
pip install injectq[taskiq]    # Taskiq integration (optional)

Where to look next

  • docs/getting-started/installation.md — installation and verification
  • docs/injection-patterns/dict-interface.md — dict-like API
  • docs/injection-patterns/inject-decorator.md@inject usage
  • docs/injection-patterns/factory-methods.md — factory patterns (DI, parameterized, hybrid)
  • docs/integrations/ — integration guides for FastAPI and Taskiq

License

MIT — see the LICENSE file.

Run tests with coverage

Activate the project's virtualenv and run pytest (coverage threshold is configured to 73%):

source .venv/bin/activate
python -m pytest

Coverage reports are written to htmlcov/ and coverage.xml.

Performance Benchmarks

InjectQ includes comprehensive performance benchmarks to ensure production-ready performance:

# Run all benchmarks
pytest tests/test_benchmarks.py --benchmark-only

# Run with verbose statistics
pytest tests/test_benchmarks.py --benchmark-only --benchmark-verbose

# Save results for comparison
pytest tests/test_benchmarks.py --benchmark-only --benchmark-autosave

Performance Highlights

  • Ultra-fast operations: Basic operations (bind, get, has) execute in 270-780 nanoseconds
  • Efficient resolution: Dependency resolution completes in ~1 microsecond
  • Excellent scalability: Handles 1,000+ operations with sub-millisecond performance
  • Thread-safe: Concurrent access with minimal overhead (~24 μs)
  • Production-ready: Web request simulation (10 services) completes in 142 microseconds

📊 See BENCHMARK_REPORT.md for detailed analysis and BENCHMARK_QUICK_GUIDE.md for usage guide.

Download files

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

Source Distribution

injectq-0.4.2.tar.gz (2.2 MB view details)

Uploaded Source

Built Distribution

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

injectq-0.4.2-py3-none-any.whl (74.1 kB view details)

Uploaded Python 3

File details

Details for the file injectq-0.4.2.tar.gz.

File metadata

  • Download URL: injectq-0.4.2.tar.gz
  • Upload date:
  • Size: 2.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.9

File hashes

Hashes for injectq-0.4.2.tar.gz
Algorithm Hash digest
SHA256 efcb6416e3b80d5a0b10c32138b05fe7128640287da15482e5314372d32222df
MD5 5150561b1917b7e1a9fbdc365cf37617
BLAKE2b-256 c7618399d1a71eeab69af49566e89401092dd59d70807b721b0a4fb73db63dfb

See more details on using hashes here.

File details

Details for the file injectq-0.4.2-py3-none-any.whl.

File metadata

  • Download URL: injectq-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 74.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.9

File hashes

Hashes for injectq-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a8b8873e3b1d53ea2a3020478f42ba2698b39436eed2855fac4ee6698b5e650f
MD5 659d1e7a1539d36cca2ccb9ffbb1a0db
BLAKE2b-256 34a7329aa7afeb0617b413fcd8b10d0e9c11eef8c9bfd8db5a254b15bd7d5b73

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.4.2 This release

2 files

0.4.1

2 files

0.4.0

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

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