injectq


Nameinjectq JSON
Version 0.3.1 PyPI version JSON
download
home_pageNone
SummaryModern Python dependency injection library combining simplicity, power, and performance
upload_time2025-09-08 05:37:47
maintainerNone
docs_urlNone
authorInjectQ Contributors
requires_python>=3.10
licenseNone
keywords container dependency-injection di inversion-of-control ioc
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # InjectQ
[![PyPI version](https://badge.fury.io/py/injectq.svg)](https://pypi.org/project/injectq/)
[![Python versions](https://img.shields.io/pypi/pyversions/injectq.svg)](https://pypi.org/project/injectq/)
[![License](https://img.shields.io/github/license/Iamsdt/injectq.svg)](https://github.com/Iamsdt/injectq/blob/main/LICENSE)
[![Coverage](https://img.shields.io/badge/coverage-73%25-yellow.svg)](#)


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

## Documentation
Full documentation is hosted at https://iamsdt.github.io/injectq/ 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
- 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.

```python
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:

```python
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):

```python
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.

## Installation

Install from PyPI:

```bash
pip install injectq
```

Optional framework integrations (install only what you need):

```bash
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/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%):

```bash
source .venv/bin/activate
python -m pytest
```

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

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "injectq",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "container, dependency-injection, di, inversion-of-control, ioc",
    "author": "InjectQ Contributors",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/29/fa/8d324712876d3361bbb6a21b8dfa77a077ac2047b5bdadd7b1a08983054f/injectq-0.3.1.tar.gz",
    "platform": null,
    "description": "# InjectQ\n[![PyPI version](https://badge.fury.io/py/injectq.svg)](https://pypi.org/project/injectq/)\n[![Python versions](https://img.shields.io/pypi/pyversions/injectq.svg)](https://pypi.org/project/injectq/)\n[![License](https://img.shields.io/github/license/Iamsdt/injectq.svg)](https://github.com/Iamsdt/injectq/blob/main/LICENSE)\n[![Coverage](https://img.shields.io/badge/coverage-73%25-yellow.svg)](#)\n\n\nInjectQ is a modern, lightweight Python dependency injection library focused on clarity, type-safety, and seamless framework integration.\n\n## Documentation\nFull documentation is hosted at https://iamsdt.github.io/injectq/ and the repository `docs/` contains the source.\n\n## Key features\n\n- Simplicity-first dict-like API for quick starts\n- Flexible decorator- and type-based injection (`@inject`, `Inject[T]`)\n- Type-friendly: designed to work with static type checkers\n- Built-in integrations for frameworks (FastAPI, Taskiq) as optional extras\n- Factory and async factory support\n- Scope management and testing utilities\n\n## Quick Start (recommended pattern)\n\nPrefer 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.\n\n```python\nfrom injectq import InjectQ, inject, singleton\n\ncontainer = InjectQ.get_instance()\n\n# Basic value binding\ncontainer[str] = \"Hello, World!\"\n\n@singleton\nclass UserService:\n    def __init__(self, message: str):\n        self.message = message\n\n    def greet(self) -> str:\n        return f\"Service says: {self.message}\"\n\n@inject\ndef main(service: UserService) -> None:\n    print(service.greet())\n\nif __name__ == \"__main__\":\n    main()  # Prints: Service says: Hello, World!\n```\n\nNotes:\n- Use `container[...]` for simple bindings and values.\n- Use `@inject` and `Inject[T]` for function/class injection.\n\n## Enhanced Features\n\n### Nullable Dependencies\n\nInjectQ supports binding `None` values for optional dependencies using the `allow_none` parameter:\n\n```python\nfrom injectq import InjectQ\n\ncontainer = InjectQ()\n\n# Optional service - can be None\nclass EmailService:\n    def send_email(self, to: str, message: str) -> str:\n        return f\"Email sent to {to}: {message}\"\n\nclass NotificationService:\n    def __init__(self, email_service: EmailService | None = None):\n        self.email_service = email_service\n    \n    def notify(self, message: str) -> str:\n        if self.email_service:\n            return self.email_service.send_email(\"user\", message)\n        return f\"Basic notification: {message}\"\n\n# Bind None for optional dependency\ncontainer.bind(EmailService, None, allow_none=True)\ncontainer.bind(NotificationService, NotificationService)\n\nservice = container.get(NotificationService)\nprint(service.notify(\"Hello\"))  # Prints: Basic notification: Hello\n```\n\n### Abstract Class Validation\n\nInjectQ automatically prevents binding abstract classes and raises a `BindingError` during binding (not at resolution time):\n\n```python\nfrom abc import ABC, abstractmethod\nfrom injectq import InjectQ\nfrom injectq.utils.exceptions import BindingError\n\nclass PaymentProcessor(ABC):  # Abstract class\n    @abstractmethod\n    def process_payment(self, amount: float) -> str:\n        pass\n\nclass CreditCardProcessor(PaymentProcessor):  # Concrete implementation\n    def process_payment(self, amount: float) -> str:\n        return f\"Processing ${amount} via credit card\"\n\ncontainer = InjectQ()\n\n# This will raise BindingError immediately\ntry:\n    container.bind(PaymentProcessor, PaymentProcessor)  # Error!\nexcept BindingError:\n    print(\"Cannot bind abstract class\")\n\n# This works fine\ncontainer.bind(PaymentProcessor, CreditCardProcessor)  # OK\n```\n\nSee `examples/enhanced_features_demo.py` for a complete demonstration.\n\n## Installation\n\nInstall from PyPI:\n\n```bash\npip install injectq\n```\n\nOptional framework integrations (install only what you need):\n\n```bash\npip install injectq[fastapi]   # FastAPI integration (optional)\npip install injectq[taskiq]    # Taskiq integration (optional)\n```\n\n## Where to look next\n\n- `docs/getting-started/installation.md` \u2014 installation and verification\n- `docs/injection-patterns/dict-interface.md` \u2014 dict-like API\n- `docs/injection-patterns/inject-decorator.md` \u2014 `@inject` usage\n- `docs/integrations/` \u2014 integration guides for FastAPI and Taskiq\n\n## License\n\nMIT \u2014 see the `LICENSE` file.\n\n## Run tests with coverage\n\nActivate the project's virtualenv and run pytest (coverage threshold is configured to 73%):\n\n```bash\nsource .venv/bin/activate\npython -m pytest\n```\n\nCoverage reports are written to `htmlcov/` and `coverage.xml`.",
    "bugtrack_url": null,
    "license": null,
    "summary": "Modern Python dependency injection library combining simplicity, power, and performance",
    "version": "0.3.1",
    "project_urls": {
        "Documentation": "https://github.com/Iamsdt/injectq",
        "Homepage": "https://github.com/Iamsdt/injectq",
        "Issues": "https://github.com/Iamsdt/injectq/issues",
        "Repository": "https://github.com/Iamsdt/injectq"
    },
    "split_keywords": [
        "container",
        " dependency-injection",
        " di",
        " inversion-of-control",
        " ioc"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "bdb61a5e2d5c04e9405b94bb0d982530a6246d2515242b38bbfbfe3ccdc29c96",
                "md5": "3171451d77b8181a8e677107cdeaabe8",
                "sha256": "e53d8ccfbe0da928e27da6794738b11c3fdff95135f3191ba9ae062d23176699"
            },
            "downloads": -1,
            "filename": "injectq-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3171451d77b8181a8e677107cdeaabe8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 64501,
            "upload_time": "2025-09-08T05:37:43",
            "upload_time_iso_8601": "2025-09-08T05:37:43.347101Z",
            "url": "https://files.pythonhosted.org/packages/bd/b6/1a5e2d5c04e9405b94bb0d982530a6246d2515242b38bbfbfe3ccdc29c96/injectq-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "29fa8d324712876d3361bbb6a21b8dfa77a077ac2047b5bdadd7b1a08983054f",
                "md5": "cc32981b4f312350d5fd002d3dbfedca",
                "sha256": "2cef919b5636ee99ded2d11035b3ca6e86a2fb3dd47ac7c7eb163c663bb516c8"
            },
            "downloads": -1,
            "filename": "injectq-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "cc32981b4f312350d5fd002d3dbfedca",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 464740,
            "upload_time": "2025-09-08T05:37:47",
            "upload_time_iso_8601": "2025-09-08T05:37:47.289369Z",
            "url": "https://files.pythonhosted.org/packages/29/fa/8d324712876d3361bbb6a21b8dfa77a077ac2047b5bdadd7b1a08983054f/injectq-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-08 05:37:47",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Iamsdt",
    "github_project": "injectq",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "injectq"
}
        
Elapsed time: 0.60988s