pyegeria 5.2.1__py3-none-any.whl → 5.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.
Files changed (311) hide show
  1. commands/cat/.DS_Store +0 -0
  2. commands/cat/Dr-Egeria_md-orig.py +166 -0
  3. commands/cat/__init__.py +23 -0
  4. commands/cat/dr_egeria_jupyter.py +122 -0
  5. commands/cat/dr_egeria_md.py +247 -0
  6. {pyegeria/commands → commands}/cat/exp_list_glossaries.py +3 -4
  7. {pyegeria/commands → commands}/cat/get_asset_graph.py +4 -4
  8. {pyegeria/commands → commands}/cat/get_collection.py +8 -9
  9. {pyegeria/commands → commands}/cat/get_project_dependencies.py +6 -8
  10. {pyegeria/commands → commands}/cat/get_project_structure.py +6 -8
  11. {pyegeria/commands → commands}/cat/get_tech_type_elements.py +13 -15
  12. {pyegeria/commands → commands}/cat/glossary_actions.py +184 -34
  13. {pyegeria/commands → commands}/cat/list_assets.py +9 -6
  14. commands/cat/list_categories.py +192 -0
  15. {pyegeria/commands → commands}/cat/list_cert_types.py +6 -6
  16. {pyegeria/commands → commands}/cat/list_collections.py +62 -19
  17. commands/cat/list_data_structures.py +223 -0
  18. {pyegeria/commands → commands}/cat/list_deployed_catalogs.py +9 -8
  19. {pyegeria/commands → commands}/cat/list_deployed_database_schemas.py +10 -9
  20. {pyegeria/commands → commands}/cat/list_deployed_databases.py +9 -8
  21. pyegeria/commands/cat/list_servers_deployed_imp.py → commands/cat/list_deployed_servers.py +3 -3
  22. {pyegeria/commands → commands}/cat/list_glossaries.py +57 -15
  23. {pyegeria/commands → commands}/cat/list_projects.py +5 -5
  24. {pyegeria/commands → commands}/cat/list_tech_type_elements.py +3 -3
  25. {pyegeria/commands → commands}/cat/list_tech_types.py +4 -4
  26. {pyegeria/commands → commands}/cat/list_terms.py +93 -45
  27. {pyegeria/commands → commands}/cat/list_todos.py +3 -3
  28. {pyegeria/commands → commands}/cat/list_user_ids.py +9 -8
  29. {pyegeria/commands → commands}/cli/__init__.py +1 -1
  30. {pyegeria/commands → commands}/cli/egeria.py +513 -250
  31. {pyegeria/commands → commands}/cli/egeria_cat.py +128 -51
  32. {pyegeria/commands → commands}/cli/egeria_login_tui.py +15 -17
  33. {pyegeria/commands → commands}/cli/egeria_my.py +22 -15
  34. {pyegeria/commands → commands}/cli/egeria_ops.py +54 -55
  35. {pyegeria/commands → commands}/cli/egeria_tech.py +364 -152
  36. {pyegeria/commands → commands}/cli/ops_config.py +18 -11
  37. commands/my/__init__.py +22 -0
  38. {pyegeria/commands → commands}/my/list_my_profile.py +6 -8
  39. {pyegeria/commands → commands}/my/list_my_roles.py +4 -4
  40. {pyegeria/commands → commands}/my/monitor_my_todos.py +7 -7
  41. {pyegeria/commands → commands}/my/monitor_open_todos.py +7 -7
  42. {pyegeria/commands → commands}/my/todo_actions.py +3 -2
  43. commands/ops/__init__.py +23 -0
  44. {pyegeria/commands → commands}/ops/gov_server_actions.py +5 -4
  45. {pyegeria/commands → commands}/ops/list_archives.py +7 -6
  46. {pyegeria/commands → commands}/ops/list_catalog_targets.py +4 -4
  47. {pyegeria/commands → commands}/ops/load_archive.py +4 -2
  48. {pyegeria/commands → commands}/ops/monitor_asset_events.py +8 -7
  49. {pyegeria/commands → commands}/ops/monitor_engine_activity.py +5 -5
  50. {pyegeria/commands → commands}/ops/monitor_engine_activity_c.py +3 -3
  51. {pyegeria/commands → commands}/ops/monitor_gov_eng_status.py +3 -2
  52. {pyegeria/commands → commands}/ops/monitor_integ_daemon_status.py +23 -15
  53. {pyegeria/commands → commands}/ops/monitor_platform_status.py +5 -4
  54. {pyegeria/commands → commands}/ops/monitor_server_startup.py +7 -7
  55. {pyegeria/commands → commands}/ops/monitor_server_status.py +16 -11
  56. {pyegeria/commands → commands}/ops/orig_monitor_server_list.py +2 -2
  57. {pyegeria/commands → commands}/ops/orig_monitor_server_status.py +3 -3
  58. {pyegeria/commands → commands}/ops/refresh_integration_daemon.py +4 -4
  59. {pyegeria/commands → commands}/ops/restart_integration_daemon.py +3 -3
  60. {pyegeria/commands → commands}/ops/table_integ_daemon_status.py +3 -3
  61. commands/tech/__init__.py +22 -0
  62. commands/tech/generic_actions.py +74 -0
  63. {pyegeria/commands → commands}/tech/get_element_info.py +5 -7
  64. {pyegeria/commands → commands}/tech/get_guid_info.py +4 -5
  65. {pyegeria/commands → commands}/tech/get_tech_details.py +8 -9
  66. {pyegeria/commands → commands}/tech/get_tech_type_template.py +4 -4
  67. pyegeria/commands/tech/list_elements.py → commands/tech/list_all_om_type_elements.py +11 -10
  68. pyegeria/commands/tech/list_elements_x.py → commands/tech/list_all_om_type_elements_x.py +11 -12
  69. pyegeria/commands/tech/list_related_elements.py → commands/tech/list_all_related_elements.py +11 -9
  70. {pyegeria/commands → commands}/tech/list_anchored_elements.py +16 -16
  71. {pyegeria/commands → commands}/tech/list_asset_types.py +4 -4
  72. commands/tech/list_elements_by_classification_by_property_value.py +200 -0
  73. commands/tech/list_elements_by_property_value.py +180 -0
  74. commands/tech/list_elements_by_property_value_x.py +201 -0
  75. {pyegeria/commands → commands}/tech/list_elements_for_classification.py +11 -9
  76. {pyegeria/commands → commands}/tech/list_gov_action_processes.py +5 -6
  77. commands/tech/list_information_supply_chains.py +167 -0
  78. {pyegeria/commands → commands}/tech/list_registered_services.py +3 -3
  79. commands/tech/list_related_elements_with_prop_value.py +221 -0
  80. {pyegeria/commands → commands}/tech/list_related_specification.py +3 -3
  81. {pyegeria/commands → commands}/tech/list_relationship_types.py +4 -5
  82. {pyegeria/commands → commands}/tech/list_relationships.py +3 -3
  83. commands/tech/list_solution_blueprints.py +181 -0
  84. commands/tech/list_solution_components.py +185 -0
  85. commands/tech/list_solution_roles.py +184 -0
  86. {pyegeria/commands → commands}/tech/list_tech_templates.py +3 -3
  87. {pyegeria/commands → commands}/tech/list_valid_metadata_values.py +5 -6
  88. {pyegeria/commands → commands}/tech/table_tech_templates.py +16 -13
  89. {pyegeria/commands → commands}/tech/x_list_related_elements.py +6 -4
  90. md_processing/__init__.py +49 -0
  91. md_processing/data/commands.json +3252 -0
  92. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +254 -0
  93. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +696 -0
  94. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +254 -0
  95. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +298 -0
  96. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +608 -0
  97. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +94 -0
  98. md_processing/dr_egeria_inbox/archive/freddie_intro.md +284 -0
  99. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +275 -0
  100. md_processing/dr_egeria_inbox/archive/test-term.md +110 -0
  101. md_processing/dr_egeria_inbox/cat_test.md +100 -0
  102. md_processing/dr_egeria_inbox/data_field.md +54 -0
  103. md_processing/dr_egeria_inbox/data_spec.md +77 -0
  104. md_processing/dr_egeria_inbox/data_spec_test.md +2406 -0
  105. md_processing/dr_egeria_inbox/data_test.md +86 -0
  106. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +168 -0
  107. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +280 -0
  108. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +313 -0
  109. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +1073 -0
  110. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +44 -0
  111. md_processing/dr_egeria_inbox/glossary_creation_experiment.ipynb +341 -0
  112. md_processing/dr_egeria_inbox/glossary_test1.md +324 -0
  113. md_processing/dr_egeria_inbox/rel.md +8 -0
  114. md_processing/dr_egeria_inbox/sb.md +119 -0
  115. md_processing/dr_egeria_inbox/search_test.md +39 -0
  116. md_processing/dr_egeria_inbox/solution-components.md +154 -0
  117. md_processing/dr_egeria_inbox/solution_blueprints.md +118 -0
  118. md_processing/dr_egeria_inbox/synonym_test.md +42 -0
  119. md_processing/dr_egeria_inbox/t2.md +268 -0
  120. md_processing/dr_egeria_outbox/processed-2025-05-15 19:52-data_test.md +94 -0
  121. md_processing/dr_egeria_outbox/processed-2025-05-16 07:39-data_test.md +88 -0
  122. md_processing/dr_egeria_outbox/processed-2025-05-17 16:01-data_field.md +56 -0
  123. md_processing/dr_egeria_outbox/processed-2025-05-18 15:51-data_test.md +103 -0
  124. md_processing/dr_egeria_outbox/processed-2025-05-18 16:47-data_test.md +94 -0
  125. md_processing/dr_egeria_outbox/processed-2025-05-19 07:14-data_test.md +96 -0
  126. md_processing/dr_egeria_outbox/processed-2025-05-19 07:20-data_test.md +100 -0
  127. md_processing/dr_egeria_outbox/processed-2025-05-19 07:22-data_test.md +88 -0
  128. md_processing/dr_egeria_outbox/processed-2025-05-19 09:26-data_test.md +91 -0
  129. md_processing/dr_egeria_outbox/processed-2025-05-19 10:27-data_test.md +91 -0
  130. md_processing/dr_egeria_outbox/processed-2025-05-19 14:04-data_test.md +91 -0
  131. md_processing/md_commands/__init__.py +3 -0
  132. md_processing/md_commands/blueprint_commands.py +303 -0
  133. md_processing/md_commands/data_designer_commands.py +1182 -0
  134. md_processing/md_commands/glossary_commands.py +1144 -0
  135. md_processing/md_commands/project_commands.py +163 -0
  136. md_processing/md_processing_utils/__init__.py +4 -0
  137. md_processing/md_processing_utils/common_md_proc_utils.py +724 -0
  138. md_processing/md_processing_utils/common_md_utils.py +172 -0
  139. md_processing/md_processing_utils/extraction_utils.py +486 -0
  140. md_processing/md_processing_utils/md_processing_constants.py +128 -0
  141. md_processing/md_processing_utils/message_constants.py +19 -0
  142. pyegeria/.DS_Store +0 -0
  143. pyegeria/__init__.py +231 -146
  144. pyegeria/_client.py +36 -13
  145. pyegeria/_exceptions.py +55 -46
  146. pyegeria/_globals.py +11 -1
  147. pyegeria/_validators.py +5 -5
  148. pyegeria/asset_catalog_omvs.py +78 -21
  149. pyegeria/automated_curation_omvs.py +11 -6
  150. pyegeria/classification_manager_omvs.py +41 -37
  151. pyegeria/collection_manager_omvs.py +722 -705
  152. pyegeria/core_omag_server_config.py +1 -1
  153. pyegeria/create_tech_guid_lists.py +13 -13
  154. pyegeria/data_designer_omvs.py +5104 -0
  155. pyegeria/dr.egeria spec.md +9 -0
  156. pyegeria/egeria_cat_client.py +5 -8
  157. pyegeria/egeria_client.py +39 -24
  158. pyegeria/egeria_config_client.py +2 -1
  159. pyegeria/egeria_my_client.py +4 -4
  160. pyegeria/egeria_tech_client.py +40 -18
  161. pyegeria/feedback_manager_omvs.py +1 -1
  162. pyegeria/full_omag_server_config.py +5 -3
  163. pyegeria/glossary_browser_omvs.py +1915 -694
  164. pyegeria/glossary_manager_omvs.py +685 -1842
  165. pyegeria/m_test.py +118 -0
  166. pyegeria/md_processing_helpers.py +58 -0
  167. pyegeria/md_processing_utils.py +2147 -0
  168. pyegeria/md_processing_utils_orig.py +1103 -0
  169. pyegeria/mermaid_utilities.py +1194 -14
  170. pyegeria/metadata_explorer_omvs.py +5 -50
  171. pyegeria/my_profile_omvs.py +3 -2
  172. pyegeria/output_formatter.py +389 -0
  173. pyegeria/platform_services.py +5 -5
  174. pyegeria/project_manager_omvs.py +97 -18
  175. pyegeria/runtime_manager_omvs.py +8 -10
  176. pyegeria/server_operations.py +2 -2
  177. pyegeria/solution_architect_omvs.py +2156 -0
  178. pyegeria/template_manager_omvs.py +13 -13
  179. pyegeria/utils.py +3 -1
  180. pyegeria/valid_metadata_omvs.py +5 -4
  181. pyegeria/x_action_author_omvs.py +3 -6
  182. {pyegeria-5.2.1.dist-info → pyegeria-5.3.dist-info}/METADATA +9 -8
  183. pyegeria-5.3.dist-info/RECORD +196 -0
  184. {pyegeria-5.2.1.dist-info → pyegeria-5.3.dist-info}/WHEEL +1 -1
  185. pyegeria-5.3.dist-info/entry_points.txt +99 -0
  186. pyegeria/commands/README.md +0 -47
  187. pyegeria/commands/__init__.py +0 -22
  188. pyegeria/commands/cat/__init__.py +0 -1
  189. pyegeria/commands/doc/README.md +0 -145
  190. pyegeria/commands/doc/Visual Command Reference/README.md +0 -511
  191. pyegeria/commands/doc/Visual Command Reference/cat/show/assets/asset-graph 2024-11-20 at 15.56.42.png +0 -0
  192. pyegeria/commands/doc/Visual Command Reference/cat/show/assets/assets-in-domain 2024-11-20 at 15.49.55@2x.png +0 -0
  193. pyegeria/commands/doc/Visual Command Reference/cat/show/assets/elements-of-type 2024-11-20 at 16.01.35.png +0 -0
  194. pyegeria/commands/doc/Visual Command Reference/cat/show/assets/tech-type-elements 2024-11-20 at 16.05.05.png +0 -0
  195. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-data-catalogs 2024-12-17 at 15.43.27@2x.png +0 -0
  196. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-data-catalogs-2024-11-20 at 16.17.43@2x.png +0 -0
  197. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-schemas 2024-11-25 at 20.14.50@2x.png +0 -0
  198. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-schemas 2024-12-17 at 15.48.38@2x.png +0 -0
  199. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-servers 2024-11-25 at 20.21.25@2x.png +0 -0
  200. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed-servers 2024-12-17 at 15.52.16@2x.png +0 -0
  201. pyegeria/commands/doc/Visual Command Reference/cat/show/deployed-data/deployed_databases 2024-12-16 at 16.40.31@2x.png +0 -0
  202. pyegeria/commands/doc/Visual Command Reference/cat/show/glossary/list-glossaries 2024-11-25 at 20.30.02.png +0 -0
  203. pyegeria/commands/doc/Visual Command Reference/cat/show/glossary/list-terms 2024-11-25 at 20.32.11.png +0 -0
  204. pyegeria/commands/doc/Visual Command Reference/cat/show/info/asset-types 2024-11-25 at 20.34.19@2x.png +0 -0
  205. pyegeria/commands/doc/Visual Command Reference/cat/show/info/certification-types 2024-11-25 at 20.37.07.png +0 -0
  206. pyegeria/commands/doc/Visual Command Reference/cat/show/info/collection-graph 2024-12-12 at 11.33.18@2x.png +0 -0
  207. pyegeria/commands/doc/Visual Command Reference/cat/show/info/list-collections 2024-12-10 at 14.25.51@2x.png +0 -0
  208. pyegeria/commands/doc/Visual Command Reference/cat/show/info/list-todos 2024-12-12 at 11.46.30@2x.png +0 -0
  209. pyegeria/commands/doc/Visual Command Reference/cat/show/info/list-user-ids 2024-12-12 at 11.51.09@2x.png +0 -0
  210. pyegeria/commands/doc/Visual Command Reference/cat/show/info/tech-types 2024-12-12 at 11.37.20@2x.png +0 -0
  211. pyegeria/commands/doc/Visual Command Reference/cat/show/projects/project_dependencies 2024-12-14 at 16.24.39@2x.png +0 -0
  212. pyegeria/commands/doc/Visual Command Reference/cat/show/projects/project_structure 2024-12-14 at 16.21.35@2x.png +0 -0
  213. pyegeria/commands/doc/Visual Command Reference/cat/show/projects/projects 2024-12-14 at 16.18.10@2x.png +0 -0
  214. pyegeria/commands/doc/Visual Command Reference/hey_egeria tui 2024-12-16 at 16.58.22@2x.png +0 -0
  215. pyegeria/commands/doc/Visual Command Reference/my/show/my_profile 2024-12-14 at 16.29.27@2x.png +0 -0
  216. pyegeria/commands/doc/Visual Command Reference/my/show/my_roles 2024-12-14 at 16.32.10@2x.png +0 -0
  217. pyegeria/commands/doc/Visual Command Reference/my/show/my_todos 2024-12-15 at 16.24.13@2x.png +0 -0
  218. pyegeria/commands/doc/Visual Command Reference/my/show/open_todos 2024-12-14 at 16.36.12@2x.png +0 -0
  219. pyegeria/commands/doc/Visual Command Reference/ops/show/engines/list_engine_activity compressed 2024-12-15 at 16.48.48@2x.png +0 -0
  220. pyegeria/commands/doc/Visual Command Reference/ops/show/engines/monitor_engine_activity 2024-12-15 at 16.32.55@2x.png +0 -0
  221. pyegeria/commands/doc/Visual Command Reference/ops/show/engines/monitor_engine_activity compressed 2024-12-15 at 16.38.29@2x.png +0 -0
  222. pyegeria/commands/doc/Visual Command Reference/ops/show/engines/monitor_engine_status 2024-12-15 at 16.51.26.jpeg +0 -0
  223. pyegeria/commands/doc/Visual Command Reference/ops/show/integrations/monitor_integration_daemon_status 2024-12-15 at 16.57.12@2x.png +0 -0
  224. pyegeria/commands/doc/Visual Command Reference/ops/show/integrations/monitor_integration_targets 2024-12-15 at 17.02.19@2x.png +0 -0
  225. pyegeria/commands/doc/Visual Command Reference/ops/show/platforms/monitor_platform_status 2024-12-15 at 19.53.18@2x.png +0 -0
  226. pyegeria/commands/doc/Visual Command Reference/ops/show/servers/monitor_server_status 2024-12-15 at 19.59.39@2x.png +0 -0
  227. pyegeria/commands/doc/Visual Command Reference/ops/show/servers/monitor_server_status full 2024-12-15 at 20.01.57@2x.png +0 -0
  228. pyegeria/commands/doc/Visual Command Reference/ops/show/servers/monitor_startup_servers 2024-12-15 at 19.56.07@2x.png +0 -0
  229. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/get_anchored_elements 2024-12-15 at 21.25.41@2x.png +0 -0
  230. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/get_elements_of_om_type 2024-12-16 at 14.39.59@2x.png +0 -0
  231. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/info_for_guid 2024-12-16 at 11.35.29@2x.png +0 -0
  232. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/list_elements_by_om-type 2024-12-16 at 14.24.18@2x.png +0 -0
  233. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/list_elements_by_om-type extended 2024-12-16 at 14.28.46@2x.png +0 -0
  234. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/list_elements_of_om_type_by_classification 2024-12-16 at 14.35.26@2x.png +0 -0
  235. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/related_elements 2024-12-16 at 14.55.01@2x.png +0 -0
  236. pyegeria/commands/doc/Visual Command Reference/tech/show/elements/show_related_specifications 2024-12-16 at 15.04.55@2x.png +0 -0
  237. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/asset_types 2024-12-16 at 15.10.16@2x.png +0 -0
  238. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/detailed_governance_action_processes 2024-12-16 at 15.16.26@2x.png +0 -0
  239. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/governance_action_processes 2024-12-16 at 15.13.01@2x.png +0 -0
  240. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/registered_services 2024-12-16 at 16.44.54@2x.png +0 -0
  241. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/relationship_types 2024-12-16 at 16.20.34@2x.png +0 -0
  242. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/relationship_types 2024-12-19 at 10.51.54@2x.png +0 -0
  243. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-info/valid_metadata_values 2024-12-16 at 15.31.56@2x.png +0 -0
  244. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-types/list_tech_type_template_specs 2024-12-16 at 16.03.22@2x.png +0 -0
  245. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-types/list_technology_types 2024-12-16 at 15.39.20@2x.png +0 -0
  246. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-types/tech_type_details 2024-12-16 at 15.37.21@2x.png +0 -0
  247. pyegeria/commands/doc/Visual Command Reference/tech/show/tech-types/tech_type_templates 2024-12-16 at 16.11.48@2x.png +0 -0
  248. pyegeria/commands/doc/glossary/basic-glossary-tui.md +0 -109
  249. pyegeria/commands/doc/glossary/images/delete-glossary-step1 2024-11-06 at 15.47.23@2x.png +0 -0
  250. pyegeria/commands/doc/glossary/images/delete-glossary-step2 2024-11-06 at 15.51.29@2x.png +0 -0
  251. pyegeria/commands/doc/glossary/images/delete-glossary-step3 2024-11-06 at 15.53.19@2x.png +0 -0
  252. pyegeria/commands/doc/glossary/images/delete-glossary-step4 2024-11-06 at 15.55.11@2x.png +0 -0
  253. pyegeria/commands/doc/glossary/images/out-create-glossary example 2024-11-05 at 20.38.04@2x.png +0 -0
  254. pyegeria/commands/doc/glossary/images/out-create-term 2024-11-06 at 20.48.29.png +0 -0
  255. pyegeria/commands/doc/glossary/images/out-delete-term 2024-11-07 at 03.57.25.png +0 -0
  256. pyegeria/commands/doc/glossary/images/out-display-terms-for-glossary-test 2024-11-06 at 20.51.28.png +0 -0
  257. pyegeria/commands/doc/glossary/images/out-export-example 2024-11-07 at 09.54.57.png +0 -0
  258. pyegeria/commands/doc/glossary/images/out-exported-terms 2024-11-06 at 21.06.32.png +0 -0
  259. pyegeria/commands/doc/glossary/images/out-glossary-list example 2024-11-05 at 20.41.02@2x.png +0 -0
  260. pyegeria/commands/doc/glossary/images/out-import-terms 2024-11-07 at 08.15.18.png +0 -0
  261. pyegeria/commands/doc/glossary/images/out-list-all-terms 2024-11-06 at 16.22.20@2x.png +0 -0
  262. pyegeria/commands/doc/glossary/images/out-list-terms-for-example 2024-11-06 at 16.40.12.png +0 -0
  263. pyegeria/commands/doc/glossary/images/out-list-terms-second 2024-11-06 at 16.45.13.png +0 -0
  264. pyegeria/commands/doc/glossary/images/out-pipx install pyegeria 2024-11-10 at 18.12.21.png +0 -0
  265. pyegeria/commands/doc/glossary/images/out-server-status-full 2024-11-10 at 18.25.14.png +0 -0
  266. pyegeria/commands/doc/glossary/images/out-servers-status 2024-11-10 at 18.15.42.png +0 -0
  267. pyegeria/commands/doc/glossary/images/out-upsert-import 2024-11-07 at 19.37.00.png +0 -0
  268. pyegeria/commands/doc/glossary/images/tui-2024-11-10 at 18.26.29.png +0 -0
  269. pyegeria/commands/doc/glossary/images/tui-create-glossary example 2024-11-05 at 20.34.24@2x.png +0 -0
  270. pyegeria/commands/doc/glossary/images/tui-create-term 2024-11-06 at 20.46.35.png +0 -0
  271. pyegeria/commands/doc/glossary/images/tui-delete-term 2024-11-07 at 03.51.57.png +0 -0
  272. pyegeria/commands/doc/glossary/images/tui-display-terms-for-example 2024-11-06 at 20.56.49.png +0 -0
  273. pyegeria/commands/doc/glossary/images/tui-export-example 2024-11-07 at 09.52.59.png +0 -0
  274. pyegeria/commands/doc/glossary/images/tui-hey-egeria 2024-11-10 at 18.31.01.png +0 -0
  275. pyegeria/commands/doc/glossary/images/tui-import-upsert-example 2024-11-07 at 10.08.37.png +0 -0
  276. pyegeria/commands/doc/glossary/images/tui-list-terms-second 2024-11-06 at 16.46.34.png +0 -0
  277. pyegeria/commands/doc/glossary/images/tui-load-archive.png +0 -0
  278. pyegeria/commands/doc/glossary/images/tui-server-status-full 2024-11-10 at 19.14.36.png +0 -0
  279. pyegeria/commands/doc/glossary/images/tui-show-glossaries 2024-11-07 at 20.00.05.png +0 -0
  280. pyegeria/commands/doc/glossary/images/tui-show-glossary-terms 2024-11-05 at 19.37.53@2x.png +0 -0
  281. pyegeria/commands/doc/glossary/images/tui-upsert 2024-11-07 at 11.49.04.png +0 -0
  282. pyegeria/commands/doc/glossary/images/upsert-example.om-terms 2024-11-07 at 11.44.05.png +0 -0
  283. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/README.md +0 -346
  284. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/CleanShot 2024-11-18 at 21.32.03@2x.png +0 -0
  285. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/Xmind 1731421782704.png +0 -0
  286. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/Xmind 1731422134920.png +0 -0
  287. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/hey_egeria 2024-11-12 at 20.38.43.png +0 -0
  288. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/hey_egeria cat 2024-11-12 at 21.41.43.png +0 -0
  289. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/out-integ-status-list 2024-11-12 at 16.45.26.png +0 -0
  290. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/out-integ-status-live 2024-11-12 at 16.44.12@2x.png +0 -0
  291. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/out-server-status 2024-11-10 at 18.15.42@2x.png +0 -0
  292. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/out-server-status-full 2024-11-10 at 18.25.14@2x.png +0 -0
  293. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/short-cut commands 2024-11-12 at 22.22.13.png +0 -0
  294. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-hey-egeria.png +0 -0
  295. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-integration-status-paging.png +0 -0
  296. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-load-archive 2024-11-10 at 19.19.09@2x.png +0 -0
  297. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-show-server-status 2024-11-10 at 18.52.01@2x.png +0 -0
  298. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-show-server-status-full 2024-11-10.png +0 -0
  299. pyegeria/commands/doc/hey_egeria: a pyegeria command line interface/images/tui-status-paging 2024-11-12 at 16.26.14@2x.png +0 -0
  300. pyegeria/commands/ops/__init__.py +0 -22
  301. pyegeria/commands/tech/__init__.py +0 -0
  302. pyegeria-5.2.1.dist-info/RECORD +0 -232
  303. pyegeria-5.2.1.dist-info/entry_points.txt +0 -81
  304. {pyegeria/commands → commands}/cat/README.md +0 -0
  305. {pyegeria/commands → commands}/cli/txt_custom_v2.tcss +0 -0
  306. {pyegeria/commands → commands}/my/README.md +0 -0
  307. {pyegeria/commands → commands}/ops/README.md +0 -0
  308. {pyegeria/commands → commands}/ops/x_engine_actions.py +0 -0
  309. {pyegeria/commands → commands}/tech/README.md +0 -0
  310. /pyegeria/commands/my/__init__.py → /md_processing/dr_egeria_inbox/t1.md +0 -0
  311. {pyegeria-5.2.1.dist-info → pyegeria-5.3.dist-info}/LICENSE +0 -0
@@ -0,0 +1,2147 @@
1
+ """
2
+
3
+ This file contains functions to parse and process Egeria Markdown (Freddie)
4
+
5
+
6
+ """
7
+ import json
8
+ import os
9
+ import re
10
+ import sys
11
+ from datetime import datetime
12
+ from typing import List, Optional, Any
13
+
14
+ from rich import print
15
+ from rich.console import Console
16
+ from rich.markdown import Markdown
17
+
18
+ from pyegeria import body_slimmer
19
+ from pyegeria._globals import (NO_GLOSSARIES_FOUND, NO_ELEMENTS_FOUND, NO_PROJECTS_FOUND, NO_CATEGORIES_FOUND, DEBUG_LEVEL)
20
+ from pyegeria.egeria_tech_client import EgeriaTech
21
+ from md_processing.md_processing_utils.md_processing_constants import (message_types,
22
+ pre_command, EXISTS_REQUIRED, load_commands, get_command_spec, get_attribute, get_attribute_labels, get_alternate_names)
23
+
24
+
25
+ from pyegeria.project_manager_omvs import ProjectManager
26
+
27
+ ALWAYS = "ALWAYS"
28
+ ERROR = "ERROR"
29
+ INFO = "INFO"
30
+ WARNING = "WARNING"
31
+ pre_command = "\n---\n==> Processing object_action:"
32
+ command_seperator = Markdown("\n---\n")
33
+ EXISTS_REQUIRED = "Exists Required"
34
+
35
+
36
+ EGERIA_WIDTH = int(os.environ.get("EGERIA_WIDTH", "170"))
37
+ console = Console(width=EGERIA_WIDTH)
38
+
39
+ command_list = ["Provenance", "Create Glossary", "Update Glossary", "Create Term", "Update Term", "List Terms", "List Term Details",
40
+ "List Glossary Terms", "List Term History", "List Term Revision History", "List Term Update History",
41
+ "List Glossary Structure", "List Glossaries", "List Categories", "List Glossary Categories",
42
+ "Create Personal Project", "Update Personal Project", "Create Category", "Update Category",
43
+ "Create Solution Blueprint", "Update Solution Blueprint", "Create Solution Component",
44
+ "Update Solution Component", "Create Term-Term Relationship", "Update Term-Term Relationship",]
45
+ # verbosity - verbose, quiet, debug
46
+
47
+ message_types = {
48
+ "INFO": "INFO-", "WARNING": "WARNING->", "ERROR": "ERROR->", "DEBUG-INFO": "DEBUG-INFO->",
49
+ "DEBUG-WARNING": "DEBUG-WARNING->", "DEBUG-ERROR": "DEBUG-ERROR->", "ALWAYS": "\n\n==> "
50
+ }
51
+ ALWAYS = "ALWAYS"
52
+ ERROR = "ERROR"
53
+ INFO = "INFO"
54
+ WARNING = "WARNING"
55
+ pre_command = "\n---\n==> Processing object_action:"
56
+ command_seperator = Markdown("\n---\n")
57
+ EXISTS_REQUIRED = "Exists Required"
58
+
59
+ GLOSSARY_NAME_LABELS = ["Glossary Name", "Glossary", "Glossaries", "Owning Glossary", "In Glossary"]
60
+ CATEGORY_NAME_LABELS = ["Glossary Category Name", "Glossary Category", "Glossary Categories", "Category Name",
61
+ "Category", "Categories"]
62
+ PARENT_CATEGORY_LABELS = ["Parent Category Name", "Parent Category", "parent category name", "parent category"]
63
+ CHILD_CATEGORY_LABELS = ["Child Categories", "Child Category", "child category names", "child categories",
64
+ "Child Category Names"]
65
+ TERM_NAME_LABELS = ["Glossary Term Name", "Glossary Term", "Glossary Terms", "Term Name", "Term", "Terms", "Term Names"]
66
+ PROJECT_NAME_LABELS = ["Project Name", "Project", "Project Names", "Projects"]
67
+ BLUEPRINT_NAME_LABELS = ["Solution Blueprint Name", "Solution Blueprint", "Solution Blueprints", "Blueprint Name",
68
+ "Blueprint", "Blueprints"]
69
+ COMPONENT_NAME_LABELS = ["Solution Component Name", "Solution Component", "Solution Components", "Component Name",
70
+ "Component", "Components", "Parent Components", "Parent Component"]
71
+ SOLUTION_ROLE_LABELS = ["Solution Role Name", "Solution Role", "Solution Roles", "Role Name", "Role", "Roles"]
72
+ SOLUTION_ACTOR_ROLE_LABELS = ["Solution Actor Role Name", "Solution Actor Role Names", "Solution Actor Role",
73
+ "Solution Actor Roles", "Actor Role Name", "Actor Role", "Actor Roles",
74
+ "Actor Role Names"]
75
+ SOLUTION_LINKING_ROLE_LABELS = ["Solution Linking Role Name", "Solution Linking Role Names", "Solution Linking Role",
76
+ "Solution Linking Roles", "Linking Role Name", "Linking Role", "Linking Roles",
77
+ "Linking Role Names"]
78
+ OUTPUT_LABELS = ["Output", "Output Format"]
79
+ SEARCH_LABELS = ['Search String', 'Filter']
80
+ GUID_LABELS = ['GUID', 'guid']
81
+
82
+ ELEMENT_OUTPUT_FORMATS = ["LIST", "DICT", "MD", "FORM", "REPORT"]
83
+ TERM_RELATIONSHPS = [
84
+ "Synonym",
85
+ "Translation",
86
+ "PreferredTerm",
87
+ "TermISATYPEOFRelationship",
88
+ "TermTYPEDBYRelationship",
89
+ "Antonym",
90
+ "ReplacementTerm",
91
+ "ValidValue",
92
+ "TermHASARelationship",
93
+ "RelatedTerm",
94
+ "ISARelationship"
95
+ ]
96
+
97
+ # Dictionary to store element information to avoid redundant API calls
98
+ element_dictionary = {}
99
+
100
+
101
+ def get_element_dictionary():
102
+ """
103
+ Get the shared element dictionary.
104
+
105
+ Returns:
106
+ dict: The shared element dictionary
107
+ """
108
+ global element_dictionary
109
+ return element_dictionary
110
+
111
+
112
+ def update_element_dictionary(key, value):
113
+ """
114
+ Update the shared element dictionary with a new key-value pair.
115
+
116
+ Args:
117
+ key (str): The key to update
118
+ value (dict): The value to associate with the key
119
+ """
120
+ global element_dictionary
121
+ if (key is None or value is None):
122
+ print(f"===>ERROR Key is {key} and value is {value}")
123
+ return
124
+ element_dictionary[key] = value
125
+
126
+
127
+ def clear_element_dictionary():
128
+ """
129
+ Clear the shared element dictionary.
130
+ """
131
+ global element_dictionary
132
+ element_dictionary.clear()
133
+
134
+
135
+ def is_present(value: str) -> bool:
136
+ global element_dictionary
137
+ present = value in element_dictionary.keys() or any(
138
+ value in inner_dict.values() for inner_dict in element_dictionary.values())
139
+ return present
140
+
141
+
142
+ def find_key_with_value(value: str) -> str | None:
143
+ """
144
+ Finds the top-level key whose nested dictionary contains the given value.
145
+
146
+ Args:
147
+ data (dict): A dictionary where keys map to nested dictionaries.
148
+ value (str): The value to search for.
149
+
150
+ Returns:
151
+ str | None: The top-level key that contains the value, or None if not found.
152
+ """
153
+ global element_dictionary
154
+ # Check if the value matches a top-level key
155
+ if value in element_dictionary.keys():
156
+ return value
157
+
158
+ # Check if the value exists in any of the nested dictionaries
159
+ for key, inner_dict in element_dictionary.items():
160
+ if value in inner_dict.values():
161
+ return key
162
+
163
+ return None # If value not found
164
+
165
+
166
+
167
+
168
+ def render_markdown(markdown_text: str) -> None:
169
+ """Renders the given markdown text in the console."""
170
+ console.print(Markdown(markdown_text))
171
+
172
+
173
+ def is_valid_iso_date(date_text) -> bool:
174
+ """Checks if the given string is a valid ISO date."""
175
+ try:
176
+ datetime.strptime(date_text, '%Y-%m-%d')
177
+ return True
178
+ except ValueError:
179
+ return False
180
+
181
+ debug_level = DEBUG_LEVEL
182
+
183
+ def set_debug_level(directive: str) -> None:
184
+ """Sets the debug level for the script."""
185
+ global debug_level
186
+ if directive == "display":
187
+ debug_level = "display-only"
188
+
189
+
190
+ def get_current_datetime_string():
191
+ """Returns the current date and time as a human-readable string."""
192
+ now = datetime.now().strftime('%Y-%m-%d %H:%M')
193
+ return now
194
+
195
+
196
+ def update_term_categories(egeria_client: EgeriaTech, term_guid: str, categories_exist: bool,
197
+ categories_list: List[str]) -> None:
198
+ """
199
+
200
+ Adds or removes a term to/from specified categories in a glossary.
201
+
202
+ This function associates a term, identified by its GUID, with one or more
203
+ categories. It uses the provided EgeriaTech client to assign the term
204
+ to the categories. If the GUID of a category is not readily available, it
205
+ is retrieved either from a pre-loaded dictionary or through a client lookup.
206
+
207
+ Args:
208
+ egeria_client (EgeriaTech): The client to interact with the glossary.
209
+ term_guid (str): The GUID of the term to be associated with categories.
210
+ categories_exist (bool): Flag indicating whether the categories already
211
+ exist.
212
+ categories_list (List[str]): A list of category names to associate with
213
+ the term.
214
+
215
+ Returns:
216
+ None
217
+ """
218
+ to_be_cat_guids: list[str] = []
219
+ # find the categories a term is currently in.
220
+ existing_categories = egeria_client.get_categories_for_term(term_guid)
221
+ if type(existing_categories) is str:
222
+ current_categories = []
223
+ else:
224
+ current_categories = [cat['elementHeader']['guid'] for cat in existing_categories]
225
+
226
+ if categories_exist is True and categories_list is not None:
227
+ if type(categories_list) is str:
228
+ categories_list = categories_list.split(",").trim()
229
+ for category in categories_list:
230
+ cat_guid = None
231
+ cat_el = category.strip()
232
+ element_dict = get_element_dictionary()
233
+ if cat_el in element_dict:
234
+ cat = element_dict.get(cat_el, None)
235
+ cat_guid = cat.get('guid', None) if cat else None
236
+ if cat_guid is None:
237
+ cat_guid = egeria_client.__get_guid__(qualified_name=cat_el)
238
+ update_element_dictionary(cat_el, {'guid': cat_guid})
239
+ to_be_cat_guids.append(cat_guid)
240
+
241
+ for cat in to_be_cat_guids:
242
+ if cat not in current_categories:
243
+ egeria_client.add_term_to_category(term_guid, cat)
244
+ current_categories.append(cat)
245
+ msg = f"Added term {term_guid} to category {cat}"
246
+ print_msg("DEBUG-INFO", msg, debug_level)
247
+
248
+ for cat in current_categories:
249
+ if cat not in to_be_cat_guids:
250
+ egeria_client.remove_term_from_category(term_guid, cat)
251
+ msg = f"Removed term {term_guid} from category {cat}"
252
+ print_msg("DEBUG-INFO", msg, debug_level)
253
+ else: # No categories specified - so remove any categories a term is in
254
+ for cat in current_categories:
255
+ egeria_client.remove_term_from_category(term_guid, cat)
256
+ msg = f"Removed term {term_guid} from category {cat}"
257
+ print_msg("DEBUG-INFO", msg, debug_level)
258
+
259
+
260
+ def extract_command_plus(block: str) -> tuple[str, str, str] | None:
261
+ """
262
+ Extracts a multi-word object and its associated action from the given block of text.
263
+
264
+ This function searches for a pattern in the format of `#...##` or `#...\n`
265
+ inside the provided string `block`. The matched pattern is split into
266
+ two parts: the action and the object type. The action is expected to
267
+ be the first part, while the rest is treated as the object type. If
268
+ no match is found, the function returns None.
269
+
270
+ Lines beginning with '>' are ignored.
271
+
272
+ Args:
273
+ block: A string containing the block of text to search for the
274
+ object_action and action.
275
+
276
+ Returns:
277
+ A tuple containing the object_action, the object type and the object action if a
278
+ match is found. Otherwise, returns None.
279
+ """
280
+ # Filter out lines beginning with '>'
281
+ filtered_lines = [line for line in block.split('\n') if not line.strip().startswith('>')]
282
+ filtered_block = '\n'.join(filtered_lines)
283
+
284
+ match = re.search(r"#(.*?)(?:##|\n|$)", filtered_block) # Using a non capturing group
285
+ if match:
286
+ clean_match = match.group(1).strip()
287
+ if ' ' in clean_match:
288
+ parts = clean_match.split(' ')
289
+ object_action = parts[0].strip()
290
+ # Join the rest of the parts to allow object_type to be one or two words
291
+ object_type = ' '.join(parts[1:]).strip()
292
+ else:
293
+ object_type = clean_match.split(' ')[1].strip()
294
+ object_action = clean_match.split(' ')[0].strip()
295
+
296
+ return clean_match, object_type, object_action
297
+ return None
298
+
299
+
300
+ def extract_command(block: str) -> str | None:
301
+ """
302
+ Extracts a object_action from a block of text that is contained between a single hash ('#') and
303
+ either a double hash ('##'), a newline character, or the end of the string.
304
+
305
+ The function searches for a specific pattern within the block of text and extracts the
306
+ content that appears immediately after a single hash ('#'). Ensures that the extracted
307
+ content is appropriately trimmed of leading or trailing whitespace, if present.
308
+
309
+ Args:
310
+ block: A string representing the block of text to process. Contains the content
311
+ in which the object_action and delimiters are expected to be present.
312
+
313
+ Returns:
314
+ The extracted object_action as a string if a match is found, otherwise None.
315
+ """
316
+ match = re.search(r"#(.*?)(?:##|\n|$)", block) # Using a non capturing group
317
+ if match:
318
+ return match.group(1).strip()
319
+ return None
320
+
321
+
322
+ def extract_attribute(text: str, labels: list[str]) -> str | None:
323
+ """
324
+ Extracts the attribute value from a string.
325
+
326
+ Args:
327
+ text: The input string.
328
+ labels: List of equivalent labels to search for
329
+
330
+ Returns:
331
+ The value of the attribute, or None if not found.
332
+
333
+ Note:
334
+ Lines beginning with '>' are ignored.
335
+ """
336
+ # Iterate over the list of labels
337
+ for label in labels:
338
+ # Construct pattern for the current label
339
+ pattern = rf"## {re.escape(label)}\n(.*?)(?:#|___|>|$)" # modified from --- to enable embedded tables
340
+ match = re.search(pattern, text, re.DOTALL)
341
+ if match:
342
+ # Extract matched text
343
+ matched_text = match.group(1).strip()
344
+
345
+ # Filter out lines beginning with '>'
346
+ filtered_lines = [line for line in matched_text.split('\n') if not line.strip().startswith('>')]
347
+ filtered_text = '\n'.join(filtered_lines)
348
+
349
+ # Replace consecutive \n with a single \n
350
+ extracted_text = re.sub(r'\n+', '\n', filtered_text)
351
+ if not extracted_text.isspace() and extracted_text:
352
+ return extracted_text.trim() # Return the cleaned text - I removed the title casing
353
+
354
+ return None
355
+
356
+
357
+ def print_msg(msg_level: str, msg: str, verbosity: str):
358
+ """
359
+ Prints a message based on its type and verbosity level.
360
+
361
+ This function handles the output of messages depending on the specified
362
+ verbosity level and message type. It uses predefined message types and
363
+ formats the output accordingly.
364
+
365
+ Args:
366
+ msg_type: The type of the message, such as 'WARNING', 'ERROR', 'INFO', or
367
+ 'ALWAYS'.
368
+ msg: The content of the message to display.
369
+ verbosity: The verbosity level, which determines how the message is
370
+ displayed ('verbose', 'quiet', or 'debug').
371
+ """
372
+ msg_level = msg_level.upper()
373
+ record = f"{message_types[msg_level]} {msg}"
374
+ if msg_level in ("WARNING", "ERROR", "INFO"):
375
+ record = f"* {record}"
376
+
377
+ match verbosity.lower():
378
+ case "verbose":
379
+ if msg_level in ("WARNING", "ERROR", "INFO", "ALWAYS"):
380
+ print(record)
381
+ case "quiet":
382
+ if msg_level in ("WARNING", "ERROR", "ALWAYS"):
383
+ print(record)
384
+ case "debug":
385
+ print(record)
386
+ case "display-only":
387
+ pass
388
+ case _:
389
+ print("Invalid verbosity level - exiting\n")
390
+ sys.exit(1)
391
+
392
+
393
+ def process_simple_attribute(txt: str, labels: list[str], if_missing: str = INFO) -> str | None:
394
+ """Process a simple attribute based on the provided labels and if_missing value.
395
+ Extract the attribute value from the text and return it if it exists.
396
+ If it doesn`t exist, return None and print an error message with severity of if_missing.
397
+
398
+ Parameters:
399
+ ----------
400
+ txt: str
401
+ The block of object_action text to extract attributes from.
402
+ labels: list
403
+ The possible attribute labels to search for. The first label will be used in messages.
404
+ if_missing: str, default is INFO
405
+ Can be one of "WARNING", "ERROR", "INFO". The severity of the missing attribute.
406
+ """
407
+ if if_missing not in ["WARNING", "ERROR", "INFO"]:
408
+ print_msg("ERROR", "Invalid severity for missing attribute", debug_level)
409
+ return None
410
+
411
+ attribute = extract_attribute(txt, labels)
412
+
413
+ if attribute is None:
414
+ if if_missing == INFO:
415
+ msg = f"Optional attribute {labels[0]} missing"
416
+ else:
417
+ msg = f"Missing {labels[0]} attribute"
418
+ print_msg(if_missing, msg, debug_level)
419
+ return None
420
+ return attribute
421
+
422
+
423
+ def update_a_command(txt: str, command: str, obj_type: str, q_name: str, u_guid: str) -> str:
424
+ """
425
+ Updates a object_action by modifying the input text with corresponding actions, GUID, and qualified name.
426
+ The function processes the provided object_action based on the given parameters, updating the relevant
427
+ sections in the text, including object_action actions, GUID, qualified name, and optionally the status
428
+ of the attributes. It ensures that proper formatting and necessary fields are present in the text.
429
+
430
+ Args:
431
+ txt (str): The input text containing the content to be updated.
432
+ command (str): The object_action to be processed (e.g., "Create Term", "Update Term").
433
+ obj_type (str): The object type related to the object_action (e.g., "Term", "Category").
434
+ q_name (str): The qualified name to be added or updated in the text.
435
+ u_guid (str): The unique identifier (GUID) to be added or updated in the text. If not provided,
436
+ it defaults to an empty string.
437
+
438
+ Returns:
439
+ str: The updated text containing the modifications based on the provided object_action.
440
+
441
+ """
442
+ u_guid = u_guid if u_guid else " "
443
+ verb = command.split(' ')[0].strip()
444
+ action = "Update" if (verb == "Create" and u_guid is not None) else "Create"
445
+ txt = txt.replace(f"{command}", f'{action} {obj_type}\n') # update the object_action
446
+
447
+ if "Qualified Name" not in txt:
448
+ txt += f"\n## Qualified Name\n{q_name}\n"
449
+ if "GUID" not in txt:
450
+ txt += f"\n## GUID\n{u_guid}\n"
451
+
452
+ status = extract_attribute(txt, ["Status"])
453
+ if command in ["Create Term", "Update Term"] and status is None:
454
+ pattern = r"(## Status\s*\n)(.*?)(#)"
455
+ replacement = r"\1\n DRAFT\n\n\3"
456
+ txt = re.sub(pattern, replacement, txt)
457
+ return txt
458
+
459
+
460
+ def process_provenance_command(file_path: str, txt: [str]) -> str:
461
+ """This md_commands processes a provenence object_action by pre-pending the current file name and time to the provenance
462
+ output"""
463
+ output = (f"* Derived from processing file {file_path} on "
464
+ f"{get_current_datetime_string()}\n")
465
+ pattern = rf"# {re.escape('Provenance')}\n(.*?)(?:#|---|$)"
466
+ match = re.search(pattern, txt, re.DOTALL)
467
+ if match:
468
+ # Extract matched text and replace consecutive \n with a single \n
469
+ extracted_text = re.sub(r'\n+', '\n', match.group(1).strip())
470
+ if not extracted_text.isspace() and extracted_text:
471
+ existing_prov = extracted_text # Return the cleaned text
472
+ else:
473
+ existing_prov = None
474
+
475
+ existing_prov = existing_prov if existing_prov else " "
476
+ return f"\n# Provenance:\n{existing_prov}\n{output}\n"
477
+
478
+
479
+ def process_element_identifiers(egeria_client: EgeriaTech, element_type: str, element_labels: list[str], txt: str,
480
+ action: str, version: str = None) -> tuple[str, str, bool, bool]:
481
+ """
482
+ Processes element identifiers by extracting display name and qualified name from the input text,
483
+ checking if the element exists in Egeria, and validating the information.
484
+
485
+ Parameters
486
+ ----------
487
+ egeria_client: EgeriaTech
488
+ Client object for interacting with Egeria.
489
+ element_type: str
490
+ type of element to process (e.g., 'blueprint', 'category', 'term')
491
+ element_labels: a list of equivalent label names to use in processing the element.
492
+ txt: str
493
+ A string representing the input text to be processed for extracting element identifiers.
494
+ action: str
495
+ The action object_action to be executed (e.g., 'Create', 'Update', 'Display', ...)
496
+ version: str, optional = None
497
+ An optional version identifier used if we need to construct the qualified name
498
+
499
+ Returns: tuple[str, str, str, bool, bool]
500
+ A tuple containing:
501
+ - qualified_name: Empty string or element identifier
502
+ - guid: Empty string or additional element information
503
+ - Valid: Boolean indicating if the element information is valid
504
+ - Exists: Boolean indicating if the element exists in Egeria
505
+ """
506
+ valid = True
507
+
508
+ element_name = extract_attribute(txt, element_labels)
509
+ qualified_name = extract_attribute(txt, ["Qualified Name"])
510
+
511
+ if qualified_name:
512
+ q_name, guid, unique, exists = get_element_by_name(egeria_client, element_type,
513
+ qualified_name) # Qualified name could be different if it
514
+ # is being updated
515
+ else:
516
+ q_name, guid, unique, exists = get_element_by_name(egeria_client, element_type, element_name)
517
+ if unique is False:
518
+ msg = f"Multiple elements named {element_name} found"
519
+ print_msg("DEBUG-ERROR", msg, debug_level)
520
+ valid = False
521
+
522
+ if action == "Update" and not exists:
523
+ msg = f"Element {element_name} does not exist"
524
+ print_msg("DEBUG-ERROR", msg, debug_level)
525
+ valid = False
526
+
527
+ elif action == "Update" and exists:
528
+ msg = f"Element {element_name} exists"
529
+ print_msg("DEBUG-INFO", msg, debug_level)
530
+
531
+ elif action == "Create" and exists:
532
+ msg = f"Element {element_name} already exists"
533
+ print_msg("DEBUG-ERROR", msg, debug_level)
534
+ valid = False
535
+
536
+ elif action == "Create" and not exists:
537
+ msg = f"{element_type} `{element_name}` does not exist"
538
+ print_msg("DEBUG-INFO", msg, debug_level)
539
+
540
+ if q_name is None and qualified_name is None:
541
+ q_name = egeria_client.__create_qualified_name__(element_type, element_name, version_identifier=version)
542
+ update_element_dictionary(q_name, {'display_name': element_name})
543
+ elif qualified_name:
544
+ update_element_dictionary(qualified_name, {'display_name': element_name})
545
+ elif action == EXISTS_REQUIRED:
546
+ if not exists:
547
+ msg = f"Required {element_type} `{element_name}` does not exist"
548
+ print_msg("DEBUG-ERROR", msg, debug_level)
549
+ valid = False
550
+ else:
551
+ msg = f"Required {element_type} `{element_name}` exists"
552
+ print_msg("DEBUG-INFO", msg, debug_level)
553
+ valid = True
554
+
555
+ return q_name, guid, valid, exists
556
+
557
+
558
+ def get_element_by_name(egeria_client, element_type: str, element_name: str) -> tuple[
559
+ str | None, str | None, bool | None, bool | None]:
560
+ """
561
+ Generalized function to retrieve an element by name based on its type.
562
+
563
+ Parameters:
564
+ egeria_client: Client
565
+ Client object for interacting with Egeria.
566
+ element_type: str
567
+ The type of element to retrieve (e.g., 'blueprint', 'category', 'term').
568
+ element_name: str
569
+ The name of the element to retrieve.
570
+
571
+ Returns:
572
+ tuple of qualified_name, guid, uniqye, exists
573
+ """
574
+ unique = None
575
+
576
+ element_dict = get_element_dictionary()
577
+ q_name = find_key_with_value(element_name)
578
+ if q_name: # use information from element_dictionary
579
+ guid = element_dict[q_name].get('guid', None)
580
+ unique = True
581
+ exists = True
582
+ if guid is not None: # Found complete entry in element_dictionary
583
+ msg = f'Found {element_type} qualified name and guid in element_dictionary for `{element_name}`'
584
+ print_msg("DEBUG-INFO", msg, debug_level)
585
+ return q_name, guid, unique, exists
586
+
587
+ else: # Missing guid from element_dictionary
588
+ guid = egeria_client.get_element_guid_by_unique_name(element_name)
589
+ if guid == NO_ELEMENTS_FOUND:
590
+ guid = None
591
+ msg = f"No {element_type} guid found with name {element_name} in Egeria"
592
+ print_msg("DEBUG-INFO", msg, debug_level)
593
+
594
+ return q_name, guid, unique, exists
595
+ else:
596
+ exists = True
597
+ update_element_dictionary(q_name, {'guid': guid})
598
+ msg = f"Found guid value of {guid} for {element_name} in Egeria"
599
+ print_msg("DEBUG-INFO", msg, debug_level)
600
+
601
+ return q_name, guid, unique, exists
602
+
603
+ # Haven't seen this element before
604
+ property_names = ['qualifiedName', 'name', 'displayName']
605
+ open_metadata_type_name = None
606
+ details = egeria_client.get_elements_by_property_value(element_name, property_names, open_metadata_type_name)
607
+ if isinstance(details, str):
608
+ msg = f"{element_type} `{element_name}` not found in Egeria"
609
+ print_msg("DEBUG-INFO", msg, debug_level)
610
+ exists = False
611
+ return None, None, unique, exists
612
+ if len(details) > 1:
613
+ msg = (f"More than one element with name {element_name} found, please specify a "
614
+ f"**Qualified Name**")
615
+ print_msg("DEBUG-ERROR", msg, debug_level)
616
+ unique = False
617
+ exists = None
618
+ return element_name, None, unique, exists
619
+
620
+ el_qname = details[0]["properties"].get('qualifiedName', None)
621
+ el_guid = details[0]['elementHeader']['guid']
622
+ el_display_name = details[0]["properties"].get('displayName', None)
623
+ update_element_dictionary(el_qname, {
624
+ 'guid': el_guid, 'displayName': el_display_name
625
+ })
626
+ msg = f"Found {element_type} `{el_display_name}` with qualified name `{el_qname}`"
627
+ print_msg("DEBUG-INFO", msg, debug_level)
628
+ exists = True
629
+ unique = True
630
+ return el_qname, el_guid, unique, exists
631
+
632
+ # Convert element_type to plural form for method name construction # if element_type.endswith('y'): # # # #
633
+ # plural_type = f"{element_type[:-1]}ies" # elif element_type.endswith('s'): # plural_type = f"{ # # #
634
+ # element_type}es" # else: # plural_type = f"{element_type}s" # # # Construct method name # method_name
635
+ # = f"get_{plural_type}_by_name" # # # Check if the method exists on the client # if hasattr(egeria_client,
636
+ # method_name): # # Call the method # method = getattr(egeria_client, method_name) # result = #
637
+ # method(element_name) # return result # else: # # Method doesn't exist # return f"Method { # #
638
+ # method_name} not found on client"
639
+
640
+
641
+ def process_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, element_labels: list[str]) -> tuple[str,
642
+ list[Any], bool | Any, bool | None | Any] | None:
643
+ """
644
+ Processes a list of names specified in the given text, retrieves details for each
645
+ element based on the provided type, and generates a list of valid qualified names.
646
+
647
+ The function reads a text block, extracts a list of element names according to the specified
648
+ element type, looks them up using the provided Egeria client, and classifies them as valid or
649
+ invalid. It returns the processed names, a list of qualified names, and validity and existence
650
+ flags.
651
+
652
+ Args:
653
+
654
+ egeria_client (EgeriaTech): The client instance to connect and query elements from an
655
+ external system.
656
+ Element_type (str): The type of element, such as schema or attribute, to process.
657
+ Txt (str): The raw input text containing element names to be processed.
658
+ element_labels: a list of equivalent label names to use in processing the element.
659
+
660
+ Returns:
661
+ tuple[str | None, list | None, bool, bool]: A tuple containing:
662
+ - Concatenated valid input names as a single string (or None if empty).
663
+ - A list of known qualified names extracted from the processed elements.
664
+ - A boolean indicating whether all elements are valid.
665
+ - A boolean indicating whether all elements exist.
666
+ """
667
+ valid = True
668
+ exists = True
669
+ elements = ""
670
+ new_element_list = []
671
+
672
+ elements_txt = extract_attribute(txt, element_labels)
673
+
674
+ if elements_txt is None:
675
+ msg = f"No {element_type} found"
676
+ print_msg("DEBUG-INFO", msg, debug_level)
677
+
678
+ else:
679
+ element_list = re.split(r'[,\n]+', elements_txt)
680
+
681
+ for element in element_list:
682
+ element_el = element.strip()
683
+
684
+ # Get the element using the generalized function
685
+ known_q_name, known_guid, el_valid, el_exists = get_element_by_name(egeria_client, element_type, element_el)
686
+ # print_msg("DEBUG-INFO", status_msg, debug_level)
687
+
688
+ if el_exists and el_valid:
689
+ elements = f"{element_el} {elements}" # list of the input names
690
+ new_element_list.append(known_q_name) # list of qualified names
691
+ elif not el_exists:
692
+ msg = f"No {element_type} `{element_el}` found"
693
+ print_msg("DEBUG-INFO", msg, debug_level)
694
+ valid = False
695
+ valid = valid if el_valid is None else (valid and el_valid)
696
+ exists = exists and el_exists
697
+
698
+ if elements:
699
+ # elements += "\n"
700
+ msg = f"Found {element_type}: {elements}"
701
+ print_msg("DEBUG-INFO", msg, debug_level)
702
+ else:
703
+ msg = f" Name list contains one or more invalid qualified names."
704
+ print_msg("DEBUG-INFO", msg, debug_level)
705
+ return elements, new_element_list, valid, exists
706
+
707
+
708
+ def process_blueprint_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
709
+ """
710
+ Processes a blueprint create or update object_action by extracting key attributes such as
711
+ blueprint name, description, and version from the given cell.
712
+
713
+ Parameters:
714
+ egeria_client: SolutionArchitect
715
+ Client object for interacting with Egeria.
716
+ txt: str
717
+ A string representing the input cell to be processed for
718
+ extracting element attributes.
719
+ directive: str, optional, default "display"
720
+ An optional string indicating the directive to be used - display, validate, or execute
721
+
722
+ Returns: str
723
+ A string summarizing the outcome of the processing.
724
+ """
725
+ command, object_type, object_action = extract_command_plus(txt)
726
+ set_debug_level(directive)
727
+ display_name = process_simple_attribute(txt, ['Display Name', 'Blueprint Name'], ERROR)
728
+ description = process_simple_attribute(txt, ['Description'])
729
+ version = process_simple_attribute(txt, ['Version', "Version Identifier", "Published Version"])
730
+
731
+ print(
732
+ Markdown(f"{pre_command} {object_action} `{object_type}` for Blueprint: `\'{display_name}\'` with directive: `"
733
+ f"{directive}`\n"))
734
+ if display_name is None:
735
+ valid = False
736
+ q_name, known_guid, exists = None
737
+ else:
738
+ element_labels = BLUEPRINT_NAME_LABELS
739
+ element_labels.append('Display Name')
740
+ q_name, known_guid, valid, exists = process_element_identifiers(egeria_client, object_type, element_labels, txt,
741
+ object_action, version)
742
+
743
+ element_display = (f"\n* Command: {object_action} {object_type}\n\t* Blueprint: {display_name}\n\t"
744
+ f"* Description: {description}\n\t"
745
+ f"* Version: {version}\n\t* Qualified Name:{q_name}\n\t* GUID: {known_guid} "
746
+ # f"\n\t* Update Description: {update_description}\n"
747
+ )
748
+
749
+ if valid:
750
+ msg = f"\n-->It is valid to **{object_action}** element \'{display_name}\'\n"
751
+ print_msg("ALWAYS", msg, debug_level)
752
+ if directive == "display":
753
+ print(Markdown(element_display))
754
+ return None
755
+ elif directive == "validate":
756
+ print(Markdown(element_display))
757
+ return valid
758
+
759
+ elif directive == "process":
760
+ print(Markdown(element_display))
761
+ try:
762
+ if not valid: # First validate the element before we process it
763
+ msg = "\nInvalid input found - please review the errors and warnings above\n"
764
+ print_msg("ERROR", msg, debug_level)
765
+ return None
766
+
767
+ if object_action == "Update" and directive == "process":
768
+ if not exists:
769
+ msg = f"\n-->Update failed - Blueprint {display_name} does not exist"
770
+ print_msg("ERROR", msg, debug_level)
771
+ return None
772
+
773
+ # call update blueprint here
774
+
775
+ msg = f"\nUpdated Blueprint `{display_name}` with GUID {known_guid}"
776
+ print_msg("ALWAYS", msg, debug_level)
777
+
778
+ # update with get blueprint by guid
779
+ return 'Would return get blueprint by guid and return md' # egeria_client.get_term_by_guid( # # #
780
+ # known_guid, 'md')
781
+
782
+ elif object_action == "Update" and directive == "validate":
783
+ return 'Would call get_blueprint_by_guid and return md' # egeria_client.get_term_by_guid( # # #
784
+ # known_guid, 'md')
785
+
786
+ elif object_action == "Create":
787
+ if exists:
788
+ msg = f"\n{WARNING}Blueprint {display_name} exists and result document updated"
789
+ print_msg("WARNING", msg, debug_level)
790
+ return update_a_command(txt, f"{object_type}{object_action}", object_type, q_name, known_guid)
791
+ else:
792
+ # create the blueprint
793
+ # term_guid = egeria_client.create_controlled_glossary_term(glossary_guid, term_body)
794
+ # if term_guid == NO_ELEMENTS_FOUND:
795
+ # print(f"{ERROR}Term {term_name} not created")
796
+ # return None
797
+ new_guid = f"guid:{get_current_datetime_string()}"
798
+ msg = f"\nCreated Blueprint `{display_name}`with GUID {new_guid}"
799
+ print_msg("ALWAYS", msg, debug_level)
800
+
801
+ update_element_dictionary(q_name, {'guid': new_guid, 'display_name': display_name})
802
+ return 'Would return get blueprint by guid results as md' # egeria_client.get_term_by_guid( #
803
+ # term_guid, 'MD')
804
+ else:
805
+ return None
806
+
807
+ except Exception as e:
808
+ msg = f"{ERROR}Error creating term {display_name}: {e}"
809
+ print_msg("ERROR", msg, debug_level)
810
+ console.print_exception(show_locals=True)
811
+ return None
812
+ else:
813
+ return None
814
+
815
+
816
+ def process_solution_component_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> \
817
+ Optional[str]:
818
+ """
819
+ Processes a solution componentt create or update object_action by extracting key attributes such as
820
+ solution component name, description, version, solution component type etc from the given cell.
821
+
822
+ Parameters:
823
+ egeria_client: SolutionArchitect
824
+ Client object for interacting with Egeria.
825
+ txt: str
826
+ A string representing the input cell to be processed for
827
+ extracting element attributes.
828
+ directive: str, optional, default "display"
829
+ An optional string indicating the directive to be used - display, validate or execute
830
+
831
+ Returns: str
832
+ A string summarizing the outcome of the processing.
833
+ """
834
+ set_debug_level(directive)
835
+ bp_qname_list = []
836
+ command, object_type, object_action = extract_command_plus(txt)
837
+
838
+ display_name = process_simple_attribute(txt, ['Display Name', 'Solution Component Name'], ERROR)
839
+ description = process_simple_attribute(txt, ['Description'])
840
+ version = process_simple_attribute(txt, ['Version', "Version Identifier", "Published Version"])
841
+ solution_component_type = process_simple_attribute(txt, ['Solution Component Type'])
842
+ planned_deployed_implementation_type = process_simple_attribute(txt, ['Planned Deployment Implementation Type'])
843
+ solution_blueprints = process_simple_attribute(txt, ['Solution Blueprints'])
844
+ parent_components = process_simple_attribute(txt, ['Parent Components'])
845
+
846
+ print(Markdown(
847
+ f"{pre_command} {object_action} `{object_type}` for Solution Component: `\'{display_name}\'` with directive: "
848
+ f"`{directive}`\n"))
849
+
850
+ if display_name is None:
851
+ valid = False
852
+ q_name, known_guid, exists = None
853
+ else:
854
+ element_labels = COMPONENT_NAME_LABELS
855
+ element_labels.append('Display Name')
856
+ known_q_name, known_guid, valid, exists = process_element_identifiers(egeria_client, object_type,
857
+ element_labels, txt, object_action,
858
+ version)
859
+
860
+ if solution_blueprints: # Find information about blueprints that include this component
861
+ msg = "Checking for blueprints that include this solution component"
862
+ print_msg("DEBUG-INFO", msg, debug_level)
863
+ solution_blueprints, bp_qname_list, bp_valid, bp_exist = process_name_list(egeria_client, 'Solution Blueprints',
864
+ txt, BLUEPRINT_NAME_LABELS)
865
+ if bp_exist and bp_valid:
866
+ msg = f"Found valid blueprints that include this solution component:\n\t{solution_blueprints}"
867
+ print_msg("INFO", msg, debug_level)
868
+ else:
869
+ msg = f"No valid blueprints that include this solution component found."
870
+ print_msg("INFO", msg, debug_level)
871
+ if parent_components is None:
872
+ msg = f"Parent Components are missing"
873
+ print_msg("INFO", msg, debug_level)
874
+ else:
875
+ parent_components, parent_qname_list, parents_valid, parent_components_exist = process_name_list(egeria_client,
876
+ 'Parent '
877
+ 'Components',
878
+ txt,
879
+ COMPONENT_NAME_LABELS)
880
+ if parent_components_exist and parents_valid:
881
+ msg = f"Found valid parent components that include this solution component:\n\t{parent_qname_list}"
882
+ print_msg("INFO", msg, debug_level)
883
+ else:
884
+ msg = f"No valid parent components that include this solution component found."
885
+ print_msg("INFO", msg, debug_level)
886
+
887
+ element_display = (f"* Command: {object_action} {object_type}\n\t* Display Name: {display_name}\n\t"
888
+ f"* Description: {description}\n\t"
889
+ f"* Version Identifier: {version}\n\t"
890
+ f"* Solution Component Type {solution_component_type}\n\t"
891
+ f"* Planned Deployment Implementation Type {planned_deployed_implementation_type}\n\t"
892
+ f"* Solution_Blueprints: {solution_blueprints}\n\t"
893
+ f"* Parent Components: {parent_components}\n\t"
894
+ f"* Qualified Name:{known_q_name}\n\t* GUID: {known_guid} "
895
+ # f"\n\t* Update Description: {update_description}"
896
+ )
897
+
898
+ if object_action == "Update": # check to see if provided information exists and is consistent with existing info
899
+ if not exists:
900
+ msg = f"Element {display_name} does not exist with input:\n"
901
+ print_msg("ERROR", msg, debug_level)
902
+ valid = False
903
+ elif not valid:
904
+ msg = (f"\n-->Validation checks failed in updating {object_type} \'{display_name}\' with: \n"
905
+ f"{element_display}")
906
+ print_msg("ERROR", msg, debug_level)
907
+ else: # it exists and is valid
908
+ msg = f"\n-->It is valid to update {object_type} \'{display_name}\' with: \n"
909
+ print_msg("ALWAYS", msg, debug_level)
910
+ if known_q_name is None:
911
+ known_q_name = egeria_client.__create_qualified_name__(object_type, display_name,
912
+ version_identifier=version)
913
+ update_element_dictionary(known_q_name, {'display_name': display_name, 'guid': known_guid})
914
+
915
+ elif object_action == 'Create': # if the object_action is create, check that it doesn't already exist
916
+ if exists:
917
+ msg = f"{object_type} `{display_name}` already exists."
918
+ print_msg("ERROR", msg, debug_level)
919
+ valid = False
920
+ elif not valid:
921
+ msg = f"\n-->Validation checks failed in creating element \'{display_name}\' with: \n"
922
+ print_msg("ERROR", msg, debug_level)
923
+ else: # valid to create - update element_dictionary
924
+ msg = f"\n-->It is valid to create element \'{display_name}\' with: \n"
925
+ print_msg("ALWAYS", msg, debug_level)
926
+ if known_q_name is None:
927
+ known_q_name = egeria_client.__create_qualified_name__(object_type, display_name,
928
+ version_identifier=version)
929
+ update_element_dictionary(known_q_name, {'display_name': display_name})
930
+ print(Markdown(element_display))
931
+ if directive == "display":
932
+ return None
933
+ elif directive == "validate":
934
+ return valid
935
+
936
+ elif directive == "process":
937
+ try:
938
+ if not valid: # First validate the term before we process it
939
+ return None
940
+
941
+ if object_action == "Update" and directive == "process":
942
+ if not exists:
943
+ msg = (f"\n-->Solution Component {display_name} does not exist")
944
+ print_msg("ERROR", msg, debug_level)
945
+ return None
946
+
947
+ # call update solution component here
948
+
949
+ msg = f"\nUpdated Solution Component `{display_name}` with GUID {known_guid}"
950
+ print_msg("ALWAYS", msg, debug_level)
951
+ # update with get solution component by guid
952
+ return 'Would return get Solution Component by guid and return md' # # # #
953
+ # egeria_client.get_term_by_guid(known_guid, 'md')
954
+
955
+ elif object_action == "Update" and directive == "validate":
956
+ return 'Would call get_blueprint_by_guid and return md' # egeria_client.get_term_by_guid( # # #
957
+ # known_guid, 'md')
958
+
959
+ elif object_action == "Create":
960
+ if exists:
961
+ f"\n{WARNING}Component {display_name} exists and result document updated"
962
+ print_msg("WARNING", msg, debug_level)
963
+ return update_a_command(txt, f"{object_type}{object_action}", object_type, known_q_name, known_guid)
964
+ else:
965
+ # create the solution component
966
+ # term_guid = egeria_client.create_controlled_glossary_term(glossary_guid, term_body)
967
+ # if term_guid == NO_ELEMENTS_FOUND:
968
+ # print(f"{ERROR}Term {term_name} not created")
969
+ # return None
970
+
971
+ msg = f"\nCreated Solution Component `{display_name}` with GUID {known_guid}"
972
+ print_msg("ALWAYS", msg, debug_level)
973
+ update_element_dictionary(known_q_name, {'guid': known_guid, 'display_name': display_name})
974
+ return 'Would return get solution component by guid results as md' # # # #
975
+ # egeria_client.get_term_by_guid(term_guid, 'MD')
976
+
977
+ except Exception as e:
978
+ msg = f"Error creating term {display_name}: {e}"
979
+ print_msg("ERROR", msg, debug_level)
980
+ console.print_exception(show_locals=True)
981
+ return None
982
+ else:
983
+ return None
984
+
985
+ def process_glossary_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
986
+ """
987
+ Processes a glossary create or update object_action by extracting key attributes such as
988
+ glossary name, language, description, and usage from the given text.
989
+
990
+ :param txt: A string representing the input cell to be processed for
991
+ extracting glossary-related attributes.
992
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
993
+ :return: A string summarizing the outcome of the processing.
994
+ """
995
+
996
+ command, object_type, object_action = extract_command_plus(txt)
997
+ set_debug_level(directive)
998
+
999
+ glossary_name = process_simple_attribute(txt, GLOSSARY_NAME_LABELS, ERROR)
1000
+ print(Markdown(
1001
+ f"{pre_command} `{object_action}` `{object_type}` for glossary: `\'{glossary_name}\'` with directive: `"
1002
+ f"{directive}` "))
1003
+ language = process_simple_attribute(txt, ['Language'], INFO)
1004
+ description = process_simple_attribute(txt, ['Description'], INFO)
1005
+ usage = process_simple_attribute(txt, ['Usage'], INFO)
1006
+ q_name = process_simple_attribute(txt, ['Qualified Name'], INFO)
1007
+ valid = True
1008
+
1009
+ if glossary_name is None:
1010
+ valid = False
1011
+ known_q_name = None
1012
+ known_guid = None
1013
+ glossary_exists = False
1014
+ else:
1015
+ element_labels = GLOSSARY_NAME_LABELS
1016
+ element_labels.append('Display Name')
1017
+ known_q_name, known_guid, valid, glossary_exists = process_element_identifiers(egeria_client, object_type,
1018
+ element_labels, txt,
1019
+ object_action, None)
1020
+ glossary_display = (f"\n* Command: `{command}`\n\t* Glossary Name: {glossary_name}\n\t"
1021
+ f"* Language: {language}\n\t* Description:\n{description}\n"
1022
+ f"* Usage: {usage}\n")
1023
+
1024
+ if object_action == 'Update':
1025
+ guid = process_simple_attribute(txt, ['GUID', 'guid', 'Guid'])
1026
+ glossary_display += f"* Qualified Name: `{q_name}`\n\t* GUID: {guid}\n\n"
1027
+ if not glossary_exists:
1028
+ msg = f"Glossary can't be updated; `{glossary_name}` not found"
1029
+ print_msg("ERROR", msg, debug_level)
1030
+ valid = False
1031
+ else:
1032
+ msg = f"Glossary can be updated; `{glossary_name}` found"
1033
+ print_msg(ALWAYS, msg, debug_level)
1034
+
1035
+
1036
+ elif object_action == "Create":
1037
+ if glossary_exists:
1038
+ msg = f"Glossary `{glossary_name}` can't be created because it already exists.\n"
1039
+ print_msg("ERROR", msg, debug_level)
1040
+ valid = False
1041
+ elif valid:
1042
+ msg = f"It is valid to create Glossary `{glossary_name}` with:\n"
1043
+ print_msg("ALWAYS", msg, debug_level)
1044
+
1045
+ if directive == "display":
1046
+ print(Markdown(glossary_display))
1047
+ return None
1048
+
1049
+ elif directive == "validate":
1050
+ if valid:
1051
+ print(Markdown(glossary_display))
1052
+ else:
1053
+ msg = f"Validation failed for Glossary `{glossary_name}`\n"
1054
+ print_msg(ERROR, msg, debug_level)
1055
+ print(Markdown(glossary_display))
1056
+
1057
+ return valid
1058
+
1059
+ elif directive == "process":
1060
+ if valid:
1061
+ print(Markdown(glossary_display))
1062
+ else:
1063
+ if glossary_exists and object_action == "Create":
1064
+ msg = f"Create failed because glossary `{glossary_name}` exists - changing `Create` to `Update` in processed output \n"
1065
+ print_msg(ERROR, msg, debug_level)
1066
+ print(Markdown(glossary_display))
1067
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1068
+ else:
1069
+ return None
1070
+ if object_action == "Update":
1071
+ if not glossary_exists:
1072
+ print(f"\n{ERROR}Glossary `{glossary_name}` does not exist! Updating result document with Create "
1073
+ f"object_action\n")
1074
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1075
+
1076
+ body = {
1077
+ "class": "ReferenceableRequestBody", "elementProperties": {
1078
+ "class": "GlossaryProperties", "qualifiedName": known_q_name, "description": description,
1079
+ "language": language, "usage": usage
1080
+ }
1081
+ }
1082
+ egeria_client.update_glossary(known_guid, body)
1083
+ print_msg(ALWAYS, f"Updated Glossary `{glossary_name}` with GUID {known_guid}", debug_level)
1084
+ update_element_dictionary(known_q_name, {
1085
+ 'guid': known_guid, 'display_name': glossary_name
1086
+ })
1087
+ return egeria_client.get_glossary_by_guid(known_guid, output_format='MD')
1088
+ elif object_action == "Create":
1089
+ glossary_guid = None
1090
+
1091
+ if glossary_exists:
1092
+ print(f"\nGlossary `{glossary_name}` already exists and result document updated\n")
1093
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1094
+ else:
1095
+ glossary_guid = egeria_client.create_glossary(glossary_name, description, language, usage)
1096
+ glossary = egeria_client.get_glossary_by_guid(glossary_guid)
1097
+ if glossary == NO_GLOSSARIES_FOUND:
1098
+ print(f"{ERROR}Just created with GUID {glossary_guid} but Glossary not found\n")
1099
+ return None
1100
+ qualified_name = glossary['glossaryProperties']["qualifiedName"]
1101
+ update_element_dictionary(qualified_name, {
1102
+ 'guid': glossary_guid, 'display_name': glossary_name
1103
+ })
1104
+ # return update_a_command(txt, object_action, object_type, qualified_name, glossary_guid)
1105
+ print_msg(ALWAYS, f"Created Glossary `{glossary_name}` with GUID {glossary_guid}", debug_level)
1106
+ return egeria_client.get_glossary_by_guid(glossary_guid, output_format='FORM')
1107
+ else:
1108
+ return None
1109
+ else:
1110
+ return None
1111
+
1112
+
1113
+ def process_category_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1114
+ """
1115
+ Processes a glossary category create or update object_action by extracting key attributes such as
1116
+ category name, qualified, description, and anchor glossary from the given txt..
1117
+
1118
+ :param txt: A string representing the input cell to be processed for
1119
+ extracting category-related attributes.
1120
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1121
+ :return: A string summarizing the outcome of the processing.
1122
+ """
1123
+ valid = True
1124
+ set_debug_level(directive)
1125
+
1126
+ command, object_type, object_action = extract_command_plus(txt)
1127
+
1128
+ category_name = process_simple_attribute(txt, ['Category Name', 'category_name', 'Cat'])
1129
+ print(Markdown(f"{pre_command} `{command}` for category: `\'{category_name}\'` with directive: `{directive}` "))
1130
+
1131
+ owning_glossary_name = extract_attribute(txt, ['Owning Glossary', 'In Glossary'])
1132
+ description = process_simple_attribute(txt, ['Description'])
1133
+ q_name = process_simple_attribute(txt, ['Qualified Name'])
1134
+
1135
+ parent_category_name = process_simple_attribute(txt, PARENT_CATEGORY_LABELS, "INFO")
1136
+
1137
+ element_labels = CATEGORY_NAME_LABELS
1138
+ element_labels.append('Display Name')
1139
+ # Check if category exists (and get qname and guid)
1140
+ if category_name is None:
1141
+ valid = False
1142
+ known_q_name, known_guid, category_exists = None
1143
+ else:
1144
+ element_labels = CATEGORY_NAME_LABELS
1145
+ element_labels.append('Display Name')
1146
+ known_q_name, known_guid, valid, category_exists = process_element_identifiers(egeria_client, object_type,
1147
+ element_labels, txt,
1148
+ object_action, None)
1149
+
1150
+ # Check if owning glossary exists (and get qname)
1151
+ if owning_glossary_name is None:
1152
+ valid = False
1153
+ known_glossary_q_name, known_glossary__guid, glossary_exists = None
1154
+
1155
+ else:
1156
+ known_glossary_q_name, known_glossary_guid, valid, owning_glossary_exists = process_element_identifiers(
1157
+ egeria_client, "Glossary", GLOSSARY_NAME_LABELS, txt, EXISTS_REQUIRED, None)
1158
+
1159
+ if parent_category_name:
1160
+ _, parent_guid, parent_valid, parent_exists = get_element_by_name(egeria_client, 'Glossary Categories',
1161
+ parent_category_name)
1162
+ else:
1163
+ parent_guid = None
1164
+ parent_exists = False
1165
+ parent_valid = False
1166
+
1167
+ category_display = (
1168
+ f"\n* Command: {command}\n\t* Category: {category_name}\n\t* In Glossary: {owning_glossary_name}\n\t"
1169
+ f"* Description:\n{description}\n\t* Parent Category: {parent_category_name}\n\t"
1170
+ f"* Qualified Name: {q_name}\n\t")
1171
+
1172
+ if object_action == 'Update':
1173
+ guid = process_simple_attribute(txt, ['GUID', 'guid', 'Guid'])
1174
+
1175
+ category_display += (f"* GUID: {guid}\n\n")
1176
+ if not category_exists:
1177
+ msg = f"Category {category_name} can't be updated; {category_name} not found."
1178
+ print_msg(ERROR, msg, debug_level)
1179
+ valid = False
1180
+ else:
1181
+ msg = f"Glossary can be updated; {category_name} found"
1182
+ print_msg(ALWAYS, msg, debug_level)
1183
+
1184
+ elif object_action == "Create":
1185
+ if category_exists:
1186
+ msg = f"Category {category_name} can't be created because it already exists.\n"
1187
+ print_msg("ERROR", msg, debug_level)
1188
+ valid = False
1189
+ elif valid:
1190
+ msg = f"It is valid to create Category `{category_name}` with:\n"
1191
+ print_msg("ALWAYS", msg, debug_level)
1192
+
1193
+ if directive == "display":
1194
+ print(Markdown(category_display))
1195
+ return None
1196
+
1197
+ elif directive == "validate":
1198
+ if valid:
1199
+ print(Markdown(category_display))
1200
+ else:
1201
+ msg = f"Validation failed for {object_type} `{category_name}`\n"
1202
+ print_msg(ERROR, msg, debug_level)
1203
+ print(Markdown(category_display))
1204
+ return valid
1205
+
1206
+ elif directive == "process":
1207
+ if valid:
1208
+ print(Markdown(category_display))
1209
+ else:
1210
+ if category_exists and object_action == "Create":
1211
+ msg = f"Create failed because category `{category_name}` exists - changing `Create` to `Update` in processed output \n"
1212
+ print_msg(ERROR, msg, debug_level)
1213
+ print(Markdown(category_display))
1214
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1215
+ else:
1216
+ return None
1217
+
1218
+ if object_action == "Update":
1219
+ if not category_exists:
1220
+ print(f"\n{ERROR}category `{category_name}` does not exist! Updating result document with Create "
1221
+ f"object_action\n")
1222
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1223
+
1224
+ # Update the basic category properties
1225
+ egeria_client.update_category(known_guid, category_name, description, known_q_name, None)
1226
+ msg = f"->Updated category `{category_name}`with GUID {known_guid}"
1227
+ print_msg(ALWAYS, msg, debug_level)
1228
+
1229
+ # Update parent-child relationships
1230
+
1231
+ update_element_dictionary(known_q_name, {
1232
+ 'guid': known_guid, 'display_name': category_name
1233
+ })
1234
+
1235
+ category_sync = update_category_parent(egeria_client, known_guid, parent_category_name)
1236
+ print_msg(ALWAYS, f"Updated Category hierarchy for `{category_name}` with outcome {category_sync}",
1237
+ debug_level)
1238
+ return egeria_client.get_category_by_guid(known_guid, output_format='FORM')
1239
+
1240
+ elif object_action == "Create":
1241
+ is_root = True
1242
+
1243
+ if category_exists:
1244
+ msg = (f"Cannot create`{category_name}` because it already exists; result document written for "
1245
+ f"category update\n")
1246
+ print_msg(WARNING, msg, debug_level)
1247
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1248
+ else:
1249
+ category_guid = egeria_client.create_category(known_glossary_guid, category_name, description, is_root)
1250
+ category_details = egeria_client.get_category_by_guid(category_guid)
1251
+
1252
+ if category_details == NO_CATEGORIES_FOUND:
1253
+ msg = f"Just created category with GUID {category_guid} but category not found"
1254
+ print_msg(ERROR, msg, debug_level)
1255
+ return None
1256
+
1257
+ qualified_name = category_details['glossaryCategoryProperties']["qualifiedName"]
1258
+ update_element_dictionary(qualified_name, {
1259
+ 'guid': category_guid, 'display_name': category_name
1260
+ })
1261
+ print_msg(ALWAYS, f"Created Category `{category_name}` with GUID {category_guid}", debug_level)
1262
+ if parent_valid and parent_guid:
1263
+ egeria_client.set_parent_category(parent_guid, category_guid)
1264
+ print_msg(ALWAYS, f"Set parent category for `{category_name}` to `{parent_category_name}`",
1265
+ debug_level)
1266
+ else:
1267
+ print_msg(ERROR,
1268
+ f"Parent category `{parent_category_name}` not found or invalid for `{category_name}`",
1269
+ debug_level)
1270
+ return egeria_client.get_category_by_guid(category_guid, output_format='FORM')
1271
+ return None
1272
+ return None
1273
+
1274
+
1275
+ def update_category_parent(egeria_client, category_guid: str, parent_category_name: str = None) -> bool:
1276
+ """
1277
+ Updates the parent relationship for a category.
1278
+
1279
+ If a parent category is specified, it will check if a parent is currently set.
1280
+ If a parent category was set and is the same as the parent category specified, no change is needed.
1281
+ If a parent category was set and is different from the parent_category_name, the parent category is updated.
1282
+ If parent_category_name is None or empty and an existing parent category was set, the parent category is removed.
1283
+
1284
+ Parameters
1285
+ ----------
1286
+ egeria_client: EgeriaTech
1287
+ The Egeria client to use for API calls
1288
+ category_guid: str
1289
+ The GUID of the category to update
1290
+ parent_category_name: str, optional
1291
+ The name of the parent category to set, or None to remove the parent
1292
+
1293
+ Returns
1294
+ -------
1295
+
1296
+ True if successful, False otherwise.
1297
+
1298
+ """
1299
+ outcome = True
1300
+ # Handle parent category updates
1301
+ if parent_category_name:
1302
+ # Check if a parent is currently set
1303
+ current_parent = egeria_client.get_category_parent(category_guid)
1304
+
1305
+ if isinstance(current_parent, str) and "No Parent Category found" in current_parent:
1306
+ # No parent currently set, need to set it
1307
+ _, parent_guid, _, parent_exists = get_element_by_name(egeria_client, 'Glossary Categories',
1308
+ parent_category_name)
1309
+
1310
+ if parent_exists and parent_guid:
1311
+ egeria_client.set_parent_category(parent_guid, category_guid)
1312
+ print_msg(ALWAYS, f"Set parent category of category to `{parent_category_name}`", debug_level)
1313
+ else:
1314
+ print_msg(ERROR, f"Parent category `{parent_category_name}` not found", debug_level)
1315
+ outcome = False
1316
+ else:
1317
+ # Parent is set, check if it's the same
1318
+ current_parent_name = current_parent.get('glossaryCategoryProperties', {}).get('qualifiedName', '')
1319
+
1320
+ if current_parent_name != parent_category_name:
1321
+ # Different parent, need to update
1322
+ # First remove the current parent
1323
+ current_parent_guid = current_parent.get('elementHeader', {}).get('guid', '')
1324
+ if current_parent_guid:
1325
+ egeria_client.remove_parent_category(current_parent_guid, category_guid)
1326
+
1327
+ # Then set the new parent
1328
+ _, parent_guid, _, parent_exists = get_element_by_name(egeria_client, 'Glossary Categories',
1329
+ parent_category_name)
1330
+
1331
+ if parent_exists and parent_guid:
1332
+ egeria_client.set_parent_category(parent_guid, category_guid)
1333
+ print_msg(ALWAYS,
1334
+ f"Updated parent category from `{current_parent_name}` to `{parent_category_name}`",
1335
+ debug_level)
1336
+ else:
1337
+ print_msg(ERROR, f"Parent category `{parent_category_name}` not found", debug_level)
1338
+ outcome = False
1339
+ elif parent_category_name is None or parent_category_name == '':
1340
+ # Check if a parent is currently set and remove it if needed
1341
+ current_parent = egeria_client.get_category_parent(category_guid)
1342
+
1343
+ if not isinstance(current_parent, str) or "No Parent Category found" not in current_parent:
1344
+ # Parent is set, need to remove it
1345
+ current_parent_guid = current_parent.get('elementHeader', {}).get('guid', '')
1346
+ current_parent_name = current_parent.get('glossaryCategoryProperties', {}).get('qualifiedName', '')
1347
+
1348
+ if current_parent_guid:
1349
+ egeria_client.remove_parent_category(current_parent_guid, category_guid)
1350
+ print_msg(ALWAYS, f"Removed parent category `{current_parent_name}`", debug_level)
1351
+
1352
+ return outcome
1353
+
1354
+
1355
+ def process_term_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1356
+ """
1357
+ Processes a term create or update object_action by extracting key attributes such as
1358
+ term name, summary, description, abbreviation, examples, usage, version, and status from the given cell.
1359
+
1360
+ :param txt: A string representing the input cell to be processed for
1361
+ extracting glossary-related attributes.
1362
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1363
+ :return: A string summarizing the outcome of the processing.
1364
+ """
1365
+ valid = True
1366
+ categories_list = None
1367
+ cats_exist = False
1368
+ set_debug_level(directive)
1369
+ known_q_name = None
1370
+ command = extract_command(txt)
1371
+ object_type = command.split(' ')[1].strip()
1372
+ object_action = command.split(' ')[0].strip()
1373
+
1374
+ term_name = process_simple_attribute(txt, ['Term Name', 'Display Name'], ERROR)
1375
+ print(Markdown(f"{pre_command} `{command}` for term:`{term_name}` with directive: `{directive}`"))
1376
+ summary = process_simple_attribute(txt, ['Summary'],INFO)
1377
+ description = process_simple_attribute(txt, ['Description'], INFO)
1378
+ abbreviation = process_simple_attribute(txt, ['Abbreviation'], INFO)
1379
+ examples = process_simple_attribute(txt, ['Examples'], INFO)
1380
+ usage = process_simple_attribute(txt, ['Usage'], INFO)
1381
+ status = process_simple_attribute(txt, ['Status'])
1382
+ status = status.upper() if status else 'DRAFT'
1383
+ version = process_simple_attribute(txt, ['Version', "Version Identifier", "Published Version"], INFO)
1384
+ q_name = process_simple_attribute(txt, ['Qualified Name'], INFO)
1385
+
1386
+ aliases = process_simple_attribute(txt, ['Aliases','Alias'], INFO)
1387
+ if aliases:
1388
+ alias_list = list(filter(None, re.split(r'[,\n]+', aliases.strip())))
1389
+ else:
1390
+ alias_list = None
1391
+
1392
+
1393
+
1394
+ # validate term name and get existing qualified_name and guid if they exist
1395
+ if term_name is None:
1396
+ valid = False
1397
+ known_q_name, known_guid, term_exists = None
1398
+ else:
1399
+ element_labels = TERM_NAME_LABELS
1400
+ element_labels.append('Display Name')
1401
+ known_q_name, known_guid, valid, term_exists = process_element_identifiers(egeria_client, object_type,
1402
+ element_labels, txt, object_action,
1403
+ version)
1404
+
1405
+ # get the glossary qualified name this term is in
1406
+ glossary_name = process_simple_attribute(txt, GLOSSARY_NAME_LABELS, ERROR)
1407
+ if glossary_name is None:
1408
+ valid = False
1409
+ known_glossary_guid = None
1410
+ known_glossary_q_name = None
1411
+ glossary_valid = False
1412
+ glossary_exists = False
1413
+ else:
1414
+ known_glossary_q_name, known_glossary_guid, glossary_valid, glossary_exists = process_element_identifiers(
1415
+ egeria_client, "Glossary", GLOSSARY_NAME_LABELS, txt, EXISTS_REQUIRED, None)
1416
+
1417
+ # process categories, if present
1418
+ categories = process_simple_attribute(txt, ['Glossary Categories', 'Glossary Category', 'Category', 'Categories'])
1419
+ if categories: # Find information about categoriess that classify this term
1420
+ msg = "Checking for categories that classify this term"
1421
+ print_msg("DEBUG-INFO", msg, debug_level)
1422
+ categories_list, cat_q_name_list, cats_valid, cats_exist = process_name_list(egeria_client, 'Glossary Categories',
1423
+ txt, CATEGORY_NAME_LABELS)
1424
+ if cats_exist and cats_valid:
1425
+ msg = f"Found valid glossary categories to classify the term:\n\t{term_name}"
1426
+ print_msg("INFO", msg, debug_level)
1427
+ else:
1428
+ msg = "No valid glossary categories found."
1429
+ print_msg("INFO", msg, debug_level)
1430
+ else:
1431
+ cats_exist = cats_valid = False
1432
+ cat_q_name_list = None
1433
+
1434
+ if object_action == "Update": # check to see if provided information exists and is consistent with existing info
1435
+ term_guid = process_simple_attribute(txt, GUID_LABELS)
1436
+ update_description = process_simple_attribute(txt, ['Update Description'])
1437
+ term_display = (f"\n* Command: {command}\n\t* Glossary: {known_glossary_q_name}\n\t"
1438
+ f"* Term Name: {term_name}\n\t* Qualified Name: {q_name}\n\t* Aliases: {aliases}\n\t"
1439
+ f"* Categories: {categories}\n\t"
1440
+ f"* Summary: {summary}\n\t* Description: {description}\n\t"
1441
+ f"* Abbreviation: {abbreviation}\n\t* Examples: {examples}\n\t* Usage: {usage}\n\t"
1442
+ f"* Version: {version}\n\t* Status: {status}\n\t* GUID: {term_guid}"
1443
+ f"\n\t* Update Description: {update_description}\n")
1444
+ if not term_exists:
1445
+ msg = f"Update request invalid, Term {term_name} does not exist\n"
1446
+ print_msg(ERROR, msg, debug_level)
1447
+ valid = False
1448
+
1449
+ elif object_action == 'Create': # if the object_action is create, check that it doesn't already exist
1450
+ term_display = (f"\n* Command: {command}\n\t* Glossary: {known_glossary_q_name}\n\t"
1451
+ f"* Term Name: {term_name}\n\t* Categories: {categories}\n\t* Summary: {summary}\n\t"
1452
+ f"* Qualified Name: {q_name}\n\t* Aliases: {aliases}\n\t* Description: {description}\n\t"
1453
+ f"* Abbreviation: {abbreviation}\n\t* Examples: {examples}\n\t* Usage: {usage}\n\t"
1454
+ f"* Version: {version}\n\t* Status: {status}\n")
1455
+ if term_exists:
1456
+ msg = f"Term `{term_name}` cannot be created since it already exists\n"
1457
+ print_msg(ERROR, msg, debug_level)
1458
+ else:
1459
+ msg = f"It is valid to create Term `{term_name}`"
1460
+ print_msg(ALWAYS, msg, debug_level)
1461
+
1462
+ if directive == "display":
1463
+ print(Markdown(term_display))
1464
+ return None
1465
+ elif directive == "validate":
1466
+ print(Markdown(term_display))
1467
+ return valid
1468
+ elif directive == "process":
1469
+ try:
1470
+ if not valid: # First validate the term before we process it
1471
+ if term_exists and object_action == "Create":
1472
+ msg = f"Create failed because term `{term_name}` exists - changing `Create` to `Update` in processed output \n"
1473
+ print_msg(ERROR, msg, debug_level)
1474
+ print(Markdown(term_display))
1475
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1476
+ else:
1477
+ return None
1478
+
1479
+ print(Markdown(term_display))
1480
+ if object_action == "Update" and directive == "process":
1481
+ if not term_exists:
1482
+ return None
1483
+ body = {
1484
+ "class": "ReferenceableRequestBody", "elementProperties": { "displayName": term_name,
1485
+ "class": "GlossaryTermProperties", "qualifiedName": known_q_name, "aliases": alias_list, "summary": summary,
1486
+ "description": description, "abbreviation": abbreviation, "examples": examples, "usage": usage,
1487
+ "publishVersionIdentifier": version, "status": status
1488
+ }, "updateDescription": update_description
1489
+ }
1490
+ egeria_client.update_term(known_guid, body_slimmer(body), is_merge_update=False)
1491
+ # if cat_exist and cat_valid:
1492
+ update_term_categories(egeria_client, known_guid, cats_exist, cat_q_name_list)
1493
+ print_msg(ALWAYS,
1494
+ f"\tUpdated Term `{term_name}` with GUID {known_guid}\n\tand categories `{categories}`",
1495
+ debug_level)
1496
+ return egeria_client.get_term_by_guid(known_guid,
1497
+ 'md') # return update_a_command(txt, object_action, object_type,
1498
+ # known_q_name, known_guid)
1499
+ elif object_action == "Update" and directive == "validate": # is sthis reachable?
1500
+ return egeria_client.get_term_by_guid(known_guid, 'md')
1501
+
1502
+ elif object_action == "Create":
1503
+ if term_exists:
1504
+ msg = f"Term {term_name} exists so result document modifies term create to term update"
1505
+ print_msg(INFO, msg, debug_level)
1506
+ return update_a_command(txt, command, object_type, q_name, known_guid)
1507
+ else:
1508
+ ## get the guid for the glossary from the name - first look in cache
1509
+ cached = get_element_dictionary().get(known_glossary_q_name, None)
1510
+
1511
+ if cached is not None:
1512
+ glossary_guid = cached.get('guid', None)
1513
+ if glossary_guid is None:
1514
+ msg = f"Glossary GUID for {known_glossary_q_name} not found in cache"
1515
+ print_msg(WARNING, msg, debug_level) # should this ever occur?
1516
+ return None
1517
+ else:
1518
+ glossary_guid = egeria_client.__get_guid__(qualified_name=known_glossary_q_name)
1519
+ if glossary_guid == NO_ELEMENTS_FOUND:
1520
+ msg = f"Glossary {known_glossary_q_name} not found"
1521
+ print_msg(WARNING, msg, debug_level)
1522
+ return None
1523
+ term_body = {
1524
+ "class": "ReferenceableRequestBody", "elementProperties": {
1525
+ "class": "GlossaryTermProperties", "qualifiedName": known_q_name, "displayName": term_name,
1526
+ "aliases": alias_list, "summary": summary, "description": description, "abbreviation": abbreviation,
1527
+ "examples": examples, "usage": usage, "publishVersionIdentifier": version
1528
+ # "additionalProperties":
1529
+ # {
1530
+ # "propertyName1": "xxxx",
1531
+ # "propertyName2": "xxxx"
1532
+ # }
1533
+ }, "initialStatus": status
1534
+ }
1535
+ term_guid = egeria_client.create_controlled_glossary_term(glossary_guid, body_slimmer(term_body))
1536
+ if term_guid == NO_ELEMENTS_FOUND:
1537
+ print(f"{ERROR}Term {term_name} not created")
1538
+ return None
1539
+ if cats_exist and categories is not None:
1540
+ update_term_categories(egeria_client, term_guid, cats_exist, cat_q_name_list)
1541
+ update_element_dictionary(known_q_name, {'guid': term_guid, 'display_name': term_name})
1542
+ print_msg(ALWAYS, f"Created term `{term_name}` with GUID {term_guid}", debug_level)
1543
+ return egeria_client.get_term_by_guid(term_guid,
1544
+ 'MD') # return update_a_command(txt, object_action,
1545
+ # object_type, q_name, term_guid)
1546
+ except Exception as e:
1547
+ print(f"{ERROR}Error creating term {term_name}: {e}")
1548
+ console.print_exception(show_locals=True)
1549
+ return None
1550
+ else:
1551
+ return None
1552
+
1553
+
1554
+
1555
+
1556
+ def process_create_term_term_relationship_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1557
+ """ Relate two terms through the specified relationship. ."""
1558
+ set_debug_level(directive)
1559
+ valid = True
1560
+ command = extract_command(txt)
1561
+ object_type = command.split(' ')[1].strip()
1562
+ object_action = command.split(' ')[0].strip()
1563
+ term1_guid = None
1564
+ term2_guid = None
1565
+
1566
+
1567
+ term_relationship = process_simple_attribute(txt, ["Term Relationship", "Relationship Type"], "ERROR")
1568
+ if term_relationship not in TERM_RELATIONSHPS:
1569
+ valid = False
1570
+
1571
+ print(Markdown(f"{pre_command} `{command}` for term relationship: `{term_relationship}` with directive: `{directive}` "))
1572
+
1573
+ term1_q_name, term1_guid, term1_valid, term1_exists = process_element_identifiers(egeria_client, object_type, ["Term 1 Name", "Term 1"], txt,
1574
+ "Exists Required", None )
1575
+
1576
+ term2_q_name, term2_guid, term2_valid, term2_exists = process_element_identifiers(egeria_client, object_type, ["Term 2 Name", "Term 2"], txt,
1577
+ "Exists Required", None )
1578
+
1579
+ request_display = (f"\n\t* Term 1 Qualified Name: {term1_q_name}\n\t* Term 2 Qualified Name {term2_q_name}\n\t"
1580
+ f"* Term Relationship: {term_relationship}")
1581
+
1582
+ if not(term1_valid and term2_valid and term1_exists and term2_exists):
1583
+ valid = False
1584
+
1585
+ if directive == "display":
1586
+ print(request_display)
1587
+ return None
1588
+ elif directive == "validate":
1589
+ print(request_display)
1590
+ return str(valid)
1591
+ elif directive == "process":
1592
+ try:
1593
+ print(request_display)
1594
+ if not valid: # First validate the term before we process it
1595
+ return None
1596
+ egeria_client.add_relationship_between_terms(term1_guid, term2_guid, term_relationship)
1597
+ print_msg(ALWAYS, f"Relationship `{term_relationship}` created", debug_level)
1598
+ update_md = (f"\n\n# Update Term-Term Relationship\n\n## Term 1 Name:\n\n{term1_q_name}"
1599
+ f"\n\n## Term 2 Name\n\n{term2_q_name}\n\n## Term Relationship:\n\n{term_relationship}")
1600
+ return update_md
1601
+
1602
+
1603
+ except Exception as e:
1604
+ print(f"{ERROR}Error performing {command}: {e}")
1605
+ console.print_exception(show_locals=True)
1606
+ return None
1607
+ else:
1608
+ return None
1609
+
1610
+
1611
+ def process_per_proj_upsert_command(egeria_client: ProjectManager, txt: str, directive: str = "display") -> str | None:
1612
+ """
1613
+ Processes a personal project create or update object_action by extracting key attributes such as
1614
+ glossary name, language, description, and usage from the given cell.
1615
+
1616
+ :param txt: A string representing the input cell to be processed for
1617
+ extracting glossary-related attributes.
1618
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1619
+ :return: A string summarizing the outcome of the processing.
1620
+ """
1621
+ command = extract_command(txt)
1622
+ object = command.split()
1623
+ object_type = f"{object[1]} {object[2]}"
1624
+ object_action = object[0]
1625
+ set_debug_level(directive)
1626
+
1627
+ project_name = process_simple_attribute(txt, ['Project Name'])
1628
+ description = process_simple_attribute(txt, ['Description'])
1629
+ project_identifier = process_simple_attribute(txt, ['Project Identifier'])
1630
+ project_status = process_simple_attribute(txt, ['Project Status'])
1631
+ project_phase = process_simple_attribute(txt, ['Project Phase'])
1632
+ project_health = process_simple_attribute(txt, ['Project Health'])
1633
+ start_date = process_simple_attribute(txt, ['Start Date'])
1634
+ planned_end_date = process_simple_attribute(txt, ['Planned End Date'])
1635
+ print(Markdown(f"{pre_command} `\'{command}\'` for project: `{project_name}` with directive: `{directive}` "))
1636
+
1637
+ project_display = (f"\n* Command: {command}\n\t* Project: {project_name}\n\t"
1638
+ f"* Status: {project_status}\n\t* Description: {description}\n\t"
1639
+ f"* Phase: {project_phase}\n\t* Health: {project_health}\n\t"
1640
+ f"* Start Date: {start_date}\n\t* Planned End Date: {planned_end_date}\n")
1641
+
1642
+ def validate_project(obj_action: str) -> tuple[bool, bool, str, str]:
1643
+ valid = True
1644
+ msg = ""
1645
+ known_guid = None
1646
+ known_q_name = None
1647
+
1648
+ project_details = egeria_client.get_projects_by_name(project_name)
1649
+ if project_details == NO_PROJECTS_FOUND:
1650
+ project_exists = False
1651
+ else:
1652
+ project_exists = True
1653
+
1654
+ if project_name is None:
1655
+ msg = f"* {ERROR}Project name is missing\n"
1656
+ valid = False
1657
+ if project_status is None:
1658
+ msg += f"* {INFO}No Project status found\n"
1659
+
1660
+ if description is None:
1661
+ msg += f"* {INFO}No Description found\n"
1662
+
1663
+ if project_identifier is None:
1664
+ msg += f"* {INFO}No Project Identifier found\n"
1665
+
1666
+ if project_phase is None:
1667
+ msg += f"* {INFO}No Project Phase found\n"
1668
+
1669
+ if project_health is None:
1670
+ msg += f"* {INFO}No Project Health found\n"
1671
+
1672
+ if start_date is None:
1673
+ msg += f"* {INFO}No Start Date found\n"
1674
+ elif not is_valid_iso_date(start_date):
1675
+ msg += f"* {ERROR}Start Date is not a valid ISO date of form YYYY-MM-DD\n"
1676
+ valid = False
1677
+
1678
+ if planned_end_date is None:
1679
+ msg += f"* {INFO} No Planned End Date found\n"
1680
+ elif not is_valid_iso_date(planned_end_date):
1681
+ msg += f"* {ERROR}Planned End Date is not a valid ISO date of form YYYY-MM-DD\n"
1682
+ valid = False
1683
+
1684
+ if obj_action == "Update":
1685
+ q_name = process_simple_attribute(txt, 'Qualified Name')
1686
+
1687
+ if not project_exists:
1688
+ msg += f"* {ERROR}Project {project_name} does not exist\n"
1689
+ valid = False
1690
+ if len(project_details) > 1 and project_exists:
1691
+ msg += f"* {ERROR}More than one project with name {project_name} found\n"
1692
+ valid = False
1693
+ if len(project_details) == 1:
1694
+ known_guid = project_details[0]['elementHeader'].get('guid', None)
1695
+ known_q_name = project_details[0]['glossaryProperties'].get('qualifiedName', None)
1696
+ if q_name is None:
1697
+ msg += f"* {INFO}Qualified Name is missing => can use known qualified name of {known_q_name}\n"
1698
+ valid = True
1699
+ elif q_name != known_q_name:
1700
+ msg += (f"* {ERROR}Project {project_name} qualifiedName mismatch between {q_name} and {known_q_name}\n")
1701
+ valid = False
1702
+ if valid:
1703
+ msg += project_display
1704
+ msg += f"* -->Project {project_name} exists and can be updated\n"
1705
+ else:
1706
+ msg += f"* --> validation failed\n"
1707
+ msg += '---'
1708
+ print(Markdown(msg))
1709
+ return valid, project_exists, known_guid, known_q_name
1710
+
1711
+ elif obj_action == "Create":
1712
+ if project_exists:
1713
+ msg += f"\n{ERROR}Project {project_name} already exists"
1714
+ else:
1715
+ msg += f"\n-->It is valid to create Project \'{project_name}\' with:\n"
1716
+ print(Markdown(msg))
1717
+ return valid, project_exists, known_guid, known_q_name
1718
+
1719
+ if directive == "display":
1720
+ print(Markdown(project_display))
1721
+ return None
1722
+
1723
+ elif directive == "validate":
1724
+ is_valid, exists, known_guid, known_q_name = validate_project(object_action)
1725
+ valid = is_valid if is_valid else None
1726
+ return valid
1727
+
1728
+ elif directive == "process":
1729
+ is_valid, exists, known_guid, known_q_name = validate_project(object_action)
1730
+ if not is_valid:
1731
+ return None
1732
+ if object_action == "Update":
1733
+ if not exists:
1734
+ print(f"\n\n-->Project {project_name} does not exist")
1735
+ return None
1736
+
1737
+ egeria_client.update_project(known_guid, known_q_name, project_identifier, project_name, description,
1738
+ project_status, project_phase, project_health, start_date, planned_end_date,
1739
+ False)
1740
+ print_msg(ALWAYS, f"Updated Project `{project_name}` with GUID {known_guid}", debug_level)
1741
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1742
+ elif object_action == "Create":
1743
+ guid = None
1744
+ if exists:
1745
+ print(f"Project `{project_name}` already exists and update document created")
1746
+ return update_a_command(txt, command, object_type, known_q_name, known_guid)
1747
+ else:
1748
+ guid = egeria_client.create_project(None, None, None, False, project_name, description,
1749
+ "PersonalProject", project_identifier, True, project_status,
1750
+ project_phase, project_health, start_date, planned_end_date)
1751
+ project_g = egeria_client.get_project_by_guid(guid)
1752
+ if project_g == NO_GLOSSARIES_FOUND:
1753
+ print(f"Just created with GUID {guid} but Project not found")
1754
+ return None
1755
+
1756
+ q_name = project_g['projectProperties']["qualifiedName"]
1757
+ update_element_dictionary(q_name, {'guid': guid, 'display_name': project_name})
1758
+ print_msg(ALWAYS, f"Created project `{project_name}` with GUID {guid}", debug_level)
1759
+ return update_a_command(txt, command, object_type, q_name, guid)
1760
+
1761
+
1762
+ def process_term_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1763
+ """ List terms as a markdown table. Filter based on optional search string. """
1764
+ set_debug_level(directive)
1765
+ valid = True
1766
+ command = extract_command(txt)
1767
+
1768
+ search_string = process_simple_attribute(txt, SEARCH_LABELS)
1769
+ if search_string is None:
1770
+ search_string = '*'
1771
+ print(Markdown(f"{pre_command} `{command}` with search string:`{search_string}` with directive: `{directive}`"))
1772
+
1773
+ glossary = process_simple_attribute(txt, ['Glossary', 'In Glossary', "Glossary Name"])
1774
+ if glossary is not None:
1775
+ _, glossary_guid, _, glossary_exists = get_element_by_name(egeria_client, "Glossary", glossary)
1776
+ msg = f"Found glossary `{glossary}` with GUID {glossary_guid}"
1777
+ print_msg(INFO, msg, debug_level)
1778
+ else:
1779
+ glossary_guid = None
1780
+ msg = f"No glossary found"
1781
+ print_msg(INFO, msg, debug_level)
1782
+
1783
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS)
1784
+ if output_format is None:
1785
+ output_format = "LIST"
1786
+ elif output_format not in ELEMENT_OUTPUT_FORMATS:
1787
+ valid = False
1788
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
1789
+
1790
+ request_display = (f"\n\t* Search String: {search_string}\n\t* Glossary: {glossary}\n\t* Output Format: "
1791
+ f"{output_format}\n")
1792
+
1793
+ if directive == "display":
1794
+ print(Markdown(request_display))
1795
+ return None
1796
+ elif directive == "validate":
1797
+ print(Markdown(request_display))
1798
+ return valid
1799
+ elif directive == "process":
1800
+ try:
1801
+ print(Markdown(request_display))
1802
+ if not valid: # First validate the term before we process it
1803
+ return None
1804
+
1805
+ term_list_md = f"\n# Term List for search string: `{search_string}`\n\n"
1806
+ if output_format == "DICT":
1807
+ struct = egeria_client.find_glossary_terms(search_string, glossary_guid, output_format=output_format)
1808
+ term_list_md += f"```{json.dumps(struct, indent=4)}```\n"
1809
+ else:
1810
+ term_list_md += egeria_client.find_glossary_terms(search_string, glossary_guid,
1811
+ output_format=output_format)
1812
+ print_msg("ALWAYS", f"Wrote Term List for search string: `{search_string}`", debug_level)
1813
+
1814
+ return term_list_md
1815
+
1816
+ md_table = egeria_client.find_glossary_terms(search_string, glossary_guid, output_format=output_format)
1817
+
1818
+ print_msg("ALWAYS", f"Wrote Term list for search string `{search_string}`", debug_level)
1819
+ return md_table
1820
+
1821
+ except Exception as e:
1822
+ print(f"{ERROR}Error performing {command}: {e}")
1823
+ console.print_exception(show_locals=True)
1824
+ return None
1825
+ else:
1826
+ return None
1827
+
1828
+
1829
+ def process_category_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1830
+ """ List terms as a markdown table. Filter based on optional search string. """
1831
+ set_debug_level(directive)
1832
+ valid = True
1833
+ command = extract_command(txt)
1834
+
1835
+ search_string = process_simple_attribute(txt, SEARCH_LABELS, "INFO")
1836
+ if search_string is None:
1837
+ search_string = '*'
1838
+ print(Markdown(f"{pre_command} `{command}` with search string:`{search_string}` with directive: `{directive}`"))
1839
+
1840
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS, "INFO")
1841
+ if output_format is None:
1842
+ output_format = "LIST"
1843
+ elif output_format not in ELEMENT_OUTPUT_FORMATS:
1844
+ valid = False
1845
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
1846
+
1847
+ request_display = f"\n\t* Search String: {search_string}\n\t* Output Format: {output_format}\n"
1848
+
1849
+ if directive == "display":
1850
+ print(Markdown(request_display))
1851
+ return None
1852
+ elif directive == "validate":
1853
+ print(Markdown(request_display))
1854
+ return valid
1855
+ elif directive == "process":
1856
+ try:
1857
+ print(Markdown(request_display))
1858
+ if not valid: # First validate the term before we process it
1859
+ return None
1860
+
1861
+ cat_list_md = f"\n# Category List for search string: `{search_string}`\n\n"
1862
+ if output_format == "DICT":
1863
+ struct = egeria_client.find_glossary_categories(search_string, output_format=output_format)
1864
+ cat_list_md += f"```{json.dumps(struct, indent=4)}```\n"
1865
+ else:
1866
+ cat_list_md += egeria_client.find_glossary_categories(search_string, output_format=output_format)
1867
+ print_msg("ALWAYS", f"Wrote Category List for search string: `{search_string}`", debug_level)
1868
+
1869
+ return cat_list_md
1870
+
1871
+ except Exception as e:
1872
+ print(f"{ERROR}Error performing {command}: {e}")
1873
+ console.print_exception(show_locals=True)
1874
+ return None
1875
+ else:
1876
+
1877
+ return None
1878
+
1879
+
1880
+ def process_glossary_structure_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1881
+ """ List terms as a markdown table. Filter based on optional search string. """
1882
+ set_debug_level(directive)
1883
+ valid = True
1884
+ command = extract_command(txt)
1885
+
1886
+ known_glossary_guid = ""
1887
+
1888
+ glossary_name = process_simple_attribute(txt, GLOSSARY_NAME_LABELS, "ERROR")
1889
+
1890
+ _, known_glossary_guid, valid, _ = process_element_identifiers(egeria_client, "Glossary", GLOSSARY_NAME_LABELS, txt,
1891
+ EXISTS_REQUIRED, None)
1892
+
1893
+ print(Markdown(f"{pre_command} `{command}` for glossary:`{glossary_name}` with directive: `{directive}`"))
1894
+
1895
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS, "INFO")
1896
+ if output_format is None:
1897
+ output_format = "MD"
1898
+ elif output_format not in ["DICT", "LIST", "MD"]:
1899
+ valid = False
1900
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
1901
+
1902
+ request_display = f"\n\t* Glossary name: {glossary_name}\n\t* Output Format: {output_format}\n"
1903
+
1904
+ if directive == "display":
1905
+ print(Markdown(request_display))
1906
+ return None
1907
+ elif directive == "validate":
1908
+ print(Markdown(request_display))
1909
+ return str(valid)
1910
+ elif directive == "process":
1911
+ try:
1912
+ print(Markdown(request_display))
1913
+ if not valid: # First validate the term before we process it
1914
+ return None
1915
+
1916
+ glossary_structure_md = f"\n# Glossary Structure for `{glossary_name}`\n\n"
1917
+ if output_format == "DICT":
1918
+ struct = egeria_client.get_glossary_category_structure(known_glossary_guid, output_format=output_format)
1919
+ glossary_structure_md += f"```{json.dumps(struct, indent=4)}```\n"
1920
+ else:
1921
+ glossary_structure_md += egeria_client.get_glossary_category_structure(known_glossary_guid,
1922
+ output_format=output_format)
1923
+ print_msg("ALWAYS", f"Wrote Glossary Structure for glossary: `{glossary_name}`", debug_level)
1924
+
1925
+ return glossary_structure_md
1926
+
1927
+ except Exception as e:
1928
+ print(f"{ERROR}Error performing {command}: {e}")
1929
+ console.print_exception(show_locals=True)
1930
+ return None
1931
+ else:
1932
+ return None
1933
+
1934
+
1935
+ def process_glossary_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1936
+ """ List terms as a markdown table. Filter based on optional search string. """
1937
+ set_debug_level(directive)
1938
+ valid = True
1939
+ command = extract_command(txt)
1940
+
1941
+ search_string = process_simple_attribute(txt, SEARCH_LABELS, "INFO")
1942
+ if search_string is None:
1943
+ search_string = '*'
1944
+ print(Markdown(f"{pre_command} `{command}` with search string:`{search_string}` with directive: `{directive}`"))
1945
+ if search_string is None:
1946
+ search_string = '*'
1947
+
1948
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS, "INFO")
1949
+ if output_format is None:
1950
+ output_format = "LIST"
1951
+ elif output_format not in ELEMENT_OUTPUT_FORMATS:
1952
+ valid = False
1953
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
1954
+
1955
+ request_display = f"\n\t* Search String: {search_string}\n\t* Output Format: {output_format}\n"
1956
+
1957
+ if directive == "display":
1958
+ print(request_display)
1959
+ return None
1960
+ elif directive == "validate":
1961
+ print(request_display)
1962
+ return valid
1963
+ elif directive == "process":
1964
+ try:
1965
+ print(request_display)
1966
+ if not valid: # First validate the term before we process it
1967
+ return None
1968
+
1969
+ glossary_list_md = f"\n# Glossary List for `{search_string}`\n\n"
1970
+ if output_format == "DICT":
1971
+ struct = egeria_client.find_glossaries(search_string, output_format=output_format)
1972
+ glossary_list_md += f"```{json.dumps(struct, indent=4)}```\n"
1973
+ else:
1974
+ glossary_list_md += egeria_client.find_glossaries(search_string, output_format=output_format)
1975
+ print_msg("ALWAYS", f"Wrote Glossary List for search string: `{search_string}`", debug_level)
1976
+
1977
+ return glossary_list_md
1978
+
1979
+ except Exception as e:
1980
+ print(f"{ERROR}Error performing {command}: {e}")
1981
+ console.print_exception(show_locals=True)
1982
+ return None
1983
+ else:
1984
+ return None
1985
+
1986
+
1987
+ def process_term_details_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1988
+ """ List terms as a markdown table. Filter based on optional search string. """
1989
+ set_debug_level(directive)
1990
+ valid = True
1991
+ command = extract_command(txt)
1992
+ object_type = command.split(' ')[1].strip()
1993
+ object_action = command.split(' ')[0].strip()
1994
+
1995
+
1996
+ term_identifier = process_simple_attribute(txt, TERM_NAME_LABELS, "ERROR")
1997
+
1998
+ print(Markdown(f"{pre_command} `{command}` for term:`{term_identifier}` with directive: `{directive}`"))
1999
+
2000
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS, "INFO")
2001
+ if output_format is None:
2002
+ output_format = "REPORT"
2003
+ else:
2004
+ output_format = output_format.upper()
2005
+
2006
+ if output_format not in ["DICT", "REPORT"]:
2007
+ valid = False
2008
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
2009
+
2010
+ request_display = f"\n\t* Term Identifier: {term_identifier}\n\t* Output Format {output_format}"
2011
+
2012
+ if directive == "display":
2013
+ print(request_display)
2014
+ return None
2015
+ elif directive == "validate":
2016
+ print(request_display)
2017
+ return valid
2018
+ elif directive == "process":
2019
+ try:
2020
+ print(request_display)
2021
+ if not valid: # First validate the term before we process it
2022
+ return None
2023
+ output = egeria_client.get_term_details(term_identifier, output_format=output_format)
2024
+ if output_format == "DICT":
2025
+ output = f"```{json.dumps(output, indent=4)}```"
2026
+ print_msg("ALWAYS", f"Wrote Term Details for term: `{term_identifier}`", debug_level)
2027
+
2028
+ return output
2029
+
2030
+ except Exception as e:
2031
+ print(f"{ERROR}Error performing {command}: {e}")
2032
+ console.print_exception(show_locals=True)
2033
+ return None
2034
+ else:
2035
+ return None
2036
+
2037
+
2038
+
2039
+ def process_term_history_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
2040
+ """ List terms as a markdown table. Filter based on optional search string. """
2041
+ set_debug_level(directive)
2042
+ valid = True
2043
+ command = extract_command(txt)
2044
+ object_type = command.split(' ')[1].strip()
2045
+ object_action = command.split(' ')[0].strip()
2046
+
2047
+ element_labels = TERM_NAME_LABELS
2048
+ element_labels.append('Display Name')
2049
+
2050
+ term_name = process_simple_attribute(txt, element_labels, "ERROR")
2051
+
2052
+ known_q_name, known_guid, valid, term_exists = process_element_identifiers(egeria_client, object_type,
2053
+ element_labels, txt, object_action, )
2054
+
2055
+ print(Markdown(f"{pre_command} `{command}` for term:`{term_name}` with directive: `{directive}`"))
2056
+
2057
+ output_format = process_simple_attribute(txt, OUTPUT_LABELS, "INFO")
2058
+ if output_format is None:
2059
+ output_format = "LIST"
2060
+ elif output_format not in ["DICT", "LIST"]:
2061
+ valid = False
2062
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
2063
+
2064
+ request_display = f"\n\t* Term Name: {term_name}\n\t* Output Format {output_format}\n\t* GUID: {known_guid}\n"
2065
+
2066
+ if directive == "display":
2067
+ print(request_display)
2068
+ return None
2069
+ elif directive == "validate":
2070
+ print(request_display)
2071
+ return valid
2072
+ elif directive == "process":
2073
+ try:
2074
+ print(request_display)
2075
+ if not valid: # First validate the term before we process it
2076
+ return None
2077
+ term_history_md = f"\n# Term History for `{term_name}`\n\n"
2078
+ if output_format == "DICT":
2079
+ struct = egeria_client.list_term_revision_history(known_guid, output_format=output_format)
2080
+ term_history_md += f"```{json.dumps(struct, indent=4)}```\n"
2081
+ else:
2082
+ term_history_md += egeria_client.list_full_term_history(known_guid, output_format)
2083
+ print_msg("ALWAYS", f"Wrote Term History for term `{term_name}`", debug_level)
2084
+
2085
+ return term_history_md
2086
+
2087
+ except Exception as e:
2088
+ print(f"{ERROR}Error performing {command}: {e}")
2089
+ console.print_exception(show_locals=True)
2090
+ return None
2091
+ else:
2092
+ return None
2093
+
2094
+
2095
+ def process_term_revision_history_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
2096
+ """ List term revision history as a markdown table or list."""
2097
+ set_debug_level(directive)
2098
+ valid = True
2099
+ command = extract_command(txt)
2100
+ object_type = command.split(' ')[1].strip()
2101
+ object_action = command.split(' ')[0].strip()
2102
+ known_q_name = None
2103
+ known_guid = None
2104
+
2105
+ element_labels = TERM_NAME_LABELS
2106
+
2107
+ term_name = process_simple_attribute(txt, element_labels, "ERROR")
2108
+ print(Markdown(f"{pre_command} `{command}` for term: `{term_name}` with directive: `{directive}` "))
2109
+
2110
+ known_q_name, known_guid, valid, _ = process_element_identifiers(egeria_client, object_type, element_labels, txt,
2111
+ object_action, )
2112
+ output_format = process_simple_attribute(txt, ['Output Format', 'Format'], 'INFO')
2113
+ if output_format is None:
2114
+ output_format = "LIST"
2115
+ elif output_format not in ["DICT", "LIST", "MD"]:
2116
+ valid = False
2117
+ print_msg(ERROR, f"Invalid output format: `{output_format}`", debug_level)
2118
+
2119
+ request_display = f"\n\t* Term Name: {term_name}\n\t* Output Format: {output_format}\n"
2120
+
2121
+ if directive == "display":
2122
+ print(request_display)
2123
+ return None
2124
+ elif directive == "validate":
2125
+ print(request_display)
2126
+ return str(valid)
2127
+ elif directive == "process":
2128
+ try:
2129
+ print(request_display)
2130
+ if not valid: # First validate the term before we process it
2131
+ return None
2132
+ term_history_md = f"\n# Term Revision History for `{term_name}`\n\n"
2133
+ if output_format == "DICT":
2134
+ struct = egeria_client.list_term_revision_history(known_guid, output_format)
2135
+ term_history_md += f"```{json.dumps(struct, indent=4)}```\n"
2136
+ else:
2137
+ term_history_md += egeria_client.list_term_revision_history(known_guid, output_format)
2138
+ print_msg("ALWAYS", f"Wrote Term Revision History for term `{term_name}`", debug_level)
2139
+ return term_history_md
2140
+
2141
+ except Exception as e:
2142
+ print(f"{ERROR}Error performing {command}: {e}")
2143
+ console.print_exception(show_locals=True)
2144
+ return None
2145
+ else:
2146
+ return None
2147
+