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,117 @@
1
+ import logging
2
+ import re
3
+ from datetime import datetime
4
+ from typing import Optional, Dict, Any
5
+
6
+ from pymongo import MongoClient
7
+
8
+ # Regular expression patterns
9
+ task_pattern = re.compile(r"task_id: ([\w\-\.]+)")
10
+ resource_pattern = re.compile(r"resource_id: ([\w\-\.]+)")
11
+
12
+
13
+ def extract_task_id(message: str) -> Optional[str]:
14
+ """Extract task ID from log message."""
15
+ match = task_pattern.search(message)
16
+ return match.group(1) if match else None
17
+
18
+
19
+ def extract_resource_id(message: str) -> Optional[str]:
20
+ """Extract resource ID from log message."""
21
+ match = resource_pattern.search(message)
22
+ return match.group(1) if match else None
23
+
24
+
25
+ class DBLogHandler(logging.Handler):
26
+ """Logging handler that stores logs in MongoDB using pymongo."""
27
+
28
+ def __init__(
29
+ self,
30
+ connection_string: str,
31
+ db_name: str,
32
+ collection_name: str = "logs",
33
+ ):
34
+ super().__init__()
35
+
36
+ # Validate configuration
37
+ if not connection_string or not isinstance(connection_string, str):
38
+ raise ValueError(f"Invalid connection string {connection_string}")
39
+ if not db_name or not isinstance(db_name, str):
40
+ raise ValueError(f"Invalid database name {db_name}")
41
+ if not collection_name or not isinstance(collection_name, str):
42
+ raise ValueError(f"Invalid collection name {collection_name}")
43
+
44
+ # Store configuration
45
+ self.connection_string = connection_string
46
+ self.db_name = db_name
47
+ self.collection_name = collection_name
48
+
49
+ # Create MongoDB client
50
+ self.client = MongoClient(self.connection_string)
51
+ self.db = self.client[self.db_name]
52
+ self.collection = self.db[self.collection_name]
53
+
54
+ def emit(self, record: logging.LogRecord) -> None:
55
+ """Process a log record by converting it to a log entry and inserting it into MongoDB."""
56
+ try:
57
+ # Create log entry as a dictionary
58
+ log_entry = self.create_log_entry(record)
59
+
60
+ # Insert the log entry into the collection
61
+ self.collection.insert_one(log_entry)
62
+
63
+ except Exception as e:
64
+ # Use print instead of logging to avoid potential recursion
65
+ print(f"Error in emit: {e}")
66
+ self.handleError(record)
67
+
68
+ def create_log_entry(self, record: logging.LogRecord) -> Dict[str, Any]:
69
+ # Format message
70
+ message = self.format(record)
71
+
72
+ # Extract task and resource IDs
73
+ task_id = extract_task_id(message)
74
+ resource_id = extract_resource_id(message)
75
+
76
+ # Create log entry dictionary
77
+ log_entry_dict = {
78
+ "timestamp": datetime.fromtimestamp(record.created),
79
+ "level": record.levelname,
80
+ "logger_name": record.name,
81
+ "message": message,
82
+ "module": record.module,
83
+ "function": record.funcName,
84
+ "line": record.lineno,
85
+ "task_id": task_id,
86
+ "resource": resource_id,
87
+ "thread_name": record.threadName,
88
+ "process_name": record.processName,
89
+ }
90
+
91
+ # Add exception info if available
92
+ if record.exc_info:
93
+ log_entry_dict.update(
94
+ {
95
+ "exception_type": record.exc_info[0].__name__
96
+ if record.exc_info and record.exc_info[0]
97
+ else None,
98
+ "exception_message": str(record.exc_info[1])
99
+ if record.exc_info and record.exc_info[1]
100
+ else None,
101
+ "exception_traceback": record.exc_text,
102
+ }
103
+ )
104
+
105
+ return log_entry_dict
106
+
107
+ def close(self) -> None:
108
+ """Close the MongoDB client connection."""
109
+ try:
110
+ if hasattr(self, "client") and self.client:
111
+ self.client.close()
112
+ except Exception as e:
113
+ print(f"Error closing DB log handler client: {e}")
114
+
115
+ def __del__(self):
116
+ """Ensure connection is closed when handler is destroyed."""
117
+ self.close()
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ from odmantic import Model
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ def default_from_model(cls_method, model: Model, **kwargs) -> Model:
10
+ model_dict = model.model_dump(exclude={"id"})
11
+ return cls_method.from_dict(model_dict, **kwargs)
12
+
13
+
14
+ def default_from_dict(cls_method, data: dict, **kwargs) -> Any:
15
+ """
16
+ Create an instance of the model from a dictionary.
17
+ Handles nested models and enum values.
18
+ """
19
+ if not isinstance(data, dict):
20
+ return data # Return as is if it's not a dictionary
21
+
22
+ processed_data = {}
23
+ for field_name, field in cls_method.model_fields.items():
24
+ if field_name not in data:
25
+ continue
26
+
27
+ field_type = field.annotation
28
+ field_value = data[field_name]
29
+
30
+ # Handle enum values
31
+ if hasattr(field_type, "__members__"):
32
+ logger.debug("Handling enum field: %s", field_name)
33
+ if isinstance(field_value, field_type):
34
+ # If it's already an enum instance, use it directly
35
+ logger.debug("Field value is enum instance: %s", field_value)
36
+ processed_data[field_name] = field_value
37
+ else:
38
+ # Try to create enum from the value
39
+ try:
40
+ processed_data[field_name] = field_type(field_value)
41
+ logger.debug(
42
+ "Converted field value to enum: %s", processed_data[field_name]
43
+ )
44
+ except ValueError:
45
+ logger.debug(
46
+ "Invalid enum value for field %s: %s", field_name, field_value
47
+ )
48
+ raise ValueError(
49
+ f"Invalid enum value '{field_value}' for field {field_name}"
50
+ )
51
+ # Handle nested models
52
+ elif hasattr(field_type, "from_dict") and isinstance(field_value, dict):
53
+ processed_data[field_name] = field_type.from_dict(field_value)
54
+ else:
55
+ processed_data[field_name] = field_value
56
+
57
+ return cls_method.model_validate(processed_data)
@@ -0,0 +1,216 @@
1
+ import fnmatch
2
+ import os
3
+ from pathlib import Path
4
+ from typing import Iterator, List, Union, Optional
5
+
6
+
7
+ class DirectoryPath:
8
+ """
9
+ Represents a directory path with excluded subdirectory patterns and provides iteration capabilities.
10
+ """
11
+
12
+ def __init__(
13
+ self,
14
+ root_path: Union[str, Path],
15
+ excluded_patterns: Optional[List[str]] = None,
16
+ file_extensions: Optional[List[str]] = None,
17
+ ):
18
+ """
19
+ Initialize the DirectoryPath.
20
+
21
+ Args:
22
+ root_path: The root directory path to traverse
23
+ excluded_patterns: List of patterns to exclude (supports wildcards like *, ?, [])
24
+ file_extensions: List of file extensions to include (e.g., ['.py', '.txt'])
25
+ """
26
+ self.root_path = Path(root_path).resolve()
27
+ self.excluded_patterns = excluded_patterns or []
28
+ self.file_extensions = file_extensions or []
29
+
30
+ if not self.root_path.exists():
31
+ raise FileNotFoundError(f"Directory does not exist: {self.root_path}")
32
+ if not self.root_path.is_dir():
33
+ raise NotADirectoryError(f"Path is not a directory: {self.root_path}")
34
+
35
+ def _is_excluded(self, path: Path) -> bool:
36
+ """
37
+ Check if a path matches any of the excluded patterns.
38
+
39
+ Args:
40
+ path: Path to check
41
+
42
+ Returns:
43
+ True if the path should be excluded, False otherwise
44
+ """
45
+ path_str = str(path)
46
+ relative_path = str(path.relative_to(self.root_path))
47
+
48
+ for pattern in self.excluded_patterns:
49
+ # Check against full path
50
+ if fnmatch.fnmatch(path_str, pattern):
51
+ return True
52
+ # Check against relative path
53
+ if fnmatch.fnmatch(relative_path, pattern):
54
+ return True
55
+ # Check against directory name only
56
+ if fnmatch.fnmatch(path.name, pattern):
57
+ return True
58
+
59
+ return False
60
+
61
+ def _matches_extensions(self, file_path: Path) -> bool:
62
+ """
63
+ Check if a file matches the specified extensions.
64
+
65
+ Args:
66
+ file_path: File path to check
67
+
68
+ Returns:
69
+ True if the file matches the extensions or no extensions specified
70
+ """
71
+ if not self.file_extensions:
72
+ return True
73
+
74
+ return file_path.suffix.lower() in [ext.lower() for ext in self.file_extensions]
75
+
76
+ def iterate_files(self) -> Iterator[Path]:
77
+ """
78
+ Iterate over all files in the directory tree, respecting exclusion patterns.
79
+
80
+ Yields:
81
+ Path objects for each file found
82
+ """
83
+ for root, dirs, files in os.walk(self.root_path):
84
+ root_path = Path(root)
85
+
86
+ # Filter out excluded directories in-place to prevent walking into them
87
+ dirs[:] = [d for d in dirs if not self._is_excluded(root_path / d)]
88
+
89
+ # Yield files that match criteria
90
+ for file in files:
91
+ file_path = root_path / file
92
+ if not self._is_excluded(file_path) and self._matches_extensions(
93
+ file_path
94
+ ):
95
+ yield file_path
96
+
97
+ def iterate_directories(self) -> Iterator[Path]:
98
+ """
99
+ Iterate over all directories in the directory tree, respecting exclusion patterns.
100
+
101
+ Yields:
102
+ Path objects for each directory found
103
+ """
104
+ for root, dirs, _ in os.walk(self.root_path):
105
+ root_path = Path(root)
106
+
107
+ # Filter and yield directories
108
+ for dir_name in dirs:
109
+ dir_path = root_path / dir_name
110
+ if not self._is_excluded(dir_path):
111
+ yield dir_path
112
+
113
+ # Filter out excluded directories to prevent walking into them
114
+ dirs[:] = [d for d in dirs if not self._is_excluded(root_path / d)]
115
+
116
+ def __iter__(self) -> Iterator[Path]:
117
+ """
118
+ Default iterator returns files.
119
+ """
120
+ return self.iterate_files()
121
+
122
+ def get_files_list(self) -> List[Path]:
123
+ """
124
+ Get a list of all files matching the criteria.
125
+
126
+ Returns:
127
+ List of Path objects
128
+ """
129
+ return list(self.iterate_files())
130
+
131
+ def get_directories_list(self) -> List[Path]:
132
+ """
133
+ Get a list of all directories matching the criteria.
134
+
135
+ Returns:
136
+ List of Path objects
137
+ """
138
+ return list(self.iterate_directories())
139
+
140
+ def add_excluded_pattern(self, pattern: str) -> None:
141
+ """
142
+ Add an exclusion pattern.
143
+
144
+ Args:
145
+ pattern: Pattern to exclude
146
+ """
147
+ if pattern not in self.excluded_patterns:
148
+ self.excluded_patterns.append(pattern)
149
+
150
+ def remove_excluded_pattern(self, pattern: str) -> None:
151
+ """
152
+ Remove an exclusion pattern.
153
+
154
+ Args:
155
+ pattern: Pattern to remove
156
+ """
157
+ if pattern in self.excluded_patterns:
158
+ self.excluded_patterns.remove(pattern)
159
+
160
+ def __str__(self) -> str:
161
+ return (
162
+ f"DirectoryPath(root='{self.root_path}', excluded={self.excluded_patterns})"
163
+ )
164
+
165
+ def __repr__(self) -> str:
166
+ return (
167
+ f"DirectoryPath(root_path='{self.root_path}', "
168
+ f"excluded_patterns={self.excluded_patterns}, "
169
+ f"file_extensions={self.file_extensions})"
170
+ )
171
+
172
+
173
+ # Example usage and utility functions
174
+ def find_python_files_with_exclusions(
175
+ root_path: str, excluded_patterns: List[str] = None
176
+ ) -> List[Path]:
177
+ """
178
+ Find Python files using the DirectoryPath class with exclusions.
179
+
180
+ Args:
181
+ root_path: Root directory to search
182
+ excluded_patterns: Patterns to exclude
183
+
184
+ Returns:
185
+ List of Python file paths
186
+ """
187
+ excluded_patterns = excluded_patterns or [
188
+ "__pycache__",
189
+ "*.pyc",
190
+ ".git",
191
+ ".venv",
192
+ "venv",
193
+ ]
194
+ dir_path = DirectoryPath(root_path, excluded_patterns, [".py"])
195
+ return dir_path.get_files_list()
196
+
197
+
198
+ if __name__ == "__main__":
199
+ # Example usage
200
+ try:
201
+ # Create a DirectoryPath instance
202
+ dp = DirectoryPath(
203
+ root_path=".",
204
+ excluded_patterns=["__pycache__", "*.pyc", ".git", "node_modules", "*.log"],
205
+ file_extensions=[".py", ".txt"],
206
+ )
207
+
208
+ print(f"Directory Path: {dp}")
209
+ print("\nFound files:")
210
+ for file_path in dp:
211
+ print(f" {file_path}")
212
+
213
+ print(f"\nTotal files found: {len(dp.get_files_list())}")
214
+
215
+ except (FileNotFoundError, NotADirectoryError) as e:
216
+ print(f"Error: {e}")
@@ -0,0 +1,186 @@
1
+ import inspect
2
+ import re
3
+ from typing import Optional, Dict, Any, List
4
+
5
+
6
+ class DocstringParser:
7
+ """
8
+ Parse a docstring into structured components.
9
+
10
+ All component getters return None when the corresponding section is not present.
11
+ Supported sections:
12
+ - Args: / Parameters:
13
+ - Returns:
14
+ - SimstackResult:
15
+ - CalledNodes:
16
+ - Raises:
17
+ """
18
+
19
+ _SECTION_NAMES = ("Args:", "Parameters:", "Returns:", "SimstackResult:", "CalledNodes:", "Raises:")
20
+
21
+ def __init__(self, docstring: Optional[str]) -> None:
22
+ self._raw = docstring or ""
23
+ self._doc = inspect.cleandoc(self._raw) if self._raw else ""
24
+ self._cache: Dict[str, Any] = {}
25
+
26
+ def _section(self, name: str, until: tuple[str, ...]) -> Optional[str]:
27
+ """
28
+ Extract the body text after `name` up to any of the `until` markers (or end).
29
+ Returns None if the section marker isn't present.
30
+ """
31
+ if not self._doc:
32
+ return None
33
+
34
+ # e.g. r"Returns:(.*?)(?:SimstackResult:|CalledNodes:|Raises:|$)"
35
+ until_alt = "|".join(map(re.escape, until)) + "|$"
36
+ pattern = rf"{re.escape(name)}(.*?)(?:{until_alt})"
37
+ match = re.search(pattern, self._doc, re.DOTALL)
38
+ if not match:
39
+ return None
40
+
41
+ body = match.group(1).strip()
42
+ return body if body else None
43
+
44
+ def description(self) -> Optional[str]:
45
+ if "description" in self._cache:
46
+ return self._cache["description"]
47
+
48
+ if not self._doc:
49
+ self._cache["description"] = None
50
+ return None
51
+
52
+ match = re.search(
53
+ r"^(.*?)(?:Args:|Parameters:|Returns:|SimstackResult:|CalledNodes:|Raises:|$)",
54
+ self._doc,
55
+ re.DOTALL,
56
+ )
57
+ desc = match.group(1).strip() if match else ""
58
+ self._cache["description"] = desc if desc else None
59
+ return self._cache["description"]
60
+
61
+ def params(self) -> Optional[Dict[str, Dict[str, Optional[str]]]]:
62
+ if "params" in self._cache:
63
+ return self._cache["params"]
64
+
65
+ param_text = self._section("Args:", ("Returns:", "SimstackResult:", "CalledNodes:", "Raises:"))
66
+ if param_text is None:
67
+ param_text = self._section("Parameters:", ("Returns:", "SimstackResult:", "CalledNodes:", "Raises:"))
68
+
69
+ if not param_text:
70
+ self._cache["params"] = None
71
+ return None
72
+
73
+ params: Dict[str, Dict[str, Optional[str]]] = {}
74
+ param_matches = re.finditer(
75
+ r"(\w+)\s*(?:\(([^)]+)\))?\s*:\s*(.+?)(?=\n\s*\w+\s*:|$)",
76
+ param_text,
77
+ re.DOTALL,
78
+ )
79
+ for match in param_matches:
80
+ param_name = match.group(1)
81
+ param_type = match.group(2) # Maybe None
82
+ param_desc = match.group(3).strip()
83
+ params[param_name] = {"type": param_type, "description": param_desc}
84
+
85
+ self._cache["params"] = params if params else None
86
+ return self._cache["params"]
87
+
88
+ def returns(self) -> Optional[Dict[str, str]]:
89
+ if "returns" in self._cache:
90
+ return self._cache["returns"]
91
+
92
+ return_text = self._section("Returns:", ("SimstackResult:", "CalledNodes:", "Raises:"))
93
+ if not return_text:
94
+ self._cache["returns"] = None
95
+ return None
96
+
97
+ self._cache["returns"] = {"description": return_text}
98
+ return self._cache["returns"]
99
+
100
+ def simstack_results(self) -> Optional[Dict[str, Dict[str, str]]]:
101
+ if "simstack_results" in self._cache:
102
+ return self._cache["simstack_results"]
103
+
104
+ simstack_text = self._section("SimstackResult:", ("CalledNodes:", "Raises:"))
105
+ if not simstack_text:
106
+ self._cache["simstack_results"] = None
107
+ return None
108
+
109
+ simstack_results: Dict[str, Dict[str, str]] = {}
110
+ simstack_matches = re.finditer(
111
+ r"(\w+)\s*\(([^)]+)\)\s*(.+?)(?=\n\s*\w+\s*\(|$)",
112
+ simstack_text,
113
+ re.DOTALL,
114
+ )
115
+ for match in simstack_matches:
116
+ result_name = match.group(1)
117
+ result_type = match.group(2).strip()
118
+ result_desc = match.group(3).strip()
119
+ simstack_results[result_name] = {"name": result_name, "type": result_type, "description": result_desc}
120
+
121
+ self._cache["simstack_results"] = simstack_results if simstack_results else None
122
+ return self._cache["simstack_results"]
123
+
124
+ def called_nodes(self) -> Optional[List[str]]:
125
+ if "called_nodes" in self._cache:
126
+ return self._cache["called_nodes"]
127
+
128
+ called_nodes_text = self._section("Called Nodes:", ("Raises:","Notes"))
129
+ if not called_nodes_text:
130
+ self._cache["called_nodes"] = None
131
+ return None
132
+
133
+ nodes = [
134
+ line.strip().lstrip("-").strip()
135
+ for line in called_nodes_text.split("\n")
136
+ if line.strip()
137
+ ]
138
+ self._cache["called_nodes"] = nodes if nodes else None
139
+ return self._cache["called_nodes"]
140
+
141
+ def raises(self) -> Optional[Dict[str, Dict[str, str]]]:
142
+ if "raises" in self._cache:
143
+ return self._cache["raises"]
144
+
145
+ raises_text = self._section("Raises:", ())
146
+ if not raises_text:
147
+ self._cache["raises"] = None
148
+ return None
149
+
150
+ raises: Dict[str, Dict[str, str]] = {}
151
+ raises_matches = re.finditer(
152
+ r"(\w+)\s*:\s*(.+?)(?=\n\s*\w+\s*:|$)",
153
+ raises_text,
154
+ re.DOTALL,
155
+ )
156
+ for match in raises_matches:
157
+ exception_name = match.group(1)
158
+ exception_desc = match.group(2).strip()
159
+ raises[exception_name] = {"description": exception_desc}
160
+
161
+ self._cache["raises"] = raises if raises else None
162
+ return self._cache["raises"]
163
+
164
+ def as_dict(self) -> Dict[str, Any]:
165
+ """
166
+ Backward-compatible structure (always includes keys),
167
+ while still using the None-returning component getters internally.
168
+ """
169
+ return {
170
+ "description": self.description() or "",
171
+ "params": self.params() or {},
172
+ "returns": self.returns() or {},
173
+ "simstack_results": self.simstack_results() or {},
174
+ "called_nodes": self.called_nodes() or [],
175
+ "raises": self.raises() or {},
176
+ }
177
+
178
+
179
+ def parse_docstring(docstring: Optional[str]) -> Dict[str, Any]:
180
+ """
181
+ Backward-compatible wrapper around DocstringParser.
182
+
183
+ Prefer using DocstringParser directly when you want per-section access with
184
+ None when a section is missing.
185
+ """
186
+ return DocstringParser(docstring).as_dict()
@@ -0,0 +1,72 @@
1
+ import hashlib
2
+ from pathlib import Path
3
+ from typing import Union, BinaryIO
4
+
5
+ def hash_file(
6
+ file_path: Union[str, Path], algorithm: str = "sha256", chunk_size: int = 8192
7
+ ) -> str:
8
+ """
9
+ Calculate hash of a file on disk.
10
+
11
+ Args:
12
+ file_path: Path to the file
13
+ algorithm: Hash algorithm (md5, sha1, sha256, etc.)
14
+ chunk_size: Size of chunks to read
15
+
16
+ Returns:
17
+ str: Hexadecimal digest of the hash
18
+ """
19
+ hash_obj = hashlib.new(algorithm)
20
+
21
+ with open(file_path, "rb") as f:
22
+ for chunk in iter(lambda: f.read(chunk_size), b""):
23
+ hash_obj.update(chunk)
24
+
25
+ return hash_obj.hexdigest()
26
+
27
+ def hash_string(string: str, algorithm: str = "sha256") -> str:
28
+ hash_obj = hashlib.new(algorithm)
29
+ hash_obj.update(string.encode())
30
+ return hash_obj.hexdigest()
31
+
32
+ def hash_file_object(
33
+ file_obj: BinaryIO, algorithm: str = "sha256", chunk_size: int = 8192
34
+ ) -> str:
35
+ """
36
+ Calculate hash of a file-like object.
37
+
38
+ Args:
39
+ file_obj: File-like object (must be in binary mode)
40
+ algorithm: Hash algorithm (md5, sha1, sha256, etc.)
41
+ chunk_size: Size of chunks to read
42
+
43
+ Returns:
44
+ str: Hexadecimal digest of the hash
45
+ """
46
+ hash_obj = hashlib.new(algorithm)
47
+
48
+ # Store current position
49
+ try:
50
+ original_position = file_obj.tell()
51
+ except (OSError, IOError, AttributeError):
52
+ original_position = None
53
+
54
+ # Seek to the beginning if possible
55
+ try:
56
+ file_obj.seek(0)
57
+ except (OSError, IOError, AttributeError):
58
+ pass
59
+
60
+ # Calculate hash
61
+ for chunk in iter(lambda: file_obj.read(chunk_size), b""):
62
+ hash_obj.update(chunk)
63
+
64
+ # Restore original position if possible
65
+ if original_position is not None:
66
+ try:
67
+ file_obj.seek(original_position)
68
+ except (OSError, IOError, AttributeError):
69
+ pass
70
+
71
+ return hash_obj.hexdigest()
72
+