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,222 @@
1
+ import logging
2
+ from dataclasses import dataclass
3
+ from typing import Optional
4
+
5
+ from odmantic import AIOEngine
6
+
7
+ from simstack.models import NodeRegistry
8
+ from simstack.models.parameters import Parameters, Resource, SlurmParameters
9
+ from simstack.models.resource_assignment import (
10
+ ResourceAssignmentRule,
11
+ SlurmParametersPatch,
12
+ )
13
+ from simstack.util.db import Database
14
+
15
+ logger = logging.getLogger("resource_assignment")
16
+
17
+ SLURM_QUEUE_NAME = "slurm-queue"
18
+
19
+
20
+ @dataclass
21
+ class ResourceAssignmentResolution:
22
+ parameters: Parameters
23
+ normalized_call_path: str
24
+ matched_rule: Optional[ResourceAssignmentRule] = None
25
+
26
+
27
+ def normalize_call_path(call_path: Optional[str]) -> str:
28
+ return (call_path or "").strip().lstrip(".")
29
+
30
+
31
+ def _normalize_queue(queue: Optional[str]) -> str:
32
+ normalized = (queue or "").strip()
33
+ return normalized or "default"
34
+
35
+
36
+ def _is_slurm_queue(queue: Optional[str]) -> bool:
37
+ return _normalize_queue(queue).lower() == SLURM_QUEUE_NAME
38
+
39
+
40
+ def _clone_parameters(parameters: Optional[Parameters]) -> Parameters:
41
+ if isinstance(parameters, Parameters):
42
+ return parameters.model_copy(deep=True)
43
+ return Parameters()
44
+
45
+
46
+ def _merge_slurm_patch(
47
+ patch: Optional[SlurmParametersPatch],
48
+ ) -> SlurmParameters:
49
+ if patch is None:
50
+ return SlurmParameters()
51
+ return SlurmParameters(**patch.model_dump(exclude_none=True))
52
+
53
+
54
+ def empty_slurm_parameters() -> SlurmParameters:
55
+ cleared_values: dict[str, object] = {}
56
+ for field_name, field_info in SlurmParameters.model_fields.items():
57
+ if field_info.default_factory is not None:
58
+ cleared_values[field_name] = field_info.default_factory()
59
+ else:
60
+ cleared_values[field_name] = None
61
+ return SlurmParameters.model_validate(cleared_values)
62
+
63
+
64
+ def _apply_assignment_patch(
65
+ base_parameters: Parameters,
66
+ rule: Optional[ResourceAssignmentRule],
67
+ ) -> Parameters:
68
+ effective = _clone_parameters(base_parameters)
69
+ if rule is None:
70
+ return effective
71
+
72
+ if rule.resource_str:
73
+ effective.resource = Resource(value=rule.resource_str)
74
+ if rule.queue is not None:
75
+ effective.queue = _normalize_queue(rule.queue)
76
+ if rule.slurm_parameters_patch:
77
+ effective.slurm_parameters = _merge_slurm_patch(
78
+ SlurmParametersPatch.model_validate(rule.slurm_parameters_patch),
79
+ )
80
+
81
+ return effective
82
+
83
+
84
+ def normalize_and_validate_effective_parameters(
85
+ parameters: Optional[Parameters],
86
+ ) -> None:
87
+ if parameters is None:
88
+ return
89
+
90
+ if not _is_slurm_queue(getattr(parameters, "queue", None)):
91
+ parameters.slurm_parameters = empty_slurm_parameters()
92
+ return
93
+
94
+ slurm_parameters = getattr(parameters, "slurm_parameters", None)
95
+ if slurm_parameters is None:
96
+ raise ValueError('Slurm queue requires "slurm_parameters".')
97
+
98
+ fields_set: set[str] = getattr(slurm_parameters, "model_fields_set", set())
99
+ has_nodes = "nodes" in fields_set and slurm_parameters.nodes is not None
100
+ has_tasks = "tasks" in fields_set and slurm_parameters.tasks is not None
101
+ has_tasks_per_node = (
102
+ "tasks_per_node" in fields_set and slurm_parameters.tasks_per_node is not None
103
+ )
104
+ uses_default_nodes = (
105
+ not has_nodes
106
+ and not has_tasks
107
+ and not has_tasks_per_node
108
+ and slurm_parameters.nodes is not None
109
+ )
110
+
111
+ if uses_default_nodes:
112
+ has_nodes = True
113
+ elif not has_nodes:
114
+ slurm_parameters.nodes = None
115
+ if not has_tasks:
116
+ slurm_parameters.tasks = None
117
+ if not has_tasks_per_node:
118
+ slurm_parameters.tasks_per_node = None
119
+
120
+ if has_tasks and has_tasks_per_node:
121
+ raise ValueError(
122
+ 'Slurm parameters conflict: use either "tasks" or "tasks_per_node".'
123
+ )
124
+ if not has_nodes and not has_tasks:
125
+ raise ValueError('Slurm requires at least one of "nodes" or "tasks".')
126
+
127
+
128
+ def _select_matching_rule(
129
+ normalized_call_path: str,
130
+ rules: list[ResourceAssignmentRule],
131
+ ) -> Optional[ResourceAssignmentRule]:
132
+ enabled_rules = [rule for rule in rules if getattr(rule, "enabled", True)]
133
+ matching_rules = [
134
+ rule
135
+ for rule in enabled_rules
136
+ if ResourceAssignmentRule.matches_call_path(
137
+ rule.regex_pattern, normalized_call_path
138
+ )
139
+ ]
140
+ if not matching_rules:
141
+ return None
142
+
143
+ highest_score = max(
144
+ ResourceAssignmentRule.pattern_specificity_score(rule.regex_pattern)
145
+ for rule in matching_rules
146
+ )
147
+ top_rules = [
148
+ rule
149
+ for rule in matching_rules
150
+ if ResourceAssignmentRule.pattern_specificity_score(rule.regex_pattern)
151
+ == highest_score
152
+ ]
153
+ if len(top_rules) > 1:
154
+ rule_names = ", ".join(sorted(rule.name for rule in top_rules))
155
+ raise ValueError(
156
+ "Ambiguous resource assignment: "
157
+ f"multiple equally specific rules matched call_path '{normalized_call_path}': {rule_names}"
158
+ )
159
+ return top_rules[0]
160
+
161
+
162
+ async def resolve_resource_assignment(
163
+ db: Database,
164
+ *,
165
+ call_path: Optional[str],
166
+ base_parameters: Optional[Parameters],
167
+ parent_parameters: Optional[Parameters] = None,
168
+ ) -> ResourceAssignmentResolution:
169
+ normalized_call_path = normalize_call_path(call_path)
170
+ effective_base = _clone_parameters(base_parameters)
171
+
172
+ if not normalized_call_path:
173
+ normalize_and_validate_effective_parameters(effective_base)
174
+ return ResourceAssignmentResolution(
175
+ parameters=effective_base,
176
+ normalized_call_path=normalized_call_path,
177
+ matched_rule=None,
178
+ )
179
+
180
+ rules = await db.find(ResourceAssignmentRule)
181
+ matched_rule = _select_matching_rule(normalized_call_path, list(rules))
182
+ effective_parameters = _apply_assignment_patch(effective_base, matched_rule)
183
+ normalize_and_validate_effective_parameters(effective_parameters)
184
+
185
+ if matched_rule is not None:
186
+ logger.info(
187
+ "Applied resource assignment rule '%s' to call_path '%s'",
188
+ matched_rule.name,
189
+ normalized_call_path,
190
+ )
191
+
192
+ return ResourceAssignmentResolution(
193
+ parameters=effective_parameters,
194
+ normalized_call_path=normalized_call_path,
195
+ matched_rule=matched_rule,
196
+ )
197
+
198
+
199
+ async def apply_resource_assignment_to_node_registry(
200
+ db: Database,
201
+ node_registry: NodeRegistry,
202
+ *,
203
+ parent_parameters: Optional[Parameters] = None,
204
+ ) -> ResourceAssignmentResolution:
205
+ resolution = await resolve_resource_assignment(
206
+ db,
207
+ call_path=getattr(node_registry, "call_path", None),
208
+ base_parameters=getattr(node_registry, "parameters", None),
209
+ parent_parameters=parent_parameters,
210
+ )
211
+
212
+ node_registry.parameters = resolution.parameters
213
+ if resolution.matched_rule is None:
214
+ node_registry.assignment_rule_id = None
215
+ node_registry.assignment_rule_name = None
216
+ node_registry.assignment_pattern = None
217
+ else:
218
+ node_registry.assignment_rule_id = str(resolution.matched_rule.id)
219
+ node_registry.assignment_rule_name = resolution.matched_rule.name
220
+ node_registry.assignment_pattern = resolution.matched_rule.regex_pattern
221
+
222
+ return resolution
@@ -0,0 +1,90 @@
1
+ import logging
2
+ from typing import List
3
+ logger = logging.getLogger("resources")
4
+
5
+
6
+ class AllowedResources:
7
+ """
8
+ Singleton class that holds a list of allowed resource strings.
9
+
10
+ This class is problematic because the @node decorator is called before the config is read.
11
+ @node may contain Parameters which set default values for resources.
12
+ The solution is to create the AllowedResources singleton class here, and set the resources from
13
+ context.initialize. Before context.initialize is called, any resource is allowed.
14
+
15
+ However, resources are validated on read, so before any node is executed, the resources must be set.
16
+ AllowedResources can be set only once.
17
+ """
18
+
19
+ _instance = None
20
+ _resources: List[str] = []
21
+
22
+ def __new__(cls):
23
+ if cls._instance is None:
24
+ cls._instance = super(AllowedResources, cls).__new__(cls)
25
+ return cls._instance
26
+
27
+ def __init__(self):
28
+ # Only initialize once
29
+ self._initialized = False
30
+
31
+ def set_resources(self, resources: List[str]) -> None:
32
+ """Set the list of allowed resources."""
33
+ if self._initialized and resources != self._resources:
34
+ raise RuntimeError("Resources can only be set once")
35
+ self._initialized = True
36
+ self._resources = resources.copy() if resources else []
37
+
38
+ def get_resources(self) -> List[str]:
39
+ """Get the list of allowed resources."""
40
+ return self._resources.copy()
41
+
42
+ def add_resource(self, resource: str) -> None:
43
+ """Add a single resource to the list."""
44
+ if resource not in self._resources:
45
+ self._resources.append(resource)
46
+
47
+ def remove_resource(self, resource: str) -> None:
48
+ if resource == "self":
49
+ raise ValueError("Cannot remove 'self' resource")
50
+ """Remove a resource from the list."""
51
+ if resource in self._resources:
52
+ self._resources.remove(resource)
53
+
54
+ def clear_resources(self) -> None:
55
+ """Clear all resources from the list."""
56
+ self._resources.clear()
57
+ self._initialized = False
58
+
59
+ def has_resource(self, resource: str) -> bool:
60
+ """Check if a resource exists in the list."""
61
+ if hasattr(self, "_initialized") and self._initialized:
62
+ return resource in self._resources
63
+ else:
64
+ return True # before this is initialized, any resource is allowed
65
+
66
+ def __len__(self) -> int:
67
+ """Return the number of resources."""
68
+ return len(self._resources)
69
+
70
+ def __iter__(self):
71
+ """Make the class iterable."""
72
+ return iter(self._resources)
73
+
74
+ def __contains__(self, resource: str) -> bool:
75
+ """Support 'in' operator."""
76
+ return resource in self._resources
77
+
78
+ def __str__(self) -> str:
79
+ """String representation."""
80
+ return f"AllowedResources({self._resources})"
81
+
82
+ def __repr__(self) -> str:
83
+ """String representation."""
84
+ return f"AllowedResources({self._resources!r})"
85
+
86
+ @property
87
+ def initialized(self):
88
+ return hasattr(self, "_initialized")
89
+
90
+ allowed_resources = AllowedResources()
@@ -0,0 +1,24 @@
1
+ from typing import List, Dict
2
+
3
+
4
+ class RouteTable:
5
+ _instance = None
6
+
7
+ def __init__(self):
8
+ if RouteTable._instance is not None:
9
+ raise RuntimeError("Use get_instance() instead")
10
+ self.targets = {}
11
+
12
+ @classmethod
13
+ def get_instance(cls) -> 'RouteTable':
14
+ if cls._instance is None:
15
+ cls._instance = cls()
16
+ return cls._instance
17
+
18
+ def add_route_set(self, source: str, targets: List[str]) -> None:
19
+ self.targets[source] = targets
20
+
21
+ def clear_routes(self) -> None:
22
+ self.targets.clear()
23
+
24
+ route_table = RouteTable.get_instance()
@@ -0,0 +1,109 @@
1
+ from simstack.models import NodeRegistry
2
+ from simstack.core.definitions import TaskStatus
3
+ from simstack.core.context import context
4
+ import asyncio
5
+ import platform
6
+ import subprocess
7
+ import logging
8
+ import os
9
+ import locale
10
+
11
+ logger = logging.getLogger("DockerRunner")
12
+
13
+ async def run_docker(registry_entry: NodeRegistry) -> bool:
14
+ resource = context.config.resource
15
+ parameters = registry_entry.parameters
16
+
17
+
18
+ program_config = context.resource_config.get_program(registry_entry.name)
19
+ image= program_config.get("docker_image", None)
20
+ if image is None:
21
+ logger.error(f"Docker image not found for task_id={registry_entry.id}")
22
+ registry_entry.status = TaskStatus.FAILED
23
+ await context.db.save(registry_entry)
24
+ return False
25
+ docker_cmd = program_config.get("docker_cmd", None)
26
+ if docker_cmd is None:
27
+ docker_cmd = "docker"
28
+
29
+ if docker_cmd == "apptainer":
30
+ if not image.endswith(".sif") and not image.startswith("docker://"):
31
+ image += ".sif"
32
+
33
+ workdir = context.config.workdir
34
+ host_simstack_toml = context.config.project_root / "simstack.toml"
35
+
36
+ if docker_cmd == "docker":
37
+ cmd = [
38
+ "docker", "run",
39
+ "-e", f"SIMSTACK_DB_DATABASE={context.config.db_name}",
40
+ "-e", f"SIMSTACK_DB_TEST_DATABASE={context.config.db_name}",
41
+ "-e", f"SIMSTACK_DB_CONNECTION_STRING={context.config.connection_string}",
42
+ "-v", f"{workdir}:/root/simstack",
43
+ "-v", f"{host_simstack_toml}:/app/simstack.toml",
44
+ image,
45
+ "--node-id", str(registry_entry.id), "--resource", str(resource), "--project-root", "/app"
46
+ ]
47
+ elif docker_cmd == "apptainer":
48
+ cmd = [
49
+ "apptainer", "run",
50
+ "--env", f"SIMSTACK_DB_DATABASE={context.config.db_name}",
51
+ "--env", f"SIMSTACK_DB_TEST_DATABASE={context.config.db_name}",
52
+ "--env", f"SIMSTACK_DB_CONNECTION_STRING={context.config.connection_string}",
53
+ "--bind", f"{workdir}:/root/simstack",
54
+ "--bind", f"{host_simstack_toml}:/app/simstack.toml",
55
+ image,
56
+ "--node-id", str(registry_entry.id),
57
+ "--resource", str(resource),
58
+ "--project-root", "/app",
59
+ ]
60
+ else:
61
+ logger.error(f"Unsupported command {docker_cmd} for task_id={registry_entry.id}")
62
+ registry_entry.status = TaskStatus.FAILED
63
+ await context.db.save(registry_entry)
64
+ return False
65
+
66
+ # Use platform specific flags to ensure the process survives if runner is killed
67
+ creationflags = 0
68
+ if platform.system() == "Windows":
69
+ creationflags = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
70
+
71
+ try:
72
+ process = await asyncio.create_subprocess_exec(
73
+ *cmd,
74
+ stdout=asyncio.subprocess.PIPE,
75
+ stderr=asyncio.subprocess.PIPE,
76
+ creationflags=creationflags,
77
+ start_new_session=True if platform.system() != "Windows" else False
78
+ )
79
+
80
+ stdout_b, stderr_b = await process.communicate()
81
+
82
+ enc = locale.getpreferredencoding(False) or "utf-8"
83
+ stdout = (stdout_b or b"").decode(enc, errors="replace").strip()
84
+ stderr = (stderr_b or b"").decode(enc, errors="replace").strip()
85
+
86
+ if process.returncode != 0:
87
+ logger.error(
88
+ "docker run failed for task_id=%s rc=%s stderr=%s stdout=%s cmd=%s",
89
+ registry_entry.id, process.returncode, stderr, stdout, cmd
90
+ )
91
+ registry_entry.status = TaskStatus.FAILED
92
+ await context.db.save(registry_entry)
93
+ return False
94
+
95
+ if stdout:
96
+ # For `docker run` without -d, stdout is the actual output of the command
97
+ logger.info("Docker container output for task_id=%s: %s", registry_entry.id, stdout)
98
+ else:
99
+ logger.info("Docker container spawned for task_id=%s", registry_entry.id)
100
+ if stderr:
101
+ # Some Docker setups warn on stderr even on success
102
+ logger.warning("docker run stderr for task_id=%s: %s", registry_entry.id, stderr)
103
+
104
+ return True
105
+ except Exception as e:
106
+ logger.exception(f"fatal error in running docker task_id: {registry_entry.id} {str(e)}")
107
+ registry_entry.status = TaskStatus.FAILED
108
+ await context.db.save(registry_entry)
109
+ return False
@@ -0,0 +1,71 @@
1
+ import argparse
2
+ import asyncio
3
+ import logging
4
+ import sys
5
+ import os
6
+
7
+ from simstack.core.context import context
8
+ from simstack.core.definitions import TaskStatus
9
+ from simstack.core.node import node_from_database
10
+ from simstack.core.services.node_execution_service import run_node_from_registry
11
+
12
+ logger = logging.getLogger("Run Node")
13
+
14
+ async def run_node_from_id(node_id: str, resource_str: str, project_root: str = None):
15
+ """Run a single node by its ID from the database"""
16
+ logger.info(f"Initializing node run: node_id={node_id}, resource={resource_str}, project_root={project_root}")
17
+ try:
18
+ await context.initialize(resource=resource_str, project_root=project_root)
19
+ except Exception as e:
20
+ logger.error(f"Failed to initialize context: {str(e)}", exc_info=True)
21
+ return False
22
+ registry_entry = None
23
+ try:
24
+ registry_entry = await context.db.load_task_by_id(node_id)
25
+ if not registry_entry:
26
+ logger.error(f"Node with ID {node_id} not found in the database")
27
+ return False
28
+ return await run_node_from_registry(registry_entry)
29
+ except Exception as e:
30
+ logger.exception(f"Error running node task_id: {node_id}: {str(e)}")
31
+ if registry_entry:
32
+ registry_entry.status = TaskStatus.FAILED
33
+ await context.db.save(registry_entry)
34
+ return False
35
+
36
+ def run_node_main():
37
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', stream=sys.stdout)
38
+ logger.info("Starting run_node_main")
39
+ parser = argparse.ArgumentParser(description="Run nodes for a specific resource")
40
+ parser.add_argument(
41
+ "--node-id",
42
+ type=str,
43
+ help="Specific node ID to run (overrides resource-based polling)",
44
+ )
45
+
46
+ parser.add_argument(
47
+ "--resource",
48
+ default="local",
49
+ nargs="?",
50
+ type=str,
51
+ help="resource to load",
52
+ )
53
+
54
+ parser.add_argument(
55
+ "--project-root",
56
+ default=None,
57
+ nargs="?",
58
+ type=str,
59
+ help="project root directory",
60
+ )
61
+
62
+ args = parser.parse_args()
63
+
64
+
65
+ if args.node_id:
66
+ # Run a specific node once
67
+ asyncio.run(run_node_from_id(args.node_id, args.resource, args.project_root))
68
+
69
+
70
+ if __name__ == "__main__":
71
+ run_node_main()
@@ -0,0 +1,169 @@
1
+ import argparse
2
+ import asyncio
3
+ import logging
4
+ import os
5
+ import sys
6
+
7
+ from simstack.core.definitions import DBType
8
+
9
+ if sys.version_info >= (3, 11):
10
+ import tomllib # Python 3.11+
11
+ else:
12
+ import tomli as tomllib # type: ignore[import-not-found]
13
+
14
+ from simstack.core.context import context
15
+ from simstack.models.resource_definition import ResourceDefinition
16
+ from simstack.tables.node_table import make_node_table
17
+ from simstack.tables.model_table import make_model_table
18
+ from simstack.core.services.runner_manager import RunnerManager
19
+
20
+ logger = logging.getLogger("NodeRunner")
21
+
22
+
23
+ async def initialize_default_resource() -> ResourceDefinition | None:
24
+ """
25
+ Checks if the current resource is the default one.
26
+ If so, syncs the node and model tables based on config.toml.
27
+ """
28
+ resource_def = await context.db.find_one(
29
+ ResourceDefinition,
30
+ ResourceDefinition.resource_str == str(context.config.resource),
31
+ )
32
+
33
+ if resource_def is None:
34
+ logger.warning(
35
+ "No ResourceDefinition found for '%s'; skipping default-resource initialization.",
36
+ str(context.config.resource),
37
+ )
38
+ return None
39
+
40
+ if resource_def.is_default:
41
+ config_path = context.config.project_root / "config.toml"
42
+ if not config_path.exists():
43
+ logger.warning(f"Default resource detected, but {config_path} not found.")
44
+ return resource_def
45
+
46
+ try:
47
+ with open(config_path, "rb") as f:
48
+ config_data = tomllib.load(f)
49
+
50
+ active_dirs = config_data.get("active_dirs", [])
51
+ if not active_dirs:
52
+ logger.info("No active_dirs found in config.toml.")
53
+ return resource_def
54
+
55
+ logger.info(f"Default resource: initializing tables for {active_dirs}")
56
+ await make_model_table(context.db, dirs=active_dirs)
57
+ await make_node_table(context.db, dirs=active_dirs)
58
+
59
+ except Exception as e:
60
+ logger.error(f"Failed to initialize default resource tables: {e}")
61
+
62
+ return resource_def
63
+
64
+
65
+ async def async_main(args: argparse.Namespace) -> None:
66
+ """Async entry point"""
67
+ if args.connection_string == "none" or args.db_name == "none":
68
+ await context.initialize(resource=args.resource, config_file=args.config)
69
+ else:
70
+ await context.initialize(
71
+ resource=args.resource,
72
+ db_name=args.db_name,
73
+ connection_string=args.connection_string,
74
+ db_type=DBType.MONGODB,
75
+ config_file=args.config,
76
+ )
77
+
78
+ # Initialize tables if this is the default resource
79
+ resource_def = await initialize_default_resource()
80
+ is_default_resource = bool(resource_def and resource_def.is_default)
81
+
82
+ if args.resource:
83
+ logger.info(f"Setting resource for runner to {args.resource}")
84
+ runner_manager = RunnerManager(
85
+ context.config.resource,
86
+ detach=args.detach,
87
+ no_pull=args.no_pull,
88
+ is_default=is_default_resource,
89
+ with_file_transfer=args.with_file_transfer,
90
+ )
91
+ await runner_manager.run_nodes_for_resource(
92
+ args.polling_interval, 10, timeout=args.timeout
93
+ )
94
+
95
+
96
+ def runner_main() -> None:
97
+ parser = argparse.ArgumentParser(description="Run nodes for a specific resource")
98
+ parser.add_argument(
99
+ "--config",
100
+ type=str,
101
+ # default="config.toml",
102
+ help="Path to the configuration file",
103
+ )
104
+
105
+ parser.add_argument(
106
+ "--resource",
107
+ type=str,
108
+ default="local",
109
+ help="Resource name to process tasks for",
110
+ )
111
+
112
+ parser.add_argument(
113
+ "--db-name",
114
+ type=str,
115
+ default="none",
116
+ help="Specify a non-standard database",
117
+ )
118
+
119
+ parser.add_argument(
120
+ "--connection-string",
121
+ type=str,
122
+ default="none",
123
+ help="Specify a non-standard connection string",
124
+ )
125
+
126
+ parser.add_argument(
127
+ "--polling-interval",
128
+ type=int,
129
+ default=20,
130
+ help="Interval in seconds between polling for new tasks",
131
+ )
132
+
133
+ parser.add_argument(
134
+ "--detach",
135
+ type=lambda x: (str(x).lower() not in ["false", "0", "no"]),
136
+ default=True,
137
+ help="If true (default), run nodes in an external process. Set to 'false' to run inline.",
138
+ )
139
+
140
+ parser.add_argument(
141
+ "--timeout",
142
+ type=int,
143
+ default=None,
144
+ help="Timeout in minutes after which the runner will terminate",
145
+ )
146
+
147
+ parser.add_argument(
148
+ "--no-pull",
149
+ action="store_true",
150
+ default=False,
151
+ help="If true, do not pull from git (GitUvUpdateService will not be started)",
152
+ )
153
+
154
+ parser.add_argument(
155
+ "--with-file-transfer",
156
+ type=lambda x: (str(x).lower() not in ["false", "0", "no"]),
157
+ default=True,
158
+ help="If true (default), start the FileTransferService.",
159
+ )
160
+
161
+ args = parser.parse_args()
162
+ # Run the async main function
163
+ asyncio.run(async_main(args))
164
+ pid = os.getpid()
165
+ logger.info(f"runner with pid {pid} shutting down normally")
166
+
167
+
168
+ if __name__ == "__main__":
169
+ runner_main()
@@ -0,0 +1,11 @@
1
+ from simstack.core.services.base_service import BaseService, RestartService
2
+ from simstack.core.services.git_uv_update_service import GitUvUpdateService
3
+ from simstack.core.services.node_execution_service import NodeExecutionService
4
+ from simstack.core.services.runner_status_service import RunnerStatusService
5
+ from simstack.core.services.resource_branch_monitor_service import ResourceBranchMonitorService
6
+ from simstack.core.services.runner_cleanup_service import RunnerCleanupService
7
+ from simstack.core.services.slurm_status_service import SlurmStatusService
8
+ from simstack.core.services.git_restart_service import GitRestartService
9
+ from simstack.core.services.stop_check_service import StopCheckService
10
+ from simstack.core.services.timeout_restart_service import TimeoutRestartService
11
+ from simstack.core.services.runner_manager import RunnerManager