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
@@ -6,23 +6,32 @@ This module contains an initial version of the glossary_browser omvs module. The
6
6
  added in subsequent versions of the glossary_omvs module.
7
7
 
8
8
  """
9
+
9
10
  import asyncio
10
11
  from datetime import datetime
11
12
 
12
- # import json
13
+ from pyegeria import NO_GLOSSARIES_FOUND, max_paging_size
13
14
  from pyegeria._client import Client
14
- from pyegeria._validators import (
15
- validate_name,
16
- validate_guid,
17
- validate_search_string,
18
- )
15
+ from pyegeria._exceptions import InvalidParameterException, PropertyServerException, UserNotAuthorizedException
16
+ from pyegeria._globals import NO_CATEGORIES_FOUND, NO_TERMS_FOUND
17
+ from pyegeria._validators import validate_guid, validate_name, validate_search_string
19
18
  from pyegeria.utils import body_slimmer
19
+ from pyegeria.output_formatter import (
20
+ make_preamble,
21
+ make_md_attribute,
22
+ format_for_markdown_table,
23
+ generate_entity_md,
24
+ generate_entity_md_table,
25
+ generate_entity_dict,
26
+ generate_output,
27
+ MD_SEPARATOR
28
+ )
20
29
 
21
30
 
22
31
  class GlossaryBrowser(Client):
23
32
  """
24
33
  GlossaryBrowser is a class that extends the Client class. It provides methods to search and retrieve glossaries,
25
- terms and categories.
34
+ terms, and categories.
26
35
 
27
36
  Attributes:
28
37
 
@@ -38,14 +47,7 @@ class GlossaryBrowser(Client):
38
47
 
39
48
  """
40
49
 
41
- def __init__(
42
- self,
43
- view_server: str,
44
- platform_url: str,
45
- user_id: str,
46
- user_pwd: str = None,
47
- token: str = None,
48
- ):
50
+ def __init__(self, view_server: str, platform_url: str, user_id: str, user_pwd: str = None, token: str = None, ):
49
51
  self.view_server = view_server
50
52
  self.platform_url = platform_url
51
53
  self.user_pwd = user_pwd
@@ -54,6 +56,764 @@ class GlossaryBrowser(Client):
54
56
 
55
57
  Client.__init__(self, view_server, platform_url, user_id, user_pwd, token)
56
58
 
59
+
60
+ def _extract_glossary_properties(self, element: dict, output_format: str = None) -> dict:
61
+ """
62
+ Extract common properties from a glossary element.
63
+
64
+ Args:
65
+ element (dict): The glossary element
66
+ output_format (str, optional): The output format (FORM, REPORT, etc.)
67
+
68
+ Returns:
69
+ dict: Dictionary of extracted properties
70
+ """
71
+ guid = element['elementHeader'].get("guid", None)
72
+ properties = element['glossaryProperties']
73
+ display_name = properties.get("displayName", "") or ""
74
+ description = properties.get("description", "") or ""
75
+ language = properties.get("language", "") or ""
76
+ usage = properties.get("usage", "") or ""
77
+ qualified_name = properties.get("qualifiedName", "") or ""
78
+
79
+ categories = self.get_categories_for_glossary(guid)
80
+ cat_md_display = ''
81
+ cat_md_qn = ''
82
+ category_names = ''
83
+ category_qualified_names = ''
84
+
85
+ if type(categories) is list:
86
+ for category in categories:
87
+ cat_md_display += f" {category['glossaryCategoryProperties'][('displayName')]},\n"
88
+ cat_md_qn += f" {category['glossaryCategoryProperties'][('qualifiedName')]},\n"
89
+ category_names = cat_md_display.rstrip(',')
90
+ category_qualified_names = cat_md_qn.rstrip(',')
91
+
92
+ result = {
93
+ 'guid': guid, 'properties': properties, 'display_name': display_name, 'description': description,
94
+ 'language': language, 'usage': usage, 'qualified_name': qualified_name
95
+ }
96
+
97
+ # Include appropriate category information based on output format
98
+ if output_format == 'FORM':
99
+ result['categories_qualified_names'] = category_qualified_names
100
+ else:
101
+ result['categories_names'] = category_names
102
+
103
+ return result
104
+
105
+ def _generate_entity_md(self, elements: list, elements_action: str, output_format: str, entity_type: str,
106
+ extract_properties_func, get_additional_props_func=None) -> str:
107
+ """
108
+ Generic method to generate markdown for entities (glossaries, terms, categories).
109
+
110
+ Args:
111
+ elements (list): List of entity elements
112
+ elements_action (str): Action description for elements
113
+ output_format (str): Output format
114
+ entity_type (str): Type of entity (Glossary, Term, Category)
115
+ extract_properties_func: Function to extract properties from an element
116
+ get_additional_props_func: Optional function to get additional properties
117
+
118
+ Returns:
119
+ str: Markdown representation
120
+ """
121
+ return generate_entity_md(
122
+ elements=elements,
123
+ elements_action=elements_action,
124
+ output_format=output_format,
125
+ entity_type=entity_type,
126
+ extract_properties_func=extract_properties_func,
127
+ get_additional_props_func=get_additional_props_func
128
+ )
129
+
130
+ def _generate_glossary_md(self, elements: list, elements_action: str, output_format: str) -> str:
131
+ """
132
+ Generate markdown for glossaries.
133
+
134
+ Args:
135
+ elements (list): List of glossary elements
136
+ elements_action (str): Action description for elements
137
+ output_format (str): Output format
138
+
139
+ Returns:
140
+ str: Markdown representation
141
+ """
142
+ # Store the current output format for use by _extract_glossary_properties_with_format
143
+ self._current_output_format = output_format
144
+
145
+ return self._generate_entity_md(elements=elements, elements_action=elements_action, output_format=output_format,
146
+ entity_type="Glossary",
147
+ extract_properties_func=self._extract_glossary_properties_with_format)
148
+
149
+ def _generate_entity_md_table(self, elements: list, search_string: str, entity_type: str, extract_properties_func,
150
+ columns: list, get_additional_props_func=None, output_format: str = 'LIST') -> str:
151
+ """
152
+ Generic method to generate a markdown table for entities (glossaries, terms, categories).
153
+
154
+ Args:
155
+ elements (list): List of entity elements
156
+ search_string (str): The search string used
157
+ entity_type (str): Type of entity (Glossary, Term, Category)
158
+ extract_properties_func: Function to extract properties from an element
159
+ columns: List of column definitions, each containing 'name', 'key', and 'format' (optional)
160
+ get_additional_props_func: Optional function to get additional properties
161
+ output_format (str): Output format (FORM, REPORT, LIST, etc.)
162
+
163
+ Returns:
164
+ str: Markdown table
165
+ """
166
+ return generate_entity_md_table(
167
+ elements=elements,
168
+ search_string=search_string,
169
+ entity_type=entity_type,
170
+ extract_properties_func=extract_properties_func,
171
+ columns=columns,
172
+ get_additional_props_func=get_additional_props_func,
173
+ output_format=output_format
174
+ )
175
+
176
+ def _generate_glossary_md_table(self, elements: list, search_string: str) -> str:
177
+ """
178
+ Generate a markdown table for glossaries.
179
+
180
+ Args:
181
+ elements (list): List of glossary elements
182
+ search_string (str): The search string used
183
+
184
+ Returns:
185
+ str: Markdown table
186
+ """
187
+ # Store the current output format for use by _extract_glossary_properties_with_format
188
+ self._current_output_format = 'LIST' # Tables use LIST format
189
+
190
+ columns = [{'name': 'Glossary Name', 'key': 'display_name'},
191
+ {'name': 'Qualified Name', 'key': 'qualified_name'},
192
+ {'name': 'Language', 'key': 'language', 'format': True},
193
+ {'name': 'Description', 'key': 'description', 'format': True},
194
+ {'name': 'Usage', 'key': 'usage', 'format': True},
195
+ {'name': 'Categories', 'key': 'categories_names', 'format': True}, ]
196
+
197
+ return self._generate_entity_md_table(elements=elements, search_string=search_string, entity_type="Glossary",
198
+ extract_properties_func=self._extract_glossary_properties_with_format,
199
+ columns=columns)
200
+
201
+ def _generate_entity_dict(self, elements: list, extract_properties_func, get_additional_props_func=None,
202
+ include_keys=None, exclude_keys=None, output_format: str = 'DICT') -> list:
203
+ """
204
+ Generic method to generate a dictionary representation of entities (glossaries, terms, categories).
205
+
206
+ Args:
207
+ elements (list): List of entity elements
208
+ extract_properties_func: Function to extract properties from an element
209
+ get_additional_props_func: Optional function to get additional properties
210
+ include_keys: Optional list of keys to include in the result (if None, include all)
211
+ exclude_keys: Optional list of keys to exclude from the result (if None, exclude none)
212
+ output_format (str): Output format (FORM, REPORT, DICT, etc.)
213
+
214
+ Returns:
215
+ list: List of entity dictionaries
216
+ """
217
+ return generate_entity_dict(
218
+ elements=elements,
219
+ extract_properties_func=extract_properties_func,
220
+ get_additional_props_func=get_additional_props_func,
221
+ include_keys=include_keys,
222
+ exclude_keys=exclude_keys,
223
+ output_format=output_format
224
+ )
225
+
226
+ def _generate_glossary_dict(self, elements: list, output_format: str = 'DICT') -> list:
227
+ """
228
+ Generate a dictionary representation of glossaries.
229
+
230
+ Args:
231
+ elements (list): List of glossary elements
232
+ output_format (str): Output format (FORM, REPORT, DICT, etc.)
233
+
234
+ Returns:
235
+ list: List of glossary dictionaries
236
+ """
237
+ # Store the current output format for use by _extract_glossary_properties_with_format
238
+ self._current_output_format = output_format
239
+
240
+ return self._generate_entity_dict(elements=elements, extract_properties_func=self._extract_glossary_properties_with_format,
241
+ exclude_keys=['properties'], output_format=output_format)
242
+
243
+ def _extract_glossary_properties_with_format(self, element: dict) -> dict:
244
+ """
245
+ Wrapper function for _extract_glossary_properties that passes the current output format.
246
+ This is used internally by generate_glossaries_md.
247
+
248
+ Args:
249
+ element (dict): The glossary element
250
+
251
+ Returns:
252
+ dict: Dictionary of extracted properties
253
+ """
254
+ # The output_format is stored as an instance variable during generate_glossaries_md
255
+ return self._extract_glossary_properties(element, self._current_output_format)
256
+
257
+ def generate_glossaries_md(self, elements: list | dict, search_string: str,
258
+ output_format: str = 'MD') -> str | list:
259
+ """
260
+ Generate markdown or dictionary representation of glossaries.
261
+
262
+ Args:
263
+ elements (list | dict): List or dictionary of glossary elements
264
+ search_string (str): The search string used
265
+ output_format (str): Output format (MD, FORM, REPORT, LIST, DICT)
266
+
267
+ Returns:
268
+ str | list: Markdown string or list of dictionaries depending on output_format
269
+ """
270
+ # Store the current output format for use by _extract_glossary_properties_with_format
271
+ self._current_output_format = output_format
272
+
273
+ # Define columns for LIST format
274
+ columns = [
275
+ {'name': 'Glossary Name', 'key': 'display_name'},
276
+ {'name': 'Qualified Name', 'key': 'qualified_name'},
277
+ {'name': 'Language', 'key': 'language', 'format': True},
278
+ {'name': 'Description', 'key': 'description', 'format': True},
279
+ {'name': 'Usage', 'key': 'usage', 'format': True},
280
+ {'name': 'Categories', 'key': 'categories_names', 'format': True},
281
+ ]
282
+
283
+ return generate_output(
284
+ elements=elements,
285
+ search_string=search_string,
286
+ entity_type="Glossary",
287
+ output_format=output_format,
288
+ extract_properties_func=self._extract_glossary_properties_with_format,
289
+ columns=columns if output_format == 'LIST' else None
290
+ )
291
+
292
+ def _extract_term_properties(self, element: dict) -> dict:
293
+ """
294
+ Extract common properties from a term element.
295
+
296
+ Args:
297
+ element (dict): The term element
298
+
299
+ Returns:
300
+ dict: Dictionary of extracted properties
301
+ """
302
+ guid = element['elementHeader'].get("guid", None)
303
+ properties = element['glossaryTermProperties']
304
+ display_name = properties.get("displayName", "") or ""
305
+ summary = properties.get("summary", "") or ""
306
+ description = properties.get("description", "") or ""
307
+ examples = properties.get("examples", "") or ""
308
+ usage = properties.get("usage", "") or ""
309
+ pub_version = properties.get("publishVersionIdentifier", "") or ""
310
+ qualified_name = properties.get("qualifiedName", "") or ""
311
+ status = element['elementHeader'].get('status', "") or ""
312
+ aliases = ", ".join(properties.get("aliases", "")) or ""
313
+
314
+ return {
315
+ 'guid': guid, 'properties': properties, 'display_name': display_name, 'aliases': aliases,
316
+ 'summary': summary, 'description': description, 'examples': examples, 'usage': usage,
317
+ 'version identifier': pub_version, 'qualified_name': qualified_name, 'status': status
318
+ }
319
+
320
+ def _get_categories_for_term(self, term_guid: str, output_format: str = None) -> tuple[list, str]:
321
+ """
322
+ Get a list of categories for a given term.
323
+
324
+ Args:
325
+ term_guid (str): The GUID of the term
326
+ output_format (str): Output format (FORM, REPORT, LIST, etc.)
327
+
328
+ Returns:
329
+ tuple: A tuple containing:
330
+ - list: List of category names
331
+ - str: Formatted string of category names for markdown
332
+ """
333
+ category_names = []
334
+ category_list_md = "\n"
335
+
336
+ category_list = self.get_categories_for_term(term_guid)
337
+ if type(category_list) is str and category_list == NO_CATEGORIES_FOUND:
338
+ category_list_md = ''
339
+ elif isinstance(category_list, list) and len(category_list) > 0:
340
+ first_cat = True
341
+ for category in category_list:
342
+ # Use qualified name for FORM output, display name for REPORT and LIST output
343
+ if output_format in ['REPORT', 'LIST']:
344
+ category_name = category["glossaryCategoryProperties"].get("displayName", '---')
345
+ else:
346
+ category_name = category["glossaryCategoryProperties"].get("qualifiedName", '---')
347
+
348
+ if category_name:
349
+ category_names.append(category_name)
350
+ if first_cat:
351
+ category_list_md += f" {category_name}\n"
352
+ first_cat = False
353
+ else:
354
+ category_list_md += f", {category_name}\n"
355
+ else:
356
+ category_list_md = '---'
357
+
358
+ return category_names, category_list_md
359
+
360
+ def _get_term_table_properties(self, element: dict, term_guid: str, output_format: str = None) -> dict:
361
+ """
362
+ Get properties for a term table row.
363
+
364
+ Args:
365
+ element (dict): The term element
366
+ term_guid (str): The GUID of the term
367
+ output_format (str): Output format (FORM, REPORT, etc.)
368
+
369
+ Returns:
370
+ dict: Dictionary of properties for the table row
371
+ """
372
+ # Get glossary information
373
+ glossary_qualified_name = self._get_glossary_name_for_element(element, output_format)
374
+
375
+ # Get categories
376
+ category_names, _ = self._get_categories_for_term(term_guid, output_format)
377
+ categories_str = ", ".join(category_names) if category_names else "---"
378
+
379
+ return {
380
+ 'glossary': glossary_qualified_name, 'categories_str': categories_str
381
+ }
382
+
383
+ def _generate_term_md_table(self, elements: list, search_string: str, output_format: str = 'LIST') -> str:
384
+ """
385
+ Generate a markdown table for terms.
386
+
387
+ Args:
388
+ elements (list): List of term elements
389
+ search_string (str): The search string used
390
+ output_format (str): Output format (FORM, REPORT, LIST, etc.)
391
+
392
+ Returns:
393
+ str: Markdown table
394
+ """
395
+ columns = [{'name': 'Term Name', 'key': 'display_name'}, {'name': 'Qualified Name', 'key': 'qualified_name'},
396
+ {'name': 'Aliases', 'key': 'aliases', 'format': True},
397
+ {'name': 'Summary', 'key': 'summary', 'format': True}, {'name': 'Glossary', 'key': 'glossary'},
398
+ {'name': 'Categories', 'key': 'categories_str', 'format': True}]
399
+
400
+ # Create a wrapper function to pass output_format to _get_term_table_properties
401
+ def get_table_props_with_format(element, term_guid, output_format_param=None):
402
+ return self._get_term_table_properties(element, term_guid, output_format)
403
+
404
+ return self._generate_entity_md_table(elements=elements, search_string=search_string, entity_type="Term",
405
+ extract_properties_func=self._extract_term_properties, columns=columns,
406
+ get_additional_props_func=get_table_props_with_format)
407
+
408
+ def _get_term_dict_properties(self, element: dict, term_guid: str, output_format: str = None) -> dict:
409
+ """
410
+ Get additional properties for a term dictionary.
411
+
412
+ Args:
413
+ element (dict): The term element
414
+ term_guid (str): The GUID of the term
415
+ output_format (str): Output format (FORM, REPORT, etc.)
416
+
417
+ Returns:
418
+ dict: Dictionary of additional properties
419
+ """
420
+ # Get glossary information
421
+ glossary_qualified_name = self._get_glossary_name_for_element(element, output_format)
422
+
423
+ # Get categories
424
+ category_names, _ = self._get_categories_for_term(term_guid, output_format)
425
+
426
+ return {
427
+ 'in_glossary': glossary_qualified_name, 'categories': category_names,
428
+ 'version': element['glossaryTermProperties'].get('publishfinVersionIdentifier', '')
429
+ }
430
+
431
+ def _generate_term_dict(self, elements: list, output_format: str = 'DICT') -> list:
432
+ """
433
+ Generate a dictionary representation of terms.
434
+
435
+ Args:
436
+ elements (list): List of term elements
437
+ output_format (str): Output format (FORM, REPORT, DICT, etc.)
438
+
439
+ Returns:
440
+ list: List of term dictionaries
441
+ """
442
+
443
+ # Create a wrapper function to pass output_format to _get_term_dict_properties
444
+ def get_dict_props_with_format(element, term_guid, output_format_param=None):
445
+ return self._get_term_dict_properties(element, term_guid, output_format)
446
+
447
+ return self._generate_entity_dict(elements=elements, extract_properties_func=self._extract_term_properties,
448
+ get_additional_props_func=get_dict_props_with_format,
449
+ exclude_keys=['properties', 'pub_version']
450
+ # Exclude raw properties and pub_version (renamed to version)
451
+ )
452
+
453
+ def _get_term_additional_properties(self, element: dict, term_guid: str, output_format: str = None) -> dict:
454
+ """
455
+ Get additional properties for a term.
456
+
457
+ Args:
458
+ element (dict): The term element
459
+ term_guid (str): The GUID of the term
460
+ output_format (str): Output format (FORM, REPORT, etc.)
461
+
462
+ Returns:
463
+ dict: Dictionary of additional properties
464
+ """
465
+ # Get glossary information
466
+ glossary_qualified_name = self._get_glossary_name_for_element(element, output_format)
467
+
468
+ # Get categories
469
+ _, category_list_md = self._get_categories_for_term(term_guid, output_format)
470
+
471
+ return {
472
+ 'in_glossary': glossary_qualified_name, 'categories': category_list_md
473
+ }
474
+
475
+ def _generate_term_md(self, elements: list, elements_action: str, output_format: str) -> str:
476
+ """
477
+ Generate markdown for terms.
478
+
479
+ Args:
480
+ elements (list): List of term elements
481
+ elements_action (str): Action description for elements
482
+ output_format (str): Output format
483
+
484
+ Returns:
485
+ str: Markdown representation
486
+ """
487
+ return self._generate_entity_md(elements=elements, elements_action=elements_action, output_format=output_format,
488
+ entity_type="Term", extract_properties_func=self._extract_term_properties,
489
+ get_additional_props_func=self._get_term_additional_properties)
490
+
491
+ def generate_terms_md(self, elements: list | dict, search_string: str, output_format: str = 'MD') -> str | list:
492
+ """
493
+ Generate markdown or dictionary representation of terms.
494
+
495
+ Args:
496
+ elements (list | dict): List or dictionary of term elements
497
+ search_string (str): The search string used
498
+ output_format (str): Output format (MD, MD-TABLE, DICT, FORM, REPORT)
499
+
500
+ Returns:
501
+ str | list: Markdown string or list of dictionaries depending on output_format
502
+ """
503
+ # Define columns for LIST format
504
+ columns = [
505
+ {'name': 'Term Name', 'key': 'display_name'},
506
+ {'name': 'Qualified Name', 'key': 'qualified_name'},
507
+ {'name': 'Summary', 'key': 'summary', 'format': True},
508
+ {'name': 'Description', 'key': 'description', 'format': True},
509
+ {'name': 'Status', 'key': 'status'},
510
+ {'name': 'Categories', 'key': 'categories', 'format': True},
511
+ {'name': 'Glossary', 'key': 'glossary_name'},
512
+ ]
513
+
514
+ return generate_output(
515
+ elements=elements,
516
+ search_string=search_string,
517
+ entity_type="Term",
518
+ output_format=output_format,
519
+ extract_properties_func=self._extract_term_properties,
520
+ get_additional_props_func=self._get_term_additional_properties,
521
+ columns=columns if output_format == 'LIST' else None
522
+ )
523
+
524
+ def _get_parent_category_name(self, category_guid: str, output_format: str = None) -> str:
525
+ """
526
+ Get the parent category name for a given category.
527
+
528
+ Args:
529
+ category_guid (str): The GUID of the category
530
+ output_format (str): Output format (FORM, REPORT, LIST, etc.)
531
+
532
+ Returns:
533
+ str: The parent category name or ' ' if no parent
534
+ """
535
+ parent_cat = self.get_category_parent(category_guid)
536
+ if isinstance(parent_cat, str):
537
+ return ' '
538
+
539
+ # Return qualified name for FORM output, display name for REPORT and LIST output
540
+ if output_format == 'FORM':
541
+ return parent_cat['glossaryCategoryProperties']['qualifiedName']
542
+ elif output_format in ['REPORT', 'LIST']:
543
+ return parent_cat['glossaryCategoryProperties']['displayName']
544
+ else:
545
+ # Default to qualified name for backward compatibility
546
+ return parent_cat['glossaryCategoryProperties']['qualifiedName']
547
+
548
+ def _get_subcategories_list(self, category_guid: str, output_format: str = None) -> tuple[list, str]:
549
+ """
550
+ Get a list of subcategories for a given category.
551
+
552
+ Args:
553
+ category_guid (str): The GUID of the category
554
+ output_format (str): Output format (FORM, REPORT, LIST, etc.)
555
+
556
+ Returns:
557
+ tuple: A tuple containing:
558
+ - list: List of subcategory names
559
+ - str: Formatted string of subcategory names for markdown
560
+ """
561
+ subcategories = self.get_glossary_subcategories(category_guid)
562
+ subcategory_list = []
563
+
564
+ if isinstance(subcategories, str) and subcategories == NO_CATEGORIES_FOUND:
565
+ subcategory_list_md = '---'
566
+ elif isinstance(subcategories, list) and len(subcategories) > 0:
567
+ for subcat in subcategories:
568
+ # Use qualified name for FORM output, display name for REPORT and LIST output
569
+ if output_format == 'FORM':
570
+ subcat_name = subcat["glossaryCategoryProperties"].get("qualifiedName", '')
571
+ elif output_format in ['REPORT', 'LIST']:
572
+ subcat_name = subcat["glossaryCategoryProperties"].get("displayName", '')
573
+ else:
574
+ # Default to qualified name for backward compatibility
575
+ subcat_name = subcat["glossaryCategoryProperties"].get("qualifiedName", '')
576
+
577
+ if subcat_name:
578
+ subcategory_list.append(subcat_name)
579
+ subcategory_list_md = ", ".join(subcategory_list)
580
+ else:
581
+ subcategory_list_md = '---'
582
+
583
+ return subcategory_list, subcategory_list_md
584
+
585
+ def _get_glossary_name_for_element(self, element: dict, output_format: str = None) -> str:
586
+ """
587
+ Get the glossary name for a given element.
588
+
589
+ Args:
590
+ element (dict): The element dictionary
591
+ output_format (str): Output format (FORM, REPORT, etc.)
592
+
593
+ Returns:
594
+ str: The glossary name or '---' if not found
595
+ """
596
+ classification_props = element["elementHeader"]['classifications'][0].get('classificationProperties', None)
597
+ if classification_props is None:
598
+ return '---'
599
+
600
+ glossary_guid = classification_props.get('anchorScopeGUID', '---')
601
+ if glossary_guid == '---':
602
+ return '---'
603
+
604
+ glossary = self.get_glossary_by_guid(glossary_guid)
605
+
606
+ # Return display name for REPORT output, qualified name otherwise
607
+ if output_format == 'REPORT':
608
+ return glossary['glossaryProperties']['displayName']
609
+ else:
610
+ return glossary['glossaryProperties']['qualifiedName']
611
+
612
+ def _extract_category_properties(self, element: dict) -> dict:
613
+ """
614
+ Extract common properties from a category element.
615
+
616
+ Args:
617
+ element (dict): The category element
618
+
619
+ Returns:
620
+ dict: Dictionary of extracted properties
621
+ """
622
+ guid = element['elementHeader'].get("guid", None)
623
+ properties = element['glossaryCategoryProperties']
624
+ display_name = properties.get("displayName", "") or ""
625
+ description = properties.get("description", "") or ""
626
+ qualified_name = properties.get("qualifiedName", "") or ""
627
+
628
+ return {
629
+ 'guid': guid, 'properties': properties, 'display_name': display_name, 'description': description,
630
+ 'qualified_name': qualified_name
631
+ }
632
+
633
+ def _get_category_table_properties(self, element: dict, category_guid: str, output_format: str = None) -> dict:
634
+ """
635
+ Get properties for a category table row.
636
+
637
+ Args:
638
+ element (dict): The category element
639
+ category_guid (str): The GUID of the category
640
+ output_format (str): Output format (FORM, REPORT, etc.)
641
+
642
+ Returns:
643
+ dict: Dictionary of properties for the table row
644
+ """
645
+ # Get parent category
646
+ parent_cat_md = self._get_parent_category_name(category_guid, output_format)
647
+
648
+ # Get subcategories
649
+ _, subcategory_list_md = self._get_subcategories_list(category_guid, output_format)
650
+
651
+ return {
652
+ 'parent_category': parent_cat_md, 'subcategories': subcategory_list_md
653
+ }
654
+
655
+ def _generate_category_md_table(self, elements: list, search_string: str, output_format: str = 'LIST') -> str:
656
+ """
657
+ Generate a markdown table for categories.
658
+
659
+ Args:
660
+ elements (list): List of category elements
661
+ search_string (str): The search string used
662
+ output_format (str): Output format (FORM, REPORT, etc.)
663
+
664
+ Returns:
665
+ str: Markdown table
666
+ """
667
+ columns = [{'name': 'Display Name', 'key': 'display_name'},
668
+ {'name': 'Description', 'key': 'description', 'format': True},
669
+ {'name': 'Qualified Name', 'key': 'qualified_name'},
670
+ {'name': 'Parent Category', 'key': 'parent_category'},
671
+ {'name': 'Subcategories', 'key': 'subcategories', 'format': True}]
672
+
673
+ # Create a wrapper function to pass output_format to _get_category_table_properties
674
+ def get_table_props_with_format(element, category_guid, output_format_param=None):
675
+ return self._get_category_table_properties(element, category_guid, output_format)
676
+
677
+ return self._generate_entity_md_table(elements=elements, search_string=search_string, entity_type="Category",
678
+ extract_properties_func=self._extract_category_properties,
679
+ columns=columns, get_additional_props_func=get_table_props_with_format)
680
+
681
+ def _get_category_dict_properties(self, element: dict, category_guid: str, output_format: str = None) -> dict:
682
+ """
683
+ Get additional properties for a category dictionary.
684
+
685
+ Args:
686
+ element (dict): The category element
687
+ category_guid (str): The GUID of the category
688
+ output_format (str): Output format (FORM, REPORT, etc.)
689
+
690
+ Returns:
691
+ dict: Dictionary of additional properties
692
+ """
693
+ # Get parent category
694
+ parent_cat_md = self._get_parent_category_name(category_guid, output_format)
695
+
696
+ # Get subcategories
697
+ subcategory_list, _ = self._get_subcategories_list(category_guid, output_format)
698
+
699
+ # Get glossary information
700
+ glossary_qualified_name = self._get_glossary_name_for_element(element, output_format)
701
+
702
+ return {
703
+ 'parent_category': parent_cat_md, 'subcategories': subcategory_list, 'in_glossary': glossary_qualified_name
704
+ }
705
+
706
+ def _generate_category_dict(self, elements: list, output_format: str = 'DICT') -> list:
707
+ """
708
+ Generate a dictionary representation of categories.
709
+
710
+ Args:
711
+ elements (list): List of category elements
712
+ output_format (str): Output format (FORM, REPORT, etc.)
713
+
714
+ Returns:
715
+ list: List of category dictionaries
716
+ """
717
+
718
+ # Create a wrapper function to pass output_format to _get_category_dict_properties
719
+ def get_dict_props_with_format(element, category_guid, output_format_param=None):
720
+ return self._get_category_dict_properties(element, category_guid, output_format)
721
+
722
+ return self._generate_entity_dict(elements=elements, extract_properties_func=self._extract_category_properties,
723
+ get_additional_props_func=get_dict_props_with_format,
724
+ exclude_keys=['properties'], # Exclude raw properties
725
+ output_format=output_format)
726
+
727
+ def _get_category_additional_properties(self, element: dict, category_guid: str, output_format: str = None) -> dict:
728
+ """
729
+ Get additional properties for a category.
730
+
731
+ Args:
732
+ element (dict): The category element
733
+ category_guid (str): The GUID of the category
734
+ output_format (str): Output format (FORM, REPORT, etc.)
735
+
736
+ Returns:
737
+ dict: Dictionary of additional properties
738
+ """
739
+ # Get parent category
740
+ parent_cat_md = self._get_parent_category_name(category_guid, output_format)
741
+
742
+ # Get glossary information
743
+ glossary_qualified_name = self._get_glossary_name_for_element(element, output_format)
744
+
745
+ # Only include subcategories if output_format is not FORM, REPORT, or MD
746
+ if output_format not in ['FORM', 'REPORT', 'MD']:
747
+ # Get subcategories
748
+ _, subcategory_list_md = self._get_subcategories_list(category_guid, output_format)
749
+ return {
750
+ 'in_glossary': glossary_qualified_name, 'parent_category': parent_cat_md,
751
+ 'subcategories': subcategory_list_md
752
+ }
753
+ else:
754
+ return {
755
+ 'in_glossary': glossary_qualified_name, 'parent_category': parent_cat_md
756
+ }
757
+
758
+ def _generate_category_md(self, elements: list, elements_action: str, output_format: str) -> str:
759
+ """
760
+ Generate markdown for categories.
761
+
762
+ Args:
763
+ elements (list): List of category elements
764
+ elements_action (str): Action description for elements
765
+ output_format (str): Output format
766
+
767
+ Returns:
768
+ str: Markdown representation
769
+ """
770
+
771
+ # Create a wrapper function to pass output_format to _get_category_additional_properties
772
+ def get_additional_props_with_format(element, category_guid, output_format_param=None):
773
+ return self._get_category_additional_properties(element, category_guid, output_format)
774
+
775
+ return self._generate_entity_md(elements=elements, elements_action=elements_action, output_format=output_format,
776
+ entity_type="Category",
777
+ extract_properties_func=self._extract_category_properties,
778
+ get_additional_props_func=get_additional_props_with_format)
779
+
780
+ def generate_categories_md(self, elements: list | dict, search_string: str,
781
+ output_format: str = 'MD') -> str | list:
782
+ """
783
+ Generate markdown or dictionary representation of categories.
784
+
785
+ Args:
786
+ elements (list | dict): List or dictionary of category elements
787
+ search_string (str): The search string used
788
+ output_format (str): Output format (MD, LIST, DICT, FORM, REPORT)
789
+
790
+ Returns:
791
+ str | list: Markdown string or list of dictionaries depending on output_format
792
+ """
793
+ # Define columns for LIST format
794
+ columns = [
795
+ {'name': 'Category Name', 'key': 'display_name'},
796
+ {'name': 'Qualified Name', 'key': 'qualified_name'},
797
+ {'name': 'Description', 'key': 'description', 'format': True},
798
+ {'name': 'Parent Category', 'key': 'parent_category', 'format': True},
799
+ {'name': 'Subcategories', 'key': 'subcategories', 'format': True},
800
+ {'name': 'Glossary', 'key': 'glossary_name'},
801
+ ]
802
+
803
+ # Create a wrapper function to pass output_format to _get_category_additional_properties
804
+ def get_additional_props_with_format(element, category_guid, output_format_param=None):
805
+ return self._get_category_additional_properties(element, category_guid, output_format)
806
+
807
+ return generate_output(
808
+ elements=elements,
809
+ search_string=search_string,
810
+ entity_type="Category",
811
+ output_format=output_format,
812
+ extract_properties_func=self._extract_category_properties,
813
+ get_additional_props_func=get_additional_props_with_format,
814
+ columns=columns if output_format == 'LIST' else None
815
+ )
816
+
57
817
  #
58
818
  # Get Valid Values for Enumerations
59
819
  #
@@ -72,10 +832,8 @@ class GlossaryBrowser(Client):
72
832
 
73
833
  """
74
834
 
75
- url = (
76
- f"{self.platform_url}/servers/{self.view_server}"
77
- f"/api/open-metadata/glossary-browser/glossaries/terms/status-list"
78
- )
835
+ url = (f"{self.platform_url}/servers/{self.view_server}"
836
+ f"/api/open-metadata/glossary-browser/glossaries/terms/status-list")
79
837
 
80
838
  response = await self._async_make_request("GET", url)
81
839
  return response.json().get("statuses", [])
@@ -113,10 +871,8 @@ class GlossaryBrowser(Client):
113
871
 
114
872
  """
115
873
 
116
- url = (
117
- f"{self.platform_url}/servers/{self.view_server}"
118
- f"/api/open-metadata/glossary-browser/glossaries/terms/relationships/status-list"
119
- )
874
+ url = (f"{self.platform_url}/servers/{self.view_server}"
875
+ f"/api/open-metadata/glossary-browser/glossaries/terms/relationships/status-list")
120
876
 
121
877
  response = await self._async_make_request("GET", url)
122
878
  return response.json().get("statuses", [])
@@ -154,10 +910,8 @@ class GlossaryBrowser(Client):
154
910
 
155
911
  """
156
912
 
157
- url = (
158
- f"{self.platform_url}/servers/{self.view_server}"
159
- f"/api/open-metadata/glossary-browser/glossaries/terms/activity-types"
160
- )
913
+ url = (f"{self.platform_url}/servers/{self.view_server}"
914
+ f"/api/open-metadata/glossary-browser/glossaries/terms/activity-types")
161
915
 
162
916
  response = await self._async_make_request("GET", url)
163
917
  return response.json().get("types", [])
@@ -179,26 +933,54 @@ class GlossaryBrowser(Client):
179
933
  response = loop.run_until_complete(self._async_get_glossary_term_statuses())
180
934
  return response
181
935
 
936
+ async def _async_get_term_relationship_types(self) -> [str]:
937
+ """Return the list of term relationship types enum values. Async version.
938
+
939
+ Parameters
940
+ ----------
941
+
942
+
943
+ Returns
944
+ -------
945
+ List[str]
946
+ A list of glossary term relationships retrieved from the server.
947
+
948
+ """
949
+
950
+ url = (f"{self.platform_url}/servers/{self.view_server}"
951
+ f"/api/open-metadata/glossary-manager/glossaries/terms/relationships/type-names")
952
+
953
+ response = await self._async_make_request("GET", url)
954
+ return response.json().get("names", [])
955
+
956
+ def get_term_relationship_types(self) -> [str]:
957
+ """Return the list of term relationship type enum values.
958
+
959
+ Parameters
960
+ ----------
961
+
962
+
963
+ Returns
964
+ -------
965
+ list of str
966
+ A list of term relationship types. Each status is represented as a string.
967
+
968
+ """
969
+ loop = asyncio.get_event_loop()
970
+ response = loop.run_until_complete(self._async_get_term_relationship_types())
971
+ return response
972
+
182
973
  #
183
974
  # Glossaries
184
975
  #
185
976
 
186
- async def _async_find_glossaries(
187
- self,
188
- search_string: str,
189
- effective_time: str = None,
190
- starts_with: bool = False,
191
- ends_with: bool = False,
192
- ignore_case: bool = False,
193
- for_lineage: bool = False,
194
- for_duplicate_processing: bool = False,
195
- type_name: str = None,
196
- start_from: int = 0,
197
- page_size: int = None,
198
- ) -> list | str:
977
+ async def _async_find_glossaries(self, search_string: str, effective_time: str = None, starts_with: bool = False,
978
+ ends_with: bool = False, ignore_case: bool = False, for_lineage: bool = False,
979
+ for_duplicate_processing: bool = False, type_name: str = None, start_from: int = 0,
980
+ page_size: int = None, output_format: str = 'JSON') -> list | str:
199
981
  """Retrieve the list of glossary metadata elements that contain the search string. Async version.
200
982
  The search string is located in the request body and is interpreted as a plain string.
201
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
983
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
202
984
 
203
985
  Parameters
204
986
  ----------
@@ -227,6 +1009,13 @@ class GlossaryBrowser(Client):
227
1009
  page_size: int, [default=None]
228
1010
  The number of items to return in a single page. If not specified, the default will be taken from
229
1011
  the class instance.
1012
+ output_format: str, default = 'JSON'
1013
+ Type of output to produce:
1014
+ JSON - output standard json
1015
+ MD - output standard markdown with no preamble
1016
+ FORM - output markdown with a preamble for a form
1017
+ REPORT - output markdown with a preamble for a report
1018
+
230
1019
  Returns
231
1020
  -------
232
1021
  List | str
@@ -259,40 +1048,37 @@ class GlossaryBrowser(Client):
259
1048
  search_string = None
260
1049
 
261
1050
  body = {
262
- "class": "SearchStringRequestBody",
263
- "searchString": search_string,
264
- "effectiveTime": effective_time,
1051
+ "class": "SearchStringRequestBody", "searchString": search_string, "effectiveTime": effective_time,
265
1052
  "typeName": type_name,
266
- }
1053
+ }
267
1054
  body = body_slimmer(body)
268
- # print(f"\n\nBody is: \n{body}")
269
-
270
- url = (
271
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
272
- f"by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
273
- f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
274
- f"forDuplicateProcessing={for_duplicate_processing_s}"
275
- )
276
1055
 
277
- response = await self._async_make_request("POST", url, body)
278
- return response.json().get("elementList", "No Glossaries found")
279
-
280
- def find_glossaries(
281
- self,
282
- search_string: str,
283
- effective_time: str = None,
284
- starts_with: bool = False,
285
- ends_with: bool = False,
286
- ignore_case: bool = False,
287
- for_lineage: bool = False,
288
- for_duplicate_processing: bool = False,
289
- type_name: str = None,
290
- start_from: int = 0,
291
- page_size: int = None,
292
- ) -> list | str:
1056
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1057
+ f"by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
1058
+ f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
1059
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
1060
+
1061
+ response = await self._async_make_request("POST", url, body_slimmer(body))
1062
+ element = response.json().get("elementList", NO_GLOSSARIES_FOUND)
1063
+ if element == NO_GLOSSARIES_FOUND:
1064
+ if output_format == 'JSON':
1065
+ return NO_GLOSSARIES_FOUND
1066
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
1067
+ return "\n# No glossaries found.\n"
1068
+ elif output_format == 'DICT':
1069
+ return None
1070
+
1071
+ if output_format != 'JSON': # return a simplified markdown representation
1072
+ return self.generate_glossaries_md(element, search_string, output_format)
1073
+ return response.json().get("elementList", NO_GLOSSARIES_FOUND)
1074
+
1075
+ def find_glossaries(self, search_string: str, effective_time: str = None, starts_with: bool = False,
1076
+ ends_with: bool = False, ignore_case: bool = False, for_lineage: bool = False,
1077
+ for_duplicate_processing: bool = False, type_name: str = None, start_from: int = 0,
1078
+ page_size: int = None, output_format: str = "JSON") -> list | str:
293
1079
  """Retrieve the list of glossary metadata elements that contain the search string.
294
1080
  The search string is located in the request body and is interpreted as a plain string.
295
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
1081
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
296
1082
 
297
1083
  Parameters
298
1084
  ----------
@@ -322,6 +1108,15 @@ class GlossaryBrowser(Client):
322
1108
  page_size: int, [default=None]
323
1109
  The number of items to return in a single page. If not specified, the default will be taken from
324
1110
  the class instance.
1111
+ output_format: str, default = 'JSON'
1112
+ Type of output to produce:
1113
+ JSON - output standard json
1114
+ MD - output standard markdown with no preamble
1115
+ FORM - output markdown with a preamble for a form
1116
+ REPORT - output markdown with a preamble for a report
1117
+ LIST - output a markdown table with columns for Glossary Name, Qualified Name, Language, Description,
1118
+ Usage
1119
+ DICT - output a dictionary structure containing all attributes
325
1120
  Returns
326
1121
  -------
327
1122
  List | str
@@ -341,25 +1136,13 @@ class GlossaryBrowser(Client):
341
1136
  """
342
1137
  loop = asyncio.get_event_loop()
343
1138
  response = loop.run_until_complete(
344
- self._async_find_glossaries(
345
- search_string,
346
- effective_time,
347
- starts_with,
348
- ends_with,
349
- ignore_case,
350
- for_lineage,
351
- for_duplicate_processing,
352
- type_name,
353
- start_from,
354
- page_size,
355
- )
356
- )
1139
+ self._async_find_glossaries(search_string, effective_time, starts_with, ends_with, ignore_case, for_lineage,
1140
+ for_duplicate_processing, type_name, start_from, page_size, output_format))
357
1141
 
358
1142
  return response
359
1143
 
360
- async def _async_get_glossary_by_guid(
361
- self, glossary_guid: str, effective_time: str = None
362
- ) -> dict:
1144
+ async def _async_get_glossary_by_guid(self, glossary_guid: str, effective_time: str = None,
1145
+ output_format: str = "JSON") -> dict | str:
363
1146
  """Retrieves information about a glossary
364
1147
  Parameters
365
1148
  ----------
@@ -368,11 +1151,21 @@ class GlossaryBrowser(Client):
368
1151
  effective_time: str, optional
369
1152
  Effective time of the query. If not specified will default to any time. Time format is
370
1153
  "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1154
+ output_format: str, default = 'JSON'
1155
+ Type of output to produce:
1156
+ JSON - output standard json
1157
+ MD - output standard markdown with no preamble
1158
+ FORM - output markdown with a preamble for a form
1159
+ REPORT - output markdown with a preamble for a report
1160
+ LIST - output a markdown table with columns for Glossary Name, Qualified Name, Language, Description,
1161
+ Usage
1162
+ DICT - output a dictionary structure containing all attributes
1163
+
371
1164
  Returns
372
1165
  -------
373
- dict
374
- The glossary definition associated with the glossary_guid
375
-
1166
+ dict | str
1167
+ if output format is JSON: The glossary definition associated with the glossary_guid
1168
+ if output format is MD: A markdown string with the same information.
376
1169
  Raises
377
1170
  ------
378
1171
  InvalidParameterException
@@ -384,24 +1177,23 @@ class GlossaryBrowser(Client):
384
1177
  Notes
385
1178
  -----
386
1179
  """
387
-
1180
+ output_format = output_format.upper()
388
1181
  validate_guid(glossary_guid)
389
1182
 
390
1183
  body = {
391
- "class": "EffectiveTimeQueryRequestBody",
392
- "effectiveTime": effective_time,
393
- }
394
-
395
- url = (
396
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
397
- f"{glossary_guid}/retrieve"
398
- )
399
- response = await self._async_make_request("POST", url, body)
400
- return response.json().get("elementList", "No glossaries found")
401
-
402
- def get_glossary_by_guid(
403
- self, glossary_guid: str, effective_time: str = None
404
- ) -> dict:
1184
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time
1185
+ }
1186
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1187
+ f"{glossary_guid}/retrieve")
1188
+ response = await self._async_make_request("POST", url, body_slimmer(body))
1189
+ element = response.json().get("element", NO_GLOSSARIES_FOUND)
1190
+ if element == NO_GLOSSARIES_FOUND:
1191
+ return NO_GLOSSARIES_FOUND
1192
+ if output_format != 'JSON': # return a simplified markdown representation
1193
+ return self.generate_glossaries_md(element, "GUID", output_format)
1194
+ return response.json().get("element", NO_GLOSSARIES_FOUND)
1195
+
1196
+ def get_glossary_by_guid(self, glossary_guid: str, effective_time: str = None, output_format: str = "JSON") -> dict:
405
1197
  """Retrieves information about a glossary
406
1198
  Parameters
407
1199
  ----------
@@ -410,6 +1202,15 @@ class GlossaryBrowser(Client):
410
1202
  effective_time: str, optional
411
1203
  Effective time of the query. If not specified will default to any time. Time format is
412
1204
  "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1205
+ output_format: str, default = 'JSON'
1206
+ Type of output to produce:
1207
+ JSON - output standard json
1208
+ MD - output standard markdown with no preamble
1209
+ FORM - output markdown with a preamble for a form
1210
+ REPORT - output markdown with a preamble for a report
1211
+ LIST - output a markdown table with columns for Glossary Name, Qualified Name, Language, Description,
1212
+ Usage
1213
+ DICT - output a dictionary structure containing all attributes
413
1214
 
414
1215
  Returns
415
1216
  -------
@@ -429,17 +1230,11 @@ class GlossaryBrowser(Client):
429
1230
  """
430
1231
  loop = asyncio.get_event_loop()
431
1232
  response = loop.run_until_complete(
432
- self._async_get_glossary_by_guid(glossary_guid, effective_time)
433
- )
1233
+ self._async_get_glossary_by_guid(glossary_guid, effective_time, output_format))
434
1234
  return response
435
1235
 
436
- async def _async_get_glossaries_by_name(
437
- self,
438
- glossary_name: str,
439
- effective_time: str = None,
440
- start_from: int = 0,
441
- page_size: int = None,
442
- ) -> dict | str:
1236
+ async def _async_get_glossaries_by_name(self, glossary_name: str, effective_time: str = None, start_from: int = 0,
1237
+ page_size: int = None, ) -> dict | str:
443
1238
  """Retrieve the list of glossary metadata elements with an exactly matching qualified or display name.
444
1239
  There are no wildcards supported on this request.
445
1240
 
@@ -485,21 +1280,14 @@ class GlossaryBrowser(Client):
485
1280
  else:
486
1281
  body = {"name": glossary_name, "effectiveTime": effective_time}
487
1282
 
488
- url = (
489
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
490
- f"by-name?startFrom={start_from}&pageSize={page_size}"
491
- )
1283
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1284
+ f"by-name?startFrom={start_from}&pageSize={page_size}")
492
1285
 
493
1286
  response = await self._async_make_request("POST", url, body)
494
1287
  return response.json().get("elementList", "No glossaries found")
495
1288
 
496
- def get_glossaries_by_name(
497
- self,
498
- glossary_name: str,
499
- effective_time: str = None,
500
- start_from: int = 0,
501
- page_size: int = None,
502
- ) -> dict | str:
1289
+ def get_glossaries_by_name(self, glossary_name: str, effective_time: str = None, start_from: int = 0,
1290
+ page_size: int = None, ) -> dict | str:
503
1291
  """Retrieve the list of glossary metadata elements with an exactly matching qualified or display name.
504
1292
  There are no wildcards supported on this request.
505
1293
 
@@ -515,7 +1303,7 @@ class GlossaryBrowser(Client):
515
1303
  When multiple pages of results are available, the page number to start from.
516
1304
  page_size: int, [default=None]
517
1305
  The number of items to return in a single page. If not specified, the default will be taken from
518
- he class instance.
1306
+ the class instance.
519
1307
 
520
1308
  Returns
521
1309
  -------
@@ -535,23 +1323,99 @@ class GlossaryBrowser(Client):
535
1323
  """
536
1324
  loop = asyncio.get_event_loop()
537
1325
  response = loop.run_until_complete(
538
- self._async_get_glossaries_by_name(
539
- glossary_name, effective_time, start_from, page_size
540
- )
541
- )
1326
+ self._async_get_glossaries_by_name(glossary_name, effective_time, start_from, page_size))
542
1327
  return response
543
1328
 
544
1329
  #
545
1330
  # Glossary Categories
546
1331
  #
547
1332
 
548
- async def _async_get_glossary_for_category(
549
- self,
550
- glossary_category_guid: str,
551
- effective_time: str = None,
552
- ) -> dict | str:
553
- """Retrieve the glossary metadata element for the requested category. The optional request body allows you to
554
- specify that the glossary element should only be returned if it was effective at a particular time.
1333
+ async def _async_get_glossary_for_category(self, glossary_category_guid: str,
1334
+ effective_time: str = None, ) -> dict | str:
1335
+ """Retrieve the glossary metadata element for the requested category. The optional request body allows you to
1336
+ specify that the glossary element should only be returned if it was effective at a particular time.
1337
+
1338
+ Parameters
1339
+ ----------
1340
+ glossary_category_guid: str,
1341
+ Unique identifier for the glossary category.
1342
+ effective_time: datetime, [default=None], optional
1343
+ Effective time of the query. If not specified will default to any effective time. Time format is
1344
+ "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1345
+
1346
+ If not provided, the server name associated with the instance is used.
1347
+
1348
+ Returns
1349
+ -------
1350
+ A dict structure with the glossary metadata element for the requested category.
1351
+
1352
+ Raises
1353
+ ------
1354
+
1355
+ InvalidParameterException
1356
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1357
+ PropertyServerException
1358
+ Raised by the server when an issue arises in processing a valid request
1359
+ NotAuthorizedException
1360
+ The principle specified by the user_id does not have authorization for the requested action
1361
+ ConfigurationErrorException
1362
+ Raised when configuration parameters passed on earlier calls turn out to be
1363
+ invalid or make the new call invalid.
1364
+ """
1365
+
1366
+ body = {
1367
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time,
1368
+ }
1369
+
1370
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1371
+ f"for-category/{glossary_category_guid}/retrieve")
1372
+
1373
+ response = await self._async_make_request("POST", url, body)
1374
+ return response.json().get("elementList", "No categories found")
1375
+
1376
+ def get_glossary_for_category(self, glossary_category_guid: str, effective_time: str = None, ) -> dict | str:
1377
+ """Retrieve the glossary metadata element for the requested category. The optional request body allows you to
1378
+ specify that the glossary element should only be returned if it was effective at a particular time.
1379
+
1380
+ Parameters
1381
+ ----------
1382
+ glossary_category_guid: str,
1383
+ Unique identifier for the glossary category.
1384
+ effective_time: datetime, [default=None], optional
1385
+ Effective time of the query. If not specified will default to any effective time. Time format is
1386
+ "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1387
+
1388
+ If not provided, the server name associated with the instance is used.
1389
+
1390
+ Returns
1391
+ -------
1392
+ A dict structure with the glossary metadata element for the requested category.
1393
+
1394
+ Raises
1395
+ ------
1396
+
1397
+ InvalidParameterException
1398
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1399
+ PropertyServerException
1400
+ Raised by the server when an issue arises in processing a valid request
1401
+ NotAuthorizedException
1402
+ The principle specified by the user_id does not have authorization for the requested action
1403
+ ConfigurationErrorException
1404
+ Raised when configuration parameters passed on earlier calls turn out to be
1405
+ invalid or make the new call invalid.
1406
+ """
1407
+ loop = asyncio.get_event_loop()
1408
+ response = loop.run_until_complete(
1409
+ self._async_get_glossary_for_category(glossary_category_guid, effective_time))
1410
+ return response
1411
+
1412
+ async def _async_get_glossary_subcategories(self, glossary_category_guid: str, effective_time: str = None,
1413
+ start_from: int = 0, page_size: int = max_paging_size,
1414
+ for_lineage: bool = False,
1415
+ for_duplicate_processing: bool = False, ) -> dict | str:
1416
+ """Glossary categories can be organized in a hierarchy. Retrieve the subcategories for the glossary category
1417
+ metadata element with the supplied unique identifier. If the requested category does not have any subcategories,
1418
+ null is returned. The optional request body contain an effective time for the query.
555
1419
 
556
1420
  Parameters
557
1421
  ----------
@@ -560,12 +1424,18 @@ class GlossaryBrowser(Client):
560
1424
  effective_time: datetime, [default=None], optional
561
1425
  Effective time of the query. If not specified will default to any effective time. Time format is
562
1426
  "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
563
-
564
- If not provided, the server name associated with the instance is used.
1427
+ start_from: int, [default=0], optional
1428
+ The page to start from.
1429
+ page_size: int, [default=max_paging_size], optional
1430
+ The number of results per page to return.
1431
+ for_lineage: bool, [default=False], optional
1432
+ Indicates the search is for lineage.
1433
+ for_duplicate_processing: bool, [default=False], optional
1434
+ If set to True the user will handle duplicate processing.
565
1435
 
566
1436
  Returns
567
1437
  -------
568
- A dict structure with the glossary metadata element for the requested category.
1438
+ A dict list with the glossary metadata element for the requested category.
569
1439
 
570
1440
  Raises
571
1441
  ------
@@ -580,27 +1450,30 @@ class GlossaryBrowser(Client):
580
1450
  Raised when configuration parameters passed on earlier calls turn out to be
581
1451
  invalid or make the new call invalid.
582
1452
  """
1453
+ for_lineage_s = str(for_lineage).lower()
1454
+ for_duplicate_processing_s = str(for_duplicate_processing).lower()
583
1455
 
584
1456
  body = {
585
- "class": "EffectiveTimeQueryRequestBody",
586
- "effectiveTime": effective_time,
587
- }
588
-
589
- url = (
590
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
591
- f"for-category/{glossary_category_guid}/retrieve"
592
- )
1457
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time,
1458
+ }
1459
+
1460
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1461
+ f"categories/{glossary_category_guid}/subcategories/retrieve?startFrom={start_from}&pageSize="
1462
+ f"{page_size}&"
1463
+ f"forLineage={for_lineage_s}&forDuplicateProcessing={for_duplicate_processing_s}")
1464
+ if effective_time:
1465
+ response = await self._async_make_request("POST", url, body_slimmer(body))
1466
+ else:
1467
+ response = await self._async_make_request("POST", url)
593
1468
 
594
- response = await self._async_make_request("POST", url, body)
595
1469
  return response.json().get("elementList", "No categories found")
596
1470
 
597
- def get_glossary_for_category(
598
- self,
599
- glossary_category_guid: str,
600
- effective_time: str = None,
601
- ) -> dict | str:
602
- """Retrieve the glossary metadata element for the requested category. The optional request body allows you to
603
- specify that the glossary element should only be returned if it was effective at a particular time.
1471
+ def get_glossary_subcategories(self, glossary_category_guid: str, effective_time: str = None, start_from: int = 0,
1472
+ page_size: int = max_paging_size, for_lineage: bool = False,
1473
+ for_duplicate_processing: bool = False, ) -> dict | str:
1474
+ """Glossary categories can be organized in a hierarchy. Retrieve the subcategories for the glossary category
1475
+ metadata element with the supplied unique identifier. If the requested category does not have any subcategories,
1476
+ null is returned. The optional request body contain an effective time for the query.
604
1477
 
605
1478
  Parameters
606
1479
  ----------
@@ -609,12 +1482,18 @@ class GlossaryBrowser(Client):
609
1482
  effective_time: datetime, [default=None], optional
610
1483
  Effective time of the query. If not specified will default to any effective time. Time format is
611
1484
  "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
612
-
613
- If not provided, the server name associated with the instance is used.
1485
+ start_from: int, [default=0], optional
1486
+ The page to start from.
1487
+ page_size: int, [default=max_paging_size], optional
1488
+ The number of results per page to return.
1489
+ for_lineage: bool, [default=False], optional
1490
+ Indicates the search is for lineage.
1491
+ for_duplicate_processing: bool, [default=False], optional
1492
+ If set to True the user will handle duplicate processing.
614
1493
 
615
1494
  Returns
616
1495
  -------
617
- A dict structure with the glossary metadata element for the requested category.
1496
+ A dict list with the glossary metadata element for the requested category.
618
1497
 
619
1498
  Raises
620
1499
  ------
@@ -631,25 +1510,17 @@ class GlossaryBrowser(Client):
631
1510
  """
632
1511
  loop = asyncio.get_event_loop()
633
1512
  response = loop.run_until_complete(
634
- self._async_get_glossary_for_category(
635
- glossary_category_guid, effective_time
636
- )
637
- )
1513
+ self._async_get_glossary_subcategories(glossary_category_guid, effective_time, start_from, page_size,
1514
+ for_lineage, for_duplicate_processing))
638
1515
  return response
639
1516
 
640
- async def _async_find_glossary_categories(
641
- self,
642
- search_string: str,
643
- effective_time: str = None,
644
- starts_with: bool = False,
645
- ends_with: bool = False,
646
- ignore_case: bool = False,
647
- start_from: int = 0,
648
- page_size: int = None,
649
- ) -> list | str:
1517
+ async def _async_find_glossary_categories(self, search_string: str, effective_time: str = None,
1518
+ starts_with: bool = False, ends_with: bool = False,
1519
+ ignore_case: bool = False, start_from: int = 0, page_size: int = None,
1520
+ output_format: str = "JSON") -> list | str:
650
1521
  """Retrieve the list of glossary category metadata elements that contain the search string.
651
1522
  The search string is located in the request body and is interpreted as a plain string.
652
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
1523
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
653
1524
  Async version.
654
1525
 
655
1526
  Parameters
@@ -673,6 +1544,13 @@ class GlossaryBrowser(Client):
673
1544
  page_size: int, [default=None]
674
1545
  The number of items to return in a single page. If not specified, the default will be taken from
675
1546
  the class instance.
1547
+ output_format: str, default = 'JSON'
1548
+ Type of output to produce:
1549
+ JSON - output standard json
1550
+ MD - output standard markdown with no preamble
1551
+ FORM - output markdown with a preamble for a form
1552
+ REPORT - output markdown with a preamble for a report
1553
+
676
1554
  Returns
677
1555
  -------
678
1556
  List | str
@@ -703,34 +1581,31 @@ class GlossaryBrowser(Client):
703
1581
  search_string = None
704
1582
 
705
1583
  body = {
706
- "class": "SearchStringRequestBody",
707
- "searchString": search_string,
708
- "effectiveTime": effective_time,
709
- }
710
- body = body_slimmer(body)
711
-
712
- url = (
713
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
714
- f"categories/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
715
- f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}"
716
- )
717
-
718
- response = await self._async_make_request("POST", url, body)
719
- return response.json().get("elementList", "No Categories found")
720
-
721
- def find_glossary_categories(
722
- self,
723
- search_string: str,
724
- effective_time: str = None,
725
- starts_with: bool = False,
726
- ends_with: bool = False,
727
- ignore_case: bool = False,
728
- start_from: int = 0,
729
- page_size: int = None,
730
- ) -> list | str:
1584
+ "class": "SearchStringRequestBody", "searchString": search_string, "effectiveTime": effective_time,
1585
+ }
1586
+
1587
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1588
+ f"categories/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
1589
+ f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}")
1590
+ response = await self._async_make_request("POST", url, body_slimmer(body))
1591
+ element = response.json().get("elementList", NO_CATEGORIES_FOUND)
1592
+ if element == NO_CATEGORIES_FOUND:
1593
+ if output_format == 'JSON':
1594
+ return NO_CATEGORIES_FOUND
1595
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
1596
+ return "\n# No categories found.\n"
1597
+ elif output_format == 'DICT':
1598
+ return None
1599
+ if output_format != 'JSON': # return a simplified markdown representation
1600
+ return self.generate_categories_md(element, search_string, output_format)
1601
+ return response.json().get("elementList", NO_CATEGORIES_FOUND)
1602
+
1603
+ def find_glossary_categories(self, search_string: str, effective_time: str = None, starts_with: bool = False,
1604
+ ends_with: bool = False, ignore_case: bool = False, start_from: int = 0,
1605
+ page_size: int = None, output_format: str = "JSON") -> list | str:
731
1606
  """Retrieve the list of glossary category metadata elements that contain the search string.
732
1607
  The search string is located in the request body and is interpreted as a plain string.
733
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
1608
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
734
1609
 
735
1610
  Parameters
736
1611
  ----------
@@ -749,11 +1624,18 @@ class GlossaryBrowser(Client):
749
1624
  Ends with the supplied string
750
1625
  ignore_case : bool, [default=False], optional
751
1626
  Ignore case when searching
752
- start_from: int, [default=0], optional
1627
+ start_from: int, [default=0], optional
753
1628
  When multiple pages of results are available, the page number to start from.
754
- page_size: int, [default=None]
1629
+ page_size: int, [default=None]
755
1630
  The number of items to return in a single page. If not specified, the default will be taken from
756
1631
  the class instance.
1632
+ output_format: str, default = 'JSON'
1633
+ Type of output to produce:
1634
+ JSON - output standard json
1635
+ MD - output standard markdown with no preamble
1636
+ FORM - output markdown with a preamble for a form
1637
+ REPORT - output markdown with a preamble for a report
1638
+
757
1639
  Returns
758
1640
  -------
759
1641
  List | str
@@ -773,25 +1655,13 @@ class GlossaryBrowser(Client):
773
1655
  """
774
1656
  loop = asyncio.get_event_loop()
775
1657
  response = loop.run_until_complete(
776
- self._async_find_glossary_categories(
777
- search_string,
778
- effective_time,
779
- starts_with,
780
- ends_with,
781
- ignore_case,
782
- start_from,
783
- page_size,
784
- )
785
- )
1658
+ self._async_find_glossary_categories(search_string, effective_time, starts_with, ends_with, ignore_case,
1659
+ start_from, page_size, output_format))
786
1660
 
787
1661
  return response
788
1662
 
789
- async def _async_get_categories_for_glossary(
790
- self,
791
- glossary_guid: str,
792
- start_from: int = 0,
793
- page_size: int = None,
794
- ) -> list | str:
1663
+ async def _async_get_categories_for_glossary(self, glossary_guid: str, start_from: int = 0,
1664
+ page_size: int = None, ) -> list | str:
795
1665
  """Return the list of categories associated with a glossary.
796
1666
  Async version.
797
1667
 
@@ -827,20 +1697,14 @@ class GlossaryBrowser(Client):
827
1697
  if page_size is None:
828
1698
  page_size = self.page_size
829
1699
 
830
- url = (
831
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
832
- f"{glossary_guid}/categories/retrieve?startFrom={start_from}&pageSize={page_size}"
833
- )
1700
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1701
+ f"{glossary_guid}/categories/retrieve?startFrom={start_from}&pageSize={page_size}")
834
1702
 
835
1703
  response = await self._async_make_request("POST", url)
836
1704
  return response.json().get("elementList", "No Categories found")
837
1705
 
838
- def get_categories_for_glossary(
839
- self,
840
- glossary_guid: str,
841
- start_from: int = 0,
842
- page_size: int = None,
843
- ) -> list | str:
1706
+ def get_categories_for_glossary(self, glossary_guid: str, start_from: int = 0,
1707
+ page_size: int = None, ) -> list | str:
844
1708
  """Return the list of categories associated with a glossary.
845
1709
 
846
1710
  Parameters
@@ -873,18 +1737,11 @@ class GlossaryBrowser(Client):
873
1737
  """
874
1738
  loop = asyncio.get_event_loop()
875
1739
  response = loop.run_until_complete(
876
- self._async_get_categories_for_glossary(
877
- glossary_guid, start_from, page_size
878
- )
879
- )
1740
+ self._async_get_categories_for_glossary(glossary_guid, start_from, page_size))
880
1741
  return response
881
1742
 
882
- async def _async_get_categories_for_term(
883
- self,
884
- glossary_term_guid: str,
885
- start_from: int = 0,
886
- page_size: int = None,
887
- ) -> list | str:
1743
+ async def _async_get_categories_for_term(self, glossary_term_guid: str, start_from: int = 0,
1744
+ page_size: int = None, ) -> list | str:
888
1745
  """Return the list of categories associated with a glossary term.
889
1746
  Async version.
890
1747
 
@@ -919,20 +1776,14 @@ class GlossaryBrowser(Client):
919
1776
  if page_size is None:
920
1777
  page_size = self.page_size
921
1778
 
922
- url = (
923
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
924
- f"{glossary_term_guid}/categories/retrieve?startFrom={start_from}&pageSize={page_size}"
925
- )
1779
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
1780
+ f"{glossary_term_guid}/categories/retrieve?startFrom={start_from}&pageSize={page_size}")
926
1781
 
927
1782
  response = await self._async_make_request("POST", url)
928
- return response.json().get("elementList", "No Categories found")
1783
+ return response.json().get("elementList", NO_CATEGORIES_FOUND)
929
1784
 
930
- def get_categories_for_term(
931
- self,
932
- glossary_term_guid: str,
933
- start_from: int = 0,
934
- page_size: int = None,
935
- ) -> list | str:
1785
+ def get_categories_for_term(self, glossary_term_guid: str, start_from: int = 0,
1786
+ page_size: int = None, ) -> list | str:
936
1787
  """Return the list of categories associated with a glossary term.
937
1788
 
938
1789
  Parameters
@@ -964,20 +1815,11 @@ class GlossaryBrowser(Client):
964
1815
  """
965
1816
  loop = asyncio.get_event_loop()
966
1817
  response = loop.run_until_complete(
967
- self._async_get_categories_for_term(
968
- glossary_term_guid, start_from, page_size
969
- )
970
- )
1818
+ self._async_get_categories_for_term(glossary_term_guid, start_from, page_size))
971
1819
  return response
972
1820
 
973
- async def _async_get_categories_by_name(
974
- self,
975
- name: str,
976
- glossary_guid: str = None,
977
- status: [str] = ["ACTIVE"],
978
- start_from: int = 0,
979
- page_size: int = None,
980
- ) -> list | str:
1821
+ async def _async_get_categories_by_name(self, name: str, glossary_guid: str = None, status: [str] = ["ACTIVE"],
1822
+ start_from: int = 0, page_size: int = None, ) -> list | str:
981
1823
  """Retrieve the list of glossary category metadata elements that either have the requested qualified name or
982
1824
  display name. The name to search for is located in the request body and is interpreted as a plain string.
983
1825
  The request body also supports the specification of a glossaryGUID to restrict the search to within a single
@@ -991,12 +1833,8 @@ class GlossaryBrowser(Client):
991
1833
  category name to search for.
992
1834
  glossary_guid: str, optional
993
1835
  The identity of the glossary to search. If not specified, all glossaries will be searched.
994
- status: [str], optional
995
- A list of statuses to optionally restrict results. Default is Active
996
-
997
- If not provided, the server name associated with the instance is used.
998
1836
  start_from: int, [default=0], optional
999
- When multiple pages of results are available, the page number to start from.
1837
+ When multiple pages of results are available, the page number to start from.
1000
1838
  page_size: int, [default=None]
1001
1839
  The number of items to return in a single page. If not specified, the default will be taken from
1002
1840
  the class instance.
@@ -1024,27 +1862,18 @@ class GlossaryBrowser(Client):
1024
1862
 
1025
1863
  url = (
1026
1864
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/categories/"
1027
- f"by-name?startFrom={start_from}&pageSize={page_size}"
1028
- )
1865
+ f"by-name?startFrom={start_from}&pageSize={page_size}")
1029
1866
 
1030
1867
  body = {
1031
- "class": "GlossaryNameRequestBody",
1032
- "name": name,
1033
- "glossaryGUID": glossary_guid,
1868
+ "class": "GlossaryNameRequestBody", "name": name, "glossaryGUID": glossary_guid,
1034
1869
  "limitResultsByStatus": status,
1035
- }
1870
+ }
1036
1871
 
1037
1872
  response = await self._async_make_request("POST", url, body)
1038
- return response.json().get("elementList", "No Categories found")
1873
+ return response.json().get("elementList", NO_CATEGORIES_FOUND)
1039
1874
 
1040
- def get_categories_by_name(
1041
- self,
1042
- name: str,
1043
- glossary_guid: str = None,
1044
- status: [str] = ["ACTIVE"],
1045
- start_from: int = 0,
1046
- page_size: int = None,
1047
- ) -> list | str:
1875
+ def get_categories_by_name(self, name: str, glossary_guid: str = None, status: [str] = ["ACTIVE"],
1876
+ start_from: int = 0, page_size: int = None) -> list | str:
1048
1877
  """Retrieve the list of glossary category metadata elements that either have the requested qualified name or
1049
1878
  display name. The name to search for is located in the request body and is interpreted as a plain string.
1050
1879
  The request body also supports the specification of a glossaryGUID to restrict the search to within a
@@ -1056,10 +1885,6 @@ class GlossaryBrowser(Client):
1056
1885
  category name to search for.
1057
1886
  glossary_guid: str, optional
1058
1887
  The identity of the glossary to search. If not specified, all glossaries will be searched.
1059
- status: [str], optional
1060
- A list of statuses to optionally restrict results. Default is Active
1061
-
1062
- If not provided, the server name associated with the instance is used.
1063
1888
  start_from: int, [default=0], optional
1064
1889
  When multiple pages of results are available, the page number to start from.
1065
1890
  page_size: int, [default=None]
@@ -1084,17 +1909,11 @@ class GlossaryBrowser(Client):
1084
1909
  """
1085
1910
  loop = asyncio.get_event_loop()
1086
1911
  response = loop.run_until_complete(
1087
- self._async_get_categories_by_name(
1088
- name, glossary_guid, status, start_from, page_size
1089
- )
1090
- )
1912
+ self._async_get_categories_by_name(name, glossary_guid, status, start_from, page_size))
1091
1913
  return response
1092
1914
 
1093
- async def _async_get_categories_by_guid(
1094
- self,
1095
- glossary_category_guid: str,
1096
- effective_time: str = None,
1097
- ) -> list | str:
1915
+ async def _async_get_category_by_guid(self, glossary_category_guid: str, effective_time: str = None,
1916
+ output_format: str = 'JSON', ) -> list | str:
1098
1917
  """Retrieve the requested glossary category metadata element. The optional request body contain an effective
1099
1918
  time for the query..
1100
1919
 
@@ -1108,7 +1927,12 @@ class GlossaryBrowser(Client):
1108
1927
  If specified, the category should only be returned if it was effective at the specified time.
1109
1928
  Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1110
1929
 
1111
- If not provided, the server name associated with the instance is used.
1930
+ output_format: str, default = 'JSON'
1931
+ Type of output to produce:
1932
+ JSON - output standard json
1933
+ MD - output standard markdown with no preamble
1934
+ FORM - output markdown with a preamble for a form
1935
+ REPORT - output markdown with a preamble for a report
1112
1936
 
1113
1937
  Returns
1114
1938
  -------
@@ -1127,25 +1951,25 @@ class GlossaryBrowser(Client):
1127
1951
  The principle specified by the user_id does not have authorization for the requested action
1128
1952
 
1129
1953
  """
1130
-
1954
+ output_format = output_format.upper()
1131
1955
  url = (
1132
1956
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/categories/"
1133
- f"{glossary_category_guid}/retrieve"
1134
- )
1957
+ f"{glossary_category_guid}/retrieve")
1135
1958
 
1136
1959
  body = {
1137
- "class": "EffectiveTimeQueryRequestBody",
1138
- "effectiveTime": effective_time,
1139
- }
1140
-
1141
- response = await self._async_make_request("POST", url, body)
1142
- return response.json().get("element", "No Category found")
1143
-
1144
- def get_categories_by_guid(
1145
- self,
1146
- glossary_category_guid: str,
1147
- effective_time: str = None,
1148
- ) -> list | str:
1960
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time,
1961
+ }
1962
+
1963
+ response = await self._async_make_request("POST", url, body_slimmer(body))
1964
+ element = response.json().get("element", NO_CATEGORIES_FOUND)
1965
+ if element == NO_CATEGORIES_FOUND:
1966
+ return NO_CATEGORIES_FOUND
1967
+ if output_format != 'JSON': # return a simplified markdown representation
1968
+ return self.generate_categories_md(element, "GUID", output_format)
1969
+ return response.json().get("element", NO_CATEGORIES_FOUND)
1970
+
1971
+ def get_category_by_guid(self, glossary_category_guid: str, effective_time: str = None,
1972
+ output_format: str = 'JSON', ) -> list | str:
1149
1973
  """Retrieve the requested glossary category metadata element. The optional request body contain an effective
1150
1974
  time for the query..
1151
1975
 
@@ -1157,7 +1981,12 @@ class GlossaryBrowser(Client):
1157
1981
  If specified, the category should only be returned if it was effective at the specified time.
1158
1982
  Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
1159
1983
 
1160
- If not provided, the server name associated with the instance is used.
1984
+ output_format: str, default = 'JSON'
1985
+ Type of output to produce:
1986
+ JSON - output standard json
1987
+ MD - output standard markdown with no preamble
1988
+ FORM - output markdown with a preamble for a form
1989
+ REPORT - output markdown with a preamble for a report
1161
1990
 
1162
1991
  Returns
1163
1992
  -------
@@ -1178,15 +2007,10 @@ class GlossaryBrowser(Client):
1178
2007
  """
1179
2008
  loop = asyncio.get_event_loop()
1180
2009
  response = loop.run_until_complete(
1181
- self._async_get_categories_by_guid(glossary_category_guid, effective_time)
1182
- )
2010
+ self._async_get_category_by_guid(glossary_category_guid, effective_time, output_format))
1183
2011
  return response
1184
2012
 
1185
- async def _async_get_category_parent(
1186
- self,
1187
- glossary_category_guid: str,
1188
- effective_time: str = None,
1189
- ) -> list | str:
2013
+ async def _async_get_category_parent(self, glossary_category_guid: str, effective_time: str = None, ) -> list | str:
1190
2014
  """Glossary categories can be organized in a hierarchy. Retrieve the parent glossary category metadata
1191
2015
  element for the glossary category with the supplied unique identifier. If the requested category
1192
2016
  does not have a parent category, null is returned. The optional request body contain an effective time
@@ -1224,22 +2048,16 @@ class GlossaryBrowser(Client):
1224
2048
 
1225
2049
  url = (
1226
2050
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/categories/"
1227
- f"{glossary_category_guid}/parent/retrieve"
1228
- )
2051
+ f"{glossary_category_guid}/parent/retrieve")
1229
2052
 
1230
2053
  body = {
1231
- "class": "EffectiveTimeQueryRequestBody",
1232
- "effectiveTime": effective_time,
1233
- }
2054
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time,
2055
+ }
1234
2056
 
1235
2057
  response = await self._async_make_request("POST", url, body)
1236
2058
  return response.json().get("element", "No Parent Category found")
1237
2059
 
1238
- def get_category_parent(
1239
- self,
1240
- glossary_category_guid: str,
1241
- effective_time: str = None,
1242
- ) -> list | str:
2060
+ def get_category_parent(self, glossary_category_guid: str, effective_time: str = None, ) -> list | str:
1243
2061
  """Glossary categories can be organized in a hierarchy. Retrieve the parent glossary category metadata
1244
2062
  element for the glossary category with the supplied unique identifier. If the requested category
1245
2063
  does not have a parent category, null is returned. The optional request body contain an effective time
@@ -1273,22 +2091,171 @@ class GlossaryBrowser(Client):
1273
2091
 
1274
2092
  """
1275
2093
  loop = asyncio.get_event_loop()
1276
- response = loop.run_until_complete(
1277
- self._async_get_category_parent(glossary_category_guid, effective_time)
1278
- )
2094
+ response = loop.run_until_complete(self._async_get_category_parent(glossary_category_guid, effective_time))
1279
2095
  return response
1280
2096
 
2097
+ def get_glossary_category_structure(self, glossary_guid: str, output_format: str = "DICT") -> dict | str:
2098
+ """Derive the category structure of an Egeria glossary.
2099
+
2100
+ This method builds a hierarchical representation of the categories in a glossary,
2101
+ showing the parent-child relationships between categories.
2102
+
2103
+ Parameters
2104
+ ----------
2105
+ glossary_guid: str
2106
+ The unique identifier of the glossary.
2107
+ output_format: str, default = 'DICT'
2108
+ The format of the output:
2109
+ - DICT: Returns a Python dictionary structure
2110
+ - LIST: Returns a markdown table
2111
+ - MD: Returns a markdown outline with bullets and indentations
2112
+
2113
+ Returns
2114
+ -------
2115
+ dict | str
2116
+ If output_format is DICT, returns a dictionary structure representing the category hierarchy.
2117
+ If output_format is LIST, returns a markdown table representing the category hierarchy.
2118
+ If output_format is MD, returns a markdown outline with bullets and indentations.
2119
+
2120
+ Raises
2121
+ ------
2122
+ InvalidParameterException
2123
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
2124
+ PropertyServerException
2125
+ Raised by the server when an issue arises in processing a valid request
2126
+ NotAuthorizedException
2127
+ The principle specified by the user_id does not have authorization for the requested action
2128
+ """
2129
+ from pyegeria._validators import validate_guid
2130
+
2131
+ validate_guid(glossary_guid)
2132
+
2133
+ # Get all categories in the glossary
2134
+ all_categories = self.get_categories_for_glossary(glossary_guid)
2135
+ if isinstance(all_categories, str):
2136
+ return NO_CATEGORIES_FOUND
2137
+
2138
+ # Create a dictionary to store categories by GUID for quick lookup
2139
+ categories_by_guid = {cat['elementHeader']['guid']: cat for cat in all_categories}
2140
+
2141
+ # Identify root categories (categories with no parent)
2142
+ root_guids = []
2143
+ for cat_guid in categories_by_guid.keys():
2144
+ parent = self.get_category_parent(cat_guid)
2145
+ if isinstance(parent, str):
2146
+ root_guids.append(cat_guid) # This category has no parent
2147
+
2148
+ # Build the category tree
2149
+ category_tree = []
2150
+
2151
+ def build_category_tree(category_guid):
2152
+ """Recursively build a category tree for a category."""
2153
+ if category_guid not in categories_by_guid:
2154
+ return None
2155
+
2156
+ category = categories_by_guid[category_guid]
2157
+ display_name = category['glossaryCategoryProperties'].get('displayName', '---')
2158
+ qualified_name = category['glossaryCategoryProperties'].get('qualifiedName', '---')
2159
+ description = category['glossaryCategoryProperties'].get('description', '---')
2160
+
2161
+ # Get subcategories
2162
+ subcategories = self.get_glossary_subcategories(category_guid)
2163
+ children = []
2164
+
2165
+ if isinstance(subcategories, list):
2166
+ for subcat in subcategories:
2167
+ subcat_guid = subcat['elementHeader']['guid']
2168
+ child_tree = build_category_tree(subcat_guid)
2169
+ if child_tree:
2170
+ children.append(child_tree)
2171
+
2172
+ # Get parent category information
2173
+ parent_info = None
2174
+ parent = self.get_category_parent(category_guid)
2175
+ if not isinstance(parent, str):
2176
+ parent_guid = parent['elementHeader']['guid']
2177
+ parent_name = parent['glossaryCategoryProperties'].get('displayName', '---')
2178
+ parent_info = {
2179
+ 'guid': parent_guid, 'name': parent_name
2180
+ }
2181
+
2182
+ return {
2183
+ 'guid': category_guid, 'name': display_name, 'qualifiedName': qualified_name,
2184
+ 'description': description, 'parent': parent_info, 'children': children
2185
+ }
2186
+
2187
+ # Build tree for each root category
2188
+ for root_guid in root_guids:
2189
+ tree = build_category_tree(root_guid)
2190
+ if tree:
2191
+ category_tree.append(tree)
2192
+
2193
+ # Format the output according to the specified output_format
2194
+ if output_format == "DICT":
2195
+ return {
2196
+ 'glossary_guid': glossary_guid, 'categories': category_tree
2197
+ }
2198
+ elif output_format == "LIST":
2199
+ # Generate markdown table
2200
+ md_table = "| Category | Path | Description | Parent Category | Child Categories |\n"
2201
+ md_table += "|---------|------|-------------|----------------|------------------|\n"
2202
+
2203
+ def add_categories_to_table(categories, path=""):
2204
+ nonlocal md_table
2205
+ for category in categories:
2206
+ category_path = f"{path}/{category['name']}" if path else category['name']
2207
+
2208
+ # Get parent category name
2209
+ parent_name = "None"
2210
+ if category['parent']:
2211
+ parent_name = category['parent']['name']
2212
+
2213
+ # Get child categories names
2214
+ child_names = []
2215
+ for child in category['children']:
2216
+ child_names.append(child['name'])
2217
+ child_categories = ", ".join(child_names) if child_names else "None"
2218
+
2219
+ md_table += (f"| {category['name']} | {category_path} | "
2220
+ f"{self._format_for_markdown_table(category['description'])} | "
2221
+ f"{parent_name} | {child_categories} |\n")
2222
+ if category['children']:
2223
+ add_categories_to_table(category['children'], category_path)
2224
+
2225
+ add_categories_to_table(category_tree)
2226
+ return md_table
2227
+ elif output_format == "MD":
2228
+ # Generate markdown outline with bullets and indentations
2229
+ md_outline = f"# Category Structure for Glossary (GUID: {glossary_guid})\n\n"
2230
+
2231
+ def add_categories_to_outline(categories, indent_level=0):
2232
+ nonlocal md_outline
2233
+ for category in categories:
2234
+ # Add bullet with proper indentation
2235
+ indent = " " * indent_level
2236
+ md_outline += f"{indent}- **{category['name']}**"
2237
+
2238
+ # Add description if available
2239
+ if category['description'] and category['description'] != '---':
2240
+ md_outline += f": {category['description']}"
2241
+
2242
+ md_outline += "\n"
2243
+
2244
+ # Process children with increased indentation
2245
+ if category['children']:
2246
+ add_categories_to_outline(category['children'], indent_level + 1)
2247
+
2248
+ add_categories_to_outline(category_tree)
2249
+ return md_outline
2250
+ else:
2251
+ return f"Unsupported output format: {output_format}. Use 'DICT', 'LIST', or 'MD'."
2252
+
1281
2253
  #
1282
2254
  # Terms
1283
2255
  #
1284
2256
 
1285
- async def _async_get_terms_for_category(
1286
- self,
1287
- glossary_category_guid: str,
1288
- effective_time: str = None,
1289
- start_from: int = 0,
1290
- page_size: int = None,
1291
- ) -> list | str:
2257
+ async def _async_get_terms_for_category(self, glossary_category_guid: str, effective_time: str = None,
2258
+ start_from: int = 0, page_size: int = None, ) -> list | str:
1292
2259
  """Retrieve ALL the glossary terms in a category.
1293
2260
  The request body also supports the specification of an effective time for the query.
1294
2261
 
@@ -1298,7 +2265,6 @@ class GlossaryBrowser(Client):
1298
2265
  ----------
1299
2266
  glossary_category_guid : str
1300
2267
  Unique identifier for the glossary category to retrieve terms from.
1301
-
1302
2268
  effective_time : str, optional
1303
2269
  If specified, the terms are returned if they are active at the `effective_time
1304
2270
  Time format is "YYYY-MM-DDTHH:MM:SS" (ISO 8601)
@@ -1308,7 +2274,7 @@ class GlossaryBrowser(Client):
1308
2274
  The number of elements to retrieve
1309
2275
  Returns
1310
2276
  -------
1311
- dict
2277
+ [dict]
1312
2278
  The glossary definition associated with the glossary_guid
1313
2279
 
1314
2280
  Raises
@@ -1319,8 +2285,7 @@ class GlossaryBrowser(Client):
1319
2285
  Raised by the server when an issue arises in processing a valid request.
1320
2286
  NotAuthorizedException
1321
2287
  The principle specified by the user_id does not have authorization for the requested action.
1322
- Notes
1323
- -----
2288
+
1324
2289
  """
1325
2290
 
1326
2291
  validate_guid(glossary_category_guid)
@@ -1329,9 +2294,8 @@ class GlossaryBrowser(Client):
1329
2294
  page_size = self.page_size
1330
2295
 
1331
2296
  url = (
1332
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
1333
- f"{glossary_category_guid}/terms/retrieve?startFrom={start_from}&pageSize={page_size}"
1334
- )
2297
+ f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/categories/"
2298
+ f"{glossary_category_guid}/terms/retrieve?startFrom={start_from}&pageSize={page_size}")
1335
2299
 
1336
2300
  if effective_time is not None:
1337
2301
  body = {"effectiveTime": effective_time}
@@ -1341,13 +2305,8 @@ class GlossaryBrowser(Client):
1341
2305
 
1342
2306
  return response.json().get("elementList", "No terms found")
1343
2307
 
1344
- def get_terms_for_category(
1345
- self,
1346
- glossary_category_guid: str,
1347
- effective_time: str = None,
1348
- start_from: int = 0,
1349
- page_size: int = None,
1350
- ) -> list | str:
2308
+ def get_terms_for_category(self, glossary_category_guid: str, effective_time: str = None, start_from: int = 0,
2309
+ page_size: int = None, ) -> list | str:
1351
2310
  """Retrieve ALL the glossary terms in a category.
1352
2311
  The request body also supports the specification of an effective time for the query.
1353
2312
 
@@ -1383,23 +2342,12 @@ class GlossaryBrowser(Client):
1383
2342
  """
1384
2343
  loop = asyncio.get_event_loop()
1385
2344
  response = loop.run_until_complete(
1386
- self._async_get_terms_for_category(
1387
- glossary_category_guid,
1388
- effective_time,
1389
- start_from,
1390
- page_size,
1391
- )
1392
- )
2345
+ self._async_get_terms_for_category(glossary_category_guid, effective_time, start_from, page_size, ))
1393
2346
 
1394
2347
  return response
1395
2348
 
1396
- async def _async_get_terms_for_glossary(
1397
- self,
1398
- glossary_guid: str,
1399
- effective_time: str = None,
1400
- start_from: int = 0,
1401
- page_size: int = None,
1402
- ) -> list | str:
2349
+ async def _async_get_terms_for_glossary(self, glossary_guid: str, effective_time: str = None, start_from: int = 0,
2350
+ page_size: int = None, ) -> list | str:
1403
2351
  """Retrieve the list of glossary terms associated with a glossary.
1404
2352
  The request body also supports the specification of an effective time for the query.
1405
2353
  Parameters
@@ -1436,10 +2384,8 @@ class GlossaryBrowser(Client):
1436
2384
  if page_size is None:
1437
2385
  page_size = self.page_size
1438
2386
 
1439
- url = (
1440
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1441
- f"{glossary_guid}/terms/retrieve?startFrom={start_from}&pageSize={page_size}"
1442
- )
2387
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2388
+ f"{glossary_guid}/terms/retrieve?startFrom={start_from}&pageSize={page_size}")
1443
2389
 
1444
2390
  if effective_time is not None:
1445
2391
  body = {"effectiveTime": effective_time}
@@ -1449,13 +2395,8 @@ class GlossaryBrowser(Client):
1449
2395
 
1450
2396
  return response.json().get("elementList", "No terms found")
1451
2397
 
1452
- def get_terms_for_glossary(
1453
- self,
1454
- glossary_guid: str,
1455
- effective_time: str = None,
1456
- start_from: int = 0,
1457
- page_size: int = None,
1458
- ) -> list | str:
2398
+ def get_terms_for_glossary(self, glossary_guid: str, effective_time: str = None, start_from: int = 0,
2399
+ page_size: int = None, ) -> list | str:
1459
2400
  """Retrieve the list of glossary terms associated with a glossary.
1460
2401
  The request body also supports the specification of an effective time for the query.
1461
2402
  Parameters
@@ -1488,22 +2429,14 @@ class GlossaryBrowser(Client):
1488
2429
  """
1489
2430
  loop = asyncio.get_event_loop()
1490
2431
  response = loop.run_until_complete(
1491
- self._async_get_terms_for_glossary(
1492
- glossary_guid, effective_time, start_from, page_size
1493
- )
1494
- )
2432
+ self._async_get_terms_for_glossary(glossary_guid, effective_time, start_from, page_size))
1495
2433
 
1496
2434
  return response
1497
2435
 
1498
- async def _async_get_term_relationships(
1499
- self,
1500
- term_guid: str,
1501
- effective_time: str = None,
1502
- start_from: int = 0,
1503
- page_size: int = None,
1504
- ) -> list | str:
2436
+ async def _async_get_related_terms(self, term_guid: str, effective_time: str = None, start_from: int = 0,
2437
+ page_size: int = None, output_format: str = "JSON") -> list | str:
1505
2438
  """This call retrieves details of the glossary terms linked to this glossary term.
1506
- Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship..
2439
+ Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship.
1507
2440
  Parameters
1508
2441
  ----------
1509
2442
  term_guid : str
@@ -1538,10 +2471,8 @@ class GlossaryBrowser(Client):
1538
2471
  if page_size is None:
1539
2472
  page_size = self.page_size
1540
2473
 
1541
- url = (
1542
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
1543
- f"{term_guid}/related-terms?startFrom={start_from}&pageSize={page_size}"
1544
- )
2474
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
2475
+ f"{term_guid}/related-terms?startFrom={start_from}&pageSize={page_size}")
1545
2476
 
1546
2477
  if effective_time is not None:
1547
2478
  body = {"effectiveTime": effective_time}
@@ -1549,15 +2480,20 @@ class GlossaryBrowser(Client):
1549
2480
  else:
1550
2481
  response = await self._async_make_request("POST", url)
1551
2482
 
1552
- return response.json().get("elementList", "No terms found")
1553
-
1554
- def get_term_relationships(
1555
- self,
1556
- term_guid: str,
1557
- effective_time: str = None,
1558
- start_from: int = 0,
1559
- page_size: int = None,
1560
- ) -> list | str:
2483
+ term_elements = response.json().get("elementList", NO_TERMS_FOUND)
2484
+ if term_elements == NO_TERMS_FOUND:
2485
+ if output_format == 'JSON':
2486
+ return NO_TERMS_FOUND
2487
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
2488
+ return "\n# No Terms found.\n"
2489
+ elif output_format == 'DICT':
2490
+ return None
2491
+ if output_format != "JSON": # return a simplified markdown representation
2492
+ return self.generate_related_terms_md(term_elements, term_guid, output_format)
2493
+ return response.json().get("elementList", NO_TERMS_FOUND)
2494
+
2495
+ def get_related_terms(self, term_guid: str, effective_time: str = None, start_from: int = 0, page_size: int = None,
2496
+ output_format="JSON") -> list | str:
1561
2497
  """This call retrieves details of the glossary terms linked to this glossary term.
1562
2498
  Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship..
1563
2499
  Parameters
@@ -1590,16 +2526,207 @@ class GlossaryBrowser(Client):
1590
2526
  """
1591
2527
  loop = asyncio.get_event_loop()
1592
2528
  response = loop.run_until_complete(
1593
- self._async_get_term_relationships(
1594
- term_guid, effective_time, start_from, page_size
1595
- )
1596
- )
2529
+ self._async_get_related_terms(term_guid, effective_time, start_from, page_size, output_format))
1597
2530
 
1598
2531
  return response
1599
2532
 
1600
- async def _async_get_glossary_for_term(
1601
- self, term_guid: str, effective_time: str = None
1602
- ) -> dict | str:
2533
+ def generate_related_terms_md(self, term_elements: list, term_guid: str, output_format: str = 'MD') -> str | list:
2534
+ """
2535
+ Generate a simplified representation of related terms.
2536
+
2537
+ Args:
2538
+ term_elements (list): List of term elements with relationship information
2539
+ term_guid (str): GUID of the term for which to generate related terms
2540
+ output_format (str): Output format (MD, LIST, DICT, etc.)
2541
+
2542
+ Returns:
2543
+ str | list: Markdown string or list of dictionaries depending on output_format
2544
+ """
2545
+ # Get the first term's display name and qualified name
2546
+ term_name = "Term"
2547
+ try:
2548
+ term_info = self.get_term_by_guid(term_guid, output_format="DICT")
2549
+ # Handle case where term_info is a list of dictionaries
2550
+ if isinstance(term_info, list) and len(term_info) > 0:
2551
+ term_info = term_info[0] # Get the first term
2552
+ if isinstance(term_info, dict) and 'display_name' in term_info:
2553
+ term_name = term_info['display_name']
2554
+ except:
2555
+ # If we can't get the term info, just use the default name
2556
+ pass
2557
+
2558
+ # Create a list to store the simplified related terms
2559
+ related_terms = []
2560
+
2561
+ # Process each term element
2562
+ for element in term_elements:
2563
+ # Extract relationship type from the relationship header
2564
+ relationship_type = element['relatedBy']['relationshipHeader']['type']['typeName']
2565
+
2566
+ # Extract related term information
2567
+ related_term = {
2568
+ 'first_term_display_name': term_name, 'first_term_qualified_name': term_info.get('qualified_name', ''),
2569
+ 'related_term_display_name': element['glossaryTermProperties'].get('displayName', ''),
2570
+ 'related_term_qualified_name': element['glossaryTermProperties'].get('qualifiedName', ''),
2571
+ 'relationship_type': relationship_type
2572
+ }
2573
+
2574
+ related_terms.append(related_term)
2575
+
2576
+ # Return based on output format
2577
+ if output_format == 'DICT':
2578
+ return related_terms
2579
+
2580
+ # For MD, LIST, FORM, REPORT formats, create a markdown representation
2581
+ md_output = f"# Related Terms for {term_name}\n\n"
2582
+
2583
+ if output_format == 'LIST':
2584
+ # Create a table
2585
+ md_output += ("| First Term | First Term Qualified Name | Related Term | Related Term Qualified Name | "
2586
+ "Relationship Type |\n")
2587
+ md_output += \
2588
+ "|------------|---------------------------|--------------|------------------------------|-------------------|\n"
2589
+
2590
+ for term in related_terms:
2591
+ md_output += f"| {term['first_term_display_name']} | {term['first_term_qualified_name']} | "
2592
+ md_output += f"{term['related_term_display_name']} | {term['related_term_qualified_name']} | "
2593
+ md_output += f"{term['relationship_type']} |\n"
2594
+ else:
2595
+ # For other formats, create a more detailed representation
2596
+ for term in related_terms:
2597
+ md_output += f"## {term['relationship_type']} Relationship\n\n"
2598
+ md_output += (f"**First Term:** {term['first_term_display_name']} ("
2599
+ f"{term['first_term_qualified_name']})\n\n")
2600
+ md_output += f"**Related Term:** {term[('related_term_dis'
2601
+ 'play_name')]} ({term['related_term_qualified_name']})\n\n"
2602
+ md_output += "---\n\n"
2603
+
2604
+ return md_output
2605
+
2606
+ def get_term_details(self, term_name: str, effective_time: str = None, output_format: str = 'DICT') -> dict | str:
2607
+ """Retrieve detailed information about a term, combining basic term details and related terms.
2608
+
2609
+ This method combines the term details retrieved from get_term_by_guid and the related terms
2610
+ information from generate_related_terms_md.
2611
+
2612
+ Parameters
2613
+ ----------
2614
+ term_name : str
2615
+ Either the display name or the qualified name of the term to retrieve.
2616
+ effective_time : str, optional
2617
+ Time at which the term is active. If not specified, the current time is used.
2618
+ output_format : str, default = 'DICT'
2619
+ Type of output to produce:
2620
+ DICT - output a dictionary with combined term details and related terms
2621
+ REPORT - output a markdown report with combined term details and related terms
2622
+
2623
+ Returns
2624
+ -------
2625
+ dict | str
2626
+ A dictionary or markdown string containing the combined term details and related terms.
2627
+
2628
+ Raises
2629
+ ------
2630
+ InvalidParameterException
2631
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values.
2632
+ PropertyServerException
2633
+ Raised by the server when an issue arises in processing a valid request.
2634
+ NotAuthorizedException
2635
+ The principle specified by the user_id does not have authorization for the requested action.
2636
+ """
2637
+ # Check if the output format is supported
2638
+ if output_format not in ["DICT", "REPORT"]:
2639
+ return f"Unsupported output format: {output_format}. Supported formats are DICT and REPORT."
2640
+
2641
+ # Search for the term using the qualified name
2642
+ terms = self.get_terms_by_name(term_name, effective_time=effective_time, output_format="DICT")
2643
+
2644
+ # Check if we found any terms
2645
+ if not terms or (isinstance(terms, str) and terms == NO_TERMS_FOUND):
2646
+ return f"No term found with name: {term_name}"
2647
+
2648
+ # Make sure we only have one term
2649
+ if isinstance(terms, list) and len(terms) > 1:
2650
+ return f"Multiple terms found with name: {term_name} - please specify the qualified name."
2651
+
2652
+ term_details = terms[0]
2653
+
2654
+ # Get related terms
2655
+ try:
2656
+ related_terms_response = self.get_related_terms(term_details.get('guid', ''), output_format="DICT")
2657
+ except (InvalidParameterException, PropertyServerException, UserNotAuthorizedException):
2658
+ # If we can't get related terms, set to empty list
2659
+ related_terms_response = []
2660
+
2661
+ # If no related terms were found, set to empty list
2662
+ if isinstance(related_terms_response, str) and related_terms_response == NO_TERMS_FOUND:
2663
+ related_terms = []
2664
+ elif related_terms_response is None:
2665
+ related_terms = []
2666
+ else:
2667
+ related_terms = related_terms_response
2668
+
2669
+ # Combine the data
2670
+ if output_format == "DICT":
2671
+ # Create a combined dictionary
2672
+ combined_data = {
2673
+ "term_details": term_details, "related_terms": related_terms
2674
+ }
2675
+ return combined_data
2676
+ elif output_format == "REPORT":
2677
+ # Create a markdown report
2678
+ md_output = f"# Term Details Report for `{term_name}` \n\n"
2679
+
2680
+ # Add term details
2681
+ md_output += "## Basic Term Information\n\n"
2682
+ md_output += f"**Display Name:** {term_details.get('display_name', '')}\n\n"
2683
+ md_output += f"**Qualified Name:** {term_details.get('qualified_name', '')}\n\n"
2684
+ md_output += f"**GUID:** {term_details.get('guid', '')}\n\n"
2685
+
2686
+ if 'summary' in term_details and term_details['summary']:
2687
+ md_output += f"**Summary:** {term_details.get('summary', '')}\n\n"
2688
+
2689
+ if 'description' in term_details and term_details['description']:
2690
+ md_output += f"**Description:** {term_details.get('description', '')}\n\n"
2691
+
2692
+ if 'examples' in term_details and term_details['examples']:
2693
+ md_output += f"**Examples:** {term_details.get('examples', '')}\n\n"
2694
+
2695
+ if 'usage' in term_details and term_details['usage']:
2696
+ md_output += f"**Usage:** {term_details.get('usage', '')}\n\n"
2697
+
2698
+ if 'aliases' in term_details and term_details['aliases']:
2699
+ md_output += f"**Aliases:** {term_details.get('aliases', '')}\n\n"
2700
+
2701
+ if 'status' in term_details and term_details['status']:
2702
+ md_output += f"**Status:** {term_details.get('status', '')}\n\n"
2703
+
2704
+ if 'in_glossary' in term_details and term_details['in_glossary']:
2705
+ md_output += f"**Glossary:** {term_details.get('in_glossary', '')}\n\n"
2706
+
2707
+ if 'categories' in term_details and term_details['categories']:
2708
+ md_output += f"**Categories:** {', '.join(term_details.get('categories', []))}\n\n"
2709
+
2710
+ # Add related terms
2711
+ md_output += "## Related Terms\n\n"
2712
+
2713
+ if not related_terms:
2714
+ md_output += "No related terms found.\n\n"
2715
+ else:
2716
+ # Create a table for related terms
2717
+ md_output += "| Related Term | Qualified Name | Relationship Type |\n"
2718
+ md_output += "|--------------|---------------|-------------------|\n"
2719
+
2720
+ for term in related_terms:
2721
+ md_output += f"| {term.get('related_term_display_name', '')} | "
2722
+ md_output += f"{term.get('related_term_qualified_name', '')} | "
2723
+ md_output += f"{term.get('relationship_type', '')} |\n"
2724
+
2725
+ return md_output
2726
+ else:
2727
+ return f"Unsupported output format: {output_format}. Supported formats are DICT and REPORT."
2728
+
2729
+ async def _async_get_glossary_for_term(self, term_guid: str, effective_time: str = None) -> dict | str:
1603
2730
  """Retrieve the glossary metadata element for the requested term. The optional request body allows you to
1604
2731
  specify that the glossary element should only be returned if it was effective at a particular time.
1605
2732
 
@@ -1633,20 +2760,15 @@ class GlossaryBrowser(Client):
1633
2760
  validate_guid(term_guid)
1634
2761
 
1635
2762
  body = {
1636
- "class": "EffectiveTimeQueryRequestBody",
1637
- "effectiveTime": effective_time,
1638
- }
1639
- url = (
1640
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1641
- f"for-term/{term_guid}/retrieve"
1642
- )
2763
+ "class": "EffectiveTimeQueryRequestBody", "effectiveTime": effective_time,
2764
+ }
2765
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2766
+ f"for-term/{term_guid}/retrieve")
1643
2767
 
1644
- response = await self._async_make_request("POST", url, body)
1645
- return response.json().get("element", "No glossary found")
2768
+ response = await self._async_make_request("POST", url, body_slimmer(body))
2769
+ return response.json().get("element", NO_GLOSSARIES_FOUND)
1646
2770
 
1647
- def get_glossary_for_term(
1648
- self, term_guid: str, effective_time: str = None
1649
- ) -> dict | str:
2771
+ def get_glossary_for_term(self, term_guid: str, effective_time: str = None) -> dict | str:
1650
2772
  """Retrieve the glossary metadata element for the requested term. The optional request body allows you to
1651
2773
  specify that the glossary element should only be returned if it was effective at a particular time.
1652
2774
 
@@ -1677,22 +2799,13 @@ class GlossaryBrowser(Client):
1677
2799
  -----
1678
2800
  """
1679
2801
  loop = asyncio.get_event_loop()
1680
- response = loop.run_until_complete(
1681
- self._async_get_glossary_for_term(term_guid, effective_time)
1682
- )
2802
+ response = loop.run_until_complete(self._async_get_glossary_for_term(term_guid, effective_time))
1683
2803
  return response
1684
2804
 
1685
- async def _async_get_terms_by_name(
1686
- self,
1687
- term: str,
1688
- glossary_guid: str = None,
1689
- status_filter: list = [],
1690
- effective_time: str = None,
1691
- for_lineage: bool = False,
1692
- for_duplicate_processing: bool = False,
1693
- start_from: int = 0,
1694
- page_size: int = None,
1695
- ) -> list:
2805
+ async def _async_get_terms_by_name(self, term: str, glossary_guid: str = None, status_filter: list = [],
2806
+ effective_time: str = None, for_lineage: bool = False,
2807
+ for_duplicate_processing: bool = False, start_from: int = 0,
2808
+ page_size: int = None, output_format="JSON") -> list:
1696
2809
  """Retrieve glossary terms by display name or qualified name. Async Version.
1697
2810
 
1698
2811
  Parameters
@@ -1715,6 +2828,13 @@ class GlossaryBrowser(Client):
1715
2828
  The index of the first term to retrieve. Default is 0.
1716
2829
  page_size : int, optional
1717
2830
  The number of terms to retrieve per page. If not provided, it will use the default page size.
2831
+ output_format: str, default = 'JSON'
2832
+ Type of output to produce:
2833
+ JSON - output standard json
2834
+ MD - output standard markdown with no preamble
2835
+ FORM - output markdown with a preamble for a form
2836
+ REPORT - output markdown with a preamble for a report
2837
+ DICT - output a simplified DICT structure
1718
2838
 
1719
2839
  Returns
1720
2840
  -------
@@ -1740,36 +2860,32 @@ class GlossaryBrowser(Client):
1740
2860
  for_duplicate_processing_s = str(for_duplicate_processing).lower()
1741
2861
 
1742
2862
  body = {
1743
- "class": "GlossaryNameRequestBody",
1744
- "glossaryGUID": glossary_guid,
1745
- "name": term,
1746
- "effectiveTime": effective_time,
1747
- "limitResultsByStatus": status_filter,
1748
- }
2863
+ "class": "GlossaryNameRequestBody", "glossaryGUID": glossary_guid, "name": term,
2864
+ "effectiveTime": effective_time, "limitResultsByStatus": status_filter,
2865
+ }
1749
2866
  # body = body_slimmer(body)
1750
2867
 
1751
- url = (
1752
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
1753
- f"terms/by-name?startFrom={start_from}&pageSize={page_size}&"
1754
- f"&forLineage={for_lineage_s}&forDuplicateProcessing={for_duplicate_processing_s}"
1755
- )
2868
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2869
+ f"terms/by-name?startFrom={start_from}&pageSize={page_size}&"
2870
+ f"&forLineage={for_lineage_s}&forDuplicateProcessing={for_duplicate_processing_s}")
1756
2871
 
1757
2872
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
1758
-
1759
- response = await self._async_make_request("POST", url, body)
1760
- return response.json().get("elementList", "No terms found")
1761
-
1762
- def get_terms_by_name(
1763
- self,
1764
- term: str,
1765
- glossary_guid: str = None,
1766
- status_filter: list = [],
1767
- effective_time: str = None,
1768
- for_lineage: bool = False,
1769
- for_duplicate_processing: bool = False,
1770
- start_from: int = 0,
1771
- page_size: int = None,
1772
- ) -> list:
2873
+ response = await self._async_make_request("POST", url, body_slimmer(body))
2874
+ term_elements = response.json().get("elementList", NO_TERMS_FOUND)
2875
+ if term_elements == NO_TERMS_FOUND:
2876
+ if output_format == 'JSON':
2877
+ return NO_TERMS_FOUND
2878
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
2879
+ return "\n# No Terms found.\n"
2880
+ elif output_format == 'DICT':
2881
+ return None
2882
+ if output_format != "JSON": # return a simplified markdown representation
2883
+ return self.generate_terms_md(term_elements, term, output_format)
2884
+ return response.json().get("elementList", NO_TERMS_FOUND)
2885
+
2886
+ def get_terms_by_name(self, term: str, glossary_guid: str = None, status_filter: list = [],
2887
+ effective_time: str = None, for_lineage: bool = False, for_duplicate_processing: bool = False,
2888
+ start_from: int = 0, page_size: int = None, output_format="JSON") -> list:
1773
2889
  """Retrieve glossary terms by display name or qualified name.
1774
2890
 
1775
2891
  Parameters
@@ -1792,6 +2908,13 @@ class GlossaryBrowser(Client):
1792
2908
  The index of the first term to retrieve. Default is 0.
1793
2909
  page_size : int, optional
1794
2910
  The number of terms to retrieve per page. If not provided, it will use the default page size.
2911
+ output_format: str, default = 'JSON'
2912
+ Type of output to produce:
2913
+ JSON - output standard json
2914
+ MD - output standard markdown with no preamble
2915
+ FORM - output markdown with a preamble for a form
2916
+ REPORT - output markdown with a preamble for a report
2917
+ DICT - output a simplified DICT structure
1795
2918
 
1796
2919
  Returns
1797
2920
  -------
@@ -1810,26 +2933,22 @@ class GlossaryBrowser(Client):
1810
2933
  """
1811
2934
  loop = asyncio.get_event_loop()
1812
2935
  response = loop.run_until_complete(
1813
- self._async_get_terms_by_name(
1814
- term,
1815
- glossary_guid,
1816
- status_filter,
1817
- effective_time,
1818
- for_lineage,
1819
- for_duplicate_processing,
1820
- start_from,
1821
- page_size,
1822
- )
1823
- )
2936
+ self._async_get_terms_by_name(term, glossary_guid, status_filter, effective_time, for_lineage,
2937
+ for_duplicate_processing, start_from, page_size, output_format))
1824
2938
  return response
1825
2939
 
1826
- async def _async_get_terms_by_guid(self, term_guid: str) -> dict | str:
2940
+ async def _async_get_term_by_guid(self, term_guid: str, output_format: str = 'JSON') -> dict | str:
1827
2941
  """Retrieve a term using its unique id. Async version.
1828
2942
  Parameters
1829
2943
  ----------
1830
2944
  term_guid : str
1831
2945
  The GUID of the glossary term to retrieve.
1832
-
2946
+ output_format: str, default = 'JSON'
2947
+ Type of output to produce:
2948
+ JSON - output standard json
2949
+ MD - output standard markdown with no preamble
2950
+ FORM - output markdown with a preamble for a form
2951
+ REPORT - output markdown with a preamble for a report
1833
2952
 
1834
2953
  Returns
1835
2954
  -------
@@ -1846,31 +2965,36 @@ class GlossaryBrowser(Client):
1846
2965
  NotAuthorizedException
1847
2966
  The principle specified by the user_id does not have authorization for the requested action.
1848
2967
  """
1849
-
2968
+ output_format = output_format.upper()
1850
2969
  validate_guid(term_guid)
1851
2970
 
1852
- url = (
1853
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
1854
- f"{term_guid}/retrieve"
1855
- )
1856
-
2971
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
2972
+ f"{term_guid}/retrieve")
1857
2973
  response = await self._async_make_request("POST", url)
1858
- return response.json().get("element", "No term found")
1859
-
1860
- def get_terms_by_guid(self, term_guid: str) -> dict | str:
2974
+ term_element = response.json().get("element", NO_TERMS_FOUND)
2975
+ if term_element == NO_TERMS_FOUND:
2976
+ return NO_TERMS_FOUND
2977
+ if output_format != 'JSON': # return a simplified markdown representation
2978
+ return self.generate_terms_md(term_element, "GUID", output_format)
2979
+ return response.json().get("element", NO_TERMS_FOUND)
2980
+
2981
+ def get_term_by_guid(self, term_guid: str, output_format: str = 'JSON') -> dict | str:
1861
2982
  """Retrieve a term using its unique id. Async version.
1862
2983
  Parameters
1863
2984
  ----------
1864
2985
  term_guid : str
1865
2986
  The GUID of the glossary term to retrieve.
1866
-
1867
-
2987
+ output_format: str, default = 'JSON'
2988
+ Type of output to produce:
2989
+ JSON - output standard json
2990
+ MD - output standard markdown with no preamble
2991
+ FORM - output markdown with a preamble for a form
2992
+ REPORT - output markdown with a preamble for a report
1868
2993
  Returns
1869
2994
  -------
1870
2995
  dict | str
1871
2996
  A dict detailing the glossary term represented by the GUID. If no term is found, the string
1872
2997
  "No term found" will be returned.
1873
-
1874
2998
  Raises
1875
2999
  ------
1876
3000
  InvalidParameterException
@@ -1882,16 +3006,16 @@ class GlossaryBrowser(Client):
1882
3006
  """
1883
3007
 
1884
3008
  loop = asyncio.get_event_loop()
1885
- response = loop.run_until_complete(self._async_get_terms_by_guid(term_guid))
3009
+ response = loop.run_until_complete(self._async_get_term_by_guid(term_guid, output_format))
1886
3010
 
1887
3011
  return response
1888
3012
 
1889
- async def _async_get_terms_versions(
1890
- self,
1891
- term_guid: str,
1892
- start_from: int = 0,
1893
- page_size=None,
1894
- ) -> dict | str:
3013
+ async def _async_get_term_versions(self, term_guid: str, effective_time: str = None, from_time: str = None,
3014
+ to_time: str = None, oldest_first: bool = False, for_lineage: bool = False,
3015
+ for_duplicate_processing: bool = False, start_from: int = 0,
3016
+ page_size=max_paging_size,
3017
+
3018
+ ) -> list | str:
1895
3019
  """Retrieve the versions of a glossary term. Async version.
1896
3020
  Parameters
1897
3021
  ----------
@@ -1904,8 +3028,8 @@ class GlossaryBrowser(Client):
1904
3028
  The number of terms to retrieve per page. If not provided, it will use the default page size.
1905
3029
  Returns
1906
3030
  -------
1907
- dict | str
1908
- A dict detailing the glossary term represented by the GUID. If no term is found, the string
3031
+ list | str
3032
+ A [dict] detailing the glossary term represented by the GUID. If no term is found, the string
1909
3033
  "No term found" will be returned.
1910
3034
 
1911
3035
  Raises
@@ -1916,27 +3040,37 @@ class GlossaryBrowser(Client):
1916
3040
  Raised by the server when an issue arises in processing a valid request.
1917
3041
  NotAuthorizedException
1918
3042
  The principle specified by the user_id does not have authorization for the requested action.
3043
+
3044
+ Args:
3045
+ term_guid:
3046
+ effective_time:
3047
+ from_time:
3048
+ to_time:
3049
+ oldest_first:
3050
+ for_lineage:
3051
+ for_duplicate_processing:
3052
+ start_from:
3053
+ page_size:
1919
3054
  """
1920
3055
 
1921
- if page_size is None:
1922
- page_size = self.page_size
3056
+ body = {
3057
+ "effective_time": effective_time, "fromTime": from_time, "toTime": to_time, "forLineage": for_lineage,
3058
+ "forDuplicateProcessing": for_duplicate_processing
3059
+ }
1923
3060
 
3061
+ oldest_first_s = str(oldest_first).lower()
1924
3062
  validate_guid(term_guid)
1925
3063
 
1926
- url = (
1927
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
1928
- f"{term_guid}/history?startFrom={start_from}&pageSize={page_size}"
1929
- )
3064
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/terms/"
3065
+ f"{term_guid}/history?startFrom={start_from}&pageSize={page_size}&oldestFirst={oldest_first_s}&"
3066
+ f"forDuplicateProcessing={for_duplicate_processing}&forLineage={for_lineage}")
1930
3067
 
1931
- response = await self._async_make_request("POST", url)
1932
- return response.json().get("element", "No term found")
1933
-
1934
- def get_terms_versions(
1935
- self,
1936
- term_guid: str,
1937
- start_from: int = 0,
1938
- page_size=None,
1939
- ) -> dict | str:
3068
+ response = await self._async_make_request("POST", url, body_slimmer(body))
3069
+ return response.json().get("elementList", "No term found")
3070
+
3071
+ def get_term_versions(self, term_guid: str, effective_time: str = None, from_time: str = None, to_time: str = None,
3072
+ oldest_first: bool = False, for_lineage: bool = False, for_duplicate_processing: bool = False,
3073
+ start_from: int = 0, page_size=max_paging_size, ) -> dict | str:
1940
3074
  """Retrieve the versions of a glossary term.
1941
3075
  Parameters
1942
3076
  ----------
@@ -1949,8 +3083,8 @@ class GlossaryBrowser(Client):
1949
3083
  The number of terms to retrieve per page. If not provided, it will use the default page size.
1950
3084
  Returns
1951
3085
  -------
1952
- dict | str
1953
- A dict detailing the glossary term represented by the GUID. If no term is found, the string
3086
+ [dict] | str
3087
+ A [dict] detailing the glossary term represented by the GUID. If no term is found, the string
1954
3088
  "No term found" will be returned.
1955
3089
 
1956
3090
  Raises
@@ -1965,17 +3099,12 @@ class GlossaryBrowser(Client):
1965
3099
 
1966
3100
  loop = asyncio.get_event_loop()
1967
3101
  response = loop.run_until_complete(
1968
- self._async_get_terms_versions(term_guid, start_from, page_size)
1969
- )
3102
+ self._async_get_term_versions(term_guid, effective_time, from_time, to_time, oldest_first, for_lineage,
3103
+ for_duplicate_processing, start_from, page_size))
1970
3104
 
1971
3105
  return response
1972
3106
 
1973
- async def _async_get_term_revision_logs(
1974
- self,
1975
- term_guid: str,
1976
- start_from: int = 0,
1977
- page_size=None,
1978
- ) -> dict | str:
3107
+ async def _async_get_term_revision_logs(self, term_guid: str, start_from: int = 0, page_size=None, ) -> dict | str:
1979
3108
  """Retrieve the revision log history for a term. Async version.
1980
3109
  Parameters
1981
3110
  ----------
@@ -2007,20 +3136,13 @@ class GlossaryBrowser(Client):
2007
3136
 
2008
3137
  validate_guid(term_guid)
2009
3138
 
2010
- url = (
2011
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/elements/"
2012
- f"{term_guid}/notes/retrieve?startFrom={start_from}&pageSize={page_size}"
2013
- )
3139
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/elements/"
3140
+ f"{term_guid}/note-logs/retrieve?startFrom={start_from}&pageSize={page_size}")
2014
3141
 
2015
3142
  response = await self._async_make_request("POST", url)
2016
3143
  return response.json().get("elementList", "No log found")
2017
3144
 
2018
- def get_term_revision_logs(
2019
- self,
2020
- term_guid: str,
2021
- start_from: int = 0,
2022
- page_size=None,
2023
- ) -> dict | str:
3145
+ def get_term_revision_logs(self, term_guid: str, start_from: int = 0, page_size=None, ) -> dict | str:
2024
3146
  """Retrieve the revision log history for a term.
2025
3147
  Parameters
2026
3148
  ----------
@@ -2048,18 +3170,12 @@ class GlossaryBrowser(Client):
2048
3170
  """
2049
3171
 
2050
3172
  loop = asyncio.get_event_loop()
2051
- response = loop.run_until_complete(
2052
- self._async_get_term_revision_logs(term_guid, start_from, page_size)
2053
- )
3173
+ response = loop.run_until_complete(self._async_get_term_revision_logs(term_guid, start_from, page_size))
2054
3174
 
2055
3175
  return response
2056
3176
 
2057
- async def _async_get_term_revision_history(
2058
- self,
2059
- term_revision_log_guid: str,
2060
- start_from: int = 0,
2061
- page_size=None,
2062
- ) -> dict | str:
3177
+ async def _async_get_term_revision_history(self, term_revision_log_guid: str, start_from: int = 0,
3178
+ page_size=None, ) -> dict | str:
2063
3179
  """Retrieve the revision history for a glossary term. Async version.
2064
3180
 
2065
3181
  Parameters
@@ -2097,20 +3213,14 @@ class GlossaryBrowser(Client):
2097
3213
 
2098
3214
  validate_guid(term_revision_log_guid)
2099
3215
 
2100
- url = (
2101
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/note-logs/"
2102
- f"{term_revision_log_guid}/notes/retrieve?startFrom={start_from}&pageSize={page_size}"
2103
- )
3216
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/note-logs/"
3217
+ f"{term_revision_log_guid}/notes/retrieve?startFrom={start_from}&pageSize={page_size}")
2104
3218
 
2105
3219
  response = await self._async_make_request("POST", url)
2106
3220
  return response.json().get("elementList", "No logs found")
2107
3221
 
2108
- def get_term_revision_history(
2109
- self,
2110
- term_revision_log_guid: str,
2111
- start_from: int = 0,
2112
- page_size=None,
2113
- ) -> dict | str:
3222
+ def get_term_revision_history(self, term_revision_log_guid: str, start_from: int = 0,
3223
+ page_size=None, ) -> dict | str:
2114
3224
  """Retrieve the revision history for a glossary term.
2115
3225
 
2116
3226
  Parameters
@@ -2145,27 +3255,190 @@ class GlossaryBrowser(Client):
2145
3255
 
2146
3256
  loop = asyncio.get_event_loop()
2147
3257
  response = loop.run_until_complete(
2148
- self._async_get_term_revision_history(
2149
- term_revision_log_guid, start_from, page_size
2150
- )
2151
- )
3258
+ self._async_get_term_revision_history(term_revision_log_guid, start_from, page_size))
2152
3259
 
2153
3260
  return response
2154
3261
 
2155
- async def _async_find_glossary_terms(
2156
- self,
2157
- search_string: str,
2158
- glossary_guid: str = None,
2159
- status_filter: list = [],
2160
- effective_time: str = None,
2161
- starts_with: bool = False,
2162
- ends_with: bool = False,
2163
- ignore_case: bool = False,
2164
- for_lineage: bool = False,
2165
- for_duplicate_processing: bool = False,
2166
- start_from: int = 0,
2167
- page_size: int = None,
2168
- ) -> list | str:
3262
+ def list_term_revision_history(self, term_guid: str, output_format: str = "DICT") -> list | str:
3263
+ """
3264
+ Retrieve the revision history for a term.
3265
+
3266
+ This method retrieves the revision logs associated with a term, and for each revision log,
3267
+ retrieves the revision history. The results are formatted according to the specified output format.
3268
+
3269
+ Parameters
3270
+ ----------
3271
+ term_guid : str
3272
+ The GUID of the glossary term to retrieve the revision history for.
3273
+ output_format : str, optional
3274
+ The format in which to return the results. Can be "DICT", "MD", or "LIST".
3275
+ Defaults to "DICT".
3276
+
3277
+ Returns
3278
+ -------
3279
+ list | str
3280
+ If output_format is "DICT", returns a list of dictionaries containing the revision history.
3281
+ If output_format is "MD", returns a markdown representation of the revision history.
3282
+ If output_format is "LIST", returns a markdown table of the revision history.
3283
+ If no revision logs are found, returns a string message "No revision logs found".
3284
+ """
3285
+ validate_guid(term_guid)
3286
+
3287
+ # Get revision logs for the term
3288
+ revision_logs = self.get_term_revision_logs(term_guid)
3289
+ if isinstance(revision_logs, str):
3290
+ return "No revision logs found"
3291
+
3292
+ # Process each revision log
3293
+ all_entries = []
3294
+ for log in revision_logs:
3295
+ log_guid = log['elementHeader']['guid']
3296
+ qualified_name = log.get('properties', {}).get('qualifiedName', '---')
3297
+
3298
+ # Get revision history for this log
3299
+ history = self.get_term_revision_history(log_guid)
3300
+ if isinstance(history, str):
3301
+ continue
3302
+
3303
+ # Process each entry in the history
3304
+ for entry in history:
3305
+ # Extract update time from the title
3306
+ title = entry.get('properties', {}).get('title', '---')
3307
+
3308
+ keyword_index = title.index('on')
3309
+ update_time = title[keyword_index + 2:].strip()
3310
+
3311
+ entry_data = {
3312
+ 'qualifiedName': qualified_name, 'title': title,
3313
+ 'text': entry.get('properties', {}).get('text', '---'), 'updateTime': update_time
3314
+ # Use extracted date/time or fall back to title
3315
+ }
3316
+ all_entries.append(entry_data)
3317
+
3318
+ # Sort entries by update time
3319
+ sorted_entries = sorted(all_entries, key=lambda x: x['updateTime'] if x['updateTime'] != '---' else '',
3320
+ reverse=True)
3321
+
3322
+ # Return in the specified format
3323
+ if output_format == "DICT":
3324
+ return sorted_entries
3325
+ elif output_format == "LIST":
3326
+ # Create markdown table
3327
+ if not sorted_entries:
3328
+ return "No revision entries found"
3329
+
3330
+ # Get headers
3331
+ headers = sorted_entries[0].keys()
3332
+
3333
+ # Create header row
3334
+ header_row = " | ".join(headers)
3335
+ separator_row = " | ".join(["---"] * len(headers))
3336
+
3337
+ # Create rows
3338
+ rows = []
3339
+ for entry in sorted_entries:
3340
+ row = " | ".join(str(entry.get(header, "---")) for header in headers)
3341
+ rows.append(row)
3342
+
3343
+ # Combine into table
3344
+ markdown_table = f"{header_row}\n{separator_row}\n" + "\n".join(rows)
3345
+ return markdown_table
3346
+ elif output_format == "MD":
3347
+ # Create markdown representation
3348
+ if not sorted_entries:
3349
+ return "No revision entries found"
3350
+
3351
+ md_output = "\n"
3352
+
3353
+ for entry in sorted_entries:
3354
+ md_output += f"* Note Log Name: \n{entry['qualifiedName']}\n\n"
3355
+ md_output += f"* Note Log Entry Title: \n{entry['title']}\n\n"
3356
+ md_output += f"* Note Log Entry: \n\t{entry['text']}\n\n"
3357
+ md_output += "---\n\n"
3358
+
3359
+ return md_output
3360
+ else:
3361
+ # Default to DICT format
3362
+ return sorted_entries
3363
+
3364
+ def list_full_term_history(self, term_guid: str, output_type: str = "DICT") -> list | str:
3365
+ """
3366
+ Retrieves and formats the entire version history of a specific term in the repository.
3367
+ The version history is either returned as a list of dictionaries or in a Markdown table
3368
+ format.
3369
+
3370
+ The returned history includes details about the creation and update timestamps, user
3371
+ information, and additional glossary term properties such as `displayName`,
3372
+ `qualifiedName`, `description`, and others.
3373
+
3374
+ Parameter
3375
+ ---------
3376
+ term_guid: The unique identifier of the glossary term for which the version
3377
+ history needs to be retrieved.
3378
+ output_type: The format in which the history should be returned. It can be
3379
+ either "DICT" (a list of dictionaries) or "LIST" (a Markdown table).
3380
+ Defaults to "DICT".
3381
+
3382
+ Returns
3383
+ -------
3384
+ list | str: A list of dictionaries representing the version history
3385
+ (if output_type is "DICT"), or a Markdown table of the version details
3386
+ (if output_type is "LIST"). If no history is found, returns a string
3387
+ message "No History Found".
3388
+ """
3389
+ history = self.get_term_versions(term_guid)
3390
+ if type(history) is str:
3391
+ return "No History Found"
3392
+ version_history = []
3393
+ for ver in history:
3394
+ create_time = ver["elementHeader"]["versions"].get("createTime", " ")
3395
+ update_time = ver["elementHeader"]["versions"].get("createTime", " ")
3396
+ created_by = ver["elementHeader"]["versions"].get("createdBy", " ")
3397
+ updated_by = ver["elementHeader"]["versions"].get("updatedBy", "---")
3398
+ version = ver["elementHeader"]["versions"].get("version")
3399
+
3400
+ qualified_name = ver["glossaryTermProperties"].get("qualifiedName", ' ')
3401
+ display_name = ver["glossaryTermProperties"].get("displayName", ' ')
3402
+ summary = ver["glossaryTermProperties"].get("summary", ' ')
3403
+ description = ver["glossaryTermProperties"].get("description", ' ')
3404
+ examples = ver["glossaryTermProperties"].get("examples", ' ')
3405
+ usage = ver["glossaryTermProperties"].get("usage", ' ')
3406
+ version_identifier = ver["glossaryTermProperties"].get("versionIdentifier", ' ')
3407
+
3408
+ version_history.append({
3409
+ "version": version, "displayName": display_name, "summary": summary, "created": create_time,
3410
+ "updated": update_time, "createdBy": created_by, "updatedBy": updated_by,
3411
+ "qualifiedName": qualified_name, "description": description, "examples": examples, "usage": usage,
3412
+ "versionIdentifier": version_identifier,
3413
+ })
3414
+ sorted_history = sorted(version_history, key=lambda i: i['version'], reverse=True)
3415
+ if output_type == "DICT":
3416
+ return sorted_history
3417
+ elif output_type == "LIST":
3418
+ # Get the headers from the keys of the first dictionary
3419
+ headers = sorted_history[0].keys()
3420
+
3421
+ # Create the header row
3422
+ header_row = " | ".join(headers)
3423
+ separator_row = " | ".join(["---"] * len(headers)) # Markdown separator row
3424
+
3425
+ # Create the rows for the table
3426
+ rows = []
3427
+ for entry in sorted_history:
3428
+ row = " | ".join(str(entry.get(header, "---")) for header in headers)
3429
+ rows.append(row)
3430
+
3431
+ # Combine everything into a Markdown table string
3432
+ markdown_table = f"{header_row}\n{separator_row}\n" + "\n".join(rows)
3433
+ return markdown_table
3434
+ else:
3435
+ return None
3436
+
3437
+ async def _async_find_glossary_terms(self, search_string: str, glossary_guid: str = None, status_filter: list = [],
3438
+ effective_time: str = None, starts_with: bool = False, ends_with: bool = False,
3439
+ ignore_case: bool = False, for_lineage: bool = False,
3440
+ for_duplicate_processing: bool = False, start_from: int = 0,
3441
+ page_size: int = None, output_format: str = "JSON", ) -> list | str:
2169
3442
  """Retrieve the list of glossary term metadata elements that contain the search string.
2170
3443
 
2171
3444
  Parameters
@@ -2196,6 +3469,12 @@ class GlossaryBrowser(Client):
2196
3469
  Page of results to start from
2197
3470
  page_size : int, optional
2198
3471
  Number of elements to return per page - if None, then default for class will be used.
3472
+ output_format: str, default = 'JSON'
3473
+ Type of output to produce:
3474
+ JSON - output standard json
3475
+ MD - output standard markdown with no preamble
3476
+ FORM - output markdown with a preamble for a form
3477
+ REPORT - output markdown with a preamble for a report
2199
3478
 
2200
3479
  Returns
2201
3480
  -------
@@ -2215,7 +3494,7 @@ class GlossaryBrowser(Client):
2215
3494
  Notes
2216
3495
  -----
2217
3496
  The search string is located in the request body and is interpreted as a plain string.
2218
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
3497
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
2219
3498
  The request body also supports the specification of a glossaryGUID to restrict the search to within a single
2220
3499
  glossary.
2221
3500
  """
@@ -2235,42 +3514,33 @@ class GlossaryBrowser(Client):
2235
3514
  # validate_search_string(search_string)
2236
3515
 
2237
3516
  body = {
2238
- "class": "GlossarySearchStringRequestBody",
2239
- "glossaryGUID": glossary_guid,
2240
- "searchString": search_string,
2241
- "effectiveTime": effective_time,
2242
- "limitResultsByStatus": status_filter,
2243
- }
2244
- # body = body_slimmer(body)
2245
-
2246
- url = (
2247
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2248
- f"terms/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
2249
- f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
2250
- f"forDuplicateProcessing={for_duplicate_processing_s}"
2251
- )
2252
-
2253
- # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2254
-
2255
- response = await self._async_make_request("POST", url, body)
2256
- return response.json().get(
2257
- "elementList", "No terms found"
2258
- ) # return response.text
2259
-
2260
- def find_glossary_terms(
2261
- self,
2262
- search_string: str,
2263
- glossary_guid: str = None,
2264
- status_filter: list = [],
2265
- effective_time: str = None,
2266
- starts_with: bool = False,
2267
- ends_with: bool = False,
2268
- ignore_case: bool = False,
2269
- for_lineage: bool = False,
2270
- for_duplicate_processing: bool = False,
2271
- start_from: int = 0,
2272
- page_size: int = None,
2273
- ) -> list | str:
3517
+ "class": "GlossarySearchStringRequestBody", "glossaryGUID": glossary_guid, "searchString": search_string,
3518
+ "effectiveTime": effective_time, "limitResultsByStatus": status_filter,
3519
+ }
3520
+
3521
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
3522
+ f"terms/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
3523
+ f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
3524
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
3525
+
3526
+ response = await self._async_make_request("POST", url, body_slimmer(body))
3527
+ term_elements = response.json().get("elementList", NO_TERMS_FOUND)
3528
+ if term_elements == NO_TERMS_FOUND:
3529
+ if output_format == 'JSON':
3530
+ return NO_TERMS_FOUND
3531
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
3532
+ return "\n# No Terms found.\n"
3533
+ elif output_format == 'DICT':
3534
+ return None
3535
+ if output_format != "JSON": # return a simplified markdown representation
3536
+ return self.generate_terms_md(term_elements, search_string, output_format)
3537
+ return response.json().get("elementList", NO_TERMS_FOUND)
3538
+
3539
+ def find_glossary_terms(self, search_string: str, glossary_guid: str = None, status_filter: list = [],
3540
+ effective_time: str = None, starts_with: bool = False, ends_with: bool = False,
3541
+ ignore_case: bool = False, for_lineage: bool = False,
3542
+ for_duplicate_processing: bool = False, start_from: int = 0, page_size: int = None,
3543
+ output_format: str = "JSON", ) -> list | str:
2274
3544
  """Retrieve the list of glossary term metadata elements that contain the search string.
2275
3545
 
2276
3546
  Parameters
@@ -2302,6 +3572,12 @@ class GlossaryBrowser(Client):
2302
3572
  Page of results to start from
2303
3573
  page_size : int, optional
2304
3574
  Number of elements to return per page - if None, then default for class will be used.
3575
+ output_format: str, default = 'JSON'
3576
+ Type of output to produce:
3577
+ JSON - output standard json
3578
+ MD - output standard markdown with no preamble
3579
+ FORM - output markdown with a preamble for a form
3580
+ REPORT - output markdown with a preamble for a report
2305
3581
 
2306
3582
  Returns
2307
3583
  -------
@@ -2321,40 +3597,24 @@ class GlossaryBrowser(Client):
2321
3597
  Notes
2322
3598
  -----
2323
3599
  The search string is located in the request body and is interpreted as a plain string.
2324
- The request parameters, startsWith, endsWith and ignoreCase can be used to allow a fuzzy search.
3600
+ The request parameters, startsWith, endsWith, and ignoreCase can be used to allow a fuzzy search.
2325
3601
  The request body also supports the specification of a glossaryGUID to restrict the search to within a
2326
3602
  single glossary.
2327
3603
  """
2328
3604
 
2329
3605
  loop = asyncio.get_event_loop()
2330
3606
  response = loop.run_until_complete(
2331
- self._async_find_glossary_terms(
2332
- search_string,
2333
- glossary_guid,
2334
- status_filter,
2335
- effective_time,
2336
- starts_with,
2337
- ends_with,
2338
- ignore_case,
2339
- for_lineage,
2340
- for_duplicate_processing,
2341
- start_from,
2342
- page_size,
2343
- )
2344
- )
3607
+ self._async_find_glossary_terms(search_string, glossary_guid, status_filter, effective_time, starts_with,
3608
+ ends_with, ignore_case, for_lineage, for_duplicate_processing, start_from,
3609
+ page_size, output_format))
2345
3610
 
2346
3611
  return response
2347
3612
 
2348
3613
  #
2349
3614
  # Feedback
2350
3615
  #
2351
- async def _async_get_comment(
2352
- self,
2353
- commemt_guid: str,
2354
- effective_time: str,
2355
- for_lineage: bool = False,
2356
- for_duplicate_processing: bool = False,
2357
- ) -> dict | list:
3616
+ async def _async_get_comment(self, commemt_guid: str, effective_time: str, for_lineage: bool = False,
3617
+ for_duplicate_processing: bool = False, ) -> dict | list:
2358
3618
  """Retrieve the comment specified by the comment GUID"""
2359
3619
 
2360
3620
  validate_guid(commemt_guid)
@@ -2367,26 +3627,17 @@ class GlossaryBrowser(Client):
2367
3627
 
2368
3628
  body = {"effective_time": effective_time}
2369
3629
 
2370
- url = (
2371
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
2372
- f"{commemt_guid}?forLineage={for_lineage_s}&"
2373
- f"forDuplicateProcessing={for_duplicate_processing_s}"
2374
- )
3630
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
3631
+ f"{commemt_guid}?forLineage={for_lineage_s}&"
3632
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
2375
3633
 
2376
3634
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2377
3635
 
2378
3636
  response = await self._async_make_request("POST", url, body)
2379
3637
  return response.json()
2380
3638
 
2381
- async def _async_add_comment_reply(
2382
- self,
2383
- comment_guid: str,
2384
- is_public: bool,
2385
- comment_type: str,
2386
- comment_text: str,
2387
- for_lineage: bool = False,
2388
- for_duplicate_processing: bool = False,
2389
- ) -> str:
3639
+ async def _async_add_comment_reply(self, comment_guid: str, is_public: bool, comment_type: str, comment_text: str,
3640
+ for_lineage: bool = False, for_duplicate_processing: bool = False, ) -> str:
2390
3641
  """Reply to a comment"""
2391
3642
 
2392
3643
  validate_guid(comment_guid)
@@ -2397,33 +3648,22 @@ class GlossaryBrowser(Client):
2397
3648
  for_duplicate_processing_s = str(for_duplicate_processing).lower()
2398
3649
 
2399
3650
  body = {
2400
- "class": "CommentRequestBody",
2401
- "commentType": comment_type,
2402
- "commentText": comment_text,
3651
+ "class": "CommentRequestBody", "commentType": comment_type, "commentText": comment_text,
2403
3652
  "isPublic": is_public,
2404
- }
3653
+ }
2405
3654
 
2406
- url = (
2407
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
2408
- f"{comment_guid}/replies?isPublic={is_public_s}&forLineage={for_lineage_s}&"
2409
- f"forDuplicateProcessing={for_duplicate_processing_s}"
2410
- )
3655
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
3656
+ f"{comment_guid}/replies?isPublic={is_public_s}&forLineage={for_lineage_s}&"
3657
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
2411
3658
 
2412
3659
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2413
3660
 
2414
3661
  response = await self._async_make_request("POST", url, body)
2415
3662
  return response
2416
3663
 
2417
- async def _async_update_comment(
2418
- self,
2419
- comment_guid: str,
2420
- is_public: bool,
2421
- comment_type: str,
2422
- comment_text: str,
2423
- is_merge_update: bool = False,
2424
- for_lineage: bool = False,
2425
- for_duplicate_processing: bool = False,
2426
- ) -> str:
3664
+ async def _async_update_comment(self, comment_guid: str, is_public: bool, comment_type: str, comment_text: str,
3665
+ is_merge_update: bool = False, for_lineage: bool = False,
3666
+ for_duplicate_processing: bool = False, ) -> str:
2427
3667
  """Update the specified comment"""
2428
3668
 
2429
3669
  validate_guid(comment_guid)
@@ -2434,37 +3674,23 @@ class GlossaryBrowser(Client):
2434
3674
  for_duplicate_processing_s = str(for_duplicate_processing).lower()
2435
3675
 
2436
3676
  body = {
2437
- "class": "CommentRequestBody",
2438
- "commentType": comment_type,
2439
- "commentText": comment_text,
3677
+ "class": "CommentRequestBody", "commentType": comment_type, "commentText": comment_text,
2440
3678
  "isPublic": is_public,
2441
- }
3679
+ }
2442
3680
 
2443
- url = (
2444
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
2445
- f"{comment_guid}/replies?isPublic={is_public_s}&forLineage={for_lineage_s}&"
2446
- f"forDuplicateProcessing={for_duplicate_processing_s}"
2447
- )
3681
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/comments/"
3682
+ f"{comment_guid}/replies?isPublic={is_public_s}&forLineage={for_lineage_s}&"
3683
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
2448
3684
 
2449
3685
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2450
3686
 
2451
3687
  response = await self._async_make_request("POST", url, body)
2452
3688
  return response
2453
3689
 
2454
- async def _async_find_comment(
2455
- self,
2456
- search_string: str,
2457
- glossary_guid: str = None,
2458
- status_filter: list = [],
2459
- effective_time: str = None,
2460
- starts_with: bool = False,
2461
- ends_with: bool = False,
2462
- ignore_case: bool = False,
2463
- for_lineage: bool = False,
2464
- for_duplicate_processing: bool = False,
2465
- start_from: int = 0,
2466
- page_size: int = None,
2467
- ):
3690
+ async def _async_find_comment(self, search_string: str, glossary_guid: str = None, status_filter: list = [],
3691
+ effective_time: str = None, starts_with: bool = False, ends_with: bool = False,
3692
+ ignore_case: bool = False, for_lineage: bool = False,
3693
+ for_duplicate_processing: bool = False, start_from: int = 0, page_size: int = None, ):
2468
3694
  """Find comments by search string"""
2469
3695
 
2470
3696
  if page_size is None:
@@ -2482,20 +3708,15 @@ class GlossaryBrowser(Client):
2482
3708
  # validate_search_string(search_string)
2483
3709
 
2484
3710
  body = {
2485
- "class": "GlossarySearchStringRequestBody",
2486
- "glossaryGUID": glossary_guid,
2487
- "searchString": search_string,
2488
- "effectiveTime": effective_time,
2489
- "limitResultsByStatus": status_filter,
2490
- }
3711
+ "class": "GlossarySearchStringRequestBody", "glossaryGUID": glossary_guid, "searchString": search_string,
3712
+ "effectiveTime": effective_time, "limitResultsByStatus": status_filter,
3713
+ }
2491
3714
  # body = body_slimmer(body)
2492
3715
 
2493
- url = (
2494
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2495
- f"terms/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
2496
- f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
2497
- f"forDuplicateProcessing={for_duplicate_processing_s}"
2498
- )
3716
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
3717
+ f"terms/by-search-string?startFrom={start_from}&pageSize={page_size}&startsWith={starts_with_s}&"
3718
+ f"endsWith={ends_with_s}&ignoreCase={ignore_case_s}&forLineage={for_lineage_s}&"
3719
+ f"forDuplicateProcessing={for_duplicate_processing_s}")
2499
3720
 
2500
3721
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2501
3722
 
@@ -2504,4 +3725,4 @@ class GlossaryBrowser(Client):
2504
3725
 
2505
3726
 
2506
3727
  if __name__ == "__main__":
2507
- print("Main-Glosssary Browser")
3728
+ print("Main-Glossary Browser")