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,31 @@
1
+ import logging
2
+
3
+ from pymongo import ReturnDocument
4
+
5
+ from simstack.core.context import context
6
+ from simstack.core.definitions import TaskStatus
7
+ from simstack.models import NodeRegistry
8
+
9
+ logger = logging.getLogger("node_claim")
10
+
11
+
12
+ async def claim_submitted_node(registry_entry: NodeRegistry) -> bool:
13
+ """Automatically claim a submitted node for execution or submission."""
14
+ if registry_entry.id is None:
15
+ return False
16
+
17
+ collection = context.db.get_collection(NodeRegistry)
18
+ claimed = await collection.find_one_and_update(
19
+ {"_id": registry_entry.id, "status": TaskStatus.SUBMITTED.value},
20
+ {"$set": {"status": TaskStatus.RETRIEVED.value}},
21
+ return_document=ReturnDocument.AFTER,
22
+ )
23
+ if claimed is None:
24
+ logger.debug(
25
+ "Task task_id: %s was already claimed before this runner could claim it",
26
+ registry_entry.id,
27
+ )
28
+ return False
29
+
30
+ registry_entry.status = TaskStatus.RETRIEVED
31
+ return True
@@ -0,0 +1,362 @@
1
+ import glob
2
+ import logging
3
+ import os
4
+ import subprocess
5
+ import uuid
6
+ from pathlib import Path
7
+ from typing import Set, List, Tuple, Union
8
+
9
+ from odmantic import ObjectId, Model
10
+
11
+ from simstack.core.definitions import TaskStatus
12
+ from simstack.core.simstack_result import SimstackResult
13
+ from simstack.models.files import FileStack
14
+
15
+
16
+ local_logger = logging.getLogger("NodeRunner")
17
+
18
+
19
+ class NodeRunner(SimstackResult):
20
+ """
21
+ A task runner class that extends SimstackResult for executing subprocess commands and managing task execution.
22
+
23
+ This class provides functionality for running shell commands, collecting output files, and managing
24
+ task status with comprehensive logging capabilities. It acts as a bridge between the Simstack node
25
+ execution environment and external processes, ensuring that output, errors, and informational files
26
+ are correctly captured and associated with the task.
27
+
28
+ Attributes:
29
+ task_id (str): Unique identifier for the task, typically a string representation of an ObjectId.
30
+ name (str): Name of the task runner instance, usually derived from the node function name.
31
+ logger (logging.Logger): Logger instance for recording task activities.
32
+ last_stdout (str): Most recent stdout from subprocess execution.
33
+ last_stderr (str): Most recent stderr from subprocess execution.
34
+ log_string (str): Cumulative log of messages recorded via the `log` method.
35
+ info_file_patterns (Set[str]): Set of file patterns (e.g., "*.log") used to collect information files.
36
+ """
37
+
38
+ def __init__(self, name: str, task_id: str | ObjectId, logger: logging.Logger = None, **kwargs):
39
+ """
40
+ Initialize the NodeRunner instance.
41
+
42
+ Args:
43
+ name (str): Name for this task runner.
44
+ task_id (str | ObjectId): Unique identifier for the task.
45
+ logger (logging.Logger, optional): Logger instance to use. If None, uses a logger named 'NodeRunner'.
46
+ kwargs: Additional keyword arguments.
47
+ """
48
+ super().__init__()
49
+ self.task_id = str(task_id) if isinstance(task_id, ObjectId) else task_id
50
+ self.name = name
51
+ self.logger = logger or local_logger
52
+ self.last_stdout = ""
53
+ self.last_stderr = ""
54
+ self.log_string = ""
55
+ self.info_file_patterns = {"*.in", "*.out", "*.err", "*.log"}
56
+ self.info(f"NodeRunner '{self.name}' initialized for task_id: {self.task_id}")
57
+
58
+
59
+ @classmethod
60
+ def from_kwargs(cls, **kwargs) -> "NodeRunner":
61
+ """
62
+ Create a NodeRunner instance from keyword arguments.
63
+
64
+ If 'node_runner' is already present in kwargs and is an instance of NodeRunner, it returns it.
65
+ Otherwise, it initializes a new NodeRunner using 'name', 'task_id', and optionally 'logger' from kwargs.
66
+
67
+ Args:
68
+ **kwargs: Keyword arguments containing 'node_runner' or initialization parameters.
69
+
70
+ Returns:
71
+ NodeRunner: An existing or newly created NodeRunner instance.
72
+ """
73
+ node_runner = kwargs.get("node_runner")
74
+ if isinstance(node_runner, cls):
75
+ return node_runner
76
+
77
+ return cls(
78
+ name=kwargs["name"],
79
+ task_id=kwargs["task_id"],
80
+ logger=kwargs.get("logger"),
81
+ )
82
+
83
+ async def make_info_files(self, *args, cwd: str | Path = ""):
84
+ """
85
+ Collect and process information files based on patterns and explicit file paths.
86
+
87
+ This method processes the provided arguments to identify file patterns and explicit
88
+ file paths, then collects all matching files into FileStack objects for later use.
89
+
90
+ Args:
91
+ *args: Variable arguments that can be:
92
+ - File patterns (strings containing '*')
93
+ - Explicit file paths (existing readable files)
94
+ cwd (str | Path, optional): The directory where to look for files.
95
+ Defaults to current directory.
96
+
97
+ Note:
98
+ Files are added to the info_files list as FileStack objects.
99
+ Only readable files are processed.
100
+ """
101
+ try:
102
+ if not cwd:
103
+ search_cwd = Path.cwd()
104
+ else:
105
+ search_cwd = Path(cwd)
106
+
107
+ files_set: Set[str] = set()
108
+ # Process args for patterns and files
109
+ for value in args:
110
+ if isinstance(value, str):
111
+ if "*" in value:
112
+ self.info_file_patterns.add(value)
113
+ else:
114
+ filepath = value if os.path.isabs(value) else str(search_cwd / value)
115
+ if os.path.exists(filepath) and os.access(filepath, os.R_OK):
116
+ files_set.add(filepath)
117
+
118
+ self.info(f"Processing patterns: {self.info_file_patterns} in {search_cwd}")
119
+
120
+ # Add files matching patterns
121
+ for pattern in self.info_file_patterns:
122
+ # If pattern is not absolute, join it with search_cwd
123
+ search_pattern = pattern if os.path.isabs(pattern) else str(search_cwd / pattern)
124
+ for filepath in glob.glob(search_pattern):
125
+ if os.path.exists(filepath) and os.access(filepath, os.R_OK):
126
+ files_set.add(filepath)
127
+
128
+ self.info(f"Found info files: {files_set}")
129
+
130
+ for file_path in files_set:
131
+ if os.path.exists(file_path):
132
+ file_stack = FileStack.from_local_file(
133
+ file_path, in_memory=True, is_hashable=True, secure_source=True
134
+ )
135
+ self.info_files.append(file_stack)
136
+ self.info(f"Info file added: {file_path}")
137
+ except Exception as e:
138
+ self.error(f"Error in make_info_files: {str(e)}")
139
+ raise RuntimeError(f"Error in make_info_files: {str(e)}") from e
140
+
141
+ def debug(self, msg):
142
+ """
143
+ Log a debug message with task context.
144
+
145
+ Args:
146
+ msg (str): Debug message to log
147
+ """
148
+ self.logger.debug(
149
+ f"Task {self.name}: {msg} for task_id: {self.task_id}",
150
+ stacklevel=2,
151
+ )
152
+
153
+ def log(self, msg: str):
154
+ """
155
+ Log a message and append it to the cumulative log string.
156
+
157
+ This method records a message in the internal `log_string` and also logs it
158
+ as a debug message using the logger. The cumulative log string can later
159
+ be saved as a log file when the task finishes.
160
+
161
+ Args:
162
+ msg (str): Message to log.
163
+ """
164
+ self.log_string += f"{msg}\n"
165
+ self.logger.debug(
166
+ f"Task {self.name}: {msg} for task_id: {self.task_id}",
167
+ stacklevel=2,
168
+ )
169
+
170
+ def info(self, msg):
171
+ """
172
+ Log an info message with task context.
173
+
174
+ Args:
175
+ msg (str): Info message to log.
176
+ """
177
+ self.logger.info(
178
+ f"Task {self.name}: {msg} task_id: {self.task_id}",
179
+ stacklevel=2,
180
+ )
181
+
182
+ def warning(self, msg):
183
+ """
184
+ Log a warning message with task context.
185
+
186
+ Args:
187
+ msg (str): Warning message to log.
188
+ """
189
+ self.logger.warning(
190
+ f"Task {self.name}: {msg} task_id: {self.task_id}",
191
+ stacklevel=2,
192
+ )
193
+
194
+ def error(self, msg):
195
+ """
196
+ Log an error message with task context and exception info.
197
+
198
+ Args:
199
+ msg (str): Error message to log.
200
+ """
201
+ self.logger.error(
202
+ f"Task {self.name}: {msg} task_id: {self.task_id}",
203
+ stacklevel=2,
204
+ exc_info=True,
205
+ )
206
+
207
+ def subprocess(self, name: str, command: str | List[str], cwd: str = "") -> bool:
208
+ """
209
+ Execute a shell command as a subprocess and capture its output.
210
+
211
+ This method runs a shell command, captures stdout and stderr, creates a log file
212
+ with the execution details, and adds the log file to the info_files collection.
213
+
214
+ Args:
215
+ name (str): Name identifier for the subprocess (used for log file naming)
216
+ command (str): Shell command to execute
217
+ cwd (str, optional): Working directory for command execution. Defaults to current directory.
218
+
219
+ Returns:
220
+ bool: True if the subprocess completed successfully (return code 0), False otherwise
221
+
222
+ Note:
223
+ - Creates a log file named "{name}.log" containing command details and output
224
+ - Updates last_stdout and last_stderr attributes with the most recent output
225
+ - Log file is automatically added to info_files collection
226
+ """
227
+ if name == "":
228
+ name = "process"
229
+ if isinstance(command, list):
230
+ command = " ".join(command)
231
+
232
+ with open(f"{name}.log", "w", encoding="utf-8") as process_log:
233
+ process_log.write(f"Command: {name}\n{command}\n")
234
+ # TODO adapt for docker
235
+ process = subprocess.run(
236
+ command,
237
+ shell=True, # Important: use shell=True for shell operators like &&
238
+ capture_output=True,
239
+ text=True,
240
+ encoding="utf-8",
241
+ cwd=cwd if cwd else None,
242
+ )
243
+ self.info(f"run script {name} finished: {process.returncode}")
244
+ self.last_stdout = process.stdout
245
+ self.last_stderr = process.stderr
246
+ process_log.write(f"Process return code:\n{process.returncode}\n\n")
247
+ process_log.write(f"Process output:\n{process.stdout}\n\n")
248
+ process_log.write(f"Process error:\n{process.stderr}\n\n")
249
+ file_stack = FileStack.from_local_file(
250
+ f"{name}.log", in_memory=True, is_hashable=True, secure_source=True
251
+ )
252
+ self.info_files.append(file_stack)
253
+ self.info(f"Subprocess '{name}' log added to info files: {file_stack.name}")
254
+ return process.returncode == 0
255
+
256
+ def submit_to_watchdog(self, name: str, command: str) -> bool:
257
+ """
258
+ Submit a command to an external watchdog process for execution.
259
+
260
+ This method prepares the necessary files and environment to submit a command
261
+ to a watchdog process that will handle its execution. It uses a specified queue directory
262
+ to manage job files and signals.
263
+
264
+ Args:
265
+ name (str): Name identifier for the watchdog job (used for log file naming).
266
+ command (str): Command to be executed by the watchdog.
267
+
268
+ Returns:
269
+ bool: True if the submission and execution were successful, False otherwise.
270
+
271
+ Note:
272
+ - The method sets the task status to FAILED if the submission or execution fails.
273
+ - Job logs are automatically added to the info_files collection.
274
+ """
275
+ # we are inside a slurm job, so we need to use the queue dir of the job
276
+ queue_dir = Path.cwd() / "queue"
277
+ queue_dir.mkdir(parents=True, exist_ok=True)
278
+ if name == "":
279
+ name = "process"
280
+ from simstack.util.submit_to_watchdog import submit_to_watchdog
281
+
282
+ try:
283
+ with open(f"{name}.log", "w") as process_log:
284
+ process_log.write(f"Command: {name}\n{command}\n")
285
+
286
+ job_id = str(self.task_id) + "_" + uuid.uuid4().hex
287
+ result = submit_to_watchdog(command, job_id, queue_dir)
288
+ if result.status == "ok":
289
+ self.info(f"watchdog {result.exit_code}")
290
+ else:
291
+ err_msg = f"watchdog submission failed: {result.returncode}"
292
+ self.fail(err_msg)
293
+ self.last_stdout = result.stdout
294
+ self.last_stderr = result.stderr
295
+ process_log.write(f"Process return code:\n{result.exit_code}\n\n")
296
+ process_log.write(f"Process output:\n{result.stdout}\n\n")
297
+ process_log.write(f"Process error:\n{result.stderr}\n\n")
298
+ file_stack = FileStack.from_local_file(
299
+ f"{name}.log", in_memory=True, is_hashable=True, secure_source=True
300
+ )
301
+ self.info_files.append(file_stack)
302
+ self.info(f"Watchdog job '{name}' log added to info files: {file_stack.name}")
303
+ return result.status == "ok" and result.returncode == 0
304
+ except Exception as e:
305
+ err_msg = f"watchdog submission exception: {str(e)}"
306
+ self.fail(err_msg)
307
+ return False
308
+
309
+ def _make_log_file(self):
310
+ """
311
+ Create a log file from the cumulative log string and add it to info_files.
312
+
313
+ This internal method checks if `log_string` contains any messages. If it does,
314
+ it creates a `FileStack` from the string and appends it to the `info_files` list,
315
+ making it available as part of the task's results.
316
+ """
317
+ if len(self.log_string) > 0:
318
+ log_file = FileStack.from_string(self.log_string, file_name="log.txt")
319
+ self.info_files.append(log_file)
320
+ self.info(f"Log string saved to info files as: {log_file.name}")
321
+
322
+ def fail(self, msg: str) -> "NodeRunner":
323
+ """
324
+ Mark the task as failed and record an error message.
325
+
326
+ This method updates the task status to FAILED, sets the error message,
327
+ logs the error, and ensures the cumulative log file is created.
328
+
329
+ Args:
330
+ msg (str): Error message describing the failure.
331
+
332
+ Returns:
333
+ NodeRunner: Self reference for chaining.
334
+ """
335
+ self._make_log_file()
336
+ self.logger.error(
337
+ f"Task {self.name}: {msg} task_id: {self.task_id}",
338
+ stacklevel=2,
339
+ exc_info=True,
340
+ )
341
+ self.error_message = msg
342
+ self.status = TaskStatus.FAILED
343
+ return self
344
+
345
+ def succeed(self, msg: str = "") -> "NodeRunner":
346
+ """
347
+ Mark the task as successfully completed.
348
+
349
+ This method updates the task status to COMPLETED, sets an optional
350
+ success message, logs the success, and ensures the cumulative log file is created.
351
+
352
+ Args:
353
+ msg (str, optional): Success message. Defaults to "".
354
+
355
+ Returns:
356
+ NodeRunner: Self reference for chaining.
357
+ """
358
+ self._make_log_file()
359
+ self.info(f"succeeded {msg}")
360
+ self.message = msg
361
+ self.status = TaskStatus.COMPLETED
362
+ return self
@@ -0,0 +1,102 @@
1
+ from typing import Any, Tuple, List, Union
2
+ from odmantic import ObjectId, Model
3
+ from simstack.core.simstack_result import SimstackResult
4
+ from simstack.models import BooleanData
5
+ from simstack.models.files import FileStack
6
+
7
+ from simstack.core.context import context
8
+ from simstack.models import ModelMapping
9
+ from simstack.models.file_list import FileListModel
10
+ from simstack.models.simstack_model import is_simstack_model
11
+
12
+ from simstack.models.named_data_reference import NamedDataReference
13
+
14
+ import logging
15
+ logger = logging.getLogger("process_results")
16
+
17
+ async def process_result_helper(
18
+ result: Union[SimstackResult,Model, bool, BooleanData], task_id: str = "NA"
19
+ ) -> Tuple[List[NamedDataReference], List[Model]]:
20
+ """
21
+ Computes the results_references and returns a List[Model].
22
+ It works if the result is a SimstackResult, a single Model or a bool.
23
+ """
24
+
25
+ results_references: List[NamedDataReference] = []
26
+ result_models: List[Model] = []
27
+
28
+ if isinstance(result, bool) or isinstance(result, BooleanData) :
29
+ # Convert bool to BooleanData
30
+ if isinstance(result, bool):
31
+ boolean_data = BooleanData(value=result)
32
+ else:
33
+ boolean_data = result
34
+ result_model = await context.db.save(boolean_data)
35
+ result_models.append(result_model)
36
+ results_references.append(NamedDataReference.from_variable(
37
+ boolean_data,
38
+ variable_name="value",
39
+ task_id=task_id
40
+ ))
41
+
42
+ return results_references, result_models
43
+
44
+ if isinstance(result, SimstackResult):
45
+ # check if there are files in the result
46
+ if len(result.files) > 0:
47
+ file_list_model = FileListModel()
48
+ # this goes into the results must be a model
49
+ for file_stack in result.files:
50
+ if file_stack:
51
+ if isinstance(file_stack, FileStack):
52
+ logger.info(f"Task task_id: {task_id} saving file: {file_stack.name} {file_stack.id}")
53
+ file_list_model.append(file_stack)
54
+ else:
55
+ logger.error(f"Task task_id: {task_id} cannot save file: FileStack expected but got {file_stack}")
56
+ raise ValueError(
57
+ f"Task task_id: {task_id} cannot save file: FileStack expected but got {type(file_stack)}"
58
+ )
59
+ else:
60
+ logger.error(f"Task task_id: {task_id} saving file is NONE")
61
+ raise ValueError("saving file is NONE")
62
+
63
+ saved = await context.db.save(file_list_model)
64
+ results_references.append(NamedDataReference.from_variable(
65
+ saved,
66
+ variable_name="files",
67
+ task_id=task_id
68
+ ))
69
+ result_models.append(saved)
70
+
71
+ extra = getattr(result, "__pydantic_extra__", {})
72
+ if extra is None:
73
+ extra = {}
74
+ for key, value in extra.items():
75
+ # gather only non-callable public attributes
76
+ if (
77
+ not key.startswith("_")
78
+ and not callable(value)
79
+ and is_simstack_model(value)
80
+ ):
81
+ if isinstance(value, Model):
82
+ result_model = await context.db.save(value)
83
+ result_models.append(result_model)
84
+ results_references.append(NamedDataReference.from_variable(
85
+ result_model,
86
+ variable_name=key,
87
+ task_id=task_id
88
+ ))
89
+ else:
90
+ raise ValueError(
91
+ f"task_id: {task_id} cannot save model: {key} is not a model"
92
+ )
93
+ elif is_simstack_model(result) and isinstance(result, Model):
94
+ result_model = await context.db.save(result)
95
+ result_models.append(result_model)
96
+ results_references.append(NamedDataReference.from_variable(
97
+ result_model,
98
+ variable_name=result.__class__.__name__,
99
+ task_id=task_id
100
+ ))
101
+
102
+ return results_references, result_models
@@ -0,0 +1,117 @@
1
+ import logging
2
+
3
+ from simstack.core.artifacts import ArtifactArguments, create_artifacts
4
+ from simstack.core.context import context
5
+ from simstack.core.definitions import TaskStatus
6
+ from simstack.core.node import node_from_database
7
+ from simstack.models import NodeRegistry, ArtifactModel
8
+ from simstack.models.charts_artifact import ChartArtifactModel
9
+ from simstack.models.table_artifact import TableArtifactModel
10
+ from simstack.util.importer import import_class
11
+ from simstack.util.importer import import_function
12
+
13
+ logger = logging.getLogger("recompute_artifacts")
14
+
15
+
16
+ async def recompute_artifacts(node_registry: NodeRegistry):
17
+ """
18
+ Recomputes artifacts for a node and all its children recursively.
19
+
20
+ First processes all children nodes recursively, then removes and recomputes
21
+ the current node's artifacts.
22
+
23
+ :param node_registry: The registry entry for the node to process
24
+ :type node_registry: NodeRegistry
25
+ """
26
+ # Create Node from the registry
27
+
28
+ db = context.db
29
+ node = await node_from_database(node_registry)
30
+ if node is None:
31
+ logger.error(f"Failed to create node from registry task_id: {node_registry.id}")
32
+ return
33
+
34
+ if node.status != TaskStatus.COMPLETED:
35
+ logger.error(f"Cannot recompute artifacts for task_id: {node_registry.id} name: {node.name} status: {node.status}")
36
+ return
37
+
38
+ # Find all children of this node
39
+ children = await db.find(NodeRegistry, NodeRegistry.parent_ids.in_([node_registry.id]))
40
+
41
+ # Recursively recompute artifacts for all children first
42
+ for child_registry in children:
43
+ await recompute_artifacts(child_registry)
44
+
45
+ # Remove current node's artifacts
46
+ table_artifacts = await db.find(
47
+ TableArtifactModel, TableArtifactModel.parent_id == node_registry.id
48
+ )
49
+ for table_artifact in table_artifacts:
50
+ await db.delete(table_artifact)
51
+
52
+ chart_artifacts = await db.find(
53
+ ChartArtifactModel, ChartArtifactModel.parent_id == node_registry.id
54
+ )
55
+ for chart_artifact in chart_artifacts:
56
+ await db.delete(chart_artifact)
57
+
58
+ if node_registry.artifact_ids:
59
+ logger.info(f"Removing {len(node_registry.artifact_ids)} artifacts for node {node_registry.id}")
60
+
61
+ # Delete artifacts from the database
62
+ for artifact_id in node_registry.artifact_ids:
63
+ instance = await db.find_one(
64
+ ArtifactModel, ArtifactModel.id == artifact_id
65
+ )
66
+ if instance:
67
+ await db.delete(instance)
68
+ else:
69
+ logger.warning(
70
+ f"task_id: {node_registry.id} Failed to delete artifact {artifact_id} from database"
71
+ )
72
+ node_registry.artifact_ids = []
73
+
74
+ # Recompute artifacts for this node
75
+ if node_registry.status == TaskStatus.COMPLETED:
76
+ logger.info(f"Recomputing artifacts for node {node_registry.id} {node_registry.name}")
77
+
78
+ # Load the result to create new artifacts
79
+ result = await node.load_results()
80
+ if result is not None:
81
+ artifact_arguments = ArtifactArguments(result, node_registry.id)
82
+ # Reconstruct the function arguments for artifact creation
83
+ args = []
84
+ for ref in node_registry.input_references:
85
+ model = await import_class(ref.variable_mapping, context.db)
86
+ arg = await db.find_one(model, model.id == ref.reference)
87
+ if arg:
88
+ args.append(arg)
89
+
90
+ # Get the function for artifact creation
91
+ wrapped_func = await import_function(node_registry.func_mapping, context.db)
92
+ func = (
93
+ wrapped_func
94
+ if not hasattr(wrapped_func, "_inner")
95
+ else wrapped_func._inner
96
+ )
97
+
98
+ # Create node kwargs similar to run_local
99
+ node_kwargs = {
100
+ "parent_id": node_registry.id,
101
+ "task_id": node_registry.id,
102
+ "call_path": node_registry.call_path,
103
+ "parent_parameters": node_registry.parameters,
104
+ }
105
+
106
+ artifact_arguments.add_attributes(func, *args, **node_kwargs)
107
+ node_registry.artifact_ids = await create_artifacts(artifact_arguments, node_registry)
108
+
109
+ # Save the updated registry
110
+ await db.save(node_registry)
111
+ logger.info(
112
+ f"Recomputed {len(node_registry.artifact_ids)} artifacts for node {node_registry.id}"
113
+ )
114
+ else:
115
+ logger.warning(
116
+ f"Node {node_registry.id} is not completed, cannot recompute artifacts"
117
+ )
@@ -0,0 +1,12 @@
1
+ from simstack.core.context import context
2
+
3
+
4
+ async def main():
5
+ await context.initialize()
6
+ await context.db.reset_database()
7
+
8
+
9
+ if __name__ == "__main__":
10
+ import asyncio
11
+
12
+ asyncio.run(main())