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
File without changes
@@ -0,0 +1,191 @@
1
+ import inspect
2
+ import json
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ from odmantic.exceptions import DocumentParsingError
7
+ from pydantic import ValidationError
8
+
9
+ from simstack.core.context import context
10
+ from simstack.models.models import ModelMapping
11
+ from simstack.models.simstack_model import is_simstack_model
12
+ from simstack.util.db import Database
13
+ from simstack.util.path_manager import path_manager
14
+ from simstack.tables.table_builder import TableBuilderBase
15
+
16
+ logger = logging.getLogger("ModelTable")
17
+
18
+
19
+ class CreateModelTable(TableBuilderBase):
20
+ """
21
+ Helper class to build the model table without passing around many parameters.
22
+
23
+ Usage:
24
+ creator = CreateModelTable(db)
25
+ await creator.make_model_table()
26
+ """
27
+
28
+ @property
29
+ def logger(self) -> logging.Logger:
30
+ return logger
31
+
32
+ async def build(self, *args, **kwargs) -> None:
33
+ await super().build(*args, **kwargs)
34
+ await context.refresh_mappings(models=True, nodes=False)
35
+
36
+ async def _process_module(self, module, drops: str) -> None:
37
+ await self._create_models_from_module(module, drops)
38
+
39
+ async def _create_models_from_module(self, module, drops: str):
40
+ """Create ModelMapping entries for all relevant classes in a module."""
41
+ classes = inspect.getmembers(module, inspect.isclass)
42
+
43
+ for class_name, new_class in classes:
44
+ # this is required because of the Odmantic Metaclass Model
45
+ # subclass does not work even if applied to the imported classes
46
+ # this is a bug in importlib
47
+ bases = [base.__name__ for base in new_class.__bases__]
48
+ is_ui_model = any("UIModel" in s for s in bases) or is_simstack_model(
49
+ new_class
50
+ )
51
+ is_model = any(s == "Model" for s in bases)
52
+
53
+ is_embedded_model = any(s == "EmbeddedModel" for s in bases)
54
+
55
+ if not (is_model or is_ui_model or is_embedded_model):
56
+ continue
57
+ if class_name == "Model":
58
+ continue
59
+ if new_class.__module__ != module.__name__:
60
+ continue
61
+
62
+ new_modules = new_class.__module__.split(".")
63
+ # Use drops from the path_info dictionary
64
+ if drops != "":
65
+ drop_modules = drops.split(".")
66
+ while (
67
+ new_modules and drop_modules and new_modules[0] == drop_modules[0]
68
+ ):
69
+ new_modules.pop(0)
70
+ drop_modules.pop(0)
71
+ # if len(drop_modules) > 0:
72
+ # raise ValueError(
73
+ # "drop modules not empty: ", drop_modules, new_class.__module__
74
+ # )
75
+ full_mapping = ".".join(new_modules) + "." + class_name
76
+ logger.debug(f" Class: {class_name} Model Mapping: {full_mapping}")
77
+
78
+ # Remove any existing ModelMapping entry for this class
79
+
80
+ try:
81
+ existing_entries = await self.db.find(
82
+ ModelMapping, ModelMapping.name == class_name
83
+ )
84
+ except (ValidationError, NameError, DocumentParsingError) as e:
85
+ logger.error(
86
+ f"Error finding existing ModelMapping for {class_name}: {e}"
87
+ )
88
+ existing_entries = []
89
+
90
+ if len(existing_entries) > 1:
91
+ error_msg = f"Fatal error: Found {len(existing_entries)} ModelMapping entries for class_name '{class_name}'. Expected at most one."
92
+ logger.fatal(error_msg)
93
+ raise RuntimeError(error_msg)
94
+
95
+ if len(existing_entries) == 1:
96
+ existing_mapping = existing_entries[0].mapping
97
+ if existing_mapping != full_mapping:
98
+ logger.warning(
99
+ f"Replacing ModelMapping entry for {class_name}: "
100
+ f"old mapping '{existing_mapping}' -> new mapping '{full_mapping}'"
101
+ )
102
+
103
+ await self.db.delete(existing_entries[0])
104
+ logger.debug(f"Deleted ModelMapping entry for {class_name}")
105
+
106
+ # EmbeddedModels have no collection by may be simstack_models. They are never saved/retrieved
107
+ collection_name = getattr(new_class, "__collection__", None)
108
+ if collection_name is None:
109
+ if is_embedded_model:
110
+ collection_name = "EmbeddedModel"
111
+ else:
112
+ logger.error(f"No collection specified for {class_name}")
113
+
114
+ # Create the new ModelMapping entry (pickle functionality removed)
115
+ if is_ui_model:
116
+ model_entry = ModelMapping(
117
+ name=class_name,
118
+ mapping=full_mapping,
119
+ collection_name=collection_name,
120
+ json_schema=json.dumps(new_class.json_schema()),
121
+ ui_schema=json.dumps(new_class.ui_schema()),
122
+ route="",
123
+ )
124
+ logger.debug(
125
+ f"SimStack Model: {class_name} Mapping: {full_mapping} Collection: {collection_name}"
126
+ )
127
+ # open a file in a subdirectory of the current file schema/model.json
128
+ if self.write_schema:
129
+ project_root = self.project_root
130
+ json_file_dir = project_root / "schema"
131
+ json_file_dir.mkdir(parents=True, exist_ok=True)
132
+
133
+ combined_schema = {
134
+ "json_schema": new_class.json_schema(),
135
+ "ui_schema": new_class.ui_schema(),
136
+ }
137
+ with open(json_file_dir / f"{class_name}.json", "w") as f:
138
+ f.write(json.dumps(combined_schema, indent=4))
139
+ else:
140
+ model_entry = ModelMapping(
141
+ name=class_name,
142
+ mapping=full_mapping,
143
+ collection_name=collection_name,
144
+ )
145
+ logger.debug(
146
+ f"Model: {class_name} Mapping: {full_mapping} Collection: {collection_name}"
147
+ )
148
+
149
+ await self.db.save(model_entry)
150
+
151
+ async def _make_models_for_path(self, path_name: str):
152
+ """Build model mappings for all Python files under a configured path."""
153
+ path_info = path_manager.get_path(path_name)
154
+ path = path_info["path"]
155
+ drops = path_info.get("drops", "")
156
+ logger.info(f"Making model_table entries for files in {path}")
157
+
158
+ # Process each file in this path
159
+ for file_path in path_manager.find_python_files(path_name):
160
+ await self._create_model_models_from_file(file_path, drops)
161
+
162
+ async def clear_table(self) -> None:
163
+ self.logger.info("Clearing ModelMapping collection")
164
+ await self.db.get_collection(ModelMapping).drop()
165
+
166
+
167
+ # Public API preserved for existing callers (e.g. tests)
168
+ async def make_model_table(
169
+ db : Database,
170
+ dirs: list[str] = None,
171
+ drops: str = "",
172
+ write_schema: bool = False,
173
+ clear: bool = False,
174
+ project_root: Path = None,
175
+ ignore_entrypoints: bool = False,
176
+ ):
177
+ """
178
+ Rebuild the model table using the given database.
179
+
180
+ This is a thin wrapper around CreateModelTable for backward compatibility.
181
+ """
182
+ creator = CreateModelTable(db, write_schema=write_schema, project_root=project_root)
183
+ await creator.build(dirs=dirs, drops=drops, clear=clear, ignore_entrypoints=ignore_entrypoints)
184
+
185
+
186
+ def create_model_table_main():
187
+ TableBuilderBase.cli_main(CreateModelTable)
188
+
189
+
190
+ if __name__ == "__main__":
191
+ create_model_table_main()
@@ -0,0 +1,219 @@
1
+ import ast
2
+ import importlib
3
+ import inspect
4
+ import os
5
+ from typing import Optional, Callable, List, Dict
6
+ from simstack.models import NodeModel
7
+ from simstack.util.importer import import_function
8
+ from simstack.util.docstring_parser import DocstringParser
9
+
10
+ import logging
11
+ logger = logging.getLogger("node_children")
12
+
13
+ def _import_callable_from_mapping(function_mapping: str) -> Optional[Callable]:
14
+ """
15
+ Import a callable from a 'module.submodule.func' mapping string.
16
+ """
17
+ try:
18
+ module_path, _, attr = function_mapping.rpartition(".")
19
+ if not module_path or not attr:
20
+ logger.warning(f"Invalid function_mapping '{function_mapping}' (expected 'module.func').")
21
+ return None
22
+
23
+ module = importlib.import_module(module_path)
24
+ obj = getattr(module, attr, None)
25
+ if obj is None or not callable(obj):
26
+ logger.warning(f"Could not resolve callable for '{function_mapping}'.")
27
+ return None
28
+
29
+ return obj
30
+ except Exception as e:
31
+ logger.warning(f"Could not import '{function_mapping}': {e}")
32
+ return None
33
+
34
+ def _extract_called_functions(func: Callable) -> List[str]:
35
+ """
36
+ Inspect the function code and return all the function calls made within it.
37
+
38
+ Returns:
39
+ List of function names called within the function.
40
+ """
41
+ called_functions: List[str] = []
42
+
43
+ try:
44
+ source = inspect.getsource(func)
45
+ tree = ast.parse(source)
46
+
47
+ task_creators = {"create_tasks", "ensure_future"}
48
+
49
+ for node in ast.walk(tree):
50
+ if isinstance(node, ast.Call):
51
+ if isinstance(node.func, ast.Name):
52
+ # Direct function call: func_name()
53
+ called_functions.append(node.func.id)
54
+ elif isinstance(node.func, ast.Attribute):
55
+ # Attribute function call: obj.method()
56
+ if isinstance(node.func.value, ast.Name):
57
+ called_functions.append(f"{node.func.value.id}.{node.func.attr}")
58
+ else:
59
+ called_functions.append(node.func.attr)
60
+
61
+ # Detect async task creation: create_tasks(func()), ensure_future(func()), etc.
62
+ if isinstance(node.func, ast.Name) and node.func.id in task_creators:
63
+ if node.args and isinstance(node.args[0], ast.Call):
64
+ task_call = node.args[0]
65
+ if isinstance(task_call.func, ast.Name):
66
+ called_functions.append(task_call.func.id)
67
+ elif isinstance(task_call.func, ast.Attribute):
68
+ if isinstance(task_call.func.value, ast.Name):
69
+ called_functions.append(f"{task_call.func.value.id}.{task_call.func.attr}")
70
+ else:
71
+ called_functions.append(task_call.func.attr)
72
+
73
+ elif isinstance(node.func, ast.Attribute) and node.func.attr in task_creators:
74
+ if node.args and isinstance(node.args[0], ast.Call):
75
+ task_call = node.args[0]
76
+ if isinstance(task_call.func, ast.Name):
77
+ called_functions.append(task_call.func.id)
78
+ elif isinstance(task_call.func, ast.Attribute):
79
+ if isinstance(task_call.func.value, ast.Name):
80
+ called_functions.append(f"{task_call.func.value.id}.{task_call.func.attr}")
81
+ else:
82
+ called_functions.append(task_call.func.attr)
83
+
84
+ except Exception as e:
85
+ logger.warning(f"Could not extract called functions from {getattr(func, '__name__', '<unknown>')}: {e}")
86
+
87
+ return called_functions
88
+
89
+ def normalize_text(s: str) -> str:
90
+ return s.encode("utf-8", errors="replace").decode("utf-8")
91
+
92
+ async def update_node_children(database, drops: str) -> None:
93
+ """
94
+ 1) Read all registered nodes from NodeModel.
95
+ 2) For each node, import its function and extract called functions.
96
+ 3) Keep only those calls that correspond to nodes in the table.
97
+ 4) Update the NodeModel.called_nodes of the original function with a list of *function_mapping* strings.
98
+ """
99
+ node_models: List[NodeModel] = await database.find(NodeModel)
100
+
101
+ # Build lookup tables to resolve extracted names -> NodeModel.function_mapping
102
+ mapping_by_node_name: Dict[str, str] = { nm.name: nm.function_mapping for nm in node_models}
103
+ mapping_set: set[str] = set(nm.function_mapping for nm in node_models)
104
+
105
+ for nm in node_models:
106
+ func = await import_function(nm.function_mapping, database, None, True)
107
+ if func is None:
108
+ continue
109
+
110
+ parser = DocstringParser(inspect.getdoc(func))
111
+
112
+ called = _extract_called_functions(func)
113
+ logger.debug(f"Node {nm.name} called: {called}")
114
+ called_from_docstring = parser.called_nodes()
115
+ resolved: set[str] = set()
116
+ for called_name in called:
117
+ # If the extractor ever returns a full mapping, accept it directly
118
+ if called_name in mapping_set:
119
+ resolved.add(called_name)
120
+ continue
121
+
122
+ # If it matches a node name, resolve via node name
123
+ if called_name in mapping_by_node_name:
124
+ resolved.add(mapping_by_node_name[called_name])
125
+ continue
126
+
127
+ # Otherwise, resolve by last segment (handles "obj.method" and "module.func")
128
+ short = called_name.split(".")[-1]
129
+ if short in mapping_by_node_name:
130
+ resolved.add(mapping_by_node_name[short])
131
+ if called_from_docstring is not None and short in called_from_docstring:
132
+ del called_from_docstring[short]
133
+ continue
134
+
135
+ # go over the leftovers in the docstring
136
+ if called_from_docstring is not None:
137
+ for called_name in called_from_docstring:
138
+ if called_name in mapping_set:
139
+ resolved.add(called_name)
140
+ continue
141
+
142
+ # If it matches a node name, resolve via node name
143
+ if called_name in mapping_by_node_name:
144
+ resolved.add(mapping_by_node_name[called_name])
145
+ continue
146
+
147
+ # Otherwise, resolve by last segment (handles "obj.method" and "module.func")
148
+ # short = called_name.split(".")[-1]
149
+ # if short in mapping_by_node_name:
150
+ # resolved.add(mapping_by_short_name[short])
151
+ # continue
152
+
153
+ if len(resolved) != 0:
154
+ logger.debug(f"Resolved children of {nm.name} to {resolved}")
155
+ nm.called_nodes = sorted(resolved)
156
+
157
+
158
+ await database.get_collection(NodeModel).update_one(
159
+ {"_id": nm.id},
160
+ {"$set": {"called_nodes": nm.called_nodes}},
161
+ )
162
+
163
+ with open("node_models.txt", "w") as outfile:
164
+ for nm in node_models:
165
+ mapping_set.add(nm.function_mapping)
166
+ mapping_by_node_name[nm.name] = nm.function_mapping
167
+
168
+ # Write formatted NodeModel information
169
+ outfile.write(f"{'=' * 80}\n")
170
+
171
+ outfile.write(f"Node: {nm.name if nm.name else 'WARNING: Missing name'}\n")
172
+ outfile.write(
173
+ f"Function Mapping: {nm.function_mapping if nm.function_mapping else 'WARNING: Missing function_mapping'}\n")
174
+
175
+ if hasattr(nm, 'description') and nm.description:
176
+ try:
177
+ cleaned_description = normalize_text(nm.description)
178
+ outfile.write(f"Description: {cleaned_description}\n")
179
+ except Exception as e:
180
+ logger.warning(f"Could not normalize description for {nm.name}: {e}")
181
+ else:
182
+
183
+ outfile.write(f"Description: WARNING: Missing description\n")
184
+
185
+ # Write input_mappings in table format
186
+ outfile.write(f"\nInput Mappings:\n")
187
+ if hasattr(nm, 'input_mappings') and nm.input_mappings:
188
+ outfile.write(f" {'Arg Name':<20} | {'Model':<50} | {'Field':<20}\n")
189
+ outfile.write(f" {'-' * 20}-+-{'-' * 50}-+-{'-' * 20}\n")
190
+ for mapping in nm.input_mappings:
191
+ arg_name = getattr(mapping, 'name', 'N/A')
192
+ model = getattr(mapping, 'mapping', 'N/A')
193
+ field = getattr(mapping, 'description', 'N/A')
194
+ outfile.write(f" {str(arg_name):<20} | {str(model):<50} | {str(field):<20}\n")
195
+ else:
196
+ outfile.write(f" (none)\n")
197
+
198
+ # Write result_mappings in table format
199
+ outfile.write(f"\nResult Mappings:\n")
200
+ if hasattr(nm, 'result_mappings') and nm.result_mappings:
201
+ outfile.write(f" {'Arg Name':<20} | {'Model':<50} | {'Field':<20}\n")
202
+ outfile.write(f" {'-' * 20}-+-{'-' * 50}-+-{'-' * 20}\n")
203
+ for mapping in nm.result_mappings:
204
+ arg_name = getattr(mapping, 'name', 'N/A')
205
+ model = getattr(mapping, 'mapping', 'N/A')
206
+ field = getattr(mapping, 'description', 'N/A')
207
+ outfile.write(f" {str(arg_name):<20} | {str(model):<50} | {str(field):<20}\n")
208
+ else:
209
+ outfile.write(f" (none)\n")
210
+
211
+ # Write called_nodes (node children)
212
+ outfile.write(f"\nCalled Nodes (Children):\n")
213
+ if hasattr(nm, 'called_nodes') and nm.called_nodes:
214
+ for called_node in nm.called_nodes:
215
+ outfile.write(f" - {called_node}\n")
216
+ else:
217
+ outfile.write(f" (none)\n")
218
+
219
+ outfile.write(f"{'-' * 80}\n\n")