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,118 @@
1
+ import math
2
+ from typing import List
3
+
4
+
5
+ def _normalize_vector(v: List[float]) -> List[float]:
6
+ """Normalize a vector to unit length."""
7
+ norm = math.sqrt(sum(x * x for x in v))
8
+ if norm < 1e-10:
9
+ return [1.0, 0.0, 0.0] # Default direction for zero vector
10
+ return [x / norm for x in v]
11
+
12
+
13
+ def _cross_product(a: List[float], b: List[float]) -> List[float]:
14
+ """Calculate cross product of two 3D vectors."""
15
+ return [
16
+ a[1] * b[2] - a[2] * b[1],
17
+ a[2] * b[0] - a[0] * b[2],
18
+ a[0] * b[1] - a[1] * b[0],
19
+ ]
20
+
21
+
22
+ def _get_perpendicular_direction(v1: List[float]) -> List[float]:
23
+ """Get a direction perpendicular to v1."""
24
+ # Find the component with smallest absolute value
25
+ min_idx = min(range(3), key=lambda i: abs(v1[i]))
26
+
27
+ # Create perpendicular vector
28
+ v2 = [0.0, 0.0, 0.0]
29
+ v2[min_idx] = 1.0
30
+
31
+ # Make it perpendicular using Gram-Schmidt
32
+ dot_product = sum(v1[i] * v2[i] for i in range(3))
33
+ for i in range(3):
34
+ v2[i] -= dot_product * v1[i]
35
+
36
+ return v2
37
+
38
+
39
+ def _get_principal_direction(matrix: List[List[float]]) -> List[float]:
40
+ """Get the principal direction (largest eigenvalue direction) using power iteration."""
41
+ # Start with random vector
42
+ v = [1.0, 1.0, 1.0]
43
+
44
+ # Power iteration
45
+ for _ in range(10): # Usually converges quickly
46
+ # v = matrix * v
47
+ new_v = [0.0, 0.0, 0.0]
48
+ for i in range(3):
49
+ for j in range(3):
50
+ new_v[i] += matrix[i][j] * v[j]
51
+
52
+ # Normalize
53
+ norm = math.sqrt(sum(x * x for x in new_v))
54
+ if norm > 1e-10:
55
+ v = [x / norm for x in new_v]
56
+
57
+ return v
58
+
59
+
60
+ def _get_eigenvectors_3x3(matrix: List[List[float]]) -> List[List[float]]:
61
+ """
62
+ Get eigenvectors of a 3x3 matrix using simplified approach.
63
+ For the inertia tensor, we'll use a simplified canonical form.
64
+ """
65
+ # For molecular hashing, we can use a simplified approach
66
+ # that still provides rotation invariance
67
+
68
+ # Create an orthonormal basis from the inertia tensor
69
+ # Start with the direction of maximum variance
70
+ v1 = _get_principal_direction(matrix)
71
+
72
+ # Get a perpendicular direction
73
+ v2 = _get_perpendicular_direction(v1)
74
+
75
+ # Third direction is cross product
76
+ v3 = _cross_product(v1, v2)
77
+
78
+ # Normalize all vectors
79
+ v1 = _normalize_vector(v1)
80
+ v2 = _normalize_vector(v2)
81
+ v3 = _normalize_vector(v3)
82
+
83
+ # Return as columns of transformation matrix
84
+ return [[v1[0], v2[0], v3[0]], [v1[1], v2[1], v3[1]], [v1[2], v2[2], v3[2]]]
85
+
86
+
87
+ def _get_canonical_orientation(coords: List[List[float]]) -> List[List[float]]:
88
+ """
89
+ Get coordinates in a canonical orientation using the inertia tensor.
90
+
91
+ :param coords: Centered coordinates of atoms
92
+ :return: Coordinates in canonical orientation
93
+ """
94
+ if len(coords) < 2:
95
+ return coords
96
+
97
+ # Calculate inertia tensor (3x3 matrix)
98
+ inertia_tensor = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
99
+
100
+ for pos in coords:
101
+ # I_ij = sum(r_k * r_l) where k,l are coordinate indices
102
+ for i in range(3):
103
+ for j in range(3):
104
+ inertia_tensor[i][j] += pos[i] * pos[j]
105
+
106
+ # Get eigenvalues and eigenvectors using power iteration method
107
+ eigenvectors = _get_eigenvectors_3x3(inertia_tensor)
108
+
109
+ # Transform coordinates to canonical orientation
110
+ canonical_coords = []
111
+ for coord in coords:
112
+ new_coord = [0.0, 0.0, 0.0]
113
+ for i in range(3):
114
+ for j in range(3):
115
+ new_coord[i] += coord[j] * eigenvectors[j][i]
116
+ canonical_coords.append(new_coord)
117
+
118
+ return canonical_coords
@@ -0,0 +1,20 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from simstack.core.context import context
5
+ from simstack.util.project_root_finder import find_project_root
6
+
7
+
8
+ # Get the module name from the current file path
9
+ def get_module_path(file_path: str):
10
+ # Get the absolute path of the current file
11
+ file_path = Path(file_path).resolve()
12
+ # If not found in sys.path, use an alternative approach
13
+ project_root = context.config.project_root # Assumes running from project root
14
+ try:
15
+ relative_path = file_path.relative_to(project_root)
16
+
17
+ module_path = str(relative_path.with_suffix("")).replace(os.sep, ".")
18
+ return module_path
19
+ except ValueError:
20
+ return None
@@ -0,0 +1,65 @@
1
+ import logging
2
+ import os
3
+ import subprocess
4
+ import time
5
+ from datetime import datetime
6
+
7
+ logger = logging.getLogger("git_pull")
8
+
9
+
10
+ def git_pull_periodically(repo_path, interval_minutes=1, log_file=None):
11
+ """
12
+ Performs git pull in the specified repository at regular intervals.
13
+
14
+ Args:
15
+ repo_path (str): Path to the Git repository
16
+ interval_minutes (int): Time interval between pulls in minutes
17
+ log_file (str, optional): Path to log file. If None, logs to console.
18
+
19
+ Returns:
20
+ None
21
+ """
22
+
23
+ # Convert minutes to seconds
24
+ interval_seconds = interval_minutes * 60
25
+ logger.info("git_pull " + repo_path)
26
+ # Check if the path is a valid git repository
27
+ if not os.path.exists(os.path.join(repo_path, ".git")):
28
+ logging.error(f"The directory {repo_path} is not a valid Git repository.")
29
+ return
30
+
31
+ logging.info(
32
+ f"Starting periodic git pull every {interval_minutes} minutes for {repo_path}"
33
+ )
34
+
35
+ try:
36
+ while True:
37
+ try:
38
+ # Change to the repository directory
39
+ os.chdir(repo_path)
40
+
41
+ # Log the start time
42
+ now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
43
+ logging.info(f"Executing git pull at {now}")
44
+
45
+ # Execute git pull
46
+ result = subprocess.run(
47
+ ["git", "pull", "--recurse-submodules"], capture_output=True, text=True, check=True
48
+ )
49
+
50
+ # Log the output
51
+ logging.info(f"Git pull output: {result.stdout.strip()}")
52
+ if result.stderr:
53
+ logging.warning(f"Git pull stderr: {result.stderr.strip()}")
54
+
55
+ except subprocess.CalledProcessError as e:
56
+ logging.error(f"Git pull failed: {e.stderr.strip()}")
57
+ except Exception as e:
58
+ logging.error(f"Error during git pull: {str(e)}")
59
+
60
+ # Wait for the next interval
61
+ logging.info(f"Waiting {interval_minutes} minutes until next pull...")
62
+ time.sleep(interval_seconds)
63
+
64
+ except KeyboardInterrupt:
65
+ logging.info("Git pull process stopped by user.")
@@ -0,0 +1,95 @@
1
+ # Python
2
+ import subprocess
3
+ from pathlib import Path
4
+ from typing import Optional, Dict
5
+
6
+
7
+ def get_git_status(repo_path: Path) -> Dict[str, Optional[object]]:
8
+ """
9
+ Get the current Git short commit hash and whether the branch is up to date with its upstream.
10
+
11
+ Returns a dict:
12
+ {
13
+ "short_hash": Optional[str], # e.g., "a1b2c3d", None if not a git repo
14
+ "branch": Optional[str], # current branch name or "HEAD" if detached, None if not a repo
15
+ "up_to_date": Optional[bool], # True/False if upstream exists, None if unknown/no upstream
16
+ "ahead": Optional[int], # commits ahead of upstream (0 if up to date), None if unknown
17
+ "behind": Optional[int], # commits behind upstream (0 if up to date), None if unknown
18
+ }
19
+ """
20
+
21
+ def run_git(args, check=False):
22
+
23
+ return subprocess.run(
24
+ ["git", "-C", str(repo_path), *args],
25
+ capture_output=True,
26
+ text=True,
27
+ check=check,
28
+ timeout=30,
29
+ )
30
+
31
+ result: Dict[str, Optional[object]] = {
32
+ "short_hash": None,
33
+ "branch": None,
34
+ "up_to_date": None,
35
+ "ahead": None,
36
+ "behind": None,
37
+ }
38
+
39
+ # Verify we're in a git repository
40
+ try:
41
+ inside = run_git(["rev-parse", "--is-inside-work-tree"])
42
+ if inside.returncode != 0 or inside.stdout.strip() != "true":
43
+ return result # Not a repository
44
+ except Exception:
45
+ return result
46
+
47
+ # Get short hash
48
+ try:
49
+ hash_res = run_git(["rev-parse", "--short", "HEAD"], check=True)
50
+ result["short_hash"] = hash_res.stdout.strip()
51
+ except subprocess.CalledProcessError:
52
+ # Detached or other state where HEAD isn't resolvable
53
+ result["short_hash"] = None
54
+
55
+ # Get branch (or "HEAD" if detached)
56
+ try:
57
+ branch_res = run_git(["rev-parse", "--abbrev-ref", "HEAD"], check=True)
58
+ result["branch"] = branch_res.stdout.strip()
59
+ except subprocess.CalledProcessError:
60
+ result["branch"] = None
61
+
62
+ # Find upstream; if none, we can't determine up-to-date status against a remote
63
+ try:
64
+ upstream_res = run_git(
65
+ ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"]
66
+ )
67
+ if upstream_res.returncode != 0:
68
+ # No upstream configured
69
+ return result
70
+
71
+ upstream_ref = upstream_res.stdout.strip()
72
+
73
+ # Ensure we compare against the latest remote state
74
+ run_git(["fetch", "--quiet"])
75
+
76
+ # Compute ahead/behind relative to upstream
77
+ # Format: "<behind> <ahead>" because left is upstream, right is HEAD
78
+ counts_res = run_git(
79
+ ["rev-list", "--left-right", "--count", f"{upstream_ref}...HEAD"],
80
+ check=True,
81
+ )
82
+ behind_str, ahead_str = counts_res.stdout.strip().split()
83
+ behind, ahead = int(behind_str), int(ahead_str)
84
+
85
+ result["behind"] = behind
86
+ result["ahead"] = ahead
87
+ result["up_to_date"] = behind == 0 and ahead == 0
88
+ except subprocess.CalledProcessError:
89
+ # If comparison fails, leave up_to_date/ahead/behind as None
90
+ pass
91
+ except ValueError:
92
+ # Unexpected parsing format
93
+ pass
94
+
95
+ return result
@@ -0,0 +1,63 @@
1
+ import importlib
2
+ import logging
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ logger = logging.getLogger("import_module_from_file")
7
+
8
+
9
+ def import_module_from_file(file_path: Path, root_dir: Path):
10
+ """
11
+ Import a Python file as a module.
12
+
13
+ Args:
14
+ root_dir:
15
+ file_path: Path object pointing to the Python file to import
16
+
17
+ Returns:
18
+ Imported module or None if import failed
19
+ """
20
+ try:
21
+ # logger.debug(f"Attempting to import module from: {file_path}")
22
+ if not file_path.exists():
23
+ print(f"File not found: {file_path}")
24
+ return []
25
+
26
+ relative_path = file_path.relative_to(root_dir)
27
+
28
+ basename = relative_path.stem
29
+ module_name = ".".join(relative_path.parts[:-1]) + "." + basename
30
+
31
+ if root_dir not in sys.path:
32
+ sys.path.insert(0, str(root_dir))
33
+ # logger.debug(f"Added {root_dir} to sys.path")
34
+ # Try a simple import first
35
+ try:
36
+ if module_name is None or module_name == "":
37
+ raise ImportError(f"Module name is None for file: {file_path}")
38
+ module = importlib.import_module(module_name)
39
+ return module
40
+ except ImportError as e:
41
+ logger.warning(f"Direct import failed: {e} -- Trying spec-based import")
42
+
43
+ # Fall back to spec-based import
44
+ spec = importlib.util.spec_from_file_location(module_name, str(file_path))
45
+ if spec is None or spec.loader is None:
46
+ logger.error(f"Failed to create spec for {file_path}")
47
+ return None
48
+
49
+ module = importlib.util.module_from_spec(spec)
50
+ sys.modules[module_name] = module
51
+ try:
52
+ spec.loader.exec_module(module)
53
+ return module
54
+ except Exception as e:
55
+ logger.error(f"Import error when processing module: {file_path} {e}")
56
+ return None
57
+
58
+ except Exception as e:
59
+ logger.error(f"Error importing module from {file_path}: {e}")
60
+ import traceback
61
+
62
+ traceback.print_exc()
63
+ return None
@@ -0,0 +1,312 @@
1
+ import importlib
2
+ import logging
3
+ import re
4
+ from typing import Any, Callable, Optional, Type, cast
5
+ from odmantic import Model, AIOEngine, ObjectId
6
+
7
+ from simstack.core.context import context
8
+ from simstack.models.models import ModelMapping, NodeModel
9
+ from simstack.util.db import Database
10
+
11
+ logger = logging.getLogger("importer")
12
+
13
+ NODES_SEARCH_BY_NAME_FALLBACK = True
14
+ MODELS_SEARCH_BY_NAME_FALLBACK = True
15
+
16
+ def _get_initialized_context() -> Any | None:
17
+ try:
18
+ from simstack.core.context import context
19
+
20
+ if context.initialized:
21
+ return context
22
+ except RuntimeError:
23
+ return None
24
+ return None
25
+
26
+
27
+ def _context_cache_matches_engine(ctx: Any | None, db: Database | None = None) -> bool:
28
+ if ctx is None:
29
+ return False
30
+ if db is None:
31
+ return True
32
+ try:
33
+ return ctx.db is not None and db is ctx.db
34
+ except RuntimeError:
35
+ return False
36
+
37
+
38
+ def _resolve_engine(ctx: Any | None, engine: AIOEngine | None = None) -> AIOEngine:
39
+ if engine is not None:
40
+ return engine
41
+ if ctx is not None:
42
+ try:
43
+ if ctx.db is not None:
44
+ return cast(AIOEngine, ctx.db.core_engine)
45
+ except RuntimeError:
46
+ pass
47
+ raise RuntimeError(
48
+ "Could not resolve engine both engine and context have no engine"
49
+ )
50
+
51
+
52
+ def _lookup_node_cache(node_mappings: Any, function_path: str) -> Optional[NodeModel]:
53
+ if node_mappings is None:
54
+ return None
55
+ node_model = node_mappings.get_by_mapping(function_path)
56
+ if node_model is None and NODES_SEARCH_BY_NAME_FALLBACK:
57
+ if "." in function_path:
58
+ _, function_name = function_path.rsplit(".", 1)
59
+ else:
60
+ function_name = function_path
61
+ node_model = node_mappings.get_by_name(function_name)
62
+ return node_model
63
+
64
+
65
+ async def _find_node_model(function_path: str, db: Database) -> Optional[NodeModel]:
66
+ if context.node_mappings is None:
67
+ await context.refresh_mappings(models=False, nodes=True)
68
+
69
+ node_model = _lookup_node_cache(context.node_mappings, function_path)
70
+ if node_model is not None:
71
+ return node_model
72
+
73
+ await context.refresh_mappings(models=False, nodes=True)
74
+ node_model = _lookup_node_cache(context.node_mappings, function_path)
75
+ if node_model is not None:
76
+ return node_model
77
+
78
+ node_model = await db.find_one(
79
+ NodeModel, NodeModel.function_mapping == function_path
80
+ )
81
+ if node_model is None and NODES_SEARCH_BY_NAME_FALLBACK:
82
+ if "." in function_path:
83
+ _, function_name = function_path.rsplit(".", 1)
84
+ else:
85
+ function_name = function_path
86
+ node_model = await db.find_one(NodeModel, NodeModel.name == function_name)
87
+ return node_model
88
+
89
+
90
+ async def _find_node_model_by_name(
91
+ function_name: str, db: Database
92
+ ) -> Optional[NodeModel]:
93
+ if context.node_mappings is None:
94
+ await context.refresh_mappings(models=False, nodes=True)
95
+
96
+ node_model = context.node_mappings.get_by_name(function_name)
97
+ if node_model is not None:
98
+ return node_model
99
+
100
+ await context.refresh_mappings(models=False, nodes=True)
101
+ node_model = context.node_mappings.get_by_name(function_name)
102
+ if node_model is not None:
103
+ return node_model
104
+ return await db.find_one(NodeModel, NodeModel.name == function_name)
105
+
106
+
107
+ def _lookup_model_cache(
108
+ model_mappings: Any, class_path: str, class_name: str
109
+ ) -> Optional[ModelMapping]:
110
+ if model_mappings is None:
111
+ return None
112
+ model_mapping = None
113
+ if MODELS_SEARCH_BY_NAME_FALLBACK:
114
+ model_mapping = model_mappings.get_by_name(class_name)
115
+ if not model_mapping:
116
+ model_mapping = model_mappings.get_by_mapping(class_path)
117
+ return model_mapping
118
+
119
+
120
+ async def _find_model_mapping(model_path: str, db: Database) -> Optional[ModelMapping]:
121
+ _, model_name = model_path.rsplit(".", 1)
122
+
123
+ if context.model_mappings is None:
124
+ await context.refresh_mappings(models=True, nodes=False)
125
+
126
+ model_mapping = _lookup_model_cache(context.model_mappings, model_path, model_name)
127
+ if model_mapping is not None:
128
+ return model_mapping
129
+
130
+ await context.refresh_mappings(models=True, nodes=False)
131
+ model_mapping = _lookup_model_cache(context.model_mappings, model_path, model_name)
132
+ if model_mapping is not None:
133
+ return model_mapping
134
+
135
+ model_mapping = None
136
+ if MODELS_SEARCH_BY_NAME_FALLBACK:
137
+ model_mapping = await db.find_one(ModelMapping, ModelMapping.name == model_name)
138
+ if model_mapping is None:
139
+ model_mapping = await db.find_one(
140
+ ModelMapping, ModelMapping.mapping == model_path
141
+ )
142
+ return model_mapping
143
+
144
+
145
+ # TODO engines remove: duplicate of find_class_mapping_by_name
146
+ async def _find_model_mapping_by_name(
147
+ class_name: str, db: Database
148
+ ) -> Optional[ModelMapping]:
149
+ if context.model_mappings is None:
150
+ await context.refresh_mappings(models=True, nodes=False)
151
+
152
+ model_mapping = context.model_mappings.get_by_name(class_name)
153
+ if model_mapping is not None:
154
+ return model_mapping
155
+
156
+ await context.refresh_mappings(models=True, nodes=False)
157
+ model_mapping = context.model_mappings.get_by_name(class_name)
158
+ if model_mapping is not None:
159
+ return model_mapping
160
+
161
+ return await db.find_one(ModelMapping, ModelMapping.name == class_name)
162
+
163
+
164
+ async def _function_from_model(
165
+ node_model: NodeModel, task_id: ObjectId | None = None
166
+ ) -> Callable[..., Any]:
167
+ """
168
+ Get the function from the NodeModel. Here the mapping may already be fixed if the original mapping was wrong
169
+ Otherwise, it is imported from the function_mapping.
170
+
171
+ Args:
172
+ node_model: NodeModel object
173
+ task_id: Optional task id
174
+
175
+ Returns:
176
+ The function object
177
+ """
178
+
179
+ function_path = node_model.function_mapping
180
+ try:
181
+ module_path, function_name = function_path.rsplit(".", 1)
182
+ module = importlib.import_module(module_path)
183
+ return cast(Callable[..., Any], getattr(module, function_name))
184
+ except (ImportError, AttributeError, ValueError) as e:
185
+ if NODES_SEARCH_BY_NAME_FALLBACK:
186
+ try:
187
+ # Try to load by the name field which might contain the correct path
188
+ # if it was a name-only search that found this model.
189
+ if "." in node_model.name:
190
+ module_path, function_name = node_model.name.rsplit(".", 1)
191
+ module = importlib.import_module(module_path)
192
+ return cast(Callable[..., Any], getattr(module, function_name))
193
+ except (ImportError, AttributeError, ValueError):
194
+ pass
195
+ logger.error(
196
+ f"task_id: {task_id} Error importing function {function_path}: {e}"
197
+ )
198
+ raise e
199
+
200
+
201
+ async def import_function(
202
+ function_path: str,
203
+ db: Database,
204
+ task_id: ObjectId | None = None,
205
+ tolerate_missing_function: bool = False,
206
+ ) -> Optional[Callable[..., Any]]:
207
+ """
208
+ Dynamically import a function from a module using its full path, including a migration mechanism.
209
+ load the function information using NodeModel
210
+ load the pickled version if it exists
211
+ if there is no pickled version, use regular import.
212
+
213
+ Args:
214
+ function_path: Dot notation path to the function (e.g. 'methods.submodule.function_name')
215
+ db: Database object
216
+ task_id: Optional task id
217
+ tolerate_missing_function: If True, return None if function is not found, otherwise raise exception
218
+
219
+ Returns:
220
+ The imported function object or None if import fails
221
+ """
222
+ node_model = await _find_node_model(function_path, db)
223
+
224
+ if node_model is None:
225
+ try:
226
+ module_path, function_name = function_path.rsplit(".", 1)
227
+ module = importlib.import_module(module_path)
228
+ return cast(Callable[..., Any], getattr(module, function_name))
229
+ except (ImportError, AttributeError, ValueError):
230
+ raise LookupError(
231
+ f"task_id: {task_id} Function {function_path} not found in the NodeModel Table"
232
+ )
233
+
234
+ try:
235
+ return await _function_from_model(node_model, task_id)
236
+ except Exception as e:
237
+ if tolerate_missing_function:
238
+ return None
239
+ else:
240
+ raise e
241
+
242
+
243
+ async def import_function_by_name(
244
+ function_name: str, db: Database, task_id: ObjectId
245
+ ) -> Optional[Callable[..., Any]]:
246
+ node_model = await _find_node_model_by_name(function_name, db)
247
+
248
+ if node_model is None:
249
+ logger.error(f"Could not find function mapping for name: {function_name}")
250
+ raise ValueError(f"Could not find function mapping for name: {function_name}")
251
+
252
+ return await _function_from_model(node_model, task_id)
253
+
254
+
255
+ async def import_class(class_path: str, db: Database) -> Type[Model] | None:
256
+ """
257
+ Dynamically import a class from a module using its full path.
258
+ First tries to load the class from the database using ModelMapping
259
+
260
+ A pickled version of the class is used primarily
261
+ Args:
262
+
263
+ :param class_path: class_path: Dot notation path to the class (e.g. 'models.submodule.ClassName')
264
+ :param db: db: Database object
265
+ Returns:
266
+ The imported class object or None if import fails
267
+ """
268
+
269
+ try:
270
+ # Split the path into module path and class name
271
+ module_path, class_name = class_path.rsplit(".", 1)
272
+ model_mapping = await _find_model_mapping(class_path, db)
273
+
274
+ # If not found by name, try by mapping
275
+ if not model_mapping:
276
+ model_mapping = await db.find_one(
277
+ ModelMapping, ModelMapping.mapping == class_path
278
+ )
279
+ else: # when searching by name, the path may have changed
280
+ module_path, class_name = model_mapping.mapping.rsplit(".", 1)
281
+
282
+ if model_mapping is None:
283
+ try:
284
+ # Import the module
285
+ module = importlib.import_module(module_path)
286
+ # Get the class from the module
287
+ return cast(Type[Model], getattr(module, class_name))
288
+ except (ImportError, AttributeError):
289
+ logger.error(f"Error finding ModelMapping for {class_name}")
290
+ raise LookupError(f"Error finding ModelMapping for {class_name}")
291
+
292
+ # Import the module
293
+ module = importlib.import_module(module_path)
294
+
295
+ # Get the class from the module
296
+ return cast(Type[Model], getattr(module, class_name))
297
+ except (ImportError, AttributeError, ValueError) as e:
298
+ logger.error(f"Error importing class {class_path}: {e}")
299
+ raise e
300
+
301
+
302
+ async def import_class_by_name(class_name: str, db: Database) -> Type[Model]:
303
+ model_mapping = await _find_model_mapping_by_name(class_name, db)
304
+
305
+ if not model_mapping:
306
+ logger.error(f"Error finding ModelMapping for {class_name}")
307
+ raise LookupError(f"Error finding ModelMapping for {class_name}")
308
+
309
+ model_class = await import_class(model_mapping.mapping, db)
310
+ if model_class is None:
311
+ raise LookupError(f"Error importing mapped model class for {class_name}")
312
+ return model_class