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,314 @@
1
+ import argparse
2
+ import asyncio
3
+ import importlib
4
+ import logging
5
+ from abc import ABC, abstractmethod
6
+ from pathlib import Path
7
+ from typing import Iterable, Optional, Type
8
+ import fnmatch # <-- added
9
+
10
+ from simstack.core.context import context
11
+ from simstack.core.find_simstack_modules import find_simstack_modules
12
+ from simstack.util.db import Database
13
+ from simstack.util.import_module import import_module_from_file
14
+ from simstack.util.path_manager import path_manager
15
+
16
+
17
+
18
+ class TableBuilderBase(ABC):
19
+ """
20
+ Shared pipeline for building "tables" by scanning:
21
+ 1) installed simstack modules (packages)
22
+ 2) configured project paths (python files)
23
+
24
+ Subclasses only implement `_process_module(module, drops)`.
25
+ """
26
+
27
+ def __init__(self, db: Database, write_schema: bool = False, project_root: Optional[Path] = None):
28
+ self.db = db
29
+ self.write_schema = write_schema
30
+ self._project_root = project_root
31
+ self._processed_modules = set()
32
+
33
+ @property
34
+ def project_root(self) -> Path:
35
+ if self._project_root:
36
+ return self._project_root
37
+ if context.config:
38
+ return context.config.project_root
39
+ from simstack.util.project_root_finder import find_project_root
40
+ return find_project_root()
41
+
42
+ @property
43
+ @abstractmethod
44
+ def logger(self) -> logging.Logger:
45
+ raise NotImplementedError
46
+
47
+ async def build(
48
+ self,
49
+ *,
50
+ dirs: Optional[list[Path]] = None,
51
+ drops: str = "",
52
+ exclude: Optional[list[str]] = None,
53
+ clear: bool = False,
54
+ ignore_entrypoints: bool = False,
55
+ ) -> None:
56
+ """
57
+ Build the table.
58
+
59
+ - If `dirs` is None: use configured `path_manager` paths (existing behavior).
60
+ - If `dirs` is a list: scan those directories for Python files and process them.
61
+
62
+ `exclude` entries can match:
63
+ - path parts (e.g. ".venv", "__pycache__")
64
+ - glob patterns (e.g. "*.generated.py")
65
+ - nested relative paths (e.g. "src/simstack/models")
66
+ """
67
+ await self._ensure_context_initialized()
68
+ self._processed_modules.clear()
69
+ if clear:
70
+ await self.clear_table()
71
+
72
+ if not ignore_entrypoints:
73
+ await self._process_simstack_modules(drops=drops)
74
+
75
+ await self._process_dirs(dirs, drops=drops, exclude=exclude or [])
76
+
77
+ async def _ensure_context_initialized(self) -> None:
78
+ if not context.initialized:
79
+ await context.initialize()
80
+
81
+ async def _process_simstack_modules(self, drops: str) -> None:
82
+ all_modules = set(find_simstack_modules())
83
+ for module_name in all_modules:
84
+ if module_name in self._processed_modules:
85
+ continue
86
+ self.logger.debug("Processing module: %s", module_name)
87
+ module = self._import_package_module(module_name)
88
+ if module is None:
89
+ continue
90
+ await self._process_module(module, drops=drops)
91
+ self._processed_modules.add(module_name)
92
+
93
+ def _import_package_module(self, module_name: str):
94
+ try:
95
+ return importlib.import_module(module_name)
96
+ except Exception as exc:
97
+ self.logger.warning("Failed to import module %s: %s", module_name, exc)
98
+ return None
99
+
100
+ async def _process_configured_paths(self) -> None:
101
+ for path_name in path_manager.paths.keys():
102
+ await self._process_path(path_name)
103
+
104
+ async def _process_path(self, path_name: str) -> None:
105
+ path_info = path_manager.get_path(path_name)
106
+ base_path = path_info["path"]
107
+ drops = path_info.get("drops", "")
108
+
109
+ self.logger.info("Processing configured path %s: %s", path_name, base_path)
110
+
111
+ for file_path in path_manager.find_python_files(path_name):
112
+ await self._process_file(file_path, drops)
113
+
114
+ async def _process_dirs(self, dirs: list[Path], *, drops: str, exclude: list[str]) -> None:
115
+ for base_dir in dirs:
116
+ self.logger.info("Processing CLI dir: %s", base_dir)
117
+
118
+ base_dir = Path(base_dir)
119
+
120
+ # Accept either absolute paths or paths relative to project root.
121
+ base_dir_path = base_dir if base_dir.is_absolute() else (self.project_root / base_dir)
122
+
123
+ for py_file in self._iter_python_files_under_dir(base_dir_path, exclude=exclude):
124
+ await self._process_file(py_file, drops)
125
+
126
+ def _iter_python_files_under_dir(self, base_dir: Path, *, exclude: list[str]) -> Iterable[Path]:
127
+ default_exclude_parts = {
128
+ ".git",
129
+ ".hg",
130
+ ".svn",
131
+ ".venv",
132
+ "venv",
133
+ "__init__.py"
134
+ "__pycache__",
135
+ ".mypy_cache",
136
+ ".pytest_cache",
137
+ ".ipynb_checkpoints"
138
+ }
139
+
140
+ def _should_exclude(p: Path) -> bool:
141
+ # Fast path: ignore common tooling/cache dirs anywhere in the path.
142
+ if any(part in default_exclude_parts for part in p.parts):
143
+ return True
144
+
145
+ # If the caller didn't pass any excludes, we're done.
146
+ if not exclude:
147
+ return False
148
+
149
+ # Match excludes against path parts and relative path (for nested patterns).
150
+ try:
151
+ rel = p.relative_to(base_dir)
152
+ except ValueError:
153
+ rel = p
154
+
155
+ rel_posix = rel.as_posix()
156
+
157
+ for ex in exclude:
158
+ ex = (ex or "").strip()
159
+ if not ex:
160
+ continue
161
+
162
+ # 1) Exact match against any path segment (works for "build", ".tox", etc.)
163
+ if ex in p.parts or ex in rel.parts:
164
+ return True
165
+
166
+ # 2) Glob match against the relative posix path (supports nested paths + file globs)
167
+ # Examples:
168
+ # --exclude "src/simstack/models"
169
+ # --exclude "**/generated/**"
170
+ # --exclude "*.generated.py"
171
+ if fnmatch.fnmatch(rel_posix, ex) or fnmatch.fnmatch(rel_posix, ex.rstrip("/") + "/*"):
172
+ return True
173
+
174
+ # 3) Also allow Windows-ish inputs like "a\\b\\c" by normalizing to posix.
175
+ ex_posix = ex.replace("\\", "/")
176
+ if ex_posix != ex and (
177
+ fnmatch.fnmatch(rel_posix, ex_posix) or fnmatch.fnmatch(rel_posix, ex_posix.rstrip("/") + "/*")
178
+ ):
179
+ return True
180
+
181
+ return False
182
+
183
+ if base_dir.is_file() and base_dir.suffix == ".py":
184
+ if not _should_exclude(base_dir):
185
+ yield base_dir
186
+ return
187
+
188
+ if not base_dir.exists():
189
+ self.logger.warning("Skipping non-existent path: %s", base_dir)
190
+ return
191
+
192
+ if not base_dir.is_dir():
193
+ self.logger.warning("Skipping non-directory path: %s", base_dir)
194
+ return
195
+
196
+ for p in base_dir.rglob("*.py"):
197
+ if _should_exclude(p):
198
+ continue
199
+ if p.is_file():
200
+ yield p
201
+
202
+ async def _process_file(self, file_path: Path, drops: str) -> None:
203
+ self.logger.debug("Processing file: %s", file_path)
204
+ module = import_module_from_file(file_path, self.project_root)
205
+ if not module:
206
+ self.logger.debug("Skipping %s because module import returned None", file_path)
207
+ return
208
+ if module.__name__ in self._processed_modules:
209
+ self.logger.debug("Skipping %s because module %s was already processed", file_path, module.__name__)
210
+ return
211
+ await self._process_module(module, drops)
212
+ self._processed_modules.add(module.__name__)
213
+
214
+ @abstractmethod
215
+ async def _process_module(self, module, drops: str) -> None:
216
+ """Subclass hook: scan/register whatever you need from `module`."""
217
+ raise NotImplementedError
218
+
219
+ async def second_stage(self, drops: str) -> None:
220
+ """ an optional hook to run after all modules have been processed"""
221
+ pass
222
+
223
+ async def clear_table(self) -> None:
224
+ """ an optional hook to clear the table before building """
225
+ pass
226
+
227
+ @classmethod
228
+ def cli_main(cls, builder_cls: Type["TableBuilderBase"], write_schema: bool = False) -> None:
229
+ """
230
+ Reusable CLI entry point.
231
+
232
+ Options:
233
+ --dir RELPATH (repeatable) Directories (relative to CWD) to scan for *.py files.
234
+ If omitted, defaults to scanning the current working directory.
235
+ --drops STRING Drops prefix (string) applied while processing these CLI dirs.
236
+ -v/--verbose Increase logging verbosity.
237
+ """
238
+ parser = argparse.ArgumentParser()
239
+ parser.add_argument("-v", "--verbose", action="count", default=0)
240
+ parser.add_argument(
241
+ "--dir",
242
+ dest="dirs",
243
+ action="append",
244
+ default=[],
245
+ help="Path to scan (repeatable). If omitted, CWD is used.",
246
+ )
247
+ parser.add_argument(
248
+ "--exclude",
249
+ dest="exclude",
250
+ action="append",
251
+ default=[],
252
+ help=(
253
+ "Exclude a directory/name/glob from scanning (repeatable). "
254
+
255
+ "Examples: --exclude .venv --exclude __pycache__ --exclude src/simstack/models --exclude '*.generated.py'"
256
+ ),
257
+ )
258
+ parser.add_argument(
259
+ "--drops",
260
+ dest="drops",
261
+ default="",
262
+ help="Drops prefix used when processing CLI dirs (string).",
263
+ )
264
+ parser.add_argument(
265
+ "--write-schema",
266
+ dest="write_schema",
267
+ action="store_true",
268
+ help="Enable schema writing.",
269
+ )
270
+ parser.add_argument(
271
+ "--ignore-entrypoints",
272
+ dest="ignore_entrypoints",
273
+ action="store_true",
274
+ help="Do not scan for modules registered via entrypoints.",
275
+ )
276
+ parser.add_argument(
277
+ "--clear",
278
+ dest="clear",
279
+ action="store_true",
280
+ help="Clear the table before building.",
281
+ )
282
+
283
+ args = parser.parse_args()
284
+
285
+ level = logging.WARNING
286
+ if args.verbose == 1:
287
+ level = logging.INFO
288
+ elif args.verbose >= 2:
289
+ level = logging.DEBUG
290
+
291
+ # Resolve dirs relative to the current working directory
292
+ if args.dirs:
293
+ dirs = [Path.cwd() / d for d in args.dirs]
294
+ else:
295
+ dirs = [Path.cwd()]
296
+
297
+ loop = asyncio.new_event_loop()
298
+ asyncio.set_event_loop(loop)
299
+
300
+ logging.getLogger("pymongo").setLevel(logging.INFO)
301
+
302
+ async def _run() -> None:
303
+ await context.initialize(log_level=level, resource="self")
304
+ builder = builder_cls(context.db, write_schema=args.write_schema)
305
+ await builder.build(
306
+ dirs=dirs,
307
+ drops=args.drops,
308
+ exclude=args.exclude,
309
+ clear=args.clear,
310
+ ignore_entrypoints=args.ignore_entrypoints,
311
+ )
312
+ await builder.second_stage(args.drops)
313
+ loop.run_until_complete(_run())
314
+ loop.close()
File without changes
@@ -0,0 +1,18 @@
1
+ async def async_zip(async_gen1, async_gen2):
2
+ """Async version of zip for two async generators"""
3
+ async for item1, item2 in async_zip_multiple(async_gen1, async_gen2):
4
+ yield item1, item2
5
+
6
+
7
+ async def async_zip_multiple(*async_generators):
8
+ """Async version of zip for multiple async generators"""
9
+ iterators = [aiter(ag) for ag in async_generators]
10
+
11
+ while True:
12
+ try:
13
+ values = []
14
+ for it in iterators:
15
+ values.append(await anext(it))
16
+ yield tuple(values)
17
+ except StopAsyncIteration:
18
+ break
@@ -0,0 +1,23 @@
1
+ import base64
2
+ import zlib
3
+
4
+
5
+ class BytesB64Mixin:
6
+ """
7
+ Mixin that teaches Pydantic/ODMantic to serialise *bytes* fields as
8
+ base-64-encoded ASCII strings when exporting to JSON (dict / response).
9
+ """
10
+
11
+ model_config = {
12
+ "json_encoders": {bytes: lambda b: base64.b64encode(b).decode("ascii")}
13
+ }
14
+
15
+ def _compress_bytes(self, data: bytes) -> str:
16
+ """Compress bytes and encode to base64 string"""
17
+ compressed = zlib.compress(data)
18
+ return base64.b64encode(compressed).decode('utf-8')
19
+
20
+ def _decompress_bytes(self, data: str) -> bytes:
21
+ """Decode base64 string and decompress to bytes"""
22
+ compressed = base64.b64decode(data.encode('utf-8'))
23
+ return zlib.decompress(compressed)
@@ -0,0 +1,20 @@
1
+ def cleaned_json_schema(cls):
2
+ """
3
+
4
+ Generates a JSON schema for the given class and its fields, but eliminates
5
+ all fields which are models, embedded models, or references to models.
6
+
7
+ :param cls:
8
+ :return:
9
+ """
10
+ schema = cls.model_json_schema()
11
+ schema["title"] = cls.__name__
12
+
13
+ # for field_name, field in cls.model_fields.items():
14
+ # field_type = field.annotation
15
+ # if hasattr(field_type, '_is_simstack_model'):
16
+ # # If the field is a model or embedded model, remove its proprties
17
+ # if field_name in schema['$defs'] and "properties" in schema['$defs']['properties']:
18
+ # del schema['$defs']['properties']
19
+
20
+ return schema
@@ -0,0 +1,179 @@
1
+ from pathlib import Path
2
+ from typing import List, TYPE_CHECKING, Union
3
+ from simstack.core.resources import allowed_resources
4
+ from simstack.models.parameters import Resource
5
+ from simstack.models.resource_definition import ResourceDefinition, GitRepo
6
+ from simstack.util.transform_file_name import transform_file_name
7
+ from simstack.util.init_data_source import initialize_resource_from_db
8
+
9
+ from simstack.util.toml_reader import TomlReader
10
+ from simstack.util.database_information import DatabaseInformation
11
+
12
+ if TYPE_CHECKING:
13
+ from simstack.util.db import Database
14
+
15
+
16
+ class ConfigReader(DatabaseInformation):
17
+ """
18
+ Represents a configuration reader that integrates with a database and a resource
19
+ definition system.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ db_info: Union[DatabaseInformation, "Database"],
25
+ resource_definition: ResourceDefinition,
26
+ *,
27
+ project_root: Path,
28
+ git_list: list[GitRepo] | None = None,
29
+ ):
30
+ db_temp_info = DatabaseInformation.from_db_info_or_db(db_info)
31
+ super().__init__(*db_temp_info.get_information())
32
+
33
+ self._project_root = project_root
34
+ self._resource_definition = resource_definition
35
+ self._git_list = list(git_list or [])
36
+ self._resource_str = resource_definition.resource_str
37
+
38
+ @classmethod
39
+ async def create(
40
+ cls,
41
+ resource_str,
42
+ db: "Database",
43
+ toml_reader: TomlReader,
44
+ project_root: Path,
45
+ **kwargs,
46
+ ):
47
+ """
48
+
49
+ the idea here is to attempt to get:
50
+
51
+ 1) all required data from the kwargs, if available
52
+ 2) if the data is not all available, get it from the database
53
+
54
+ """
55
+ import logging
56
+
57
+ logger = logging.getLogger("config-reader") # do this here because the calling function sets the logger up
58
+
59
+ required_keys = [
60
+ "python_paths",
61
+ "workdir",
62
+ "environment_start",
63
+ ]
64
+ init_done = True
65
+ workdir_self = None
66
+ config = {"project_root": project_root}
67
+ for key in required_keys:
68
+ if key in kwargs:
69
+ config[key] = kwargs.get(key)
70
+ if key == "workdir":
71
+ workdir_self = kwargs.get("workdir")
72
+ logger.info(f"Init from kwargs: {key}: {kwargs.get(key)}")
73
+ else:
74
+ init_done = False
75
+ for key in ["server_url", "server_token"]: # these are optional
76
+ if key in kwargs:
77
+ config[key] = kwargs.get(key)
78
+ logger.info(f"Init from kwargs: {key}: {kwargs.get(key)}")
79
+
80
+ git_list = []
81
+ if not init_done:
82
+ if toml_reader is None:
83
+ raise ValueError("ConfigReader: No toml_reader provided.")
84
+ workdir_self = kwargs.get("workdir", None)
85
+ if workdir_self is None:
86
+ workdir_self = toml_reader.get("parameters.general.workdir_self", None)
87
+ if workdir_self is None:
88
+ workdir_self = toml_reader.get("resources.self.workdir", None)
89
+ if workdir_self is None:
90
+ # raise ValueError("No workdir for self specified in config file or keyword arguments.")
91
+ workdir_self = project_root / "simstack" # Default to project_root / simstack if not found
92
+ else:
93
+ workdir_self = Path(workdir_self)
94
+
95
+ resource_definition = await initialize_resource_from_db(resource_str, db, workdir_self)
96
+ # else:
97
+ # raise RuntimeError("initialization from toml file is deprecated")
98
+ # allowed_resources_list = toml_reader.get_allowed_resources()
99
+ # allowed_resources.set_resources(allowed_resources_list)
100
+ # resource_definition = toml_reader.get_resource_definition(resource_str)
101
+ # git_list = toml_reader.get_git_list()
102
+ # toml_reader.build_routes()
103
+
104
+ if resource_definition is None:
105
+ raise ValueError("No valid resource definition found.")
106
+
107
+ # override the values in resource definition with those from the keyword arguments
108
+ for key in resource_definition.__class__.model_fields.keys():
109
+ if key in config:
110
+ logger.info(f"Overriding {key} from kwargs to: {config[key]}")
111
+ resource_definition.__setattr__(key, config[key])
112
+ del config[key]
113
+ del required_keys[required_keys.index(key)]
114
+
115
+ project_root = config.pop("project_root")
116
+ git_list_final = config.pop("git_list", git_list)
117
+
118
+ if config:
119
+ logger.warning(
120
+ f"Ignoring unused ConfigReader init keys: {sorted(config.keys())}"
121
+ )
122
+
123
+ log_msg = f"Resource: {resource_definition.resource_str}"
124
+ for key, value in resource_definition.__dict__.items():
125
+ if key in ["workdir", "git-branch", "environment_start"]:
126
+ log_msg += f" {key}: {value}"
127
+ logger.info(log_msg)
128
+
129
+ return cls(
130
+ db, resource_definition, project_root=project_root, git_list=git_list_final
131
+ )
132
+
133
+ @property
134
+ def server_url(self) -> str:
135
+ return self._server_url
136
+
137
+ @property
138
+ def server_token(self) -> str:
139
+ return self._server_token
140
+
141
+ @property
142
+ def git_list(self) -> List[GitRepo]:
143
+ return self._git_list
144
+
145
+ @property
146
+ def resource(self) -> Resource:
147
+ return Resource(value=self._resource_str)
148
+
149
+ @property
150
+ def workdir(self) -> Path:
151
+ return transform_file_name(self._resource_definition.workdir, self.project_root)
152
+
153
+ @property
154
+ def environment_start(self) -> str:
155
+ return self._resource_definition.environment_start
156
+
157
+ @property
158
+ def python_paths(self) -> List[Path]:
159
+ return [transform_file_name(p) for p in self._resource_definition.python_paths]
160
+
161
+ @property
162
+ def ssh_key(self) -> Path:
163
+ return transform_file_name(self._resource_definition.ssh_key)
164
+
165
+ @property
166
+ def hostname(self):
167
+ return self._resource_definition.hostname
168
+
169
+ @resource.setter
170
+ def resource(self, value: str):
171
+ raise ValueError("ConfigReader: Resource cannot be set directly")
172
+
173
+ @property
174
+ def project_root(self) -> Path:
175
+ return self._project_root
176
+
177
+ @property
178
+ def docker(self) -> bool:
179
+ return False
@@ -0,0 +1,75 @@
1
+ from typing import Dict, Any
2
+
3
+
4
+ async def custom_model_dump(self, **kwargs) -> Dict[str, Any]:
5
+ """
6
+ Custom model dump method to handle the conversion of model instances to dictionaries.
7
+ This method recursively traverses dictionaries and lists to convert any nested
8
+ model instances to their dictionary representation.
9
+
10
+ :param self: The model instance
11
+ :param kwargs: Additional keyword arguments
12
+ :return: A dictionary representation of the model instance
13
+ """
14
+ # First get the dictionary from the standard model_dump
15
+
16
+ filtered_kwargs = {k: v for k, v in kwargs.items() if k != "engine"}
17
+ data = self.model_dump(**filtered_kwargs)
18
+
19
+ # Process each field - the key is to process the original values from self
20
+ for field_name, field in self.model_fields.items():
21
+ field_value = getattr(self, field_name)
22
+
23
+ # Skip None values
24
+ if field_value is None:
25
+ continue
26
+
27
+ data[field_name] = await _recursive_process(field_value, **kwargs)
28
+
29
+ return data
30
+
31
+
32
+ async def _recursive_process(obj, **kwargs):
33
+ """
34
+ Helper function to recursively process an object that might contain models
35
+ """
36
+ if hasattr(obj, "custom_model_dump"):
37
+ return await obj.custom_model_dump(**kwargs)
38
+ elif isinstance(obj, dict):
39
+ return {k: await _recursive_process(v, **kwargs) for k, v in obj.items()}
40
+ elif isinstance(obj, list):
41
+ return [await _recursive_process(item, **kwargs) for item in obj]
42
+ else:
43
+ return obj
44
+
45
+
46
+ async def _process_container(container, **kwargs):
47
+ """
48
+ Helper function to recursively process dictionaries and lists,
49
+ converting any model instances to their dictionary representation.
50
+
51
+ :param container: The container to process (dict or list)
52
+ :param kwargs: Additional keyword arguments
53
+ :return: Processed container with model instances converted to dictionaries
54
+ """
55
+ if isinstance(container, dict):
56
+ result = {}
57
+ for k, v in container.items():
58
+ if hasattr(v, "custom_model_dump"):
59
+ result[k] = await v.custom_model_dump(**kwargs)
60
+ elif isinstance(v, (dict, list)):
61
+ result[k] = await _process_container(v, **kwargs)
62
+ else:
63
+ result[k] = v
64
+ return result
65
+ elif isinstance(container, list):
66
+ result = []
67
+ for item in container:
68
+ if hasattr(item, "custom_model_dump"):
69
+ result.append(await item.custom_model_dump(**kwargs))
70
+ elif isinstance(item, (dict, list)):
71
+ result.append(await _process_container(item, **kwargs))
72
+ else:
73
+ result.append(item)
74
+ return result
75
+ return container