pyegeria 5.4.0.28__py3-none-any.whl → 5.5.3.3__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.

Potentially problematic release.


This version of pyegeria might be problematic. Click here for more details.

Files changed (433) hide show
  1. commands/__init__.py +24 -0
  2. commands/cat/Dr-Egeria_md-orig.py +2 -2
  3. commands/cat/collection_actions.py +197 -0
  4. commands/cat/dr_egeria_command_help.py +137 -38
  5. commands/cat/dr_egeria_jupyter.py +7 -7
  6. commands/cat/dr_egeria_md.py +10 -267
  7. commands/cat/exp_list_glossaries.py +11 -14
  8. commands/cat/get_asset_graph.py +37 -267
  9. commands/cat/{get_collection.py → get_collection_tree.py} +10 -18
  10. commands/cat/get_project_dependencies.py +14 -14
  11. commands/cat/get_project_structure.py +15 -14
  12. commands/cat/get_tech_type_elements.py +16 -116
  13. commands/cat/glossary_actions.py +145 -298
  14. commands/cat/list_assets.py +3 -11
  15. commands/cat/list_cert_types.py +17 -63
  16. commands/cat/list_collections.py +17 -139
  17. commands/cat/list_deployed_catalogs.py +15 -27
  18. commands/cat/list_deployed_database_schemas.py +27 -43
  19. commands/cat/list_deployed_databases.py +16 -31
  20. commands/cat/list_deployed_servers.py +35 -54
  21. commands/cat/list_glossaries.py +18 -17
  22. commands/cat/list_projects.py +10 -12
  23. commands/cat/list_tech_type_elements.py +21 -37
  24. commands/cat/list_tech_types.py +13 -25
  25. commands/cat/list_terms.py +38 -79
  26. commands/cat/list_todos.py +4 -11
  27. commands/cat/list_user_ids.py +3 -10
  28. commands/cat/my_reports.py +559 -0
  29. commands/cat/run_report.py +394 -0
  30. commands/cat/{list_format_set.py → run_report_orig.py} +136 -44
  31. commands/cli/egeria.py +182 -219
  32. commands/cli/egeria_cat.py +32 -59
  33. commands/cli/egeria_my.py +13 -0
  34. commands/cli/egeria_ops.py +69 -74
  35. commands/cli/egeria_tech.py +17 -93
  36. commands/{cat → deprecated}/list_data_designer.py +2 -4
  37. commands/{cat → deprecated}/list_data_structures_full.py +3 -6
  38. commands/deprecated/old_get_asset_graph.py +315 -0
  39. commands/my/__init__.py +0 -2
  40. commands/my/list_my_profile.py +27 -34
  41. commands/my/list_my_roles.py +1 -7
  42. commands/my/monitor_my_todos.py +1 -7
  43. commands/my/monitor_open_todos.py +6 -7
  44. commands/my/todo_actions.py +4 -5
  45. commands/ops/__init__.py +0 -2
  46. commands/ops/gov_server_actions.py +17 -21
  47. commands/ops/list_archives.py +17 -38
  48. commands/ops/list_catalog_targets.py +33 -40
  49. commands/ops/load_archive.py +14 -11
  50. commands/ops/{monitor_engine_activity_c.py → monitor_active_engine_activity.py} +51 -82
  51. commands/ops/{monitor_integ_daemon_status.py → monitor_daemon_status.py} +35 -55
  52. commands/ops/monitor_engine_activity.py +79 -77
  53. commands/ops/{monitor_gov_eng_status.py → monitor_engine_status.py} +10 -7
  54. commands/ops/monitor_platform_status.py +38 -50
  55. commands/ops/monitor_server_startup.py +6 -11
  56. commands/ops/monitor_server_status.py +7 -11
  57. commands/ops/orig_monitor_server_list.py +8 -8
  58. commands/ops/orig_monitor_server_status.py +1 -5
  59. commands/ops/refresh_integration_daemon.py +5 -5
  60. commands/ops/restart_integration_daemon.py +5 -5
  61. commands/ops/table_integ_daemon_status.py +6 -6
  62. commands/ops/x_engine_actions.py +7 -7
  63. commands/tech/__init__.py +0 -2
  64. commands/tech/{generic_actions.py → element_actions.py} +6 -11
  65. commands/tech/get_element_info.py +20 -29
  66. commands/tech/get_guid_info.py +23 -42
  67. commands/tech/get_tech_details.py +20 -35
  68. commands/tech/get_tech_type_template.py +28 -39
  69. commands/tech/list_all_om_type_elements.py +24 -30
  70. commands/tech/list_all_om_type_elements_x.py +22 -28
  71. commands/tech/list_all_related_elements.py +19 -28
  72. commands/tech/list_anchored_elements.py +22 -30
  73. commands/tech/list_asset_types.py +19 -24
  74. commands/tech/list_elements_by_classification_by_property_value.py +26 -32
  75. commands/tech/list_elements_by_property_value.py +19 -25
  76. commands/tech/list_elements_by_property_value_x.py +20 -28
  77. commands/tech/list_elements_for_classification.py +28 -41
  78. commands/tech/list_gov_action_processes.py +16 -27
  79. commands/tech/list_information_supply_chains.py +22 -30
  80. commands/tech/list_registered_services.py +14 -26
  81. commands/tech/list_related_elements_with_prop_value.py +15 -25
  82. commands/tech/list_related_specification.py +1 -4
  83. commands/tech/list_relationship_types.py +15 -25
  84. commands/tech/list_relationships.py +20 -36
  85. commands/tech/list_solution_blueprints.py +28 -33
  86. commands/tech/list_solution_components.py +23 -29
  87. commands/tech/list_solution_roles.py +21 -32
  88. commands/tech/list_tech_templates.py +51 -54
  89. commands/tech/list_valid_metadata_values.py +5 -9
  90. commands/tech/table_tech_templates.py +2 -6
  91. commands/tech/x_list_related_elements.py +1 -4
  92. examples/GeoSpatial Products Example.py +524 -0
  93. examples/Jupyter Notebooks/P-egeria-server-config.ipynb +2137 -0
  94. examples/Jupyter Notebooks/README.md +2 -0
  95. examples/Jupyter Notebooks/common/P-environment-check.ipynb +115 -0
  96. examples/Jupyter Notebooks/common/__init__.py +14 -0
  97. examples/Jupyter Notebooks/common/common-functions.ipynb +4694 -0
  98. examples/Jupyter Notebooks/common/environment-check.ipynb +52 -0
  99. examples/Jupyter Notebooks/common/globals.ipynb +184 -0
  100. examples/Jupyter Notebooks/common/globals.py +154 -0
  101. examples/Jupyter Notebooks/common/orig_globals.py +152 -0
  102. examples/format_sets/all_format_sets.json +910 -0
  103. examples/format_sets/custom_format_sets.json +268 -0
  104. examples/format_sets/subset_format_sets.json +187 -0
  105. examples/format_sets_save_load_example.py +291 -0
  106. examples/jacquard_data_sets.py +129 -0
  107. examples/output_formats_example.py +193 -0
  108. examples/test_jacquard_data_sets.py +54 -0
  109. examples/test_jacquard_data_sets_scenarios.py +94 -0
  110. md_processing/__init__.py +33 -24
  111. md_processing/command_dispatcher.py +33 -0
  112. md_processing/command_mapping.py +221 -0
  113. md_processing/data/commands/commands_data_designer.json +537 -0
  114. md_processing/data/commands/commands_external_reference.json +733 -0
  115. md_processing/data/commands/commands_feedback.json +155 -0
  116. md_processing/data/commands/commands_general.json +204 -0
  117. md_processing/data/commands/commands_glossary.json +218 -0
  118. md_processing/data/commands/commands_governance.json +3678 -0
  119. md_processing/data/commands/commands_product_manager.json +865 -0
  120. md_processing/data/commands/commands_project.json +642 -0
  121. md_processing/data/commands/commands_solution_architect.json +366 -0
  122. md_processing/data/commands.json +6489 -30060
  123. md_processing/data/{commands-working.json → commands_working.json} +9304 -13513
  124. md_processing/data/gened_report_specs.py +6584 -0
  125. md_processing/data/generated_format_sets.json +6533 -0
  126. md_processing/data/generated_format_sets_old.json +4137 -0
  127. md_processing/data/generated_format_sets_old.py +45 -0
  128. md_processing/dr_egeria.py +182 -0
  129. md_processing/md_commands/data_designer_commands.py +195 -583
  130. md_processing/md_commands/ext_ref_commands.py +530 -0
  131. md_processing/md_commands/feedback_commands.py +726 -0
  132. md_processing/md_commands/glossary_commands.py +106 -490
  133. md_processing/md_commands/governance_officer_commands.py +129 -18
  134. md_processing/md_commands/product_manager_commands.py +362 -115
  135. md_processing/md_commands/project_commands.py +351 -134
  136. md_processing/md_commands/solution_architect_commands.py +276 -232
  137. md_processing/md_commands/view_commands.py +295 -0
  138. md_processing/md_processing_utils/common_md_proc_utils.py +258 -166
  139. md_processing/md_processing_utils/common_md_utils.py +138 -43
  140. md_processing/md_processing_utils/determine_width.py +103 -0
  141. md_processing/md_processing_utils/extraction_utils.py +100 -39
  142. md_processing/md_processing_utils/gen_report_specs.py +643 -0
  143. md_processing/md_processing_utils/generate_dr_help.py +61 -33
  144. md_processing/md_processing_utils/generate_md_cmd_templates.py +20 -19
  145. md_processing/md_processing_utils/generate_md_templates.py +3 -12
  146. md_processing/md_processing_utils/md_processing_constants.py +1053 -72
  147. pyegeria/__init__.py +203 -158
  148. pyegeria/core/__init__.py +40 -0
  149. pyegeria/core/_base_platform_client.py +574 -0
  150. pyegeria/core/_base_server_client.py +573 -0
  151. pyegeria/{_exceptions_new.py → core/_exceptions.py} +62 -30
  152. pyegeria/{_globals.py → core/_globals.py} +14 -3
  153. pyegeria/core/_server_client.py +6073 -0
  154. pyegeria/{_validators.py → core/_validators.py} +7 -8
  155. pyegeria/core/config.py +654 -0
  156. pyegeria/{create_tech_guid_lists.py → core/create_tech_guid_lists.py} +0 -1
  157. pyegeria/core/load_config.py +37 -0
  158. pyegeria/{logging_configuration.py → core/logging_configuration.py} +1 -1
  159. pyegeria/core/mcp_adapter.py +144 -0
  160. pyegeria/core/mcp_server.py +212 -0
  161. pyegeria/core/utils.py +405 -0
  162. pyegeria/{_client.py → deprecated/_client.py} +24 -25
  163. pyegeria/{_deprecated_gov_engine.py → deprecated/_deprecated_gov_engine.py} +16 -16
  164. pyegeria/{classification_manager_omvs.py → deprecated/classification_manager_omvs.py} +1987 -1877
  165. pyegeria/{output_formatter.py → deprecated/output_formatter_with_machine_keys.py} +298 -45
  166. pyegeria/{runtime_manager_omvs.py → deprecated/runtime_manager_omvs.py} +155 -171
  167. pyegeria/{valid_metadata_omvs.py → deprecated/valid_metadata_omvs.py} +93 -93
  168. pyegeria/{x_action_author_omvs.py → deprecated/x_action_author_omvs.py} +2 -3
  169. pyegeria/egeria_cat_client.py +26 -70
  170. pyegeria/egeria_client.py +130 -93
  171. pyegeria/egeria_config_client.py +40 -46
  172. pyegeria/egeria_tech_client.py +141 -54
  173. pyegeria/models/__init__.py +150 -0
  174. pyegeria/{models.py → models/models.py} +156 -20
  175. pyegeria/omvs/__init__.py +84 -0
  176. pyegeria/omvs/action_author.py +342 -0
  177. pyegeria/omvs/actor_manager.py +5980 -0
  178. pyegeria/omvs/asset_catalog.py +842 -0
  179. pyegeria/omvs/asset_maker.py +2736 -0
  180. pyegeria/omvs/automated_curation.py +4403 -0
  181. pyegeria/omvs/classification_manager.py +11213 -0
  182. pyegeria/{collection_manager.py → omvs/collection_manager.py} +1334 -1160
  183. pyegeria/omvs/community_matters_omvs.py +468 -0
  184. pyegeria/{core_omag_server_config.py → omvs/core_omag_server_config.py} +157 -157
  185. pyegeria/{data_designer.py → omvs/data_designer.py} +1115 -660
  186. pyegeria/omvs/data_discovery.py +869 -0
  187. pyegeria/omvs/data_engineer.py +372 -0
  188. pyegeria/omvs/digital_business.py +1133 -0
  189. pyegeria/omvs/external_links.py +1752 -0
  190. pyegeria/omvs/feedback_manager.py +834 -0
  191. pyegeria/{full_omag_server_config.py → omvs/full_omag_server_config.py} +73 -69
  192. pyegeria/{glossary_manager.py → omvs/glossary_manager.py} +857 -519
  193. pyegeria/{governance_officer.py → omvs/governance_officer.py} +964 -468
  194. pyegeria/omvs/lineage_linker.py +314 -0
  195. pyegeria/omvs/location_arena.py +1525 -0
  196. pyegeria/omvs/metadata_expert.py +668 -0
  197. pyegeria/omvs/metadata_explorer_omvs.py +2943 -0
  198. pyegeria/omvs/my_profile.py +1042 -0
  199. pyegeria/omvs/notification_manager.py +358 -0
  200. pyegeria/omvs/people_organizer.py +394 -0
  201. pyegeria/{platform_services.py → omvs/platform_services.py} +113 -193
  202. pyegeria/omvs/product_manager.py +1825 -0
  203. pyegeria/omvs/project_manager.py +1907 -0
  204. pyegeria/omvs/reference_data.py +1140 -0
  205. pyegeria/omvs/registered_info.py +334 -0
  206. pyegeria/omvs/runtime_manager.py +2817 -0
  207. pyegeria/omvs/schema_maker.py +446 -0
  208. pyegeria/{server_operations.py → omvs/server_operations.py} +27 -26
  209. pyegeria/{solution_architect_omvs.py → omvs/solution_architect.py} +1886 -1505
  210. pyegeria/omvs/specification_properties.py +37 -0
  211. pyegeria/omvs/subject_area.py +1042 -0
  212. pyegeria/omvs/template_manager_omvs.py +236 -0
  213. pyegeria/omvs/time_keeper.py +1761 -0
  214. pyegeria/omvs/valid_metadata.py +3221 -0
  215. pyegeria/omvs/valid_metadata_lists.py +37 -0
  216. pyegeria/omvs/valid_type_lists.py +37 -0
  217. pyegeria/view/__init__.py +28 -0
  218. pyegeria/{_output_format_models.py → view/_output_format_models.py} +160 -24
  219. pyegeria/view/_output_formats.py +14 -0
  220. pyegeria/view/base_report_formats.py +2719 -0
  221. pyegeria/view/dr_egeria_reports.py +56 -0
  222. pyegeria/view/format_set_executor.py +397 -0
  223. pyegeria/{md_processing_utils.py → view/md_processing_utils.py} +5 -5
  224. pyegeria/{mermaid_utilities.py → view/mermaid_utilities.py} +2 -154
  225. pyegeria/view/output_formatter.py +1297 -0
  226. pyegeria-5.5.3.3.dist-info/METADATA +218 -0
  227. pyegeria-5.5.3.3.dist-info/RECORD +241 -0
  228. {pyegeria-5.4.0.28.dist-info → pyegeria-5.5.3.3.dist-info}/WHEEL +2 -1
  229. pyegeria-5.5.3.3.dist-info/entry_points.txt +103 -0
  230. pyegeria-5.5.3.3.dist-info/top_level.txt +4 -0
  231. commands/cat/.DS_Store +0 -0
  232. commands/cat/.env +0 -8
  233. commands/cat/README.md +0 -16
  234. commands/cat/debug_log +0 -1126
  235. commands/cat/debug_log.2025-08-18_11-34-38_088636.zip +0 -0
  236. commands/cat/list_categories.py +0 -192
  237. commands/cat/logs/pyegeria.log +0 -4
  238. commands/cli/debug_log +0 -0
  239. commands/cli/debug_log.log +0 -0
  240. commands/cli/txt_custom_v2.tcss +0 -19
  241. commands/my/README.md +0 -17
  242. commands/ops/README.md +0 -24
  243. commands/ops/logs/pyegeria.log +0 -0
  244. commands/ops/monitor_asset_events.py +0 -108
  245. commands/tech/README.md +0 -24
  246. md_processing/.DS_Store +0 -0
  247. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-30-37.md +0 -163
  248. md_processing/dr-egeria-outbox/Collections-2025-08-12-13-35-58.md +0 -474
  249. md_processing/dr_egeria_inbox/Derive-Dr-Gov-Defs.md +0 -8
  250. md_processing/dr_egeria_inbox/Dr.Egeria Templates.md +0 -873
  251. md_processing/dr_egeria_inbox/arch_test.md +0 -57
  252. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  253. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  254. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  255. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  256. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  257. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  258. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  259. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  260. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  261. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  262. md_processing/dr_egeria_inbox/collections.md +0 -39
  263. md_processing/dr_egeria_inbox/data_designer_debug.log +0 -6
  264. md_processing/dr_egeria_inbox/data_designer_out.md +0 -60
  265. md_processing/dr_egeria_inbox/data_designer_search_test.md +0 -11
  266. md_processing/dr_egeria_inbox/data_field.md +0 -54
  267. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  268. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2406
  269. md_processing/dr_egeria_inbox/data_test.md +0 -179
  270. md_processing/dr_egeria_inbox/data_test2.md +0 -429
  271. md_processing/dr_egeria_inbox/data_test3.md +0 -462
  272. md_processing/dr_egeria_inbox/dr_egeria_data_designer_1.md +0 -124
  273. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  274. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  275. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -318
  276. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  277. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  278. md_processing/dr_egeria_inbox/generated_help_report.md +0 -9
  279. md_processing/dr_egeria_inbox/glossary_creation_experiment.ipynb +0 -341
  280. md_processing/dr_egeria_inbox/glossary_list.md +0 -5
  281. md_processing/dr_egeria_inbox/glossary_search_test.md +0 -40
  282. md_processing/dr_egeria_inbox/glossary_test1.md +0 -324
  283. md_processing/dr_egeria_inbox/gov_def.md +0 -482
  284. md_processing/dr_egeria_inbox/gov_def2.md +0 -447
  285. md_processing/dr_egeria_inbox/img.png +0 -0
  286. md_processing/dr_egeria_inbox/product.md +0 -211
  287. md_processing/dr_egeria_inbox/rel.md +0 -8
  288. md_processing/dr_egeria_inbox/sb.md +0 -119
  289. md_processing/dr_egeria_inbox/solution-components.md +0 -136
  290. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  291. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  292. md_processing/dr_egeria_inbox/t2.md +0 -268
  293. md_processing/dr_egeria_outbox/.obsidian/app.json +0 -1
  294. md_processing/dr_egeria_outbox/.obsidian/appearance.json +0 -1
  295. md_processing/dr_egeria_outbox/.obsidian/community-plugins.json +0 -6
  296. md_processing/dr_egeria_outbox/.obsidian/core-plugins.json +0 -31
  297. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/data.json +0 -10
  298. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/main.js +0 -4459
  299. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/manifest.json +0 -10
  300. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/data.json +0 -3
  301. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/main.js +0 -153
  302. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/manifest.json +0 -11
  303. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/styles.css +0 -1
  304. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/main.js +0 -500
  305. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +0 -12
  306. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/styles.css +0 -1
  307. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/main.js +0 -37
  308. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/manifest.json +0 -11
  309. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/styles.css +0 -220
  310. md_processing/dr_egeria_outbox/.obsidian/types.json +0 -28
  311. md_processing/dr_egeria_outbox/.obsidian/workspace.json +0 -220
  312. md_processing/dr_egeria_outbox/Untitled.canvas +0 -1
  313. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:22-dr_egeria_intro_part1.md +0 -312
  314. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:23-dr_egeria_intro_part1.md +0 -265
  315. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:06-dr_egeria_intro_part1.md +0 -230
  316. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:30-dr_egeria_intro_part1.md +0 -296
  317. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:31-dr_egeria_intro_part1.md +0 -253
  318. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:08-dr_egeria_intro_part2.md +0 -343
  319. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:12-dr_egeria_intro_part2.md +0 -343
  320. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:05-product.md +0 -426
  321. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:56-product.md +0 -212
  322. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 09:43-product.md +0 -201
  323. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 14:55-product.md +0 -77
  324. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:05-product.md +0 -75
  325. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 15:11-product.md +0 -74
  326. md_processing/dr_egeria_outbox/sunday/processed-2025-07-20 20:40-collections.md +0 -49
  327. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +0 -719
  328. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +0 -41
  329. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +0 -33
  330. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +0 -192
  331. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:08-gov_def2.md +0 -486
  332. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:10-gov_def2.md +0 -486
  333. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:53-gov_def2.md +0 -486
  334. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:54-gov_def2.md +0 -486
  335. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:03-gov_def2.md +0 -486
  336. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:06-gov_def2.md +0 -486
  337. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:10-gov_def2.md +0 -486
  338. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-16 19:15-gov_def2.md +0 -527
  339. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 12:08-gov_def2.md +0 -527
  340. md_processing/dr_egeria_outbox/tuesday/processed-2025-07-17 14:27-gov_def2.md +0 -485
  341. md_processing/dr_egeria_outbox/tuesday/processed-2025-08-19 10:55-product.md +0 -209
  342. md_processing/family_docs/Data Designer/Create_Data_Class.md +0 -164
  343. md_processing/family_docs/Data Designer/Create_Data_Dictionary.md +0 -30
  344. md_processing/family_docs/Data Designer/Create_Data_Field.md +0 -162
  345. md_processing/family_docs/Data Designer/Create_Data_Specification.md +0 -36
  346. md_processing/family_docs/Data Designer/Create_Data_Structure.md +0 -38
  347. md_processing/family_docs/Data Designer/View_Data_Classes.md +0 -78
  348. md_processing/family_docs/Data Designer/View_Data_Dictionaries.md +0 -78
  349. md_processing/family_docs/Data Designer/View_Data_Fields.md +0 -78
  350. md_processing/family_docs/Data Designer/View_Data_Specifications.md +0 -78
  351. md_processing/family_docs/Data Designer/View_Data_Structures.md +0 -78
  352. md_processing/family_docs/Data Designer.md +0 -842
  353. md_processing/family_docs/Digital Product Manager/Add_Member->Collection.md +0 -42
  354. md_processing/family_docs/Digital Product Manager/Attach_Collection->Resource.md +0 -36
  355. md_processing/family_docs/Digital Product Manager/Create_Agreement.md +0 -96
  356. md_processing/family_docs/Digital Product Manager/Create_Data_Sharing_Agreement.md +0 -72
  357. md_processing/family_docs/Digital Product Manager/Create_DigitalSubscription.md +0 -102
  358. md_processing/family_docs/Digital Product Manager/Create_Digital_Product.md +0 -134
  359. md_processing/family_docs/Digital Product Manager/Link_Agreement_Items.md +0 -60
  360. md_processing/family_docs/Digital Product Manager/Link_Contracts.md +0 -26
  361. md_processing/family_docs/Digital Product Manager/Link_Digital_Product_-_Digital_Product.md +0 -30
  362. md_processing/family_docs/Digital Product Manager/Link_Subscribers.md +0 -48
  363. md_processing/family_docs/Digital Product Manager.md +0 -668
  364. md_processing/family_docs/Glossary/Attach_Category_Parent.md +0 -18
  365. md_processing/family_docs/Glossary/Attach_Term-Term_Relationship.md +0 -26
  366. md_processing/family_docs/Glossary/Create_Category.md +0 -38
  367. md_processing/family_docs/Glossary/Create_Glossary.md +0 -42
  368. md_processing/family_docs/Glossary/Create_Term.md +0 -70
  369. md_processing/family_docs/Glossary.md +0 -206
  370. md_processing/family_docs/Governance Officer/Create_Business_Imperative.md +0 -106
  371. md_processing/family_docs/Governance Officer/Create_Certification_Type.md +0 -112
  372. md_processing/family_docs/Governance Officer/Create_Governance_Approach.md +0 -114
  373. md_processing/family_docs/Governance Officer/Create_Governance_Obligation.md +0 -114
  374. md_processing/family_docs/Governance Officer/Create_Governance_Principle.md +0 -114
  375. md_processing/family_docs/Governance Officer/Create_Governance_Procedure.md +0 -128
  376. md_processing/family_docs/Governance Officer/Create_Governance_Process.md +0 -122
  377. md_processing/family_docs/Governance Officer/Create_Governance_Processing_Purpose.md +0 -106
  378. md_processing/family_docs/Governance Officer/Create_Governance_Responsibility.md +0 -122
  379. md_processing/family_docs/Governance Officer/Create_Governance_Rule.md +0 -122
  380. md_processing/family_docs/Governance Officer/Create_Governance_Strategy.md +0 -106
  381. md_processing/family_docs/Governance Officer/Create_License_Type.md +0 -112
  382. md_processing/family_docs/Governance Officer/Create_Naming_Standard_Rule.md +0 -122
  383. md_processing/family_docs/Governance Officer/Create_Regulation_Article.md +0 -106
  384. md_processing/family_docs/Governance Officer/Create_Regulation_Definition.md +0 -118
  385. md_processing/family_docs/Governance Officer/Create_Security_Access_Control.md +0 -114
  386. md_processing/family_docs/Governance Officer/Create_Security_Group.md +0 -120
  387. md_processing/family_docs/Governance Officer/Create_Service_Level_Objectives.md +0 -122
  388. md_processing/family_docs/Governance Officer/Create_Threat_Definition.md +0 -106
  389. md_processing/family_docs/Governance Officer/Link_Governance_Controls.md +0 -32
  390. md_processing/family_docs/Governance Officer/Link_Governance_Drivers.md +0 -32
  391. md_processing/family_docs/Governance Officer/Link_Governance_Policies.md +0 -32
  392. md_processing/family_docs/Governance Officer/View_Governance_Definitions.md +0 -82
  393. md_processing/family_docs/Governance Officer.md +0 -2412
  394. md_processing/family_docs/Solution Architect/Create_Information_Supply_Chain.md +0 -70
  395. md_processing/family_docs/Solution Architect/Create_Solution_Blueprint.md +0 -44
  396. md_processing/family_docs/Solution Architect/Create_Solution_Component.md +0 -96
  397. md_processing/family_docs/Solution Architect/Create_Solution_Role.md +0 -66
  398. md_processing/family_docs/Solution Architect/Link_Information_Supply_Chain_Peers.md +0 -32
  399. md_processing/family_docs/Solution Architect/Link_Solution_Component_Peers.md +0 -32
  400. md_processing/family_docs/Solution Architect/View_Information_Supply_Chains.md +0 -32
  401. md_processing/family_docs/Solution Architect/View_Solution_Blueprints.md +0 -32
  402. md_processing/family_docs/Solution Architect/View_Solution_Components.md +0 -32
  403. md_processing/family_docs/Solution Architect/View_Solution_Roles.md +0 -32
  404. md_processing/family_docs/Solution Architect.md +0 -490
  405. md_processing/md_processing_utils/debug_log +0 -574
  406. md_processing/md_processing_utils/debug_log.log +0 -0
  407. md_processing/md_processing_utils/dr-egeria-help-2025-07-17T17:22:09.md +0 -2065
  408. md_processing/md_processing_utils/generated_help_terms.md +0 -842
  409. pyegeria/.DS_Store +0 -0
  410. pyegeria/README.md +0 -35
  411. pyegeria/_client_new.py +0 -1102
  412. pyegeria/_output_formats.py +0 -730
  413. pyegeria/asset_catalog_omvs.py +0 -864
  414. pyegeria/automated_curation_omvs.py +0 -3765
  415. pyegeria/config.py +0 -523
  416. pyegeria/egeria_my_client.py +0 -91
  417. pyegeria/feedback_manager_omvs.py +0 -4573
  418. pyegeria/load_config_orig.py +0 -218
  419. pyegeria/md_processing_helpers.py +0 -58
  420. pyegeria/md_processing_utils_orig.py +0 -1103
  421. pyegeria/metadata_explorer_omvs.py +0 -2326
  422. pyegeria/my_profile_omvs.py +0 -1022
  423. pyegeria/project_manager.py +0 -1591
  424. pyegeria/registered_info.py +0 -167
  425. pyegeria/template_manager_omvs.py +0 -1414
  426. pyegeria/utils.py +0 -256
  427. pyegeria-5.4.0.28.dist-info/METADATA +0 -77
  428. pyegeria-5.4.0.28.dist-info/RECORD +0 -343
  429. pyegeria-5.4.0.28.dist-info/entry_points.txt +0 -105
  430. /commands/cat/debug_log.log → /pyegeria/deprecated/__init__.py +0 -0
  431. /pyegeria/{_exceptions.py → deprecated/_exceptions.py} +0 -0
  432. /pyegeria/{collection_models.py → models/collection_models.py} +0 -0
  433. {pyegeria-5.4.0.28.dist-info → pyegeria-5.5.3.3.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,559 @@
1
+ """ python
2
+
3
+ PDX-License-Identifier: Apache-2.0
4
+ Copyright Contributors to the ODPi Egeria project.
5
+
6
+ This file provides a utility function for my_egeria.
7
+
8
+ This file is being used to test some display layout options
9
+ This is a test file to explore different ways to display Egeria data
10
+ Author: Peter Coldicott, November 2025
11
+
12
+ This version is to test having the user input required parameters to run
13
+ customized reports
14
+
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ from typing import Any
20
+
21
+ from commands.cat.run_report import list_generic
22
+ from pydantic import ValidationError
23
+ from pyegeria.view.base_report_formats import report_spec_list, select_report_spec
24
+ from pyegeria.view.format_set_executor import exec_report_spec
25
+ from textual import on
26
+ from textual.app import App
27
+ from textual.containers import Container, Horizontal, HorizontalScroll, ScrollableContainer
28
+ from textual.widgets import Static, Button, DataTable, Header, Footer, Input, Tree, Label
29
+
30
+
31
+ class RunSpec(App):
32
+ CSS_PATH = "my_reports.tcss"
33
+
34
+ BINDINGS = [
35
+ ("q", "quit", "Quit"),
36
+ ("s", "show_report", "Show"),
37
+ ("r", "prepare_report", "Run"),
38
+ ]
39
+
40
+ # TITLE = "My_Egeria"
41
+ # SUB_TITLE = "Report Specification Details"
42
+
43
+ def __init__(self, **kwargs):
44
+ super().__init__(**kwargs)
45
+ self.Egeria_config = ["https://127.0.0.1:9443", "qs-view-server", "erinoverview", "secret"]
46
+ self.platform_url = self.Egeria_config[0]
47
+ self.view_server = self.Egeria_config[1]
48
+ self.user = self.Egeria_config[2]
49
+ self.password = self.Egeria_config[3]
50
+ self.selected_report_spec: str = ""
51
+ self.items: list = []
52
+ self.created_inputs: list[Input] = []
53
+ self.inputs_tracker: dict[str, list] = {}
54
+ self.snode_label: str = ""
55
+ # Holds rotated data as column -> list of row values
56
+ self.rotated_table: dict[str, list[str]] = {}
57
+
58
+ def compose(self):
59
+ self.title = "My_Egeria"
60
+ self.sub_title = "Report Specification Details"
61
+ yield Header()
62
+ yield Container(
63
+ Static("Start of report specification list:", id="one_start"),
64
+ Tree(label="Report Specs",id="spec_tree", classes="trees"),
65
+ Static("End of report specification list:", id="one_end"),
66
+ id="container1", classes="box")
67
+ yield Container(
68
+ Static("Report Specification Details", classes="box", id="two_start"),
69
+ DataTable(id="spec_extracted_datatable"),
70
+ Static("End of Report Specification Details", classes="box", id="two_end"),
71
+ id="container2", classes="box")
72
+ yield ScrollableContainer(
73
+ Static("Report Specs Input Fields", classes="box", id="four_start"),
74
+ Container(id="input_fields"),
75
+ Static("End of Report Specs Input Fields", classes="box", id="four_end"),
76
+ id="container4", classes="box")
77
+ yield Container(
78
+ Static("Report Specification Output)", classes="box", id="three_start"),
79
+ DataTable(id="spec_output_datatable"),
80
+ Static("End of Report Specification Output)", classes="box", id="three_end"),
81
+ id="container3", classes="box")
82
+ yield Footer()
83
+
84
+ def on_mount(self):
85
+ self.spec_tree = self.query_one("#spec_tree", Tree)
86
+ self.spec_tree.clear()
87
+ root_data = "A categorized list of PyEgeria report specifications"
88
+ self.spec_tree.root.expand()
89
+ self.spec_tree.root.label = "Report Specs"
90
+ self.spec_tree.root.data = root_data
91
+ tree_root = self.spec_tree.root
92
+ self.family: str = ""
93
+ self.heading = "Report Specs"
94
+ self.subheading = "Select a report spec to execute:"
95
+ self.description = "A list of report specifications, click on one to see its attributes\ns key to run"
96
+ self.report_spec_list: list = report_spec_list(show_family=True, sort_by_family=True, return_kind="dicts")
97
+ self.log(f"report_spec_list: {self.report_spec_list}, type: {type(self.report_spec_list)}")
98
+ for spec in self.report_spec_list:
99
+ if spec.get("family") != self.family:
100
+ self.family = spec.get("family")
101
+ family_node = tree_root.add(self.family, data="family_name")
102
+ family_node.expand()
103
+ family_node.add(spec.get("name"), data=spec.get("description"))
104
+ continue
105
+ else:
106
+ family_node.add(spec.get("name"), data=spec.get("description"))
107
+ continue
108
+ self.spec_tree.refresh()
109
+
110
+ @on(Tree.NodeSelected, "#spec_tree")
111
+ async def handle_spec_tree_node_selected(self, message: Tree.NodeSelected):
112
+ self.log(f"Node Selected, Processing selection")
113
+ self.selected_report_spec = message.node
114
+ self.log(f"selected_report_spec: {self.selected_report_spec}")
115
+ snode = message.node
116
+ self.log(f"snode: {snode}", type(snode))
117
+ if snode.data:
118
+ snode_label = str(snode.label)
119
+ self.log(f"snode_label: {snode_label}", type(snode_label))
120
+ else:
121
+ snode_label = str(snode.label)
122
+ self.log(f"snode_label: {snode_label}", type(snode_label))
123
+ # address input fields container so we can clear it from prior selections
124
+ inputs_container = self.query_one("#input_fields", Container)
125
+ # Clear previous rows
126
+ try:
127
+ self.created_inputs: list[Input] = []
128
+ # Remove all existing children synchronously
129
+ for child in list(inputs_container.children):
130
+ await child.remove()
131
+ except Exception as e:
132
+ self.log(f"Exception clearing inputs container: {e} possibly first time through")
133
+ self.snode_label = snode_label
134
+ await self.get_named_report_spec_details(snode_label)
135
+
136
+ async def get_named_report_spec_details(self, name):
137
+ """Get the details of a named report spec and render as a flat table.
138
+
139
+ Simplified approach:
140
+ - Normalize the incoming spec to a dict.
141
+ - Recursively walk dicts/lists with a small helper that yields rows.
142
+ - Use a path convention where the first segment is shown in "Attribute",
143
+ the remaining path (if any) is shown in "Value", and the leaf value in
144
+ "Extended Values". This keeps the UI compact while preserving structure.
145
+
146
+ """
147
+
148
+ self.spec_name = name
149
+ self.log(f"get_named_report_spec_details: {self.spec_name}")
150
+ selected_report_spec = select_report_spec(self.spec_name, output_type="DICT")
151
+ self.log(f"selected_report_spec: {selected_report_spec}, type: {type(selected_report_spec)}")
152
+ if selected_report_spec == None:
153
+ selected_report_spec = {"NoDetails": "No details found for selected report spec"}
154
+ # Normalize the shape of the returned spec → always a dict
155
+ if isinstance(selected_report_spec, dict) and "data" in selected_report_spec:
156
+ self.extracted_report_spec: dict = selected_report_spec.get("data") or {}
157
+ elif isinstance(selected_report_spec, dict):
158
+ self.extracted_report_spec: dict = selected_report_spec or {}
159
+ else:
160
+ error_text = f"Unknown shape: {selected_report_spec}"
161
+ self.extracted_report_spec = {"Error": error_text}
162
+
163
+ self.log(f"extracted_report_spec: {self.extracted_report_spec}, type: {type(self.extracted_report_spec)}")
164
+ response_data = self.extracted_report_spec
165
+ # Access the datatable used to display report specification attributes
166
+ self.spec_attribute_datatable = self.query_one("#spec_extracted_datatable", DataTable)
167
+ # Ensure columns exist only once
168
+ self.spec_attribute_datatable.clear(columns=True)
169
+ self.spec_attribute_datatable.add_columns("Attribute", "Value", "Extended Values")
170
+ self.spec_attribute_datatable.border = True
171
+ self.spec_attribute_datatable.zebra_stripes = True
172
+ self.spec_attribute_datatable.cursor_type = "row"
173
+ self.spec_attribute_datatable.refresh()
174
+
175
+ # if not response_data or response_data == None or response_data == "":
176
+ if not response_data:
177
+ response_data = {"NoData": "No data found for selected item"}
178
+ if isinstance(response_data, list):
179
+ for list_item in response_data:
180
+ response_data: dict = list_item
181
+ self.log(f"list_item: {list_item}")
182
+ if isinstance(response_data, dict):
183
+ for key, value in response_data.items():
184
+ self.log(f"key: {key}, value: {value}")
185
+ # check for input capable report spec parms
186
+ if key == "required_params" or key == "optional_params" or key == "spec_params" or key == "types":
187
+ self.log(f"Executing populate_input_fields for key: {key}")
188
+ await self.populate_input_fields(key, value)
189
+ self.log(f"populate_input_fields completed for key: {key}")
190
+ self.log(f"key: {key}, value: {value}")
191
+ if isinstance(value, dict):
192
+ for vkey, vvalue in value.items():
193
+ if vkey == "required_params" or vkey == "optional_params" or vkey == "spec_params" or vkey == "types":
194
+ self.log(f"Executing populate_input_fields for key: {vkey}")
195
+ await self.populate_input_fields(vkey, vvalue)
196
+ self.log(f"populate_input_fields completed for key: {vkey}")
197
+ self.log(f"vkey: {vkey}, vvalue: {vvalue}")
198
+ self.spec_attribute_datatable.add_row(vkey, vvalue)
199
+ continue
200
+ elif isinstance(value, list):
201
+ for v in value:
202
+ self.log(f"v: {v}")
203
+ self.spec_attribute_datatable.add_row(key, v)
204
+ continue
205
+ elif key == "kind" and value == "empty":
206
+ key_str = "No Data"
207
+ value_str = "For That Asset Type in this repository"
208
+ self.log(f"key_str: {key_str}, value_str: {value_str}")
209
+ self.spec_attribute_datatable.add_row(key_str, value_str)
210
+ continue
211
+ elif isinstance(value, dict):
212
+ for vkey, vvalue in value.items():
213
+ self.log(f"vkey: {vkey}, vvalue: {vvalue}")
214
+ self.spec_attribute_datatable.add_row(vkey, vvalue)
215
+ continue
216
+ else:
217
+ self.log(f"else: key {key} value: {value}")
218
+ self.spec_attribute_datatable.add_row(key, value)
219
+ continue
220
+ elif isinstance(response_data, dict):
221
+ for key, value in response_data.items():
222
+ self.log(f"key: {key}, value: {value}")
223
+ if key == "required_params" or key == "optional_params" or key == "spec_params" or key == "types":
224
+ self.log(f"Executing populate_input_fields for key: {key}")
225
+ await self.populate_input_fields(key, value)
226
+ self.log(f"populate_input_fields completed for key: {key}")
227
+ if isinstance(value, dict):
228
+ for vkey, vvalue in value.items():
229
+ if vkey == "required_params" or vkey == "optional_params" or vkey == "spec_params" or vkey == "types":
230
+ self.log(f"Executing populate_input_fields for key: {vkey}")
231
+ await self.populate_input_fields(vkey, vvalue)
232
+ self.log(f"populate_input_fields completed for key: {vkey}")
233
+ self.spec_attribute_datatable.add_row(vkey, vvalue)
234
+ continue
235
+ elif isinstance(value, list):
236
+ for v in value:
237
+ self.spec_attribute_datatable.add_row(key, v)
238
+ continue
239
+ elif key == "kind" and value == "empty":
240
+ key_str = "No Data"
241
+ value_str = "For That Asset Type in this repository"
242
+ self.spec_attribute_datatable.add_row(key_str, value_str)
243
+ continue
244
+ else:
245
+ self.spec_attribute_datatable.add_row(key, value)
246
+ continue
247
+
248
+ self.spec_attribute_datatable.refresh()
249
+ mount_point = self.query_one("#container2", Container)
250
+ await mount_point.mount(self.spec_attribute_datatable, before="#two_end")
251
+ return
252
+
253
+ async def execute_selected_report_spec(self, selected_name: str = "", additional_parameters: dict = None):
254
+ """ execute the selected report spec """
255
+ self.selected_name = selected_name
256
+ self.additional_parameters = additional_parameters
257
+ output_form = "DICT"
258
+ if len(self.additional_parameters) > 0:
259
+ self.log(f"additional_parameters: {self.additional_parameters}")
260
+ else:
261
+ self.log(f"No additional parameters provided")
262
+ self.additional_parameters = {}
263
+ if self.additional_parameters != None:
264
+ if "inp_types" in self.additional_parameters:
265
+ output_form = self.additional_parameters["inp_types"]
266
+
267
+ self.log(f"Executing report spec: {self.selected_name}")
268
+ try:
269
+ reponse = exec_report_spec(format_set_name=selected_name,
270
+ output_format=output_form,
271
+ view_server=self.view_server,
272
+ view_url=self.platform_url,
273
+ user=self.user,
274
+ user_pass=self.password,
275
+ params=self.additional_parameters,
276
+ )
277
+ self.log(f"Return from exec_report_spec:")
278
+ self.log(f"reponse: {reponse}")
279
+ except (ValidationError) as e:
280
+ self.log(f"ValidationError: {e}")
281
+ reponse = {"error": f"ValidationError: {e}"}
282
+ except Exception as e:
283
+ self.log(f"Exception: {e}")
284
+ reponse = {"error": f"Exception: {e}"}
285
+ await self.display_response(reponse)
286
+
287
+ async def display_response(self, response):
288
+ """ Display the response from executing the selected report spec"""
289
+ self.response = response
290
+ # create and/or clear datatable for displaying data
291
+ self.spec_output_datatable = self.query_one("#spec_output_datatable", DataTable)
292
+ self.spec_output_datatable.clear(columns=True)
293
+ self.log(f"self.spec_output_datatable : {self.spec_output_datatable} has been created")
294
+ # self.spec_output_datatable.id = "spec_output_datatable"
295
+ self.log(f"self.spec_output_datatable has been assigned an id : {self.spec_output_datatable.id} ")
296
+ # extract data payload from response["data"]. Then populate variables for display
297
+ if isinstance(self.response, dict) and "data" in self.response:
298
+ self.response_data = self.response.get("data")
299
+ elif isinstance(self.response, dict):
300
+ self.response_data = self.response
301
+ elif isinstance(self.response, list):
302
+ self.response_data = self.response
303
+ else:
304
+ self.response_data = [{"NoData": "No data found for selected item", "Data Content": self.response}]
305
+
306
+ self.rotated_table.clear()
307
+ if isinstance(self.response_data, list):
308
+ for list_item in self.response_data:
309
+ response_dict = list_item if isinstance(list_item, dict) else {"Value": list_item}
310
+ self.log(f"list_item: {list_item}")
311
+ for key, value in response_dict.items():
312
+ self.log(f"key: {key}, value: {value}")
313
+ if isinstance(value, dict):
314
+ for vkey, vvalue in value.items():
315
+ self.log(f"vkey: {vkey}, vvalue: {vvalue}")
316
+ self.rotated_table.setdefault(str(vkey), []).append(vvalue)
317
+ elif isinstance(value, list):
318
+ for v in value:
319
+ self.log(f"v: {v}")
320
+ self.rotated_table.setdefault(str(v), []).append(" ")
321
+ elif key == "kind" and value == "empty":
322
+ key_str: str = "NoData"
323
+ message: str = "For That Asset Type in this repository"
324
+ self.log(f"key_str: {key_str}, value_str: {message}")
325
+ # Present a single consolidated message row under NoData
326
+ self.rotated_table[key_str] = [message]
327
+ else:
328
+ self.log(f"else: key {key} value: {value}")
329
+ self.rotated_table.setdefault(str(key), []).append(value)
330
+ elif isinstance(self.response_data, dict):
331
+ for key, value in self.response_data.items():
332
+ self.log(f"key: {key}, value: {value}")
333
+ if key == "kind":
334
+ continue
335
+ elif isinstance(value, dict):
336
+ for vkey, vvalue in value.items():
337
+ self.rotated_table.setdefault(str(vkey), []).append(vvalue)
338
+ elif isinstance(value, list):
339
+ for v in value:
340
+ self.rotated_table.setdefault(str(v), []).append(" ")
341
+ elif key == "kind" and value == "empty":
342
+ key_str = "NoData"
343
+ message = "For That Asset Type in this repository"
344
+ self.log(f"key_str: {key_str}, value_str: {message}")
345
+ # Present a single consolidated message row under NoData
346
+ self.rotated_table[key_str] = [message]
347
+ else:
348
+ self.rotated_table.setdefault(str(key), []).append(value)
349
+ # now the rotated table is loaded with data, create the datatable
350
+ keys = list(self.rotated_table.keys())
351
+ for col_key in keys:
352
+ self.spec_output_datatable.add_column(str(col_key))
353
+ max_rows = max((len(self.rotated_table[k]) for k in keys), default=0)
354
+ for row_idx in range(max_rows):
355
+ row = [str(self.rotated_table[k][row_idx]) if row_idx < len(self.rotated_table[k]) else "" for k in keys]
356
+ self.spec_output_datatable.add_row(*row)
357
+
358
+ # Always refresh after populating
359
+ self.spec_output_datatable.refresh()
360
+ mount_point = self.query_one("#container3", Container)
361
+ await mount_point.mount(self.spec_output_datatable, before="#three_end")
362
+ return
363
+
364
+ async def populate_input_fields(self, key, value):
365
+ """Create interactive input rows for required/optional params."""
366
+ self.key = key
367
+ self.input = value
368
+ inp_value: Any = None
369
+ inputs_container = self.query_one("#input_fields", Container)
370
+
371
+ def safe_id(s: str) -> str:
372
+ return re.sub(r"[^0-9a-zA-Z_-]", "_", s)
373
+
374
+ self.created_inputs: list[Input] = []
375
+ # reset tracker for this render; we'll repopulate with the current inputs
376
+ self.inputs_tracker.clear()
377
+
378
+ # Build rows according to incoming shape
379
+ if isinstance(self.input, dict):
380
+ items = list(self.input.items())
381
+ for ikey, ivalue in items:
382
+ row = HorizontalScroll(id=f"input_row_{safe_id(str(ikey))}")
383
+ await inputs_container.mount(row)
384
+ await row.mount(Label(f"{ikey}:"))
385
+ self.log(f"Processing input field: {ikey}")
386
+ if ikey == "search_string":
387
+ inp_value = "*"
388
+ elif ikey == "page_size":
389
+ inp_value = '0'
390
+ elif ikey == "start_from":
391
+ inp_value = '0'
392
+ elif ikey == "starts_with":
393
+ inp_value = "True"
394
+ elif ikey == "ends_with":
395
+ inp_value = "False"
396
+ elif ikey == "ignore_case":
397
+ inp_value = "False"
398
+ elif ikey == "output_format":
399
+ inp_value = "DICT"
400
+ else:
401
+ inp_value = ""
402
+ inp = Input(value=inp_value, placeholder=str(ivalue), id=f"inp_{safe_id(str(ikey))}", classes="spaced")
403
+ await row.mount(inp)
404
+ self.created_inputs.append(inp)
405
+ # Track by input id so events can update values reliably
406
+ self.inputs_tracker[inp.id] = [str(ikey), ""]
407
+ elif isinstance(self.input, list):
408
+ # Special-case for types: just display info text
409
+ if key == "types":
410
+ row = Horizontal(id=f"input_row_{safe_id(str(key))}")
411
+ await inputs_container.mount(row)
412
+ await row.mount(Label("Output Format:"))
413
+ await row.mount(Input(value="DICT", placeholder="DICT", id=f"inp_{safe_id(str(key))}", classes="spaced"))
414
+ # informational only; no input to track
415
+ else:
416
+ for list_item in self.input:
417
+ label = str(list_item)
418
+ row = Horizontal(id=f"input_row_{safe_id(label)}")
419
+ await inputs_container.mount(row)
420
+ await row.mount(Label(f"{label}:"))
421
+ self.log(f"Processing input field: {label}")
422
+ if label == "search_string":
423
+ inp_value = "*"
424
+ elif label == "page_size":
425
+ inp_value = '0'
426
+ elif label == "start_from":
427
+ inp_value = '0'
428
+ elif label == "starts_with":
429
+ inp_value = "True"
430
+ elif label == "ends_with":
431
+ inp_value = "False"
432
+ elif label == "ignore_case":
433
+ inp_value = "False"
434
+ elif label == "output_format":
435
+ inp_value = "DICT"
436
+ else:
437
+ inp_value = ""
438
+ inp = Input(value=inp_value, placeholder="", id=f"inp_{safe_id(label)}")
439
+ await row.mount(inp)
440
+ self.created_inputs.append(inp)
441
+ # Track with a reasonable parameter name for list entries
442
+ self.inputs_tracker[inp.id] = [label, ""]
443
+ else:
444
+ # Unknown shape: show a message
445
+ row = Horizontal(id=f"input_row_{safe_id(str(key))}")
446
+ await inputs_container.mount(row)
447
+ await row.mount(Label(f"Error, Unknown Shape for {key}: {value}"))
448
+
449
+ # Give focus to the first input if any
450
+ if self.created_inputs:
451
+ self.created_inputs[0].focus()
452
+
453
+ # Refresh the container
454
+ inputs_container.refresh()
455
+ return
456
+
457
+ @on(Input.Changed, "#input_fields Input")
458
+ async def handle_input_changed(self, event: Input.Changed) -> None:
459
+ """Update the tracker whenever an input changes.
460
+
461
+ We key the tracker by the actual Input id and store [param_name, value].
462
+ """
463
+ input_id = event.input.id
464
+ value = event.value or ""
465
+ # Initialize if missing (defensive)
466
+ if input_id not in self.inputs_tracker:
467
+ # Default param name falls back to the visible label-less id
468
+ self.inputs_tracker[input_id] = [input_id, value]
469
+ else:
470
+ self.inputs_tracker[input_id][1] = value
471
+ self.log(f"Changed: {input_id} -> {value}")
472
+ return
473
+
474
+ @on(Button.Pressed, "#quit")
475
+ def handle_quit(self, event: Button.Pressed) -> None:
476
+ self.exit(200)
477
+
478
+ def action_quit(self):
479
+ self.exit(200)
480
+
481
+ async def action_prepare_report(self):
482
+ # Build additional parameters from current inputs
483
+ self.new_additional_parameters = {}
484
+ self.additional_parameters = {}
485
+ if self.inputs_tracker:
486
+ self.log(f"self.inputs_tracker: {self.inputs_tracker}")
487
+ for _, (parm_name, parm_value) in self.inputs_tracker.items():
488
+ self.additional_parameters[parm_name] = parm_value
489
+ self.log(f"additional_parameters: {self.additional_parameters}")
490
+ # run report when input fields completed
491
+ # iterate and strip the inp_ from the front of the key values if present
492
+ for key, value in self.additional_parameters.items():
493
+ new_key:str = key.removeprefix("inp_")
494
+ self.new_additional_parameters.update({new_key: value})
495
+ self.additional_parameters.clear()
496
+ # change the types key to output_format if present fior inclusion in parameters dict
497
+ value = self.new_additional_parameters.get("types")
498
+ if value:
499
+ self.new_additional_parameters.update({"output_format": value})
500
+ else:
501
+ self.new_additional_parameters.update({"output_format": "DICT"})
502
+ self.log (f"new_additional_parameters: {self.new_additional_parameters}")
503
+ self.additional_parameters = self.new_additional_parameters
504
+ self.log(f"additional_parameters trimmed: {self.additional_parameters}")
505
+ # Retrieve the output_format value
506
+ output_form = self.additional_parameters.get("output_format", "FORM")
507
+ self.log(f"output_format: {output_form}")
508
+ # if output_format is FORM, we write the report output to a file
509
+ # if not then we execute the report spec and display the output on the screen
510
+ if output_form == "FORM":
511
+ await self.report_to_file(self.snode_label, self.additional_parameters)
512
+ else:
513
+ await self.execute_selected_report_spec(self.snode_label, self.additional_parameters)
514
+ return
515
+
516
+ async def report_to_file(self, selected_name: str = "", additional_parameters: dict = None):
517
+ """ execute the selected report spec """
518
+ # self.selected_name = selected_name
519
+ # self.additional_parameters = additional_parameters
520
+ my_additional_parameters: dict = additional_parameters
521
+ output_form = "FORM"
522
+ if len(my_additional_parameters) > 0:
523
+ self.log(f"additional_parameters: {my_additional_parameters}")
524
+ if "output_format" in my_additional_parameters:
525
+ output_form = my_additional_parameters.get("output_format")
526
+ del my_additional_parameters["output_format"]
527
+ else:
528
+ output_form = "FORM"
529
+ else:
530
+ self.log(f"No additional parameters provided")
531
+ my_additional_parameters = {}
532
+
533
+ self.log(f"Executing report spec: {selected_name}")
534
+ try:
535
+ reponse = list_generic(report_spec=selected_name,
536
+ output_format=output_form,
537
+ view_server=self.view_server,
538
+ view_url=self.platform_url,
539
+ user=self.user,
540
+ user_pass=self.password,
541
+ params=my_additional_parameters,
542
+ write_file=True
543
+ )
544
+ self.log(f"Return from exec_report_spec:")
545
+ self.log(f"reponse: {reponse}")
546
+ except (ValidationError) as e:
547
+ self.log(f"ValidationError: {e}")
548
+ reponse = {"error": f"ValidationError: {e}"}
549
+ except Exception as e:
550
+ self.log(f"Exception: {e}")
551
+ reponse = {"error": f"Exception: {e}"}
552
+ await self.display_response(reponse)
553
+
554
+ def start_exp2():
555
+ app = RunSpec()
556
+ app.run()
557
+
558
+ if __name__ == "__main__":
559
+ start_exp2()