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,587 @@
1
+ from typing import Dict, Iterator, Union, Tuple, KeysView, ValuesView, ItemsView, List
2
+
3
+ from odmantic import Model, ObjectId, EmbeddedModel, Field, Reference
4
+
5
+
6
+ from simstack.models import simstack_model
7
+ from simstack.models.dataset_metadata import DataSetMetadata
8
+
9
+ from simstack.util.make_table import make_column_defs_instance
10
+ from simstack.util.make_table import make_table_entries_helper
11
+
12
+
13
+ @simstack_model
14
+ class DataSetTupleSection(EmbeddedModel):
15
+ """
16
+ Represents a section of a dataset containing tuples of models.
17
+
18
+ A DataSetSection is a list of tuples where all tuples contain the same types of models.
19
+ For example, if one tuple contains (ModelA, ModelB), then all tuples in this section
20
+ must contain (ModelA, ModelB) instances.
21
+
22
+ :ivar model_types: List of model class names that define the structure of each tuple.
23
+ :type model_types: List[str]
24
+ :ivar data: List of tuples, where each tuple contains model IDs corresponding to model_types.
25
+ :type data: List[List[ObjectId]]
26
+ """
27
+
28
+ model_types: List[str] = Field(
29
+ default_factory=list
30
+ ) # Class names of models in each tuple
31
+ data: List[List[ObjectId]] = Field(
32
+ default_factory=list
33
+ ) # List of tuples (as lists of ObjectIds)
34
+
35
+ column_defs: List[Dict] = Field(default_factory=list)
36
+
37
+ table_entries: List[List[Dict]] = Field(default_factory=list)
38
+
39
+ model_config = {"extra": "forbid"}
40
+
41
+ async def add_model_group(self, models: Union[Model, Tuple[Model, ...]]) -> None:
42
+ """
43
+ Add a tuple of models to this section.
44
+
45
+ :param models: Tuple of model instances to add
46
+ :raises ValueError: If the model types don't match the section's expected types
47
+ """
48
+ if isinstance(models, Model):
49
+ models = (models,)
50
+ model_names = [model.__class__.__name__ for model in models]
51
+
52
+ # Verify that all the models are already stored, otherwise store them
53
+ from simstack.core.context import context
54
+ engine = context.db
55
+ stored_models = []
56
+ model_ids = []
57
+ for model in models:
58
+ if model is None:
59
+ model_ids.append(None)
60
+ continue
61
+ stored_model = await engine.save(model)
62
+ stored_models.append(stored_model)
63
+ model_ids.append(model.id)
64
+
65
+
66
+ # If this is the first tuple, set the model types
67
+ if not self.model_types:
68
+ self.model_types = model_names
69
+ else:
70
+ # Verify that the model types match
71
+ if model_names != self.model_types:
72
+ raise ValueError(
73
+ f"Model types {model_names} don't match section's expected types {self.model_types}"
74
+ )
75
+
76
+ self.data.append(model_ids)
77
+
78
+ async def make_column_defs(self):
79
+ """
80
+ Generate ag-grid column definitions for all model types in this section.
81
+
82
+ :return: List of column definitions for ag-grid
83
+ """
84
+ column_defs = []
85
+ if len(self.data) == 0:
86
+ return column_defs
87
+ from simstack.core.context import context
88
+ db = context.db
89
+ from simstack.util.importer import import_class_by_name
90
+ for model_group_id, model_type in zip(self.data[0], self.model_types):
91
+ model_class = await import_class_by_name(model_type,db)
92
+ model_instance = await db.find_one(
93
+ model_class, model_class.id == model_group_id
94
+ )
95
+ if model_instance is None:
96
+ raise ValueError(f"DB-Save Model of type {model_type} with id {model_group_id} not found")
97
+ model_columns = make_column_defs_instance(model_instance)
98
+ column_defs.extend(model_columns)
99
+ return column_defs
100
+
101
+ async def make_table_entries(self):
102
+ all_data = []
103
+ from simstack.core.context import context
104
+ from simstack.util.importer import import_class_by_name
105
+ db = context.db
106
+
107
+ for model_group_ids in self.data:
108
+ data = []
109
+ for model_group_id, model_type in zip(model_group_ids, self.model_types):
110
+ model_class = await import_class_by_name(model_type, db)
111
+ model_instance = await db.find_one(
112
+ model_class, model_class.id == model_group_id
113
+ )
114
+
115
+ model_data = make_table_entries_helper(model_instance)
116
+ data.append(model_data)
117
+ all_data.append(data)
118
+ return all_data
119
+
120
+ async def get_model_group(self, index: int) -> Tuple[Model, ...]:
121
+ """
122
+ Retrieve a tuple of models at the specified index.
123
+
124
+ :param index: Index of the tuple to retrieve
125
+ :return: Tuple of model instances
126
+ """
127
+ if index >= len(self.data):
128
+ raise IndexError(
129
+ f"Index {index} out of range for section with {len(self.data)} model groups"
130
+ )
131
+
132
+ model_ids = self.data[index]
133
+ models = []
134
+
135
+ from simstack.util.importer import import_class_by_name
136
+ from simstack.core.context import context
137
+ db = context.db
138
+ for model_type, model_id in zip(self.model_types, model_ids):
139
+ model_class = await import_class_by_name(model_type, db)
140
+
141
+ if model_id is None:
142
+ models.append(None)
143
+ continue
144
+ model_instance = await db.find_one(
145
+ model_class, model_class.id == model_id
146
+ )
147
+ if model_instance is None:
148
+ raise ValueError(
149
+ f"Model of type {model_type} with id {model_id} not found"
150
+ )
151
+ models.append(model_instance)
152
+
153
+ return tuple(models)
154
+
155
+ async def get_all_model_groups(self) -> List[Tuple[Model, ...]]:
156
+ """
157
+ Retrieve all tuples in this section.
158
+
159
+ :return: List of tuples of model instances
160
+ """
161
+ all_tuples = []
162
+ for i in range(len(self.data)):
163
+ tuple_models = await self.get_model_group(i)
164
+ all_tuples.append(tuple_models)
165
+ return all_tuples
166
+
167
+ # List-like behavior methods
168
+ def __len__(self) -> int:
169
+ """Return the number of model groups in this section."""
170
+ return len(self.data)
171
+
172
+ def __getitem__(
173
+ self, index: Union[int, slice]
174
+ ) -> Union[Tuple[Model, ...], List[Tuple[Model, ...]]]:
175
+ """
176
+ Get model group(s) at the specified index or slice.
177
+
178
+ :param index: Index or slice to retrieve
179
+ :return: Single tuple or list of tuples of model instances
180
+ """
181
+ if isinstance(index, slice):
182
+ indices = list(range(*index.indices(len(self.data))))
183
+ return [self.get_model_group(i) for i in indices]
184
+ else:
185
+ return self.get_model_group(index)
186
+
187
+ def __setitem__(self, index: int, value: Tuple[Model, ...]) -> None:
188
+ """
189
+ Set model group at the specified index.
190
+
191
+ :param index: Index to set
192
+ :param value: Tuple of model instances to set
193
+ """
194
+ if index >= len(self.data):
195
+ raise IndexError(
196
+ f"Index {index} out of range for section with {len(self.data)} model groups"
197
+ )
198
+
199
+ model_names = [model.__class__.__name__ for model in value]
200
+ model_ids = [model.id for model in value]
201
+
202
+ # Verify that the model types match
203
+ if self.model_types and model_names != self.model_types:
204
+ raise ValueError(
205
+ f"Model types {model_names} don't match section's expected types {self.model_types}"
206
+ )
207
+
208
+ self.data[index] = model_ids
209
+
210
+ def __delitem__(self, index: int) -> None:
211
+ """
212
+ Delete model group at the specified index.
213
+
214
+ :param index: Index to delete
215
+ """
216
+ if index >= len(self.data):
217
+ raise IndexError(
218
+ f"Index {index} out of range for section with {len(self.data)} model groups"
219
+ )
220
+ del self.data[index]
221
+
222
+ async def append(self, models: Tuple[Model, ...]) -> None:
223
+ """
224
+ Append a tuple of models to the section.
225
+
226
+ :param models: Tuple of model instances to append
227
+ """
228
+ await self.add_model_group(models)
229
+
230
+ async def insert(self, index: int, models: Tuple[Model, ...]) -> None:
231
+ """
232
+ Insert a tuple of models at the specified index.
233
+
234
+ :param index: Index to insert at
235
+ :param models: Tuple of model instances to insert
236
+ """
237
+ model_names = [model.__class__.__name__ for model in models]
238
+ model_ids = [model.id for model in models]
239
+
240
+ # If this is the first tuple, set the model types
241
+ if not self.model_types:
242
+ self.model_types = model_names
243
+ else:
244
+ # Verify that the model types match
245
+ if model_names != self.model_types:
246
+ raise ValueError(
247
+ f"Model types {model_names} don't match section's expected types {self.model_types}"
248
+ )
249
+
250
+ self.data.insert(index, model_ids)
251
+
252
+ def extend(self, models_list: List[Tuple[Model, ...]]) -> None:
253
+ """
254
+ Extend the section with multiple tuples of models.
255
+
256
+ :param models_list: List of tuples of model instances to extend with
257
+ """
258
+ # This used to be async but the requirement is to keep it sync.
259
+ # Note: add_model_group is NOT async, so this is fine.
260
+ for models in models_list:
261
+ self.add_model_group(models)
262
+
263
+ async def pop(self, index: int = -1) -> Tuple[Model, ...]:
264
+ """
265
+ Remove and return a model group at the specified index (default last).
266
+
267
+ :param index: Index to pop (default -1 for last)
268
+ :return: Tuple of model instances that was removed
269
+ """
270
+ if len(self.data) == 0:
271
+ raise IndexError("pop from empty DataSetSection")
272
+
273
+ # Get the models first before removing
274
+ models = await self.get_model_group(index)
275
+ del self.data[index]
276
+ return models
277
+
278
+ async def remove(self, models: Tuple[Model, ...]) -> None:
279
+ """
280
+ Remove the first occurrence of the specified tuple of models.
281
+
282
+ :param models: Tuple of model instances to remove
283
+ :raises ValueError: If the tuple is not found
284
+ """
285
+ model_ids = [model.id for model in models]
286
+ try:
287
+ self.data.remove(model_ids)
288
+ except ValueError:
289
+ raise ValueError(f"Tuple {models} not found in DataSetSection")
290
+
291
+ def clear(self) -> None:
292
+ """Remove all model groups from the section."""
293
+ self.data.clear()
294
+ self.model_types.clear()
295
+
296
+ async def index(
297
+ self, models: Tuple[Model, ...], start: int = 0, stop: int = None
298
+ ) -> int:
299
+ """
300
+ Return the index of the first occurrence of the specified tuple of models.
301
+
302
+ :param models: Tuple of model instances to find
303
+ :param start: Start index for search
304
+ :param stop: Stop index for search
305
+ :return: Index of the tuple
306
+ :raises ValueError: If the tuple is not found
307
+ """
308
+ model_ids = [model.id for model in models]
309
+ if stop is None:
310
+ stop = len(self.data)
311
+
312
+ for i in range(start, min(stop, len(self.data))):
313
+ if self.data[i] == model_ids:
314
+ return i
315
+
316
+ raise ValueError(f"Tuple {models} not found in DataSetSection")
317
+
318
+ def count(self, models: Tuple[Model, ...]) -> int:
319
+ """
320
+ Return the number of occurrences of the specified tuple of models.
321
+
322
+ :param models: Tuple of model instances to count
323
+ :return: Number of occurrences
324
+ """
325
+ model_ids = [model.id for model in models]
326
+ return self.data.count(model_ids)
327
+
328
+ def reverse(self) -> None:
329
+ """Reverse the order of model groups in the section."""
330
+ self.data.reverse()
331
+
332
+ def __iter__(self):
333
+ """
334
+ Iterate over model groups in the section.
335
+
336
+ :return: Async iterator over tuples of model instances
337
+ """
338
+ for i in range(len(self.data)):
339
+ yield self.get_model_group(i)
340
+
341
+ def __contains__(self, models: Tuple[Model, ...]) -> bool:
342
+ """
343
+ Check if the specified tuple of models exists in the section.
344
+
345
+ :param models: Tuple of model instances to check for
346
+ :return: True if found, False otherwise
347
+ """
348
+ model_ids = [model.id for model in models]
349
+ return model_ids in self.data
350
+
351
+ def __bool__(self) -> bool:
352
+ """Return True if the section is not empty."""
353
+ return len(self.data) > 0
354
+
355
+ def __repr__(self) -> str:
356
+ """Return string representation of the section."""
357
+ return (
358
+ f"DataSetSection(model_types={self.model_types}, length={len(self.data)})"
359
+ )
360
+
361
+
362
+ @simstack_model
363
+ class DataSetTuple(Model):
364
+ field_name: str = Field(default="dataset")
365
+ metadata: DataSetMetadata
366
+ sections: Dict[str, DataSetTupleSection] = Field(default_factory=dict)
367
+ model_config = {"extra": "forbid"}
368
+
369
+
370
+ @property
371
+ def dataset_type(self) -> str:
372
+ return self.metadata.dataset_type
373
+
374
+ async def save(self, engine):
375
+ # engine = current_engine_context.get()
376
+ structure = self.collect_structure()
377
+ ok = await self.metadata.validate_dict(structure, dataset_tuple=True)
378
+ if not ok:
379
+ raise ValueError("Metadata validation failed")
380
+
381
+ for key, section in self.sections.items():
382
+ self.sections[key].column_defs = await section.make_column_defs()
383
+ self.sections[key].table_entries = await section.make_table_entries()
384
+
385
+ await engine.save_unchecked(self)
386
+
387
+ async def custom_model_dump(self, **kwargs) -> Dict[str, str]:
388
+ """
389
+ :return: dict with id
390
+ """
391
+ return {"id": str(self.id)}
392
+
393
+ def collect_structure(self) -> Dict[str, Dict[str,str]]:
394
+ """
395
+ Returns a dictionary where keys are section names and values are dictionaries mapping
396
+ string indices to model types at those indices.
397
+
398
+ :return: Dictionary mapping section names to their model type structures
399
+ :rtype: Dict[str, Dict[str, str]]
400
+ """
401
+ return {
402
+ section_name: {str(i): model_type for i, model_type in enumerate(section.model_types)} if len(
403
+ section) > 0 else None
404
+ for section_name, section in self.sections.items()
405
+ }
406
+
407
+ async def clone(self, new_field_name: str = None, exclude_sections: List[str] = None) -> "DataSetTuple":
408
+ """
409
+ Clone the dataset with optionally a new field name and excluding specified sections.
410
+
411
+ :param new_field_name: Optional new field name for the cloned dataset. If None, uses original field_name.
412
+ :param exclude_sections: Optional list of section names to exclude from the clone. If None, all sections are cloned.
413
+ :return: A new DataSet instance that is a clone of this dataset
414
+ """
415
+ if exclude_sections is None:
416
+ exclude_sections = []
417
+
418
+ # Clone the dataset with new or same field name
419
+ cloned_dataset = DataSetTuple(
420
+ field_name=new_field_name if new_field_name is not None else self.field_name,
421
+ metadata=self.metadata
422
+ )
423
+
424
+ # Clone sections, excluding those in the exclude list
425
+ for section_name, section in self.sections.items():
426
+ if section_name not in exclude_sections:
427
+ # Create a new DataSetSection with copied data
428
+ cloned_section = DataSetTupleSection(
429
+ model_types=section.model_types.copy(),
430
+ data=[model_ids.copy() for model_ids in section.data],
431
+ column_defs=[col_def.copy() for col_def in section.column_defs],
432
+ table_entries=[[entry.copy() for entry in row] for row in section.table_entries]
433
+ )
434
+ cloned_dataset.sections[section_name] = cloned_section
435
+
436
+ return cloned_dataset
437
+
438
+ # Dict-like behavior methods
439
+ def __getitem__(self, key: str) -> DataSetTupleSection:
440
+ if key not in self.sections:
441
+ self.sections[key] = DataSetTupleSection()
442
+ return self.sections[key]
443
+
444
+ def __setitem__(self, key: str, value: DataSetTupleSection) -> None:
445
+ if key in self.sections:
446
+ raise KeyError(f"Section {key} already exists in dataset")
447
+ self.sections[key] = value
448
+
449
+ def __delitem__(self, key: str) -> None:
450
+ del self.sections[key]
451
+
452
+ def __len__(self) -> int:
453
+ return len(self.sections)
454
+
455
+ def __iter__(self) -> Iterator[str]:
456
+ return iter(self.sections)
457
+
458
+ def __contains__(self, key: str) -> bool:
459
+ return key in self.sections
460
+
461
+ def keys(self) -> KeysView[str]:
462
+ return self.sections.keys()
463
+
464
+ def values(self) -> ValuesView[DataSetTupleSection]:
465
+ return self.sections.values()
466
+
467
+ def items(self) -> ItemsView[str, DataSetTupleSection]:
468
+ return self.sections.items()
469
+
470
+ def get(self, key: str, default: DataSetTupleSection = None) -> DataSetTupleSection:
471
+ return self.sections.get(key, default)
472
+
473
+ def pop(self, key: str, default=None) -> DataSetTupleSection:
474
+ if default is None:
475
+ return self.sections.pop(key)
476
+ return self.sections.pop(key, default)
477
+
478
+ def popitem(self) -> Tuple[str, DataSetTupleSection]:
479
+ return self.sections.popitem()
480
+
481
+ def clear(self) -> None:
482
+ self.sections.clear()
483
+
484
+ def update(
485
+ self, other: Union[Dict[str, DataSetTupleSection], "DataSetTuple"] = None, **kwargs
486
+ ) -> None:
487
+ if other is not None:
488
+ if hasattr(other, "sections"):
489
+ self.sections.update(other.sections)
490
+ else:
491
+ self.sections.update(other)
492
+ self.sections.update(kwargs)
493
+
494
+ def setdefault(self, key: str, default: DataSetTupleSection = None) -> DataSetTupleSection:
495
+ return self.sections.setdefault(key, default)
496
+
497
+ @classmethod
498
+ def ui_schema(cls) -> dict:
499
+ return {
500
+ "ui:field": "DataSetField",
501
+ "metadata": {"ui:widget": "hidden"},
502
+ "sections": {"ui:widget": "hidden"},
503
+ }
504
+
505
+
506
+ class DataSetTupleSelectionField(EmbeddedModel):
507
+ section_name: str = Field(default="default")
508
+ indices: List[int] = Field(default_factory=list)
509
+
510
+ @simstack_model
511
+ class DataSetTupleSelection(Model):
512
+ field_name: str = Field(default="dataset_selection")
513
+ dataset_id: ObjectId
514
+ dataset_selection_fields: List[DataSetTupleSelectionField] = Field(default_factory=list)
515
+
516
+ async def get_dataset(self):
517
+ from simstack.core.context import context
518
+ return await context.db.find_one(DataSetTuple, DataSetTuple.id == self.dataset_id)
519
+
520
+ async def get_selected_elements(self, section_name: str = None) -> List[Tuple[Model, ...]]:
521
+ """
522
+ Retrieve all selected model groups from the dataset.
523
+
524
+ :param section_name: Optional section name to filter results. If None, returns all sections.
525
+ :return: List of tuples of model instances for all selected elements
526
+ """
527
+ from simstack.core.context import context
528
+ db = context.db
529
+ dataset = await db.find_one(DataSetTuple, DataSetTuple.id == self.dataset_id)
530
+
531
+ if dataset is None:
532
+ raise ValueError(f"Dataset with id {self.dataset_id} not found")
533
+
534
+ selected_elements = []
535
+ for selection_field in self.dataset_selection_fields:
536
+ if section_name is not None and selection_field.section_name != section_name:
537
+ continue
538
+
539
+ section = dataset.sections.get(selection_field.section_name)
540
+ if section is None:
541
+ raise ValueError(f"Section {selection_field.section_name} not found in dataset")
542
+
543
+ for index in selection_field.indices:
544
+ if index >= len(section):
545
+ raise IndexError(
546
+ f"Index {index} out of range for section {selection_field.section_name} with {len(section)} elements"
547
+ )
548
+ model_group = section.get_model_group(index)
549
+ selected_elements.append(model_group)
550
+
551
+ return selected_elements
552
+
553
+ async def __aiter__(self, section_name: str = None):
554
+ """
555
+ Async iterator over all selected model groups.
556
+
557
+ :param section_name: Optional section name to filter results. If None, returns all sections.
558
+ :return: Async iterator yielding tuples of model instances
559
+ """
560
+ from simstack.core.context import context
561
+ db = context.db
562
+ dataset = await db.find_one(DataSetTuple, DataSetTuple.id == self.dataset_id)
563
+
564
+ if dataset is None:
565
+ raise ValueError(f"Dataset with id {self.dataset_id} not found")
566
+
567
+ for selection_field in self.dataset_selection_fields:
568
+ if section_name is not None and selection_field.section_name != section_name:
569
+ continue
570
+
571
+ section = dataset.sections.get(selection_field.section_name)
572
+ if section is None:
573
+ raise ValueError(f"Section {selection_field.section_name} not found in dataset")
574
+
575
+ for index in selection_field.indices:
576
+ if index >= len(section):
577
+ raise IndexError(
578
+ f"Index {index} out of range for section {selection_field.section_name} with {len(section)} elements"
579
+ )
580
+ yield section.get_model_group(index)
581
+
582
+ @classmethod
583
+ def ui_schema(cls) -> dict:
584
+ return {
585
+ "ui:field": "DataSetSelectionField",
586
+ }
587
+