digitalkin 0.3.0rc2__tar.gz → 0.3.1.dev0__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.
Files changed (125) hide show
  1. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/PKG-INFO +7 -7
  2. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/pyproject.toml +37 -19
  3. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/__version__.py +1 -1
  4. digitalkin-0.3.1.dev0/src/digitalkin/core/common/__init__.py +9 -0
  5. digitalkin-0.3.1.dev0/src/digitalkin/core/common/factories.py +156 -0
  6. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +128 -28
  7. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +80 -25
  8. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/job_manager/taskiq_broker.py +114 -19
  9. digitalkin-0.3.1.dev0/src/digitalkin/core/job_manager/taskiq_job_manager.py +542 -0
  10. digitalkin-0.3.1.dev0/src/digitalkin/core/task_manager/base_task_manager.py +464 -0
  11. digitalkin-0.3.1.dev0/src/digitalkin/core/task_manager/local_task_manager.py +108 -0
  12. digitalkin-0.3.1.dev0/src/digitalkin/core/task_manager/remote_task_manager.py +87 -0
  13. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/task_manager/surrealdb_repository.py +43 -4
  14. digitalkin-0.3.1.dev0/src/digitalkin/core/task_manager/task_executor.py +173 -0
  15. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/task_manager/task_session.py +34 -12
  16. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/module_server.py +2 -2
  17. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/module_servicer.py +4 -3
  18. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/registry_server.py +1 -1
  19. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/registry_servicer.py +4 -4
  20. digitalkin-0.3.1.dev0/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +53 -0
  21. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/grpc_servers/models.py +4 -4
  22. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/cost/grpc_cost.py +8 -41
  23. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +9 -38
  24. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/setup/default_setup.py +5 -6
  25. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/setup/grpc_setup.py +51 -14
  26. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/storage/grpc_storage.py +2 -2
  27. digitalkin-0.3.1.dev0/src/digitalkin/services/user_profile/__init__.py +1 -0
  28. digitalkin-0.3.1.dev0/src/digitalkin/services/user_profile/default_user_profile.py +55 -0
  29. digitalkin-0.3.1.dev0/src/digitalkin/services/user_profile/grpc_user_profile.py +69 -0
  30. digitalkin-0.3.1.dev0/src/digitalkin/services/user_profile/user_profile_strategy.py +40 -0
  31. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin.egg-info/PKG-INFO +7 -7
  32. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin.egg-info/SOURCES.txt +11 -1
  33. digitalkin-0.3.1.dev0/src/digitalkin.egg-info/requires.txt +12 -0
  34. digitalkin-0.3.0rc2/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -289
  35. digitalkin-0.3.0rc2/src/digitalkin/core/task_manager/task_manager.py +0 -442
  36. digitalkin-0.3.0rc2/src/digitalkin.egg-info/requires.txt +0 -12
  37. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/LICENSE +0 -0
  38. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/README.md +0 -0
  39. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/__init__.py +0 -0
  40. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/mock/__init__.py +0 -0
  41. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
  42. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  43. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/server_async_insecure.py +0 -0
  44. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/server_async_secure.py +0 -0
  45. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/server_sync_insecure.py +0 -0
  46. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/base_server/server_sync_secure.py +0 -0
  47. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/modules/__init__.py +0 -0
  48. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/modules/cpu_intensive_module.py +0 -0
  49. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/modules/minimal_llm_module.py +0 -0
  50. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/modules/text_transform_module.py +0 -0
  51. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/services/filesystem_module.py +0 -0
  52. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/examples/services/storage_module.py +0 -0
  53. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/setup.cfg +0 -0
  54. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/__init__.py +0 -0
  55. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/__init__.py +0 -0
  56. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
  57. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
  58. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
  59. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  60. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  61. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
  62. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  63. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/logger.py +0 -0
  64. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/__init__.py +0 -0
  65. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
  66. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/callback_mixin.py +0 -0
  67. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
  68. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
  69. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  70. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  71. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
  72. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
  73. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/__init__.py +0 -0
  74. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/core/__init__.py +0 -0
  75. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
  76. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
  77. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  78. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
  79. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/module/__init__.py +0 -0
  80. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/module/module.py +0 -0
  81. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/module/module_context.py +0 -0
  82. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/module/module_types.py +0 -0
  83. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/services/__init__.py +0 -0
  84. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/services/cost.py +0 -0
  85. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/models/services/storage.py +0 -0
  86. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/modules/__init__.py +0 -0
  87. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/modules/_base_module.py +0 -0
  88. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/modules/archetype_module.py +0 -0
  89. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/modules/tool_module.py +0 -0
  90. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/modules/trigger_handler.py +0 -0
  91. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/py.typed +0 -0
  92. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/__init__.py +0 -0
  93. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/agent/__init__.py +0 -0
  94. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/agent/agent_strategy.py +0 -0
  95. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/agent/default_agent.py +0 -0
  96. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/base_strategy.py +0 -0
  97. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
  98. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  99. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
  100. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
  101. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  102. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  103. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
  104. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/identity/default_identity.py +0 -0
  105. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  106. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
  107. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/registry/default_registry.py +0 -0
  108. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/registry/registry_strategy.py +0 -0
  109. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/services_config.py +0 -0
  110. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/services_models.py +0 -0
  111. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
  112. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  113. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/snapshot/__init__.py +0 -0
  114. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
  115. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
  116. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
  117. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/storage/default_storage.py +0 -0
  118. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  119. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/utils/__init__.py +0 -0
  120. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/utils/arg_parser.py +0 -0
  121. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/utils/development_mode_action.py +0 -0
  122. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  123. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin/utils/package_discover.py +0 -0
  124. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  125. {digitalkin-0.3.0rc2 → digitalkin-0.3.1.dev0}/src/digitalkin.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.3.0rc2
3
+ Version: 0.3.1.dev0
4
4
  Summary: SDK to build kin used in DigitalKin
5
5
  Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
6
6
  License: Attribution-NonCommercial-ShareAlike 4.0 International
@@ -452,17 +452,17 @@ Classifier: License :: Other/Proprietary License
452
452
  Requires-Python: >=3.10
453
453
  Description-Content-Type: text/markdown
454
454
  License-File: LICENSE
455
- Requires-Dist: digitalkin-proto>=0.1.16
456
- Requires-Dist: grpcio-health-checking>=1.71.0
457
- Requires-Dist: grpcio-reflection>=1.71.0
458
- Requires-Dist: grpcio-status>=1.71.0
459
- Requires-Dist: pydantic>=2.12.3
455
+ Requires-Dist: digitalkin-proto>=0.2.0.dev4
456
+ Requires-Dist: grpcio-health-checking>=1.76.0
457
+ Requires-Dist: grpcio-reflection>=1.76.0
458
+ Requires-Dist: grpcio-status>=1.76.0
459
+ Requires-Dist: pydantic>=2.12.4
460
460
  Requires-Dist: surrealdb>=1.0.6
461
461
  Provides-Extra: taskiq
462
462
  Requires-Dist: rstream>=0.40.0; extra == "taskiq"
463
463
  Requires-Dist: taskiq-aio-pika>=0.4.4; extra == "taskiq"
464
464
  Requires-Dist: taskiq-redis>=1.1.2; extra == "taskiq"
465
- Requires-Dist: taskiq[reload]>=0.11.19; extra == "taskiq"
465
+ Requires-Dist: taskiq[reload]>=0.11.20; extra == "taskiq"
466
466
  Dynamic: license-file
467
467
 
468
468
  # DigitalKin Python SDK
@@ -12,7 +12,7 @@
12
12
 
13
13
  keywords = [ "digitalkin", "kin", "agent", "gprc", "sdk" ]
14
14
 
15
- version = "0.3.0-rc2"
15
+ version = "0.3.1.dev0"
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",
@@ -28,11 +28,11 @@
28
28
  ]
29
29
 
30
30
  dependencies = [
31
- "digitalkin-proto>=0.1.16",
32
- "grpcio-health-checking>=1.71.0",
33
- "grpcio-reflection>=1.71.0",
34
- "grpcio-status>=1.71.0",
35
- "pydantic>=2.12.3",
31
+ "digitalkin-proto>=0.2.0.dev4",
32
+ "grpcio-health-checking>=1.76.0",
33
+ "grpcio-reflection>=1.76.0",
34
+ "grpcio-status>=1.76.0",
35
+ "pydantic>=2.12.4",
36
36
  "surrealdb>=1.0.6",
37
37
  ]
38
38
 
@@ -41,7 +41,7 @@
41
41
  "rstream>=0.40.0",
42
42
  "taskiq-aio-pika>=0.4.4",
43
43
  "taskiq-redis>=1.1.2",
44
- "taskiq[reload]>=0.11.19",
44
+ "taskiq[reload]>=0.11.20",
45
45
  ]
46
46
 
47
47
  [project.urls]
@@ -55,11 +55,11 @@
55
55
 
56
56
  [dependency-groups]
57
57
  dev = [
58
- "typos>=1.38.0",
59
- "ruff>=0.14.2",
58
+ "typos>=1.39.2",
59
+ "ruff>=0.14.5",
60
60
  "mypy>=1.18.2",
61
61
  "pyright>=1.1.407",
62
- "pre-commit>=4.3.0",
62
+ "pre-commit>=4.4.0",
63
63
  "bump-my-version>=1.2.4",
64
64
  "build>=1.3.0",
65
65
  "twine>=6.2.0",
@@ -68,18 +68,19 @@
68
68
  tests = [
69
69
  "freezegun>=1.5.3",
70
70
  "hdrhistogram>=0.10.3",
71
- "grpcio-testing>=1.71.0",
72
- "psutil>=7.1.2",
73
- "pytest>=8.4.2",
74
- "pytest-asyncio>=1.2.0",
71
+ "grpcio-testing>=1.76.0",
72
+ "psutil>=7.1.3",
73
+ "pytest>=9.0.1",
74
+ "pytest-asyncio>=1.3.0",
75
75
  "pytest-cov>=7.0.0",
76
76
  "pytest-html==4.1.1",
77
77
  "pytest-json-report==1.5.0",
78
+ "pytest-timeout>=2.3.1",
78
79
  ]
79
80
  docs = [
80
81
  "mike>=2.1.3",
81
82
  "markdown-callouts>=0.4",
82
- "markdown-exec>=1.8",
83
+ "markdown-exec>=1.12.1",
83
84
  "mkdocs>=1.6",
84
85
  "mkdocs-coverage>=2.0.0",
85
86
  "mkdocs-llmstxt>=0.2",
@@ -89,18 +90,18 @@
89
90
  "mkdocs-autorefs>=1.4.3",
90
91
  "mkdocs-awesome-pages-plugin>=2.10.1",
91
92
  "mkdocs-git-committers-plugin-2>=2.5.0",
92
- "mkdocs-git-revision-date-localized-plugin>=1.4.7",
93
+ "mkdocs-git-revision-date-localized-plugin>=1.5.0",
93
94
  "mkdocs-glightbox>=0.5.2",
94
95
  "mkdocs-include-markdown-plugin>=7.2.0",
95
96
  "mkdocs-literate-nav>=0.6.2",
96
- "mkdocs-material[imaging]>=9.6.22",
97
+ "mkdocs-material[imaging]>=9.7.0",
97
98
  "mkdocs-minify-plugin>=0.8.0",
98
99
  "mkdocs-section-index>=0.3.10",
99
100
  "mkdocstrings>=0.30.1",
100
- "mkdocstrings-python>=1.18.2",
101
+ "mkdocstrings-python>=1.19.0",
101
102
  "mkdocs-open-in-new-tab>=1.0.8",
102
103
  "tomli>=2.3.0",
103
- ]
104
+ ]
104
105
 
105
106
  [tool.setuptools]
106
107
  package-dir = { "" = "src" }
@@ -261,3 +262,20 @@
261
262
  testpaths = [ "tests" ]
262
263
  python_files = "test_*.py"
263
264
  asyncio_mode = "auto"
265
+
266
+ log_cli = false
267
+ log_level = "ERROR"
268
+
269
+ # Default timeout for tests (in seconds)
270
+ timeout = 10
271
+ timeout_method = "signal" # More reliable for asyncio tests on Linux
272
+
273
+ # Custom markers
274
+ markers = [
275
+ "integration: marks tests that require real SurrealDB connection (deselect with '-m \"not integration\"')",
276
+ "grpc: marks tests for gRPC service functionality",
277
+ "smoke: marks critical path tests that should always pass",
278
+ "edge_case: marks tests for boundary conditions and edge cases",
279
+ "validation: marks tests for input validation and schema checking",
280
+ "regression: marks tests for previously fixed bugs",
281
+ ]
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "0.3.0-rc2"
8
+ __version__ = "0.3.1.dev0"
@@ -0,0 +1,9 @@
1
+ """Common utilities for the core module."""
2
+
3
+ from digitalkin.core.common.factories import ConnectionFactory, ModuleFactory, QueueFactory
4
+
5
+ __all__ = [
6
+ "ConnectionFactory",
7
+ "ModuleFactory",
8
+ "QueueFactory",
9
+ ]
@@ -0,0 +1,156 @@
1
+ """Common factory functions for reducing code duplication in core module."""
2
+
3
+ import asyncio
4
+ import datetime
5
+
6
+ from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
7
+ from digitalkin.logger import logger
8
+ from digitalkin.modules._base_module import BaseModule
9
+
10
+
11
+ class ConnectionFactory:
12
+ """Factory for creating SurrealDB connections with consistent configuration."""
13
+
14
+ @staticmethod
15
+ async def create_surreal_connection(
16
+ database: str = "task_manager",
17
+ timeout: datetime.timedelta = datetime.timedelta(seconds=5),
18
+ *,
19
+ auto_init: bool = True,
20
+ ) -> SurrealDBConnection:
21
+ """Create and optionally initialize a SurrealDB connection.
22
+
23
+ This factory method centralizes the creation of SurrealDB connections
24
+ to ensure consistent configuration across the codebase.
25
+
26
+ Args:
27
+ database: Database name to connect to
28
+ timeout: Connection timeout
29
+ auto_init: Whether to automatically initialize the connection
30
+
31
+ Returns:
32
+ Initialized or uninitialized SurrealDBConnection instance
33
+
34
+ Example:
35
+ # Create and auto-initialize
36
+ conn = await ConnectionFactory.create_surreal_connection("taskiq_worker")
37
+
38
+ # Create without initialization
39
+ conn = await ConnectionFactory.create_surreal_connection(auto_init=False)
40
+ await conn.init_surreal_instance()
41
+ """
42
+ logger.debug(
43
+ "Creating SurrealDB connection for database: %s, timeout: %s",
44
+ database,
45
+ timeout,
46
+ extra={"database": database, "timeout": str(timeout)},
47
+ )
48
+
49
+ connection: SurrealDBConnection = SurrealDBConnection(database, timeout)
50
+
51
+ if auto_init:
52
+ await connection.init_surreal_instance()
53
+ logger.debug("SurrealDB connection initialized for database: %s", database)
54
+
55
+ return connection
56
+
57
+
58
+ class ModuleFactory:
59
+ """Factory for creating module instances with consistent configuration."""
60
+
61
+ @staticmethod
62
+ def create_module_instance(
63
+ module_class: type[BaseModule],
64
+ job_id: str,
65
+ mission_id: str,
66
+ setup_id: str,
67
+ setup_version_id: str,
68
+ ) -> BaseModule:
69
+ """Create a module instance with standard parameters.
70
+
71
+ This factory method centralizes module instantiation to ensure
72
+ consistent parameter passing across the codebase.
73
+
74
+ Args:
75
+ module_class: The module class to instantiate
76
+ job_id: Unique job identifier
77
+ mission_id: Mission identifier
78
+ setup_id: Setup identifier
79
+ setup_version_id: Setup version identifier
80
+
81
+ Returns:
82
+ Instantiated module
83
+
84
+ Raises:
85
+ ValueError: If job_id or mission_id is empty
86
+
87
+ Example:
88
+ module = ModuleFactory.create_module_instance(
89
+ MyModule,
90
+ job_id="job_123",
91
+ mission_id="mission:test",
92
+ setup_id="setup:config",
93
+ setup_version_id="v1.0",
94
+ )
95
+ """
96
+ # Validate parameters
97
+ if not job_id:
98
+ msg = "job_id cannot be empty"
99
+ raise ValueError(msg)
100
+ if not mission_id:
101
+ msg = "mission_id cannot be empty"
102
+ raise ValueError(msg)
103
+
104
+ logger.debug(
105
+ "Creating module instance: %s for job: %s",
106
+ module_class.__name__,
107
+ job_id,
108
+ extra={
109
+ "module_class": module_class.__name__,
110
+ "job_id": job_id,
111
+ "mission_id": mission_id,
112
+ "setup_id": setup_id,
113
+ "setup_version_id": setup_version_id,
114
+ },
115
+ )
116
+
117
+ return module_class(
118
+ job_id=job_id,
119
+ mission_id=mission_id,
120
+ setup_id=setup_id,
121
+ setup_version_id=setup_version_id,
122
+ )
123
+
124
+
125
+ class QueueFactory:
126
+ """Factory for creating asyncio queues with consistent configuration."""
127
+
128
+ # Default max queue size to prevent unbounded memory growth
129
+ DEFAULT_MAX_QUEUE_SIZE = 1000
130
+
131
+ @staticmethod
132
+ def create_bounded_queue(maxsize: int = DEFAULT_MAX_QUEUE_SIZE) -> asyncio.Queue:
133
+ """Create a bounded asyncio queue with standard configuration.
134
+
135
+ Args:
136
+ maxsize: Maximum queue size (default 1000, 0 means unlimited)
137
+
138
+ Returns:
139
+ Bounded asyncio.Queue instance
140
+
141
+ Raises:
142
+ ValueError: If maxsize is negative
143
+
144
+ Example:
145
+ queue = QueueFactory.create_bounded_queue()
146
+ # or with custom size
147
+ queue = QueueFactory.create_bounded_queue(maxsize=500)
148
+ # unlimited queue
149
+ queue = QueueFactory.create_bounded_queue(maxsize=0)
150
+ """
151
+ if maxsize < 0:
152
+ msg = "maxsize must be >= 0"
153
+ raise ValueError(msg)
154
+
155
+ logger.debug("Creating bounded queue with maxsize: %d", maxsize, extra={"maxsize": maxsize})
156
+ return asyncio.Queue(maxsize=maxsize)
@@ -5,7 +5,8 @@ from collections.abc import AsyncGenerator, AsyncIterator, Callable, Coroutine
5
5
  from contextlib import asynccontextmanager
6
6
  from typing import Any, Generic
7
7
 
8
- from digitalkin.core.task_manager.task_manager import TaskManager
8
+ from digitalkin.core.task_manager.base_task_manager import BaseTaskManager
9
+ from digitalkin.core.task_manager.task_session import TaskSession
9
10
  from digitalkin.models.core.task_monitor import TaskStatus
10
11
  from digitalkin.models.module import InputModelT, OutputModelT, SetupModelT
11
12
  from digitalkin.models.module.module import ModuleCodeModel
@@ -14,9 +15,115 @@ from digitalkin.services.services_config import ServicesConfig
14
15
  from digitalkin.services.services_models import ServicesMode
15
16
 
16
17
 
17
- class BaseJobManager(abc.ABC, TaskManager, Generic[InputModelT, SetupModelT, OutputModelT]):
18
- """Abstract base class for managing background module jobs."""
18
+ class BaseJobManager(abc.ABC, Generic[InputModelT, OutputModelT, SetupModelT]):
19
+ """Abstract base class for managing background module jobs.
19
20
 
21
+ Uses composition to delegate task lifecycle management to a TaskManager.
22
+ """
23
+
24
+ module_class: type[BaseModule]
25
+ services_mode: ServicesMode
26
+ _task_manager: BaseTaskManager
27
+
28
+ def __init__(
29
+ self,
30
+ module_class: type[BaseModule],
31
+ services_mode: ServicesMode,
32
+ task_manager: BaseTaskManager,
33
+ ) -> None:
34
+ """Initialize the job manager.
35
+
36
+ Args:
37
+ module_class: The class of the module to be managed.
38
+ services_mode: The mode of operation for the services (e.g., ASYNC or SYNC).
39
+ task_manager: The task manager instance to use for task lifecycle management.
40
+ """
41
+ self.module_class = module_class
42
+ self.services_mode = services_mode
43
+ self._task_manager = task_manager
44
+
45
+ services_config = ServicesConfig(
46
+ services_config_strategies=self.module_class.services_config_strategies,
47
+ services_config_params=self.module_class.services_config_params,
48
+ mode=services_mode,
49
+ )
50
+ setattr(self.module_class, "services_config", services_config)
51
+
52
+ # Properties to expose task manager attributes
53
+ @property
54
+ def tasks_sessions(self) -> dict[str, TaskSession]:
55
+ """Get task sessions from the task manager."""
56
+ return self._task_manager.tasks_sessions
57
+
58
+ @property
59
+ def tasks(self) -> dict[str, Any]:
60
+ """Get tasks from the task manager."""
61
+ return self._task_manager.tasks
62
+
63
+ # Delegate task lifecycle methods to task manager
64
+ async def create_task(
65
+ self,
66
+ task_id: str,
67
+ mission_id: str,
68
+ module: BaseModule,
69
+ coro: Coroutine[Any, Any, None],
70
+ **kwargs: Any, # noqa: ANN401
71
+ ) -> None:
72
+ """Create a task using the task manager.
73
+
74
+ Args:
75
+ task_id: Unique identifier for the task
76
+ mission_id: Mission identifier
77
+ module: Module instance
78
+ coro: Coroutine to execute
79
+ **kwargs: Additional arguments for task creation
80
+ """
81
+ await self._task_manager.create_task(task_id, mission_id, module, coro, **kwargs)
82
+
83
+ async def clean_session(self, task_id: str, mission_id: str) -> bool:
84
+ """Clean a task's session.
85
+
86
+ Args:
87
+ task_id: Unique identifier for the task.
88
+ mission_id: Mission identifier.
89
+
90
+ Returns:
91
+ bool: True if the task was successfully cancelled, False otherwise.
92
+ """
93
+ return await self._task_manager.clean_session(task_id, mission_id)
94
+
95
+ async def cancel_task(self, task_id: str, mission_id: str, timeout: float | None = None) -> bool:
96
+ """Cancel a task.
97
+
98
+ Args:
99
+ task_id: Unique identifier for the task.
100
+ mission_id: Mission identifier.
101
+ timeout: Optional timeout in seconds to wait for the cancellation to complete.
102
+
103
+ Returns:
104
+ bool: True if the task was successfully cancelled, False otherwise.
105
+ """
106
+ return await self._task_manager.cancel_task(task_id, mission_id, timeout)
107
+
108
+ async def send_signal(self, task_id: str, mission_id: str, signal_type: str, payload: dict) -> bool:
109
+ """Send signal to a task.
110
+
111
+ Args:
112
+ task_id: Unique identifier for the task.
113
+ mission_id: Mission identifier.
114
+ signal_type: Type of signal to send.
115
+ payload: Payload data for the signal.
116
+
117
+ Returns:
118
+ bool: True if the signal was successfully sent, False otherwise.
119
+ """
120
+ return await self._task_manager.send_signal(task_id, mission_id, signal_type, payload)
121
+
122
+ async def shutdown(self, mission_id: str, timeout: float = 30.0) -> None:
123
+ """Shutdown all tasks."""
124
+ await self._task_manager.shutdown(mission_id, timeout)
125
+
126
+ @abc.abstractmethod
20
127
  async def start(self) -> None:
21
128
  """Start the job manager.
22
129
 
@@ -52,29 +159,6 @@ class BaseJobManager(abc.ABC, TaskManager, Generic[InputModelT, SetupModelT, Out
52
159
 
53
160
  return callback_wrapper
54
161
 
55
- def __init__(
56
- self,
57
- module_class: type[BaseModule],
58
- services_mode: ServicesMode,
59
- **kwargs, # noqa: ANN003
60
- ) -> None:
61
- """Initialize the job manager.
62
-
63
- Args:
64
- module_class: The class of the module to be managed.
65
- services_mode: The mode of operation for the services (e.g., ASYNC or SYNC).
66
- **kwargs: Additional keyword arguments for the job manager.
67
- """
68
- self.module_class = module_class
69
-
70
- services_config = ServicesConfig(
71
- services_config_strategies=self.module_class.services_config_strategies,
72
- services_config_params=self.module_class.services_config_params,
73
- mode=services_mode,
74
- )
75
- setattr(self.module_class, "services_config", services_config)
76
- super().__init__(**kwargs)
77
-
78
162
  @abc.abstractmethod # type: ignore
79
163
  @asynccontextmanager # type: ignore
80
164
  async def generate_stream_consumer(self, job_id: str) -> AsyncIterator[AsyncGenerator[dict[str, Any], None]]:
@@ -110,7 +194,7 @@ class BaseJobManager(abc.ABC, TaskManager, Generic[InputModelT, SetupModelT, Out
110
194
  """
111
195
 
112
196
  @abc.abstractmethod
113
- async def generate_config_setup_module_response(self, job_id: str) -> SetupModelT:
197
+ async def generate_config_setup_module_response(self, job_id: str) -> SetupModelT | ModuleCodeModel:
114
198
  """Generate a stream consumer for a module's output data.
115
199
 
116
200
  This method creates an asynchronous generator that streams output data
@@ -121,7 +205,7 @@ class BaseJobManager(abc.ABC, TaskManager, Generic[InputModelT, SetupModelT, Out
121
205
  job_id: The unique identifier of the job.
122
206
 
123
207
  Returns:
124
- SetupModelT: the SetupModelT object fully processed.
208
+ SetupModelT | ModuleCodeModel: the SetupModelT object fully processed, or an error code.
125
209
  """
126
210
 
127
211
  @abc.abstractmethod
@@ -172,6 +256,22 @@ class BaseJobManager(abc.ABC, TaskManager, Generic[InputModelT, SetupModelT, Out
172
256
  ModuleStatu: The status of the job.
173
257
  """
174
258
 
259
+ @abc.abstractmethod
260
+ async def wait_for_completion(self, job_id: str) -> None:
261
+ """Wait for a task to complete.
262
+
263
+ This method blocks until the specified job has reached a terminal state.
264
+ The implementation varies by job manager type:
265
+ - SingleJobManager: Awaits the asyncio.Task directly
266
+ - TaskiqJobManager: Polls task status from SurrealDB
267
+
268
+ Args:
269
+ job_id: The unique identifier of the job to wait for.
270
+
271
+ Raises:
272
+ KeyError: If the job_id is not found.
273
+ """
274
+
175
275
  @abc.abstractmethod
176
276
  async def stop_all_modules(self) -> None:
177
277
  """Stop all currently running module jobs.