pyegeria 5.3.8.8__py3-none-any.whl → 5.3.8.10__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.
pyegeria/__init__.py CHANGED
@@ -11,24 +11,10 @@ the server platform and servers.
11
11
 
12
12
  """
13
13
 
14
- from ._globals import (
15
- INTEGRATION_GUIDS,
16
- TEMPLATE_GUIDS,
17
- default_time_out,
18
- disable_ssl_warnings,
19
- enable_ssl_check,
20
- is_debug,
21
- max_paging_size,
22
- NO_ELEMENTS_FOUND,
23
- NO_ASSETS_FOUND,
24
- NO_SERVERS_FOUND,
25
- NO_CATALOGS_FOUND,
26
- NO_GLOSSARIES_FOUND,
27
- NO_TERMS_FOUND,
28
- NO_CATEGORIES_FOUND,
29
- NO_ELEMENT_FOUND,
30
- NO_PROJECTS_FOUND,
31
- )
14
+ from ._globals import (INTEGRATION_GUIDS, TEMPLATE_GUIDS, default_time_out, disable_ssl_warnings, enable_ssl_check,
15
+ is_debug, max_paging_size, NO_ELEMENTS_FOUND, NO_ASSETS_FOUND, NO_SERVERS_FOUND,
16
+ NO_CATALOGS_FOUND, NO_GLOSSARIES_FOUND, NO_TERMS_FOUND, NO_CATEGORIES_FOUND, NO_ELEMENT_FOUND,
17
+ NO_PROJECTS_FOUND, )
32
18
 
33
19
  if disable_ssl_warnings:
34
20
  from urllib3 import disable_warnings
@@ -38,22 +24,10 @@ if disable_ssl_warnings:
38
24
 
39
25
  from ._client import Client
40
26
  from ._deprecated_gov_engine import GovEng
41
- from ._exceptions import (
42
- InvalidParameterException,
43
- PropertyServerException,
44
- UserNotAuthorizedException,
45
- print_exception_response,
46
- )
47
- from ._validators import (
48
- is_json,
49
- validate_guid,
50
- validate_name,
51
- validate_public,
52
- validate_search_string,
53
- validate_server_name,
54
- validate_url,
55
- validate_user_id,
56
- )
27
+ from ._exceptions import (InvalidParameterException, PropertyServerException, UserNotAuthorizedException,
28
+ print_exception_response, )
29
+ from ._validators import (is_json, validate_guid, validate_name, validate_public, validate_search_string,
30
+ validate_server_name, validate_url, validate_user_id, )
57
31
  from .asset_catalog_omvs import AssetCatalog
58
32
  from .automated_curation_omvs import AutomatedCuration
59
33
  from .classification_manager_omvs import ClassificationManager
@@ -69,16 +43,8 @@ from .feedback_manager_omvs import FeedbackManager
69
43
  from .full_omag_server_config import FullServerConfig
70
44
  from .glossary_browser_omvs import GlossaryBrowser
71
45
  from .glossary_manager_omvs import GlossaryManager
72
- from .mermaid_utilities import (
73
- construct_mermaid_web,
74
- construct_mermaid_jup,
75
- generate_process_graph,
76
- load_mermaid,
77
- parse_mermaid_code,
78
- render_mermaid,
79
- save_mermaid_graph,
80
- save_mermaid_html,
81
- )
46
+ from .mermaid_utilities import (construct_mermaid_web, construct_mermaid_jup, generate_process_graph, load_mermaid,
47
+ parse_mermaid_code, render_mermaid, save_mermaid_graph, save_mermaid_html, )
82
48
  from .metadata_explorer_omvs import MetadataExplorer
83
49
  from .my_profile_omvs import MyProfile
84
50
  from .platform_services import Platform
@@ -91,12 +57,14 @@ from .utils import body_slimmer, print_response
91
57
  from .valid_metadata_omvs import ValidMetadataManager
92
58
  from .x_action_author_omvs import ActionAuthor
93
59
  from .md_processing_utils import (extract_command, process_glossary_upsert_command, process_term_upsert_command,
94
- process_category_upsert_command,
95
- get_current_datetime_string, process_per_proj_upsert_command, command_list,
96
- render_markdown, process_provenance_command, process_blueprint_upsert_command,
97
- process_solution_component_upsert_command,
98
- process_term_list_command, process_glossary_list_command, process_category_list_command,
99
- process_term_history_command)
60
+ process_category_upsert_command, get_current_datetime_string,
61
+ process_per_proj_upsert_command, command_list, render_markdown,
62
+ process_provenance_command, process_blueprint_upsert_command,
63
+ process_solution_component_upsert_command, process_term_list_command,
64
+ process_glossary_list_command, process_category_list_command,
65
+ process_term_history_command, process_glossary_structure_command,
66
+ process_term_revision_history_command, process_create_term_term_relationship_command,
67
+ )
100
68
 
101
69
  #
102
70
  # The following assignments were generated by the `create_tech_guid_lists.py` utility that uses the pyegeria functions
@@ -482,6 +450,5 @@ INTEGRATION_GUIDS['OpenLineageCataloguer'] = '3347ac71-8dd2-403a-bc16-75a71be64b
482
450
  INTEGRATION_GUIDS['ApacheAtlasExchange'] = '5721627a-2dd4-4f95-a274-6cfb128edb97'
483
451
  INTEGRATION_GUIDS['HarvestSurveys'] = 'fae162c3-2bfd-467f-9c47-2e3b63a655de'
484
452
 
485
-
486
453
  if __name__ == "__main__":
487
454
  print("Main-Init")
@@ -13,7 +13,9 @@ from pyegeria import (extract_command, process_glossary_upsert_command, process_
13
13
  get_current_datetime_string,
14
14
  process_per_proj_upsert_command, command_list, EgeriaTech, process_blueprint_upsert_command,
15
15
  process_solution_component_upsert_command, dr_egeria_state, process_term_list_command,
16
- process_category_list_command, process_glossary_list_command, process_term_history_command)
16
+ process_category_list_command, process_glossary_list_command, process_term_history_command,
17
+ process_glossary_structure_command, process_term_revision_history_command,
18
+ process_create_term_term_relationship_command)
17
19
 
18
20
  EGERIA_METADATA_STORE = os.environ.get("EGERIA_METADATA_STORE", "active-metadata-store")
19
21
  EGERIA_KAFKA_ENDPOINT = os.environ.get("KAFKA_ENDPOINT", "localhost:9092")
@@ -89,21 +91,22 @@ def process_markdown_file(file_path: str, directive: str, server: str, url: str,
89
91
  result = process_glossary_upsert_command(client, current_block, directive)
90
92
  elif potential_command in ["Create Category", "Update Category"]:
91
93
  result = process_category_upsert_command(client, current_block, directive)
92
- # elif potential_command in ["Set Parent Category", "UnSet Parent Category"]:
93
- # result = process_set_categories_parent_command(client, dr_egeria_state.get_element_dictionary(),
94
- # current_block, directive)
95
94
  elif potential_command in ["Create Term", "Update Term"]:
96
95
  result = process_term_upsert_command(client, current_block, directive)
96
+ elif potential_command in ["Create Term-Term Relationship", "Update Term-Term Relationship"]:
97
+ result = process_create_term_term_relationship_command(client, current_block, directive)
97
98
  elif potential_command in ["List Term History", "Term History"]:
98
99
  result = process_term_history_command(client, current_block, directive)
100
+ elif potential_command in ["List Term Update History", "List Term Revision History"]:
101
+ result = process_term_revision_history_command(client, current_block, directive)
99
102
  elif potential_command in ["List Terms", "List Glossary Terms"]:
100
103
  result = process_term_list_command(client, current_block, directive)
101
104
  elif potential_command in ["List Categories", "List Glossary Categories"]:
102
- result = process_category_list_command(client, dr_egeria_state.get_element_dictionary(), current_block,
103
- directive)
105
+ result = process_category_list_command(client, current_block, directive)
106
+ elif potential_command in ["List Glossary Structure"]:
107
+ result = process_glossary_structure_command(client, current_block, directive)
104
108
  elif potential_command in ["List Glossaries"]:
105
- result = process_glossary_list_command(client, dr_egeria_state.get_element_dictionary(), current_block,
106
- directive)
109
+ result = process_glossary_list_command(client, current_block, directive)
107
110
  elif potential_command in ["Create Personal Project", "Update Personal Project"]:
108
111
  result = process_per_proj_upsert_command(client, current_block, directive)
109
112
  elif potential_command in ["Create Blueprint", "Update Blueprint", "Create Solution Blueprint",
@@ -133,8 +133,8 @@ class GlossaryBrowser(Client):
133
133
  cat_md_qn = ''
134
134
  if type(categories) is list:
135
135
  for category in categories:
136
- cat_md_display += f"* {category['glossaryCategoryProperties'][('displayName')]}\n"
137
- cat_md_qn += f"* {category['glossaryCategoryProperties'][('qualifiedName')]}\n"
136
+ cat_md_display += f" {category['glossaryCategoryProperties'][('displayName')]},\n"
137
+ cat_md_qn += f" {category['glossaryCategoryProperties'][('qualifiedName')]},\n"
138
138
  cat_md = cat_md_display.strip()
139
139
  cat_md_qn = cat_md_qn.strip()
140
140
 
@@ -423,9 +423,10 @@ class GlossaryBrowser(Client):
423
423
  pub_version = properties.get("publishVersionIdentifier", "") or ""
424
424
  qualified_name = properties.get("qualifiedName", "") or ""
425
425
  status = element['elementHeader'].get('status', "") or ""
426
+ aliases = ", ".join(properties.get("aliases", "")) or ""
426
427
 
427
428
  return {
428
- 'guid': guid, 'properties': properties, 'display_name': display_name, 'summary': summary,
429
+ 'guid': guid, 'properties': properties, 'display_name': display_name, 'aliases': aliases, 'summary': summary,
429
430
  'description': description, 'examples': examples, 'usage': usage, 'version identifier': pub_version,
430
431
  'qualified_name': qualified_name, 'status': status
431
432
  }
@@ -506,8 +507,8 @@ class GlossaryBrowser(Client):
506
507
  str: Markdown table
507
508
  """
508
509
  columns = [{'name': 'Term Name', 'key': 'display_name'}, {'name': 'Qualified Name', 'key': 'qualified_name'},
509
- {'name': 'Summary', 'key': 'summary', 'format': True}, {'name': 'Glossary', 'key': 'glossary'},
510
- {'name': 'Categories', 'key': 'categories_str', 'format': True}]
510
+ {'name': 'Aliases', 'key': 'aliases', 'format': True}, {'name': 'Summary', 'key': 'summary', 'format': True},
511
+ {'name': 'Glossary', 'key': 'glossary'}, {'name': 'Categories', 'key': 'categories_str', 'format': True}]
511
512
 
512
513
  # Create a wrapper function to pass output_format to _get_term_table_properties
513
514
  def get_table_props_with_format(element, term_guid, output_format_param=None):
@@ -640,11 +641,11 @@ class GlossaryBrowser(Client):
640
641
  output_format (str): Output format (FORM, REPORT, LIST, etc.)
641
642
 
642
643
  Returns:
643
- str: The parent category name or '---' if no parent
644
+ str: The parent category name or ' ' if no parent
644
645
  """
645
646
  parent_cat = self.get_category_parent(category_guid)
646
647
  if isinstance(parent_cat, str):
647
- return '---'
648
+ return ' '
648
649
 
649
650
  # Return qualified name for FORM output, display name for REPORT and LIST output
650
651
  if output_format == 'FORM':
@@ -1036,6 +1037,43 @@ class GlossaryBrowser(Client):
1036
1037
  response = loop.run_until_complete(self._async_get_glossary_term_statuses())
1037
1038
  return response
1038
1039
 
1040
+ async def _async_get_term_relationship_types(self) -> [str]:
1041
+ """Return the list of term relationship types enum values. Async version.
1042
+
1043
+ Parameters
1044
+ ----------
1045
+
1046
+
1047
+ Returns
1048
+ -------
1049
+ List[str]
1050
+ A list of glossary term relationships retrieved from the server.
1051
+
1052
+ """
1053
+
1054
+ url = (f"{self.platform_url}/servers/{self.view_server}"
1055
+ f"/api/open-metadata/glossary-manager/glossaries/terms/relationships/type-names")
1056
+
1057
+ response = await self._async_make_request("GET", url)
1058
+ return response.json().get("names", [])
1059
+
1060
+ def get_term_relationship_types(self) -> [str]:
1061
+ """Return the list of term relationship type enum values.
1062
+
1063
+ Parameters
1064
+ ----------
1065
+
1066
+
1067
+ Returns
1068
+ -------
1069
+ list of str
1070
+ A list of term relationship types. Each status is represented as a string.
1071
+
1072
+ """
1073
+ loop = asyncio.get_event_loop()
1074
+ response = loop.run_until_complete(self._async_get_term_relationship_types())
1075
+ return response
1076
+
1039
1077
  #
1040
1078
  # Glossaries
1041
1079
  #
@@ -2512,10 +2550,10 @@ class GlossaryBrowser(Client):
2512
2550
 
2513
2551
  return response
2514
2552
 
2515
- async def _async_get_term_relationships(self, term_guid: str, effective_time: str = None, start_from: int = 0,
2516
- page_size: int = None, ) -> list | str:
2553
+ async def _async_get_related_terms(self, term_guid: str, effective_time: str = None, start_from: int = 0,
2554
+ page_size: int = None, output_format:str = "JSON") -> list | str:
2517
2555
  """This call retrieves details of the glossary terms linked to this glossary term.
2518
- Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship..
2556
+ Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship.
2519
2557
  Parameters
2520
2558
  ----------
2521
2559
  term_guid : str
@@ -2559,10 +2597,21 @@ class GlossaryBrowser(Client):
2559
2597
  else:
2560
2598
  response = await self._async_make_request("POST", url)
2561
2599
 
2562
- return response.json().get("elementList", "No terms found")
2600
+ term_elements = response.json().get("elementList", NO_TERMS_FOUND)
2601
+ if term_elements == NO_TERMS_FOUND:
2602
+ if output_format == 'JSON':
2603
+ return NO_TERMS_FOUND
2604
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
2605
+ return "\n# No Terms found.\n"
2606
+ elif output_format == 'DICT':
2607
+ return None
2608
+ if output_format != "JSON": # return a simplified markdown representation
2609
+ return self.generate_terms_md(term_elements, term_guid, output_format)
2610
+ return response.json().get("elementList", NO_TERMS_FOUND)
2563
2611
 
2564
- def get_term_relationships(self, term_guid: str, effective_time: str = None, start_from: int = 0,
2565
- page_size: int = None, ) -> list | str:
2612
+
2613
+ def get_related_terms(self, term_guid: str, effective_time: str = None, start_from: int = 0,
2614
+ page_size: int = None, output_format = "JSON") -> list | str:
2566
2615
  """This call retrieves details of the glossary terms linked to this glossary term.
2567
2616
  Notice the original org 1 glossary term is linked via the "SourcedFrom" relationship..
2568
2617
  Parameters
@@ -2595,10 +2644,37 @@ class GlossaryBrowser(Client):
2595
2644
  """
2596
2645
  loop = asyncio.get_event_loop()
2597
2646
  response = loop.run_until_complete(
2598
- self._async_get_term_relationships(term_guid, effective_time, start_from, page_size))
2647
+ self._async_get_related_terms(term_guid, effective_time, start_from,
2648
+ page_size, output_format))
2599
2649
 
2600
2650
  return response
2601
2651
 
2652
+ def get_term_details(self, term_name:str, effective_time: str = None) -> dict | str:
2653
+ """Retrieve the details of a glossary term. Including relationships and feedback
2654
+
2655
+ output_format: str, default = 'JSON'
2656
+ Type of output to produce:
2657
+ JSON - output standard json
2658
+ MD - output standard markdown with no preamble
2659
+ DICT = output a simplified DICT structure
2660
+ """
2661
+
2662
+
2663
+ # Now lets get the term details as a dict
2664
+ core = self.get_terms_by_name(term_name, effective_time, output_format="DICT")
2665
+ if not core:
2666
+ return NO_TERMS_FOUND
2667
+
2668
+ related = self.get_related_terms(core[0]['guid'], effective_time)
2669
+ if not related:
2670
+ return "NO RELATED TERMS FOUND"
2671
+
2672
+ related_term_guid = related[0]["relatedElement"]["relatedElement"]["guid"]
2673
+ related_term_qn = related[0]["relatedElement"]["relatedElement"]["uniquedName"]
2674
+
2675
+
2676
+
2677
+
2602
2678
  async def _async_get_glossary_for_term(self, term_guid: str, effective_time: str = None) -> dict | str:
2603
2679
  """Retrieve the glossary metadata element for the requested term. The optional request body allows you to
2604
2680
  specify that the glossary element should only be returned if it was effective at a particular time.
@@ -2638,8 +2714,8 @@ class GlossaryBrowser(Client):
2638
2714
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-browser/glossaries/"
2639
2715
  f"for-term/{term_guid}/retrieve")
2640
2716
 
2641
- response = await self._async_make_request("POST", url, body)
2642
- return response.json().get("element", "No glossary found")
2717
+ response = await self._async_make_request("POST", url, body_slimmer(body))
2718
+ return response.json().get("element", NO_GLOSSARIES_FOUND)
2643
2719
 
2644
2720
  def get_glossary_for_term(self, term_guid: str, effective_time: str = None) -> dict | str:
2645
2721
  """Retrieve the glossary metadata element for the requested term. The optional request body allows you to
@@ -2677,7 +2753,7 @@ class GlossaryBrowser(Client):
2677
2753
 
2678
2754
  async def _async_get_terms_by_name(self, term: str, glossary_guid: str = None, status_filter: list = [],
2679
2755
  effective_time: str = None, for_lineage: bool = False, for_duplicate_processing: bool = False,
2680
- start_from: int = 0, page_size: int = None, ) -> list:
2756
+ start_from: int = 0, page_size: int = None, output_format = "JSON") -> list:
2681
2757
  """Retrieve glossary terms by display name or qualified name. Async Version.
2682
2758
 
2683
2759
  Parameters
@@ -2700,6 +2776,13 @@ class GlossaryBrowser(Client):
2700
2776
  The index of the first term to retrieve. Default is 0.
2701
2777
  page_size : int, optional
2702
2778
  The number of terms to retrieve per page. If not provided, it will use the default page size.
2779
+ output_format: str, default = 'JSON'
2780
+ Type of output to produce:
2781
+ JSON - output standard json
2782
+ MD - output standard markdown with no preamble
2783
+ FORM - output markdown with a preamble for a form
2784
+ REPORT - output markdown with a preamble for a report
2785
+ DICT - output a simplified DICT structure
2703
2786
 
2704
2787
  Returns
2705
2788
  -------
@@ -2735,13 +2818,23 @@ class GlossaryBrowser(Client):
2735
2818
  f"&forLineage={for_lineage_s}&forDuplicateProcessing={for_duplicate_processing_s}")
2736
2819
 
2737
2820
  # print(f"\n\nURL is: \n {url}\n\nBody is: \n{body}")
2821
+ response = await self._async_make_request("POST", url, body_slimmer(body))
2822
+ term_elements = response.json().get("elementList", NO_TERMS_FOUND)
2823
+ if term_elements == NO_TERMS_FOUND:
2824
+ if output_format == 'JSON':
2825
+ return NO_TERMS_FOUND
2826
+ elif output_format in ['MD', 'FORM', 'REPORT', 'LIST']:
2827
+ return "\n# No Terms found.\n"
2828
+ elif output_format == 'DICT':
2829
+ return None
2830
+ if output_format != "JSON": # return a simplified markdown representation
2831
+ return self.generate_terms_md(term_elements, term, output_format)
2832
+ return response.json().get("elementList", NO_TERMS_FOUND)
2738
2833
 
2739
- response = await self._async_make_request("POST", url, body)
2740
- return response.json().get("elementList", "No terms found")
2741
2834
 
2742
2835
  def get_terms_by_name(self, term: str, glossary_guid: str = None, status_filter: list = [],
2743
2836
  effective_time: str = None, for_lineage: bool = False, for_duplicate_processing: bool = False,
2744
- start_from: int = 0, page_size: int = None, ) -> list:
2837
+ start_from: int = 0, page_size: int = None, output_format = "JSON") -> list:
2745
2838
  """Retrieve glossary terms by display name or qualified name.
2746
2839
 
2747
2840
  Parameters
@@ -2764,6 +2857,13 @@ class GlossaryBrowser(Client):
2764
2857
  The index of the first term to retrieve. Default is 0.
2765
2858
  page_size : int, optional
2766
2859
  The number of terms to retrieve per page. If not provided, it will use the default page size.
2860
+ output_format: str, default = 'JSON'
2861
+ Type of output to produce:
2862
+ JSON - output standard json
2863
+ MD - output standard markdown with no preamble
2864
+ FORM - output markdown with a preamble for a form
2865
+ REPORT - output markdown with a preamble for a report
2866
+ DICT - output a simplified DICT structure
2767
2867
 
2768
2868
  Returns
2769
2869
  -------
@@ -2783,7 +2883,7 @@ class GlossaryBrowser(Client):
2783
2883
  loop = asyncio.get_event_loop()
2784
2884
  response = loop.run_until_complete(
2785
2885
  self._async_get_terms_by_name(term, glossary_guid, status_filter, effective_time, for_lineage,
2786
- for_duplicate_processing, start_from, page_size, ))
2886
+ for_duplicate_processing, start_from, page_size, output_format))
2787
2887
  return response
2788
2888
 
2789
2889
  async def _async_get_term_by_guid(self, term_guid: str, output_format: str = 'JSON') -> dict | str:
@@ -3107,6 +3207,109 @@ class GlossaryBrowser(Client):
3107
3207
 
3108
3208
  return response
3109
3209
 
3210
+ def list_term_revision_history(self, term_guid: str, output_format: str = "DICT") -> list | str:
3211
+ """
3212
+ Retrieve the revision history for a term.
3213
+
3214
+ This method retrieves the revision logs associated with a term, and for each revision log,
3215
+ retrieves the revision history. The results are formatted according to the specified output format.
3216
+
3217
+ Parameters
3218
+ ----------
3219
+ term_guid : str
3220
+ The GUID of the glossary term to retrieve the revision history for.
3221
+ output_format : str, optional
3222
+ The format in which to return the results. Can be "DICT", "MD", or "LIST".
3223
+ Defaults to "DICT".
3224
+
3225
+ Returns
3226
+ -------
3227
+ list | str
3228
+ If output_format is "DICT", returns a list of dictionaries containing the revision history.
3229
+ If output_format is "MD", returns a markdown representation of the revision history.
3230
+ If output_format is "LIST", returns a markdown table of the revision history.
3231
+ If no revision logs are found, returns a string message "No revision logs found".
3232
+ """
3233
+ import re
3234
+ validate_guid(term_guid)
3235
+
3236
+ # Get revision logs for the term
3237
+ revision_logs = self.get_term_revision_logs(term_guid)
3238
+ if isinstance(revision_logs, str):
3239
+ return "No revision logs found"
3240
+
3241
+ # Process each revision log
3242
+ all_entries = []
3243
+ for log in revision_logs:
3244
+ log_guid = log['elementHeader']['guid']
3245
+ qualified_name = log.get('properties', {}).get('qualifiedName', '---')
3246
+
3247
+ # Get revision history for this log
3248
+ history = self.get_term_revision_history(log_guid)
3249
+ if isinstance(history, str):
3250
+ continue
3251
+
3252
+ # Process each entry in the history
3253
+ for entry in history:
3254
+ # Extract update time from the title
3255
+ title = entry.get('properties', {}).get('title', '---')
3256
+
3257
+ keyword_index = title.index('on')
3258
+ update_time = title[keyword_index + 2:].strip()
3259
+
3260
+ entry_data = {
3261
+ 'qualifiedName': qualified_name,
3262
+ 'title': title,
3263
+ 'text': entry.get('properties', {}).get('text', '---'),
3264
+ 'updateTime': update_time # Use extracted date/time or fall back to title
3265
+ }
3266
+ all_entries.append(entry_data)
3267
+
3268
+ # Sort entries by update time
3269
+ sorted_entries = sorted(all_entries, key=lambda x: x['updateTime'] if x['updateTime'] != '---' else '', reverse=True)
3270
+
3271
+ # Return in the specified format
3272
+ if output_format == "DICT":
3273
+ return sorted_entries
3274
+ elif output_format == "LIST":
3275
+ # Create markdown table
3276
+ if not sorted_entries:
3277
+ return "No revision entries found"
3278
+
3279
+ # Get headers
3280
+ headers = sorted_entries[0].keys()
3281
+
3282
+ # Create header row
3283
+ header_row = " | ".join(headers)
3284
+ separator_row = " | ".join(["---"] * len(headers))
3285
+
3286
+ # Create rows
3287
+ rows = []
3288
+ for entry in sorted_entries:
3289
+ row = " | ".join(str(entry.get(header, "---")) for header in headers)
3290
+ rows.append(row)
3291
+
3292
+ # Combine into table
3293
+ markdown_table = f"{header_row}\n{separator_row}\n" + "\n".join(rows)
3294
+ return markdown_table
3295
+ elif output_format == "MD":
3296
+ # Create markdown representation
3297
+ if not sorted_entries:
3298
+ return "No revision entries found"
3299
+
3300
+ md_output = "\n"
3301
+
3302
+ for entry in sorted_entries:
3303
+ md_output += f"* Note Log Name: \n{entry['qualifiedName']}\n\n"
3304
+ md_output += f"* Note Log Entry Title: \n{entry['title']}\n\n"
3305
+ md_output += f"* Note Log Entry: \n\t{entry['text']}\n\n"
3306
+ md_output += "---\n\n"
3307
+
3308
+ return md_output
3309
+ else:
3310
+ # Default to DICT format
3311
+ return sorted_entries
3312
+
3110
3313
 
3111
3314
  def list_full_term_history(self, term_guid: str, output_type: str = "DICT") -> list | str:
3112
3315
  """
@@ -3138,19 +3341,19 @@ class GlossaryBrowser(Client):
3138
3341
  return "No History Found"
3139
3342
  version_history = []
3140
3343
  for ver in history:
3141
- create_time = ver["elementHeader"]["versions"].get("createTime", "---")
3142
- update_time = ver["elementHeader"]["versions"].get("createTime", "---")
3143
- created_by = ver["elementHeader"]["versions"].get("createdBy", "---")
3344
+ create_time = ver["elementHeader"]["versions"].get("createTime", " ")
3345
+ update_time = ver["elementHeader"]["versions"].get("createTime", " ")
3346
+ created_by = ver["elementHeader"]["versions"].get("createdBy", " ")
3144
3347
  updated_by = ver["elementHeader"]["versions"].get("updatedBy", "---")
3145
3348
  version = ver["elementHeader"]["versions"].get("version")
3146
3349
 
3147
- qualified_name = ver["glossaryTermProperties"].get("qualifiedName", '---')
3148
- display_name = ver["glossaryTermProperties"].get("displayName", '---')
3149
- summary = ver["glossaryTermProperties"].get("summary", '---')
3150
- description = ver["glossaryTermProperties"].get("description", '---')
3151
- examples = ver["glossaryTermProperties"].get("examples", '---')
3152
- usage = ver["glossaryTermProperties"].get("usage", '---')
3153
- version_identifier = ver["glossaryTermProperties"].get("versionIdentifier", '---')
3350
+ qualified_name = ver["glossaryTermProperties"].get("qualifiedName", ' ')
3351
+ display_name = ver["glossaryTermProperties"].get("displayName", ' ')
3352
+ summary = ver["glossaryTermProperties"].get("summary", ' ')
3353
+ description = ver["glossaryTermProperties"].get("description", ' ')
3354
+ examples = ver["glossaryTermProperties"].get("examples", ' ')
3355
+ usage = ver["glossaryTermProperties"].get("usage", ' ')
3356
+ version_identifier = ver["glossaryTermProperties"].get("versionIdentifier", ' ')
3154
3357
 
3155
3358
  version_history.append({
3156
3359
  "version": version, "displayName": display_name, "summary": summary, "created": create_time,
@@ -3178,6 +3381,8 @@ class GlossaryBrowser(Client):
3178
3381
  # Combine everything into a Markdown table string
3179
3382
  markdown_table = f"{header_row}\n{separator_row}\n" + "\n".join(rows)
3180
3383
  return markdown_table
3384
+ else:
3385
+ return None
3181
3386
 
3182
3387
  async def _async_find_glossary_terms(self, search_string: str, glossary_guid: str = None, status_filter: list = [],
3183
3388
  effective_time: str = None, starts_with: bool = False, ends_with: bool = False, ignore_case: bool = False,