modern-di-taskiq 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ Metadata-Version: 2.4
2
+ Name: modern-di-taskiq
3
+ Version: 2.0.0
4
+ Summary: modern-di integration for taskiq
5
+ Keywords: dependency-injection,di,ioc-container,modern-di,taskiq,python
6
+ Author: Artur Shiriev
7
+ Author-email: Artur Shiriev <me@shiriev.ru>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Typing :: Typed
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Requires-Dist: taskiq>=0.11,<0.13
19
+ Requires-Dist: modern-di>=2.25,<3
20
+ Requires-Python: >=3.10, <4
21
+ Project-URL: Homepage, https://modern-di.modern-python.org
22
+ Project-URL: Documentation, https://modern-di.modern-python.org
23
+ Project-URL: Repository, https://github.com/modern-python/modern-di-taskiq
24
+ Project-URL: Issues, https://github.com/modern-python/modern-di-taskiq/issues
25
+ Project-URL: Changelog, https://github.com/modern-python/modern-di-taskiq/releases
26
+ Description-Content-Type: text/markdown
27
+
28
+ # modern-di-taskiq
29
+
30
+ [Modern-DI](https://github.com/modern-python/modern-di) integration for [taskiq](https://taskiq-python.github.io).
31
+
32
+ ## Quickstart
33
+
34
+ ```python
35
+ import typing
36
+
37
+ from modern_di import Container, Group, Scope, providers
38
+ from modern_di_taskiq import FromDI, setup_di
39
+ from taskiq import InMemoryBroker
40
+
41
+
42
+ class Settings:
43
+ def __init__(self) -> None:
44
+ self.greeting = "hello"
45
+
46
+
47
+ class Dependencies(Group):
48
+ settings = providers.Factory(scope=Scope.APP, creator=Settings)
49
+
50
+
51
+ broker = InMemoryBroker()
52
+ setup_di(broker, Container(groups=[Dependencies], validate=True))
53
+
54
+
55
+ @broker.task
56
+ async def greet(name: str, settings: typing.Annotated[Settings, FromDI(Dependencies.settings)]) -> str:
57
+ return f"{settings.greeting}, {name}"
58
+ ```
59
+
60
+ See the [documentation](https://modern-di.modern-python.org) for the full guide.
@@ -0,0 +1,33 @@
1
+ # modern-di-taskiq
2
+
3
+ [Modern-DI](https://github.com/modern-python/modern-di) integration for [taskiq](https://taskiq-python.github.io).
4
+
5
+ ## Quickstart
6
+
7
+ ```python
8
+ import typing
9
+
10
+ from modern_di import Container, Group, Scope, providers
11
+ from modern_di_taskiq import FromDI, setup_di
12
+ from taskiq import InMemoryBroker
13
+
14
+
15
+ class Settings:
16
+ def __init__(self) -> None:
17
+ self.greeting = "hello"
18
+
19
+
20
+ class Dependencies(Group):
21
+ settings = providers.Factory(scope=Scope.APP, creator=Settings)
22
+
23
+
24
+ broker = InMemoryBroker()
25
+ setup_di(broker, Container(groups=[Dependencies], validate=True))
26
+
27
+
28
+ @broker.task
29
+ async def greet(name: str, settings: typing.Annotated[Settings, FromDI(Dependencies.settings)]) -> str:
30
+ return f"{settings.greeting}, {name}"
31
+ ```
32
+
33
+ See the [documentation](https://modern-di.modern-python.org) for the full guide.
@@ -0,0 +1,9 @@
1
+ from modern_di_taskiq.main import FromDI, fetch_di_container, setup_di, taskiq_message_provider
2
+
3
+
4
+ __all__ = [
5
+ "FromDI",
6
+ "fetch_di_container",
7
+ "setup_di",
8
+ "taskiq_message_provider",
9
+ ]
@@ -0,0 +1,64 @@
1
+ import dataclasses
2
+ import typing
3
+
4
+ import taskiq
5
+ from modern_di import Container, Scope, providers
6
+ from taskiq import AsyncBroker, Context, TaskiqDepends, TaskiqEvents, TaskiqState
7
+
8
+
9
+ taskiq_message_provider = providers.ContextProvider(taskiq.TaskiqMessage, scope=Scope.REQUEST)
10
+
11
+ # The root container lives on ``broker.state`` under this named attribute. One
12
+ # writer (``setup_di``), one reader (``fetch_di_container``) — naming it keeps
13
+ # them in provable agreement instead of relying on a bare string literal.
14
+ _ROOT_CONTAINER_ATTR = "modern_di_container"
15
+
16
+ _CONNECTION_PROVIDERS = (taskiq_message_provider,)
17
+
18
+
19
+ def setup_di(broker: AsyncBroker, container: Container) -> Container:
20
+ setattr(broker.state, _ROOT_CONTAINER_ATTR, container)
21
+ container.add_providers(*_CONNECTION_PROVIDERS)
22
+
23
+ def _open_root(_state: TaskiqState) -> None:
24
+ container.open()
25
+
26
+ async def _close_root(_state: TaskiqState) -> None:
27
+ await container.close_async()
28
+
29
+ broker.add_event_handler(TaskiqEvents.WORKER_STARTUP, _open_root)
30
+ broker.add_event_handler(TaskiqEvents.WORKER_SHUTDOWN, _close_root)
31
+ return container
32
+
33
+
34
+ def fetch_di_container(broker: AsyncBroker) -> Container:
35
+ return typing.cast(Container, getattr(broker.state, _ROOT_CONTAINER_ATTR))
36
+
37
+
38
+ T_co = typing.TypeVar("T_co", covariant=True)
39
+
40
+
41
+ async def build_di_container(
42
+ context: typing.Annotated[Context, TaskiqDepends()],
43
+ ) -> typing.AsyncIterator[Container]:
44
+ container = fetch_di_container(context.broker).build_child_container(
45
+ scope=Scope.REQUEST, context={taskiq.TaskiqMessage: context.message}
46
+ )
47
+ try:
48
+ yield container
49
+ finally:
50
+ await container.close_async()
51
+
52
+
53
+ @dataclasses.dataclass(slots=True, frozen=True)
54
+ class Dependency(typing.Generic[T_co]):
55
+ dependency: providers.AbstractProvider[T_co] | type[T_co]
56
+
57
+ async def __call__(self, request_container: typing.Annotated[Container, TaskiqDepends(build_di_container)]) -> T_co:
58
+ return request_container.resolve_dependency(self.dependency)
59
+
60
+
61
+ def FromDI( # noqa: N802
62
+ dependency: providers.AbstractProvider[T_co] | type[T_co], *, use_cache: bool = True
63
+ ) -> T_co:
64
+ return typing.cast(T_co, TaskiqDepends(Dependency(dependency), use_cache=use_cache))
File without changes
@@ -0,0 +1,84 @@
1
+ [project]
2
+ name = "modern-di-taskiq"
3
+ description = "modern-di integration for taskiq"
4
+ authors = [{ name = "Artur Shiriev", email = "me@shiriev.ru" }]
5
+ requires-python = ">=3.10,<4"
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ keywords = ["dependency-injection", "di", "ioc-container", "modern-di", "taskiq", "python"]
9
+ classifiers = [
10
+ "Development Status :: 5 - Production/Stable",
11
+ "Intended Audience :: Developers",
12
+ "Programming Language :: Python :: 3.10",
13
+ "Programming Language :: Python :: 3.11",
14
+ "Programming Language :: Python :: 3.12",
15
+ "Programming Language :: Python :: 3.13",
16
+ "Programming Language :: Python :: 3.14",
17
+ "Typing :: Typed",
18
+ "Topic :: Software Development :: Libraries",
19
+ ]
20
+ dependencies = ["taskiq>=0.11,<0.13", "modern-di>=2.25,<3"]
21
+ version = "2.0.0"
22
+
23
+ [project.urls]
24
+ Homepage = "https://modern-di.modern-python.org"
25
+ Documentation = "https://modern-di.modern-python.org"
26
+ Repository = "https://github.com/modern-python/modern-di-taskiq"
27
+ Issues = "https://github.com/modern-python/modern-di-taskiq/issues"
28
+ Changelog = "https://github.com/modern-python/modern-di-taskiq/releases"
29
+
30
+ [dependency-groups]
31
+ dev = [
32
+ "pytest",
33
+ "pytest-cov",
34
+ "pytest-asyncio",
35
+ ]
36
+ lint = [
37
+ "ty",
38
+ "ruff",
39
+ "eof-fixer",
40
+ "typing-extensions",
41
+ ]
42
+
43
+ [build-system]
44
+ requires = ["uv_build>=0.11,<1.0"]
45
+ build-backend = "uv_build"
46
+
47
+ [tool.uv.build-backend]
48
+ module-name = "modern_di_taskiq"
49
+ module-root = ""
50
+
51
+ [tool.ruff]
52
+ fix = false
53
+ unsafe-fixes = true
54
+ line-length = 120
55
+ target-version = "py310"
56
+
57
+ [tool.ruff.format]
58
+ docstring-code-format = true
59
+
60
+ [tool.ruff.lint]
61
+ select = ["ALL"]
62
+ ignore = [
63
+ "D1", # allow missing docstrings
64
+ "S101", # allow asserts
65
+ "TCH", # ignore flake8-type-checking
66
+ "FBT", # allow boolean args
67
+ "D203", # "one-blank-line-before-class" conflicting with D211
68
+ "D213", # "multi-line-summary-second-line" conflicting with D212
69
+ "COM812", # flake8-commas "Trailing comma missing"
70
+ "ISC001", # flake8-implicit-str-concat
71
+ "G004", # allow f-strings in logging
72
+ ]
73
+ isort.lines-after-imports = 2
74
+ isort.no-lines-before = ["standard-library", "local-folder"]
75
+
76
+ [tool.pytest.ini_options]
77
+ addopts = ""
78
+ asyncio_mode = "auto"
79
+ asyncio_default_fixture_loop_scope = "function"
80
+
81
+ [tool.coverage.report]
82
+ exclude_also = [
83
+ "if typing.TYPE_CHECKING:",
84
+ ]