"That Depends"
==
[![Test Coverage](https://codecov.io/gh/modern-python/that-depends/branch/main/graph/badge.svg)](https://codecov.io/gh/modern-python/that-depends)
[![MyPy Strict](https://img.shields.io/badge/mypy-strict-blue)](https://mypy.readthedocs.io/en/stable/getting_started.html#strict-mode-and-configuration)
[![Supported versions](https://img.shields.io/pypi/pyversions/that-depends.svg)](https://pypi.python.org/pypi/that-depends)
[![downloads](https://img.shields.io/pypi/dm/that-depends.svg)](https://pypistats.org/packages/that-depends)
[![GitHub stars](https://img.shields.io/github/stars/modern-python/that-depends)](https://github.com/modern-python/that-depends/stargazers)
Dependency injection framework for Python inspired by `dependency-injector`.
It is production-ready and gives you the following:
- Simple async-first DI framework with IOC-container.
- Python 3.10-3.13 support.
- Full coverage by types annotations (mypy in strict mode).
- FastAPI and LiteStar compatibility.
- Overriding dependencies for tests.
- Injecting dependencies in functions and coroutines without wiring.
- Package with zero dependencies.
📚 [Documentation](https://that-depends.readthedocs.io)
# Quickstart
## Install
```bash
pip install that-depends
```
## Describe resources and classes:
```python
import dataclasses
import logging
import typing
logger = logging.getLogger(__name__)
# singleton provider with finalization
def create_sync_resource() -> typing.Iterator[str]:
logger.debug("Resource initiated")
try:
yield "sync resource"
finally:
logger.debug("Resource destructed")
# same, but async
async def create_async_resource() -> typing.AsyncIterator[str]:
logger.debug("Async resource initiated")
try:
yield "async resource"
finally:
logger.debug("Async resource destructed")
@dataclasses.dataclass(kw_only=True, slots=True)
class DependentFactory:
sync_resource: str
async_resource: str
```
## Describe IoC-container
```python
from that_depends import BaseContainer, providers
class DIContainer(BaseContainer):
sync_resource = providers.Resource(create_sync_resource)
async_resource = providers.Resource(create_async_resource)
simple_factory = providers.Factory(SimpleFactory, dep1="text", dep2=123)
dependent_factory = providers.Factory(
sync_resource=sync_resource,
async_resource=async_resource,
)
```
## Resolve dependencies in your code
```python
# async resolving by default:
await DIContainer.simple_factory()
# sync resolving is also allowed if there is no uninitialized async resources in dependencies
DIContainer.simple_factory.sync_resolve()
# otherwise you can initialize resources beforehand one by one or in one call:
await DIContainer.init_resources()
```
## Resolve dependencies not described in container
```python
@dataclasses.dataclass(kw_only=True, slots=True)
class FreeFactory:
dependent_factory: DependentFactory
sync_resource: str
# this way container will try to find providers by names and resolve them to build FreeFactory instance
free_factory_instance = await DIContainer.resolve(FreeFactory)
```
## Inject providers in function arguments
```python
import datetime
from that_depends import inject, Provide
from tests import container
@inject
async def some_coroutine(
simple_factory: container.SimpleFactory = Provide[container.DIContainer.simple_factory],
dependent_factory: container.DependentFactory = Provide[container.DIContainer.dependent_factory],
default_zero: int = 0,
) -> None:
assert simple_factory.dep1
assert isinstance(dependent_factory.async_resource, datetime.datetime)
assert default_zero == 0
@inject
def some_function(
simple_factory: container.SimpleFactory = Provide[container.DIContainer.simple_factory],
default_zero: int = 0,
) -> None:
assert simple_factory.dep1
assert default_zero == 0
```
Raw data
{
"_id": null,
"home_page": null,
"name": "that-depends",
"maintainer": null,
"docs_url": null,
"requires_python": "<4,>=3.10",
"maintainer_email": null,
"keywords": "dependency injector, di, ioc-container, mocks, python",
"author": null,
"author_email": "Artur Shiriev <me@shiriev.ru>",
"download_url": "https://files.pythonhosted.org/packages/07/39/06e126820b4bc56ca319d7bb625878479e28519991dac15eccdb1aab1670/that_depends-1.27.0.tar.gz",
"platform": null,
"description": "\"That Depends\"\n==\n[![Test Coverage](https://codecov.io/gh/modern-python/that-depends/branch/main/graph/badge.svg)](https://codecov.io/gh/modern-python/that-depends)\n[![MyPy Strict](https://img.shields.io/badge/mypy-strict-blue)](https://mypy.readthedocs.io/en/stable/getting_started.html#strict-mode-and-configuration)\n[![Supported versions](https://img.shields.io/pypi/pyversions/that-depends.svg)](https://pypi.python.org/pypi/that-depends)\n[![downloads](https://img.shields.io/pypi/dm/that-depends.svg)](https://pypistats.org/packages/that-depends)\n[![GitHub stars](https://img.shields.io/github/stars/modern-python/that-depends)](https://github.com/modern-python/that-depends/stargazers)\n\nDependency injection framework for Python inspired by `dependency-injector`.\n\nIt is production-ready and gives you the following:\n- Simple async-first DI framework with IOC-container.\n- Python 3.10-3.13 support.\n- Full coverage by types annotations (mypy in strict mode).\n- FastAPI and LiteStar compatibility.\n- Overriding dependencies for tests.\n- Injecting dependencies in functions and coroutines without wiring.\n- Package with zero dependencies.\n\n\ud83d\udcda [Documentation](https://that-depends.readthedocs.io)\n\n# Quickstart\n## Install\n```bash\npip install that-depends\n```\n\n## Describe resources and classes:\n```python\nimport dataclasses\nimport logging\nimport typing\n\n\nlogger = logging.getLogger(__name__)\n\n\n# singleton provider with finalization\ndef create_sync_resource() -> typing.Iterator[str]:\n logger.debug(\"Resource initiated\")\n try:\n yield \"sync resource\"\n finally:\n logger.debug(\"Resource destructed\")\n\n\n# same, but async\nasync def create_async_resource() -> typing.AsyncIterator[str]:\n logger.debug(\"Async resource initiated\")\n try:\n yield \"async resource\"\n finally:\n logger.debug(\"Async resource destructed\")\n\n\n@dataclasses.dataclass(kw_only=True, slots=True)\nclass DependentFactory:\n sync_resource: str\n async_resource: str\n```\n\n## Describe IoC-container\n```python\nfrom that_depends import BaseContainer, providers\n\n\nclass DIContainer(BaseContainer):\n sync_resource = providers.Resource(create_sync_resource)\n async_resource = providers.Resource(create_async_resource)\n\n simple_factory = providers.Factory(SimpleFactory, dep1=\"text\", dep2=123)\n dependent_factory = providers.Factory(\n sync_resource=sync_resource,\n async_resource=async_resource,\n )\n```\n\n## Resolve dependencies in your code\n```python\n# async resolving by default:\nawait DIContainer.simple_factory()\n\n# sync resolving is also allowed if there is no uninitialized async resources in dependencies\nDIContainer.simple_factory.sync_resolve()\n\n# otherwise you can initialize resources beforehand one by one or in one call:\nawait DIContainer.init_resources()\n```\n\n## Resolve dependencies not described in container\n```python\n@dataclasses.dataclass(kw_only=True, slots=True)\nclass FreeFactory:\n dependent_factory: DependentFactory\n sync_resource: str\n\n# this way container will try to find providers by names and resolve them to build FreeFactory instance\nfree_factory_instance = await DIContainer.resolve(FreeFactory)\n```\n\n## Inject providers in function arguments\n```python\nimport datetime\n\nfrom that_depends import inject, Provide\n\nfrom tests import container\n\n\n@inject\nasync def some_coroutine(\n simple_factory: container.SimpleFactory = Provide[container.DIContainer.simple_factory],\n dependent_factory: container.DependentFactory = Provide[container.DIContainer.dependent_factory],\n default_zero: int = 0,\n) -> None:\n assert simple_factory.dep1\n assert isinstance(dependent_factory.async_resource, datetime.datetime)\n assert default_zero == 0\n\n@inject\ndef some_function(\n simple_factory: container.SimpleFactory = Provide[container.DIContainer.simple_factory],\n default_zero: int = 0,\n) -> None:\n assert simple_factory.dep1\n assert default_zero == 0\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Simple Dependency Injection framework",
"version": "1.27.0",
"project_urls": {
"docs": "https://that-depends.readthedocs.io",
"repository": "https://github.com/modern-python/that-depends"
},
"split_keywords": [
"dependency injector",
" di",
" ioc-container",
" mocks",
" python"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1a378bd8e79559f662b6d76884a639d7dc9863c030150906ca987f88e8ef0727",
"md5": "2eb30a6f569d4e223a83a957090949af",
"sha256": "bd98ec0a9d069032b2317715bb69658c2eddb1e361cb229ba005ea5c675944da"
},
"downloads": -1,
"filename": "that_depends-1.27.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2eb30a6f569d4e223a83a957090949af",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4,>=3.10",
"size": 15396,
"upload_time": "2024-12-17T20:11:35",
"upload_time_iso_8601": "2024-12-17T20:11:35.499129Z",
"url": "https://files.pythonhosted.org/packages/1a/37/8bd8e79559f662b6d76884a639d7dc9863c030150906ca987f88e8ef0727/that_depends-1.27.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "073906e126820b4bc56ca319d7bb625878479e28519991dac15eccdb1aab1670",
"md5": "36cca09510fe5b01a50e51df6a3d1cfa",
"sha256": "9d8b5500c97c1911a678ab88999a8cba1311e46fc6590bcc4740e36ef67f044c"
},
"downloads": -1,
"filename": "that_depends-1.27.0.tar.gz",
"has_sig": false,
"md5_digest": "36cca09510fe5b01a50e51df6a3d1cfa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4,>=3.10",
"size": 26396,
"upload_time": "2024-12-17T20:11:39",
"upload_time_iso_8601": "2024-12-17T20:11:39.971322Z",
"url": "https://files.pythonhosted.org/packages/07/39/06e126820b4bc56ca319d7bb625878479e28519991dac15eccdb1aab1670/that_depends-1.27.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-17 20:11:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "modern-python",
"github_project": "that-depends",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "that-depends"
}