simstack 2.0.1__py3-none-any.whl

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 (354) hide show
  1. simstack/__init__.py +0 -0
  2. simstack/_version.py +24 -0
  3. simstack/core/__init__.py +0 -0
  4. simstack/core/artifacts.py +406 -0
  5. simstack/core/asnyc_helper.py +14 -0
  6. simstack/core/config_file.py +60 -0
  7. simstack/core/context.py +283 -0
  8. simstack/core/definitions.py +22 -0
  9. simstack/core/engine.py +115 -0
  10. simstack/core/find_simstack_modules.py +41 -0
  11. simstack/core/hash.py +179 -0
  12. simstack/core/node.py +1137 -0
  13. simstack/core/node_claim.py +31 -0
  14. simstack/core/node_runner.py +362 -0
  15. simstack/core/process_results.py +102 -0
  16. simstack/core/recompute_artifacts.py +117 -0
  17. simstack/core/reset_db.py +12 -0
  18. simstack/core/resource_assignment.py +222 -0
  19. simstack/core/resources.py +90 -0
  20. simstack/core/route_table.py +24 -0
  21. simstack/core/run_docker.py +109 -0
  22. simstack/core/run_node.py +71 -0
  23. simstack/core/runner.py +169 -0
  24. simstack/core/services/__init__.py +11 -0
  25. simstack/core/services/base_service.py +191 -0
  26. simstack/core/services/file_transfer_service.py +117 -0
  27. simstack/core/services/git_restart_service.py +12 -0
  28. simstack/core/services/git_uv_update_service.py +105 -0
  29. simstack/core/services/node_execution_service.py +182 -0
  30. simstack/core/services/resource_branch_monitor_service.py +71 -0
  31. simstack/core/services/runner_cleanup_service.py +149 -0
  32. simstack/core/services/runner_manager.py +163 -0
  33. simstack/core/services/runner_status_service.py +10 -0
  34. simstack/core/services/slurm_status_service.py +67 -0
  35. simstack/core/services/stop_check_service.py +27 -0
  36. simstack/core/services/timeout_restart_service.py +26 -0
  37. simstack/core/simstack_result.py +39 -0
  38. simstack/core/submit_node.py +217 -0
  39. simstack/core/task_id.py +22 -0
  40. simstack/methods/__init__.py +0 -0
  41. simstack/methods/archive_files.py +292 -0
  42. simstack/methods/fire_and_forget_runner.py +113 -0
  43. simstack/methods/generate_test.py +125 -0
  44. simstack/methods/get_file.py +26 -0
  45. simstack/methods/mass_runner.py +154 -0
  46. simstack/methods/multiple_executor.py +307 -0
  47. simstack/methods/switch_git.py +16 -0
  48. simstack/methods/upload_helpers.py +81 -0
  49. simstack/models/__init__.py +74 -0
  50. simstack/models/array_list.py +21 -0
  51. simstack/models/array_storage.py +83 -0
  52. simstack/models/artifact_models.py +127 -0
  53. simstack/models/base_lists.py +51 -0
  54. simstack/models/base_types.py +209 -0
  55. simstack/models/charts_artifact.py +690 -0
  56. simstack/models/dataset.py +451 -0
  57. simstack/models/dataset_metadata.py +390 -0
  58. simstack/models/datasettuple.py +587 -0
  59. simstack/models/file_instance.py +150 -0
  60. simstack/models/file_list.py +45 -0
  61. simstack/models/files.py +424 -0
  62. simstack/models/fire_and_forget_result.py +19 -0
  63. simstack/models/images2d.py +113 -0
  64. simstack/models/log_entry_model.py +37 -0
  65. simstack/models/models.py +52 -0
  66. simstack/models/named_data_reference.py +36 -0
  67. simstack/models/node_registry.py +96 -0
  68. simstack/models/pandas_model.py +239 -0
  69. simstack/models/parameters.py +402 -0
  70. simstack/models/pickle_models.py +300 -0
  71. simstack/models/project.py +13 -0
  72. simstack/models/resource_assignment.py +170 -0
  73. simstack/models/resource_definition.py +125 -0
  74. simstack/models/runner_model.py +39 -0
  75. simstack/models/simple_table.py +79 -0
  76. simstack/models/simstack_model.py +97 -0
  77. simstack/models/slurm_info.py +17 -0
  78. simstack/models/table_artifact.py +87 -0
  79. simstack/models/tag.py +12 -0
  80. simstack/models/unused_test_file.py +5 -0
  81. simstack/simstack_marker.com +1 -0
  82. simstack/static/docs/.buildinfo +4 -0
  83. simstack/static/docs/_images/GUI Concept.webp +0 -0
  84. simstack/static/docs/_modules/index.html +434 -0
  85. simstack/static/docs/_modules/simstack/core/artifacts.html +743 -0
  86. simstack/static/docs/_modules/simstack/core/asnyc_helper.html +330 -0
  87. simstack/static/docs/_modules/simstack/core/config_file.html +379 -0
  88. simstack/static/docs/_modules/simstack/core/definitions.html +341 -0
  89. simstack/static/docs/_modules/simstack/core/engine.html +437 -0
  90. simstack/static/docs/_modules/simstack/core/find_simstack_modules.html +360 -0
  91. simstack/static/docs/_modules/simstack/core/hash.html +528 -0
  92. simstack/static/docs/_modules/simstack/core/node.html +1392 -0
  93. simstack/static/docs/_modules/simstack/core/node_claim.html +347 -0
  94. simstack/static/docs/_modules/simstack/core/node_runner.html +711 -0
  95. simstack/static/docs/_modules/simstack/core/process_results.html +418 -0
  96. simstack/static/docs/_modules/simstack/core/recompute_artifacts.html +433 -0
  97. simstack/static/docs/_modules/simstack/core/reset_db.html +328 -0
  98. simstack/static/docs/_modules/simstack/core/resource_assignment.html +553 -0
  99. simstack/static/docs/_modules/simstack/core/resources.html +424 -0
  100. simstack/static/docs/_modules/simstack/core/route_table.html +349 -0
  101. simstack/static/docs/_modules/simstack/core/run_docker.html +425 -0
  102. simstack/static/docs/_modules/simstack/core/run_node.html +390 -0
  103. simstack/static/docs/_modules/simstack/core/runner.html +491 -0
  104. simstack/static/docs/_modules/simstack/core/services/base_service.html +522 -0
  105. simstack/static/docs/_modules/simstack/core/services/file_transfer_service.html +436 -0
  106. simstack/static/docs/_modules/simstack/core/services/git_restart_service.html +331 -0
  107. simstack/static/docs/_modules/simstack/core/services/git_uv_update_service.html +427 -0
  108. simstack/static/docs/_modules/simstack/core/services/node_execution_service.html +507 -0
  109. simstack/static/docs/_modules/simstack/core/services/resource_branch_monitor_service.html +390 -0
  110. simstack/static/docs/_modules/simstack/core/services/runner_cleanup_service.html +468 -0
  111. simstack/static/docs/_modules/simstack/core/services/runner_manager.html +485 -0
  112. simstack/static/docs/_modules/simstack/core/services/runner_status_service.html +329 -0
  113. simstack/static/docs/_modules/simstack/core/services/slurm_status_service.html +386 -0
  114. simstack/static/docs/_modules/simstack/core/services/stop_check_service.html +346 -0
  115. simstack/static/docs/_modules/simstack/core/services/timeout_restart_service.html +345 -0
  116. simstack/static/docs/_modules/simstack/core/simstack_result.html +355 -0
  117. simstack/static/docs/_modules/simstack/core/submit_node.html +536 -0
  118. simstack/static/docs/_modules/simstack/core/task_id.html +344 -0
  119. simstack/static/docs/_modules/simstack/methods/archive_files.html +598 -0
  120. simstack/static/docs/_modules/simstack/methods/fire_and_forget_runner.html +432 -0
  121. simstack/static/docs/_modules/simstack/methods/generate_test.html +443 -0
  122. simstack/static/docs/_modules/simstack/methods/get_file.html +342 -0
  123. simstack/static/docs/_modules/simstack/methods/mass_runner.html +476 -0
  124. simstack/static/docs/_modules/simstack/methods/multiple_executor.html +674 -0
  125. simstack/static/docs/_modules/simstack/methods/switch_git.html +332 -0
  126. simstack/static/docs/_modules/simstack/methods/upload_helpers.html +403 -0
  127. simstack/static/docs/_modules/simstack/models/array_list.html +337 -0
  128. simstack/static/docs/_modules/simstack/models/array_storage.html +417 -0
  129. simstack/static/docs/_modules/simstack/models/base_lists.html +374 -0
  130. simstack/static/docs/_modules/simstack/models/base_types.html +588 -0
  131. simstack/static/docs/_modules/simstack/models/charts_artifact.html +1035 -0
  132. simstack/static/docs/_modules/simstack/models/dataset.html +866 -0
  133. simstack/static/docs/_modules/simstack/models/dataset_metadata.html +711 -0
  134. simstack/static/docs/_modules/simstack/models/datasettuple.html +1005 -0
  135. simstack/static/docs/_modules/simstack/models/file_instance.html +472 -0
  136. simstack/static/docs/_modules/simstack/models/file_list.html +367 -0
  137. simstack/static/docs/_modules/simstack/models/files.html +773 -0
  138. simstack/static/docs/_modules/simstack/models/fire_and_forget_result.html +335 -0
  139. simstack/static/docs/_modules/simstack/models/images2d.html +447 -0
  140. simstack/static/docs/_modules/simstack/models/log_entry_model.html +356 -0
  141. simstack/static/docs/_modules/simstack/models/models.html +374 -0
  142. simstack/static/docs/_modules/simstack/models/named_data_reference.html +355 -0
  143. simstack/static/docs/_modules/simstack/models/node_registry.html +415 -0
  144. simstack/static/docs/_modules/simstack/models/pandas_model.html +570 -0
  145. simstack/static/docs/_modules/simstack/models/parameters.html +739 -0
  146. simstack/static/docs/_modules/simstack/models/pickle_models.html +631 -0
  147. simstack/static/docs/_modules/simstack/models/project.html +329 -0
  148. simstack/static/docs/_modules/simstack/models/resource_assignment.html +501 -0
  149. simstack/static/docs/_modules/simstack/models/resource_definition.html +477 -0
  150. simstack/static/docs/_modules/simstack/models/runner_model.html +361 -0
  151. simstack/static/docs/_modules/simstack/models/simple_table.html +413 -0
  152. simstack/static/docs/_modules/simstack/models/simstack_model.html +416 -0
  153. simstack/static/docs/_modules/simstack/models/slurm_info.html +333 -0
  154. simstack/static/docs/_modules/simstack/models/table_artifact.html +406 -0
  155. simstack/static/docs/_modules/simstack/models/tag.html +328 -0
  156. simstack/static/docs/_modules/simstack/tables/model_table.html +519 -0
  157. simstack/static/docs/_modules/simstack/tables/node_children.html +538 -0
  158. simstack/static/docs/_modules/simstack/tables/node_table.html +854 -0
  159. simstack/static/docs/_modules/simstack/tables/table_builder.html +642 -0
  160. simstack/static/docs/_modules/simstack/util/async_zip_utils.html +337 -0
  161. simstack/static/docs/_modules/simstack/util/b64mixin.html +339 -0
  162. simstack/static/docs/_modules/simstack/util/cleaned_json_schema.html +336 -0
  163. simstack/static/docs/_modules/simstack/util/config_reader.html +498 -0
  164. simstack/static/docs/_modules/simstack/util/custom_model_dump.html +391 -0
  165. simstack/static/docs/_modules/simstack/util/database_information.html +488 -0
  166. simstack/static/docs/_modules/simstack/util/db.html +1392 -0
  167. simstack/static/docs/_modules/simstack/util/db_logger.html +448 -0
  168. simstack/static/docs/_modules/simstack/util/default_from_dict.html +376 -0
  169. simstack/static/docs/_modules/simstack/util/directory_iterator.html +553 -0
  170. simstack/static/docs/_modules/simstack/util/docstring_parser.html +526 -0
  171. simstack/static/docs/_modules/simstack/util/file_hashing.html +394 -0
  172. simstack/static/docs/_modules/simstack/util/file_transfer_client.html +791 -0
  173. simstack/static/docs/_modules/simstack/util/files.html +733 -0
  174. simstack/static/docs/_modules/simstack/util/find_python_files.html +349 -0
  175. simstack/static/docs/_modules/simstack/util/generate_ui_schema.html +396 -0
  176. simstack/static/docs/_modules/simstack/util/generic_list_mixin.html +487 -0
  177. simstack/static/docs/_modules/simstack/util/get_module_path.html +336 -0
  178. simstack/static/docs/_modules/simstack/util/git_pull.html +381 -0
  179. simstack/static/docs/_modules/simstack/util/git_repository_status.html +411 -0
  180. simstack/static/docs/_modules/simstack/util/import_module.html +377 -0
  181. simstack/static/docs/_modules/simstack/util/importer.html +637 -0
  182. simstack/static/docs/_modules/simstack/util/init_data_source.html +357 -0
  183. simstack/static/docs/_modules/simstack/util/make_graph.html +423 -0
  184. simstack/static/docs/_modules/simstack/util/make_table.html +1171 -0
  185. simstack/static/docs/_modules/simstack/util/mappings.html +378 -0
  186. simstack/static/docs/_modules/simstack/util/minimal_route_finder.html +388 -0
  187. simstack/static/docs/_modules/simstack/util/mock_db.html +472 -0
  188. simstack/static/docs/_modules/simstack/util/module_path_checker.html +354 -0
  189. simstack/static/docs/_modules/simstack/util/object_list_mixin.html +649 -0
  190. simstack/static/docs/_modules/simstack/util/path_manager.html +566 -0
  191. simstack/static/docs/_modules/simstack/util/project_root_finder.html +357 -0
  192. simstack/static/docs/_modules/simstack/util/queue_watcher.html +593 -0
  193. simstack/static/docs/_modules/simstack/util/resource_config.html +532 -0
  194. simstack/static/docs/_modules/simstack/util/route_finder.html +390 -0
  195. simstack/static/docs/_modules/simstack/util/runner_util.html +487 -0
  196. simstack/static/docs/_modules/simstack/util/runner_utils.html +468 -0
  197. simstack/static/docs/_modules/simstack/util/safe_code_executor.html +510 -0
  198. simstack/static/docs/_modules/simstack/util/sample_config.html +414 -0
  199. simstack/static/docs/_modules/simstack/util/sensitive_content_filter.html +364 -0
  200. simstack/static/docs/_modules/simstack/util/setup_logging.html +365 -0
  201. simstack/static/docs/_modules/simstack/util/submit_to_watchdog.html +425 -0
  202. simstack/static/docs/_modules/simstack/util/toml_reader.html +482 -0
  203. simstack/static/docs/_modules/simstack/util/transform_file_name.html +357 -0
  204. simstack/static/docs/_modules/simstack/util/ui_tools.html +541 -0
  205. simstack/static/docs/_sources/architecture.rst.txt +25 -0
  206. simstack/static/docs/_sources/array_lists.rst.txt +60 -0
  207. simstack/static/docs/_sources/ci_pipeline.rst.txt +34 -0
  208. simstack/static/docs/_sources/data.rst.txt +175 -0
  209. simstack/static/docs/_sources/database_migrations.rst.txt +310 -0
  210. simstack/static/docs/_sources/datasets.rst.txt +93 -0
  211. simstack/static/docs/_sources/developer_guide.rst.txt +25 -0
  212. simstack/static/docs/_sources/docker_nodes.rst.txt +149 -0
  213. simstack/static/docs/_sources/files.rst.txt +159 -0
  214. simstack/static/docs/_sources/fire_and_forget_runner.rst.txt +67 -0
  215. simstack/static/docs/_sources/index.rst.txt +25 -0
  216. simstack/static/docs/_sources/installation.rst.txt +213 -0
  217. simstack/static/docs/_sources/lists.rst.txt +111 -0
  218. simstack/static/docs/_sources/mass_runner.rst.txt +91 -0
  219. simstack/static/docs/_sources/misc.rst.txt +106 -0
  220. simstack/static/docs/_sources/overview.rst.txt +91 -0
  221. simstack/static/docs/_sources/recovery.rst.txt +38 -0
  222. simstack/static/docs/_sources/resource_config.rst.txt +141 -0
  223. simstack/static/docs/_sources/simstack/modules/modules.rst.txt +7 -0
  224. simstack/static/docs/_sources/simstack/modules/simstack.core.rst.txt +205 -0
  225. simstack/static/docs/_sources/simstack/modules/simstack.core.services.rst.txt +109 -0
  226. simstack/static/docs/_sources/simstack/modules/simstack.methods.rst.txt +77 -0
  227. simstack/static/docs/_sources/simstack/modules/simstack.models.rst.txt +261 -0
  228. simstack/static/docs/_sources/simstack/modules/simstack.rst.txt +22 -0
  229. simstack/static/docs/_sources/simstack/modules/simstack.tables.rst.txt +45 -0
  230. simstack/static/docs/_sources/simstack/modules/simstack.util.rst.txt +381 -0
  231. simstack/static/docs/_sources/submit.rst.txt +141 -0
  232. simstack/static/docs/_sources/tables.rst.txt +50 -0
  233. simstack/static/docs/_sources/testing_complex_nodes.rst.txt +92 -0
  234. simstack/static/docs/_sources/ui_documentation.rst.txt +272 -0
  235. simstack/static/docs/_sources/workflows.rst.txt +446 -0
  236. simstack/static/docs/_static/base-stemmer.js +476 -0
  237. simstack/static/docs/_static/basic.css +906 -0
  238. simstack/static/docs/_static/cobalt2-theme.css +1 -0
  239. simstack/static/docs/_static/debug.css +69 -0
  240. simstack/static/docs/_static/docs-build-badge.css +51 -0
  241. simstack/static/docs/_static/docs-build-badge.js +51 -0
  242. simstack/static/docs/_static/doctools.js +150 -0
  243. simstack/static/docs/_static/documentation_options.js +13 -0
  244. simstack/static/docs/_static/english-stemmer.js +1066 -0
  245. simstack/static/docs/_static/file.png +0 -0
  246. simstack/static/docs/_static/language_data.js +13 -0
  247. simstack/static/docs/_static/minus.png +0 -0
  248. simstack/static/docs/_static/plus.png +0 -0
  249. simstack/static/docs/_static/pygments.css +250 -0
  250. simstack/static/docs/_static/scripts/furo-extensions.js +0 -0
  251. simstack/static/docs/_static/scripts/furo.js +3 -0
  252. simstack/static/docs/_static/scripts/furo.js.LICENSE.txt +7 -0
  253. simstack/static/docs/_static/scripts/furo.js.map +1 -0
  254. simstack/static/docs/_static/searchtools.js +693 -0
  255. simstack/static/docs/_static/skeleton.css +296 -0
  256. simstack/static/docs/_static/sphinx_highlight.js +159 -0
  257. simstack/static/docs/_static/styles/furo-extensions.css +2 -0
  258. simstack/static/docs/_static/styles/furo-extensions.css.map +1 -0
  259. simstack/static/docs/_static/styles/furo.css +2 -0
  260. simstack/static/docs/_static/styles/furo.css.map +1 -0
  261. simstack/static/docs/architecture.html +340 -0
  262. simstack/static/docs/array_lists.html +678 -0
  263. simstack/static/docs/ci_pipeline.html +385 -0
  264. simstack/static/docs/data.html +545 -0
  265. simstack/static/docs/database_migrations.html +652 -0
  266. simstack/static/docs/datasets.html +1268 -0
  267. simstack/static/docs/developer_guide.html +359 -0
  268. simstack/static/docs/docker_nodes.html +503 -0
  269. simstack/static/docs/files.html +718 -0
  270. simstack/static/docs/fire_and_forget_runner.html +641 -0
  271. simstack/static/docs/genindex.html +6390 -0
  272. simstack/static/docs/index.html +516 -0
  273. simstack/static/docs/installation.html +553 -0
  274. simstack/static/docs/lists.html +478 -0
  275. simstack/static/docs/mass_runner.html +481 -0
  276. simstack/static/docs/misc.html +454 -0
  277. simstack/static/docs/objects.inv +0 -0
  278. simstack/static/docs/overview.html +469 -0
  279. simstack/static/docs/py-modindex.html +1111 -0
  280. simstack/static/docs/recovery.html +371 -0
  281. simstack/static/docs/resource_config.html +590 -0
  282. simstack/static/docs/search.html +327 -0
  283. simstack/static/docs/searchindex.js +1 -0
  284. simstack/static/docs/simstack/modules/modules.html +489 -0
  285. simstack/static/docs/simstack/modules/simstack.core.html +1883 -0
  286. simstack/static/docs/simstack/modules/simstack.core.services.html +698 -0
  287. simstack/static/docs/simstack/modules/simstack.html +3060 -0
  288. simstack/static/docs/simstack/modules/simstack.methods.html +1150 -0
  289. simstack/static/docs/simstack/modules/simstack.models.html +13113 -0
  290. simstack/static/docs/simstack/modules/simstack.tables.html +635 -0
  291. simstack/static/docs/simstack/modules/simstack.util.html +3320 -0
  292. simstack/static/docs/submit.html +487 -0
  293. simstack/static/docs/tables.html +539 -0
  294. simstack/static/docs/testing_complex_nodes.html +458 -0
  295. simstack/static/docs/ui_documentation.html +788 -0
  296. simstack/static/docs/workflows.html +766 -0
  297. simstack/tables/__init__.py +0 -0
  298. simstack/tables/model_table.py +191 -0
  299. simstack/tables/node_children.py +219 -0
  300. simstack/tables/node_table.py +517 -0
  301. simstack/tables/table_builder.py +314 -0
  302. simstack/util/__init__.py +0 -0
  303. simstack/util/async_zip_utils.py +18 -0
  304. simstack/util/b64mixin.py +23 -0
  305. simstack/util/cleaned_json_schema.py +20 -0
  306. simstack/util/config_reader.py +179 -0
  307. simstack/util/custom_model_dump.py +75 -0
  308. simstack/util/database_information.py +160 -0
  309. simstack/util/db.py +1013 -0
  310. simstack/util/db_logger.py +117 -0
  311. simstack/util/default_from_dict.py +57 -0
  312. simstack/util/directory_iterator.py +216 -0
  313. simstack/util/docstring_parser.py +186 -0
  314. simstack/util/file_hashing.py +72 -0
  315. simstack/util/file_transfer_client.py +427 -0
  316. simstack/util/files.py +396 -0
  317. simstack/util/find_python_files.py +33 -0
  318. simstack/util/generate_ui_schema.py +80 -0
  319. simstack/util/generic_list_mixin.py +120 -0
  320. simstack/util/geometry_utils.py +118 -0
  321. simstack/util/get_module_path.py +20 -0
  322. simstack/util/git_pull.py +65 -0
  323. simstack/util/git_repository_status.py +95 -0
  324. simstack/util/import_module.py +63 -0
  325. simstack/util/importer.py +312 -0
  326. simstack/util/init_data_source.py +41 -0
  327. simstack/util/make_graph.py +107 -0
  328. simstack/util/make_table.py +837 -0
  329. simstack/util/mappings.py +41 -0
  330. simstack/util/minimal_route_finder.py +72 -0
  331. simstack/util/mock_db.py +144 -0
  332. simstack/util/module_path_checker.py +38 -0
  333. simstack/util/object_list_mixin.py +282 -0
  334. simstack/util/path_manager.py +223 -0
  335. simstack/util/project_root_finder.py +41 -0
  336. simstack/util/queue_watcher.py +262 -0
  337. simstack/util/resource_config.py +198 -0
  338. simstack/util/route_finder.py +74 -0
  339. simstack/util/runner_util.py +166 -0
  340. simstack/util/runner_utils.py +143 -0
  341. simstack/util/safe_code_executor.py +194 -0
  342. simstack/util/sample_config.py +98 -0
  343. simstack/util/sensitive_content_filter.py +48 -0
  344. simstack/util/setup_logging.py +49 -0
  345. simstack/util/submit_to_watchdog.py +106 -0
  346. simstack/util/toml_reader.py +142 -0
  347. simstack/util/transform_file_name.py +41 -0
  348. simstack/util/ui_tools.py +213 -0
  349. simstack-2.0.1.dist-info/METADATA +454 -0
  350. simstack-2.0.1.dist-info/RECORD +354 -0
  351. simstack-2.0.1.dist-info/WHEEL +5 -0
  352. simstack-2.0.1.dist-info/entry_points.txt +12 -0
  353. simstack-2.0.1.dist-info/licenses/LICENSE +21 -0
  354. simstack-2.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,41 @@
1
+ from typing import Dict, Optional, List
2
+ from simstack.models.models import ModelMapping, NodeModel
3
+ from odmantic import AIOEngine
4
+
5
+ class ModelMappingTable:
6
+ def __init__(self, mappings: List[ModelMapping]):
7
+ self._by_name: Dict[str, ModelMapping] = {m.name: m for m in mappings}
8
+ self._by_mapping: Dict[str, ModelMapping] = {m.mapping: m for m in mappings}
9
+
10
+ def get_by_name(self, name: str) -> Optional[ModelMapping]:
11
+ return self._by_name.get(name)
12
+
13
+ def get_by_mapping(self, mapping: str) -> Optional[ModelMapping]:
14
+ return self._by_mapping.get(mapping)
15
+
16
+ @classmethod
17
+ async def load(cls, engine: AIOEngine):
18
+ mappings = await engine.find(ModelMapping)
19
+ return cls(list(mappings))
20
+
21
+ class NodeMappingTable:
22
+ def __init__(self, nodes: List[NodeModel]):
23
+ self._by_name: Dict[str, NodeModel] = {n.name: n for n in nodes}
24
+ self._by_mapping: Dict[str, NodeModel] = {n.function_mapping: n for n in nodes}
25
+
26
+ def get_by_name(self, name: str) -> Optional[NodeModel]:
27
+ return self._by_name.get(name)
28
+
29
+ def get_by_mapping(self, mapping: str) -> Optional[NodeModel]:
30
+ return self._by_mapping.get(mapping)
31
+
32
+ @classmethod
33
+ async def load(cls, engine: AIOEngine):
34
+ try:
35
+ nodes = await engine.find(NodeModel)
36
+ except Exception as e:
37
+ print(f"Error loading NodeModel from database: {e}")
38
+ print("WARNING: Returning empty NodeMappingTable to fix obviously corrupted case.")
39
+ print("Rebuild the NodeMappingTable by rerunning the database initialization or migration scripts.")
40
+ nodes = []
41
+ return cls(list(nodes))
@@ -0,0 +1,72 @@
1
+ from collections import deque
2
+ from typing import List, Dict
3
+
4
+
5
+ def find_minimal_route(
6
+ routes: List[Dict[str, str]], source: str, target: str
7
+ ) -> List[Dict[str, str]]:
8
+ """
9
+ Find the minimal (shortest) route from source to target.
10
+
11
+ Args:
12
+ routes: List of route dictionaries with 'source', 'target', and 'host'
13
+ source: The starting node
14
+ target: The destination node
15
+
16
+ Returns:
17
+ A list of route dictionaries representing the shortest path from source to target,
18
+ or an empty list if no path exists
19
+ """
20
+ if not routes:
21
+ return []
22
+
23
+ # Build the graph and route map
24
+ adj: Dict[str, List[str]] = {}
25
+ route_map: Dict[tuple, Dict[str, str]] = {}
26
+ nodes = set()
27
+
28
+ for route in routes:
29
+ src = route["source"]
30
+ dst = route["target"]
31
+ nodes.add(src)
32
+ nodes.add(dst)
33
+
34
+ if src not in adj:
35
+ adj[src] = []
36
+
37
+ # Avoid adding duplicates to adjacency list, but allow route_map update (last one wins)
38
+ if dst not in adj[src]:
39
+ adj[src].append(dst)
40
+
41
+ route_map[(src, dst)] = route
42
+
43
+ if source not in nodes or target not in nodes:
44
+ return []
45
+
46
+ # BFS to find shortest path
47
+ queue = deque([(source, [source])])
48
+ visited = {source}
49
+
50
+ while queue:
51
+ current_node, path = queue.popleft()
52
+
53
+ if current_node == target:
54
+ # Convert the path of nodes to a list of route dictionaries
55
+ path_routes = []
56
+ for i in range(len(path) - 1):
57
+ u = path[i]
58
+ v = path[i + 1]
59
+ path_routes.append(route_map[(u, v)])
60
+ return path_routes
61
+
62
+ if current_node in adj:
63
+ for neighbor in adj[current_node]:
64
+ if neighbor not in visited:
65
+ visited.add(neighbor)
66
+ queue.append((neighbor, path + [neighbor]))
67
+
68
+ return []
69
+
70
+
71
+ # Add an alias for find_minimal_route as find_shortest_route for compatibility
72
+ find_shortest_route = find_minimal_route
@@ -0,0 +1,144 @@
1
+ import asyncio
2
+ from typing import Type, TypeVar, Dict, List, Optional
3
+
4
+ from odmantic import Model, ObjectId
5
+
6
+ T = TypeVar("T", bound=Model)
7
+
8
+
9
+ class InMemoryCollection:
10
+ def __init__(self, engine: "InMemoryAIOEngine"):
11
+ self._engine = engine
12
+ self._store: List[Dict] = []
13
+
14
+ def __getitem__(self, index: int) -> Dict:
15
+ return self._store[index]
16
+
17
+ def __setitem__(self, index: int, value: Dict):
18
+ self._store[index] = value
19
+
20
+ def __iter__(self):
21
+ return iter(self._store)
22
+
23
+
24
+ class InMemoryAIOEngine:
25
+ def __init__(self):
26
+ # Stores data as {collection_name: [documents]}
27
+ self._store: Dict[str, InMemoryCollection] = {}
28
+
29
+ async def save(self, instance: T) -> T:
30
+ collection_name = (
31
+ instance.__collection__
32
+ if hasattr(instance, "__collection__")
33
+ else instance.__class__.__name__.lower()
34
+ )
35
+
36
+ obj_dict = instance.model_dump()
37
+
38
+ # Ensure the instance has an ObjectId assigned
39
+ if not instance.id:
40
+ instance.id = ObjectId()
41
+ obj_dict["id"] = instance.id
42
+
43
+ # Initialize collection if it doesn't exist
44
+ if collection_name not in self._store:
45
+ self._store[collection_name] = InMemoryCollection(self)
46
+
47
+ # Update if already exists
48
+ existing_index = next(
49
+ (
50
+ i
51
+ for i, obj in enumerate(self._store[collection_name])
52
+ if obj["id"] == instance.id
53
+ ),
54
+ None,
55
+ )
56
+ if existing_index is not None:
57
+ self._store[collection_name][existing_index] = obj_dict
58
+ else:
59
+ self._store[collection_name].append(obj_dict)
60
+
61
+ return instance
62
+
63
+ async def find(self, model: Type[T], **query) -> List[T]:
64
+ collection_name = (
65
+ model.__collection__
66
+ if hasattr(model, "__collection__")
67
+ else model.__name__.lower()
68
+ )
69
+ all_objects = self._store.get(collection_name, [])
70
+ results = []
71
+
72
+ for obj_dict in all_objects:
73
+ if all(obj_dict.get(k) == v for k, v in query.items()):
74
+ results.append(model.model_validate(obj_dict))
75
+ return results
76
+
77
+
78
+ async def find_one(self, model: Type[T], condition=None, **query) -> Optional[T]:
79
+ # Handle both keyword arguments and condition objects
80
+ if condition is not None:
81
+ # For conditions like ModelMapping.name == class_name
82
+ # This is a more robust approach to extract field name and value
83
+ condition_str = str(condition)
84
+
85
+ # Look for the pattern: field_name == value or field_name: {$eq: value}
86
+ if "==" in condition_str:
87
+ # Handle direct comparison like ModelMapping.name == 'TestClass'
88
+ parts = condition_str.split("==")
89
+ if len(parts) == 2:
90
+ field_name = parts[0].strip().split(".")[-1]
91
+ value = parts[1].strip().strip("'\"")
92
+ query[field_name] = value
93
+ elif "$eq" in condition_str:
94
+ # Handle MongoDB-style query like {'mapping': {'$eq': 'tests.core.test_import_class.TestClass'}}
95
+ import re
96
+
97
+ # Extract field name and value using regex
98
+ field_match = re.search(
99
+ r"'(\w+)':\s*\{'?\$eq'?:\s*'([^']+)'", condition_str
100
+ )
101
+ if field_match:
102
+ field_name = field_match.group(1)
103
+ value = field_match.group(2)
104
+ query[field_name] = value
105
+ else:
106
+ # Fallback - try to extract from the string representation
107
+ # Look for pattern like "ModelMapping.field_name"
108
+ field_match = re.search(r"(\w+)\.(\w+)", condition_str)
109
+ if field_match:
110
+ field_name = field_match.group(2)
111
+ # Try to extract the value (this is still a fallback)
112
+ value_match = re.search(r"'([^']+)'(?:[^']*$)", condition_str)
113
+ if value_match:
114
+ value = value_match.group(1)
115
+ query[field_name] = value
116
+
117
+ found = await self.find(model, **query)
118
+ return found[0] if found else None
119
+
120
+
121
+ # Example Usage:
122
+ if __name__ == "__main__":
123
+ from odmantic import Model
124
+
125
+ class BinaryOperationInput(Model):
126
+ arg1: int
127
+ arg2: int
128
+
129
+ async def test_engine():
130
+ engine = InMemoryAIOEngine()
131
+ obj = BinaryOperationInput(arg1=1, arg2=2)
132
+
133
+ # Saving object
134
+ await engine.save(obj)
135
+
136
+ # Finding objects
137
+ found_objs = await engine.find(BinaryOperationInput, arg1=1)
138
+ print("Found objects:", found_objs)
139
+
140
+ # Find one object
141
+ found_one = await engine.find_one(BinaryOperationInput, arg2=2)
142
+ print("Found single object:", found_one)
143
+
144
+ asyncio.run(test_engine())
@@ -0,0 +1,38 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from simstack.util.project_root_finder import find_project_root
5
+
6
+
7
+ def is_module_subpath_of_path(module_path: str, path_info_path: Path) -> bool:
8
+ """
9
+ Check whether a dot-separated module path is a subpath of an absolute path.
10
+
11
+ Args:
12
+ module_path: A dot-separated path relative to the project root (e.g., "src.simstack.core.artifacts")
13
+ path_info_path: An absolute path below the project root (e.g., "/path/to/project/src/simstack/core")
14
+
15
+ Returns:
16
+ True if the module path corresponds to a location under the given absolute path, False otherwise
17
+ """
18
+
19
+ # Convert the module path to the file system path
20
+ # Replace dots with path separators
21
+ module_file_path = module_path.replace(".", os.sep)
22
+
23
+ # Convert path_info_path to the Path object for easier manipulation
24
+ path_info_path_obj = Path(path_info_path)
25
+
26
+ # Get the project root using the existing utility function
27
+ project_root = find_project_root()
28
+
29
+ # Convert the module path to the absolute path relative to the project root
30
+ module_absolute_path = project_root / module_file_path
31
+
32
+ try:
33
+ # Check if the module path is under the given path_info_path
34
+ module_absolute_path.relative_to(path_info_path_obj)
35
+ return True
36
+ except ValueError:
37
+ # If relative_to raises ValueError, the module path is not under path_info_path
38
+ return False
@@ -0,0 +1,282 @@
1
+ import re
2
+ from typing import Generic, Optional, List, Iterator, Type, Union, Iterable, TypeVar, TYPE_CHECKING
3
+
4
+ from odmantic import ObjectId, Model
5
+
6
+ from simstack.util.generic_list_mixin import GenericListMixin
7
+
8
+ if TYPE_CHECKING:
9
+ from simstack.util.db import Database
10
+
11
+ T = TypeVar("T")
12
+
13
+
14
+ class ObjectListMixin(GenericListMixin[ObjectId], Generic[T]):
15
+ """
16
+ Mixin class for lists of Model ObjectIDs.
17
+ Stores ObjectId instances in `elements`, but allows interaction with Model instances.
18
+ """
19
+
20
+ @staticmethod
21
+ def _normalize_elements_for_init(data: dict) -> tuple[dict, Optional[List[Model]]]:
22
+ elements = data.get("elements")
23
+ if not elements:
24
+ return data, None
25
+
26
+ elements = list(elements)
27
+ contains_models = any(isinstance(element, Model) for element in elements)
28
+
29
+ if not contains_models:
30
+ return data, None
31
+
32
+ if not all(isinstance(element, Model) for element in elements):
33
+ raise ValueError("elements must contain either only model instances or only ObjectIds")
34
+
35
+ normalized_data = dict(data)
36
+ normalized_data["elements"] = [element.id for element in elements]
37
+ return normalized_data, elements
38
+
39
+ def __iter__(self) -> Iterator[T]:
40
+ return iter(self._get_cache())
41
+
42
+ def _get_model_class(self) -> Type[T]:
43
+ # T is the first type argument of ObjectListMixin
44
+ if hasattr(self, "__orig_bases__"):
45
+ for base in self.__class__.__orig_bases__:
46
+ if hasattr(base, "__origin__") and base.__origin__ is ObjectListMixin:
47
+ return base.__args__[0]
48
+ raise RuntimeError(f"Could not determine model class for {self.__class__.__name__}")
49
+
50
+ def _set_cache(self, cache: List[T]):
51
+ object.__getattribute__(self, "__dict__")["_cache"] = cache
52
+ return cache
53
+
54
+ def _get_cache(self) -> List[T]:
55
+ self_dict = object.__getattribute__(self, "__dict__")
56
+ cache = self_dict.get("_cache",None)
57
+ if cache is None:
58
+ cache = []
59
+ cache = self._set_cache(cache)
60
+ return cache
61
+
62
+
63
+ def append(self, element: T):
64
+ if not isinstance(element, Model):
65
+ raise ValueError("can only append models to ObjectListMixin")
66
+ cache = self._get_cache()
67
+ if element not in cache:
68
+ cache.append(element)
69
+ self._set_cache(cache)
70
+
71
+ obj_id = getattr(element, "id", None)
72
+ if obj_id is None:
73
+ raise ValueError("attempting to append a model without id to an ObjectListMixin class")
74
+ if obj_id not in self.elements:
75
+ self.elements.append(obj_id)
76
+
77
+ def extend(self, elements: Union[List[T], "ObjectListMixin[T]"]):
78
+ for element in elements:
79
+ self.append(element)
80
+
81
+ async def save(self, db: "Database"):
82
+ cache = self._get_cache()
83
+ # Save each element first (this might trigger their own custom saves)
84
+ for element in cache:
85
+ await db.save(element)
86
+ if isinstance(self, Model): # embedded models are save with the parent
87
+ await db.save_unchecked(self)
88
+ return self
89
+
90
+ def insert(self, index: int, element: T):
91
+ self.elements.insert(index, element.id)
92
+ cache = self._get_cache()
93
+ if index <= len(cache):
94
+ cache.insert(index, element)
95
+
96
+ def remove(self, element: T):
97
+ self.elements.remove(element.id)
98
+ cache = self._get_cache()
99
+ if element in cache:
100
+ cache.remove(element)
101
+
102
+ def pop(self, index: int = -1) -> T:
103
+ self.elements.pop(index)
104
+ cache = self._get_cache()
105
+ if index < 0:
106
+ index = len(self.elements) + 1 + index # elements already popped
107
+ if index < len(cache):
108
+ return cache.pop(index)
109
+ else:
110
+ # If it's not in cache, we might have a problem if it was never loaded.
111
+ # But pop is usually used on loaded lists.
112
+ raise IndexError("Index out of range for cache. Load elements first.")
113
+
114
+ def get(self, index: int) -> T:
115
+ """Get an element by index, loading it from DB if necessary."""
116
+ if index < 0 or index >= len(self.elements):
117
+ raise IndexError("list index out of range")
118
+
119
+ cache = self._get_cache()
120
+ if index < len(cache):
121
+ return cache[index]
122
+
123
+ raise IndexError("Index out of range for cache. Load elements first.")
124
+
125
+ def count(self, element: T) -> int:
126
+ return self.elements.count(element.id)
127
+
128
+ def index(self, element: T, start: int = 0, stop: int = None) -> int:
129
+ return self.elements.index(element.id, start, stop if stop is not None else len(self.elements))
130
+
131
+ def reverse(self):
132
+ self.elements.reverse()
133
+ self._get_cache().reverse()
134
+
135
+ def sort(self, key=None, reverse: bool = False):
136
+ # This is tricky because we need to sort both.
137
+ # Simplest is to sort the cache and then update elements.
138
+ # But we might not have a full cache.
139
+ if len(self._get_cache()) != len(self.elements):
140
+ # We can't easily sort if we don't have all elements in cache.
141
+ # For now, let's just sort the elements if key only depends on ObjectId,
142
+ # or raise if it needs the Model.
143
+ # Actually, standard list.sort() uses the objects.
144
+ raise RuntimeError("Sort requires all elements to be loaded in cache. Call _load_all_to_cache() first.")
145
+
146
+ cache = self._get_cache()
147
+ cache.sort(key=key, reverse=reverse)
148
+ self.elements[:] = [obj.id for obj in cache]
149
+
150
+ def __setitem__(self, index: Union[int, slice], value: Union[T, List[T]]):
151
+ if isinstance(index, slice):
152
+ if isinstance(value, Iterable):
153
+ ids = [v.id for v in value]
154
+ self.elements[index] = ids
155
+ cache = self._get_cache()
156
+ # Slice assignment on cache is only safe if it matches the current loaded state
157
+ # For simplicity, let's just clear cache or try to update if it fits
158
+ if index.start is not None and index.stop is not None and index.stop <= len(cache):
159
+ cache[index] = list(value)
160
+ self._set_cache(cache)
161
+ else:
162
+ raise TypeError("Can only assign an iterable to a slice")
163
+ else:
164
+ self.elements[index] = value.id
165
+ cache = self._get_cache()
166
+ if index < len(cache):
167
+ cache[index] = value
168
+ self._set_cache(cache)
169
+
170
+ def __delitem__(self, index: Union[int, slice]):
171
+ del self.elements[index]
172
+ cache = self._get_cache()
173
+ if isinstance(index, slice):
174
+ if index.start is not None and index.stop is not None and index.stop <= len(cache):
175
+ del cache[index]
176
+ else:
177
+ raise IndexError("Slice out of range for cache")
178
+ else:
179
+ if index < len(cache):
180
+ del cache[index]
181
+ self._set_cache(cache)
182
+
183
+ def copy(self) -> "ObjectListMixin[T]":
184
+ import copy
185
+ return copy.copy(self)
186
+
187
+ def __getitem__(self, index: Union[int, slice]) -> Union[T, List[T], ObjectId, List[ObjectId]]:
188
+ cache = self._get_cache()
189
+ if isinstance(index, slice):
190
+ if index.start is not None and index.stop is not None and index.stop <= len(cache):
191
+ return cache[index]
192
+ return self.elements[index]
193
+ else:
194
+ if 0 <= index < len(cache):
195
+ return cache[index]
196
+ return self.elements[index]
197
+
198
+ def find(self, pattern: str) -> Optional[T]:
199
+ regex = re.compile(pattern)
200
+ cache = self._get_cache()
201
+ for obj in cache:
202
+ name = getattr(obj, "name", None)
203
+ if name and regex.search(name):
204
+ return obj
205
+ return None
206
+
207
+ def find_all(self, pattern: str) -> Iterator[T]:
208
+ regex = re.compile(pattern)
209
+ cache = self._get_cache()
210
+ for obj in cache:
211
+ name = getattr(obj, "name", None)
212
+ if name and regex.search(name):
213
+ yield obj
214
+
215
+
216
+ async def db_find_postprocess(self, db: "Database"):
217
+ """Instance-level post-processing"""
218
+ cache = self._get_cache()
219
+ model_class = self._get_model_class()
220
+ # Identify which IDs are missing from the cache
221
+ missing_ids = [obj_id for obj_id in self.elements if not any(getattr(o, "id", None) == obj_id for o in cache)]
222
+
223
+ if missing_ids:
224
+ # Load all missing elements at once
225
+ query = model_class.id.in_(missing_ids)
226
+ # engine.find might return a cursor or a list
227
+ results = await db.find(model_class, query)
228
+
229
+ # Map results by ID for efficient lookup
230
+ loaded_map = {}
231
+ for obj in results:
232
+ # Recursively unwrap nested collections (mock DB behavior)
233
+ it = obj
234
+ while isinstance(it, (list, tuple)) and len(it) > 0:
235
+ it = it[0]
236
+
237
+ # Check for Model or duck-typed object
238
+ if hasattr(it, "id"):
239
+ loaded_map[it.id] = it
240
+
241
+ # Update cache maintaining the order of self.elements
242
+ new_cache = []
243
+ for obj_id in self.elements:
244
+ # Find in existing cache
245
+ existing = next((o for o in cache if getattr(o, "id", None) == obj_id), None)
246
+ if existing:
247
+ new_cache.append(existing)
248
+ elif obj_id in loaded_map:
249
+ new_cache.append(loaded_map[obj_id])
250
+ else:
251
+ import logging
252
+ logging.getLogger(__name__).warning(f"Could not load object {obj_id} for {model_class.__name__}")
253
+ self._set_cache(new_cache)
254
+ return self
255
+
256
+ def delete_element(self, element: Union[T, ObjectId]):
257
+ cache = self._get_cache()
258
+ if isinstance(element, Model):
259
+ obj_id = element.id
260
+ if element in cache:
261
+ cache.remove(element)
262
+ else:
263
+ obj_id = element
264
+ # If it's an ObjectId, we might need to find the object in cache to remove it
265
+ cache = [o for o in cache if getattr(o, "id", None) != obj_id]
266
+ self._set_cache(cache)
267
+ if obj_id in self.elements:
268
+ self.elements.remove(obj_id)
269
+
270
+ def clear(self):
271
+ self.elements.clear()
272
+ self._set_cache([])
273
+
274
+ def __contains__(self, element: Union[T, ObjectId]) -> bool:
275
+ if isinstance(element, Model):
276
+ return element.id in self.elements
277
+ elif isinstance(element, ObjectId):
278
+ return element in self.elements
279
+ return element in self._get_cache()
280
+
281
+ def __len__(self) -> int:
282
+ return len(self.elements)