pyegeria 5.4.0.26__py3-none-any.whl → 5.4.0.28__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 (46) hide show
  1. commands/cat/debug_log +868 -7794
  2. commands/cat/debug_log.2025-08-18_11-34-38_088636.zip +0 -0
  3. commands/cat/list_collections.py +1 -1
  4. commands/cat/list_format_set.py +6 -8
  5. commands/cli/egeria.py +2 -2
  6. commands/cli/egeria_cat.py +3 -2
  7. commands/ops/load_archive.py +2 -2
  8. md_processing/data/commands.json +7 -7
  9. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +7 -7
  10. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +36 -31
  11. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:22-dr_egeria_intro_part1.md +312 -0
  12. md_processing/dr_egeria_outbox/friday/processed-2025-08-22 21:23-dr_egeria_intro_part1.md +265 -0
  13. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:06-dr_egeria_intro_part1.md +230 -0
  14. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:30-dr_egeria_intro_part1.md +296 -0
  15. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 15:31-dr_egeria_intro_part1.md +253 -0
  16. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:08-dr_egeria_intro_part2.md +343 -0
  17. md_processing/dr_egeria_outbox/friday/processed-2025-08-23 16:12-dr_egeria_intro_part2.md +343 -0
  18. md_processing/md_commands/glossary_commands.py +888 -951
  19. md_processing/md_commands/product_manager_commands.py +8 -270
  20. md_processing/md_commands/project_commands.py +1 -1
  21. md_processing/md_processing_utils/common_md_proc_utils.py +138 -64
  22. md_processing/md_processing_utils/common_md_utils.py +2 -1
  23. pyegeria/__init__.py +2 -3
  24. pyegeria/_client_new.py +4 -3
  25. pyegeria/_output_formats.py +5 -3
  26. pyegeria/collection_manager.py +32 -29
  27. pyegeria/{load_config.py → config.py} +7 -2
  28. pyegeria/data_designer.py +154 -194
  29. pyegeria/egeria_cat_client.py +46 -28
  30. pyegeria/egeria_client.py +71 -72
  31. pyegeria/egeria_config_client.py +37 -7
  32. pyegeria/egeria_my_client.py +45 -10
  33. pyegeria/egeria_tech_client.py +68 -57
  34. pyegeria/glossary_manager.py +495 -124
  35. pyegeria/governance_officer.py +2 -2
  36. pyegeria/logging_configuration.py +1 -4
  37. pyegeria/models.py +1 -1
  38. pyegeria/project_manager.py +359 -511
  39. pyegeria/utils.py +1 -3
  40. {pyegeria-5.4.0.26.dist-info → pyegeria-5.4.0.28.dist-info}/METADATA +1 -1
  41. {pyegeria-5.4.0.26.dist-info → pyegeria-5.4.0.28.dist-info}/RECORD +44 -38
  42. md_processing/md_processing_utils/solution_architect_log.log +0 -0
  43. pyegeria/glossary_browser.py +0 -1259
  44. {pyegeria-5.4.0.26.dist-info → pyegeria-5.4.0.28.dist-info}/LICENSE +0 -0
  45. {pyegeria-5.4.0.26.dist-info → pyegeria-5.4.0.28.dist-info}/WHEEL +0 -0
  46. {pyegeria-5.4.0.26.dist-info → pyegeria-5.4.0.28.dist-info}/entry_points.txt +0 -0
@@ -21,14 +21,18 @@ from pyegeria._exceptions import InvalidParameterException
21
21
  from pyegeria._exceptions_new import PyegeriaInvalidParameterException
22
22
  from pyegeria._globals import NO_GUID_RETURNED
23
23
  from pyegeria._validators import validate_guid
24
- from pyegeria.glossary_browser import GlossaryBrowser
25
- from pyegeria.load_config import get_app_config
24
+ from pyegeria.collection_manager import CollectionManager
25
+ from pyegeria.config import settings as app_settings
26
26
  from pyegeria.models import (NewElementRequestBody,
27
27
  ReferenceableProperties, UpdateElementRequestBody, DeleteRequestBody, TemplateRequestBody,
28
- NewRelationshipRequestBody, UpdateRelationshipRequestBody, NewClassificationRequestBody)
29
- from pyegeria.utils import body_slimmer
28
+ NewRelationshipRequestBody, UpdateRelationshipRequestBody, NewClassificationRequestBody,
29
+ FilterRequestBody, GetRequestBody, SearchStringRequestBody, UpdateStatusRequestBody)
30
+ from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
31
+ from pyegeria.output_formatter import (generate_output,
32
+ _extract_referenceable_properties, populate_columns_from_properties,
33
+ get_required_relationships)
34
+ from pyegeria.utils import body_slimmer, dynamic_catch
30
35
 
31
- app_settings = get_app_config()
32
36
  EGERIA_LOCAL_QUALIFIER = app_settings.User_Profile.egeria_local_qualifier
33
37
 
34
38
 
@@ -72,7 +76,7 @@ class GlossaryTermProperties(ReferenceableProperties):
72
76
  publishVersionIdentifier: str = None
73
77
 
74
78
 
75
- class GlossaryManager(GlossaryBrowser):
79
+ class GlossaryManager(CollectionManager):
76
80
  """
77
81
  GlossaryManager is a class that extends the Client class. It provides methods to create and manage glossaries,
78
82
  terms and categories.
@@ -106,7 +110,7 @@ class GlossaryManager(GlossaryBrowser):
106
110
  self.user_id = user_id
107
111
  self.user_pwd = user_pwd
108
112
 
109
- Client2.__init__(self, view_server, platform_url, user_id, user_pwd, token)
113
+ CollectionManager.__init__(self, view_server, platform_url, user_id, user_pwd, token)
110
114
 
111
115
  #
112
116
  # Get Valid Values for Enumerations
@@ -121,108 +125,37 @@ class GlossaryManager(GlossaryBrowser):
121
125
  # Glossaries
122
126
  #
123
127
 
124
- async def _async_create_glossary(
125
- self,
126
- display_name: str,
127
- description: str,
128
- language: str = "English",
129
- usage: str = None,
130
- initial_classifications: list = None,
131
- body: dict | NewElementRequestBody = None,
132
- ) -> str:
133
- """Create a new glossary. Async version.
134
-
135
- Parameters
136
- ----------
137
- display_name: str
138
- The name of the new glossary. This will be used to produce a unique qualified name for the glossary.
139
- description: str
140
- A description of the glossary.
141
- language: str, optional, default = "English"
142
- The language the used for the glossary
143
- usage: str, optional, default = None
144
- How the glossary is intended to be used
145
128
 
146
129
 
147
- Returns
148
- -------
149
- str
150
- The GUID of the created glossary.
151
-
152
- """
153
-
154
- url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries"
155
- if body:
156
- validated_body = self.validate_new_element_request(body, "GlossaryProperties")
157
- elif (body is None) and (display_name is not None):
158
- pre = initial_classifications[0] if initial_classifications is not None else "Glossary"
159
- qualified_name = self.__create_qualified_name__(pre, display_name, EGERIA_LOCAL_QUALIFIER)
160
- if initial_classifications:
161
- initial_classifications_dict = {}
162
- for c in initial_classifications:
163
- initial_classifications_dict = initial_classifications_dict | {
164
- c: {"class": "ClassificationProperties"}
165
- }
166
-
167
- else:
168
- initial_classifications_dict = None
169
-
170
- glossary_properties = GlossaryProperties(class_="GlossaryProperties",
171
- qualified_name=qualified_name,
172
- display_name=display_name,
173
- description=description,
174
- language=language,
175
- usage=usage
176
- )
130
+ @dynamic_catch
131
+ async def _async_create_glossary(self, display_name: str, description: str = None, language: str = "English", usage: str = None,
132
+ category: str = None, body: dict | NewElementRequestBody = None) -> str:
133
+ """Create a new glossary with optional classification. """
134
+ if body is None:
135
+ qualified_name = self.__create_qualified_name__("Glossary", display_name, EGERIA_LOCAL_QUALIFIER)
177
136
  body = {
178
137
  "class": "NewElementRequestBody",
179
- "isOwnAnchor": True,
180
- "initialClassifications": initial_classifications_dict,
181
- "properties": glossary_properties.model_dump()
138
+ "is_own_anchor": True,
139
+ "properties": {
140
+ "class": "GlossaryProperties",
141
+ "displayName": display_name,
142
+ "qualifiedName": qualified_name,
143
+ "description": description,
144
+ "language": language,
145
+ "usage": usage,
146
+ "category": category
147
+ },
182
148
  }
183
- validated_body = NewElementRequestBody.model_validate(body)
184
- else:
185
- raise PyegeriaInvalidParameterException(additional_info={"reason": "Invalid input parameters"})
186
-
187
- json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
188
- logger.info(json_body)
189
- resp = await self._async_make_request("POST", url, json_body, is_json=True)
190
- logger.info(f"Create glossary with GUID: {resp.json().get('guid')}")
191
- return resp.json().get("guid", NO_GUID_RETURNED)
192
-
193
- def create_glossary(
194
- self,
195
- display_name: str,
196
- description: str,
197
- language: str = "English",
198
- usage: str = None,
199
- initial_classifications: list = None,
200
- body: dict | NewElementRequestBody = None
201
- ) -> str:
202
- """Create a new glossary.
203
-
204
- Parameters
205
- ----------
206
- display_name: str
207
- The name of the new glossary. This will be used to produce a unique qualified name for the glossary.
208
- description: str
209
- A description of the glossary.
210
- language: str, optional, default = "English"
211
- The language the used for the glossary
212
- usage: str, optional, default = None
213
- How the glossary is intended to be used
214
-
215
-
216
- Returns
217
- -------
218
- str
219
- The GUID of the created glossary.
149
+ response = await self._async_create_collection(body=body)
150
+ return response
220
151
 
221
- """
152
+ def create_glossary(self, display_name: str, description: str = None, language: str = "English",
153
+ usage: str = None,
154
+ category: str = None, body: dict | NewElementRequestBody = None) -> str:
155
+ """Create a new glossary with optional classification. """
222
156
  loop = asyncio.get_event_loop()
223
157
  response = loop.run_until_complete(
224
- self._async_create_glossary(display_name, description, language, usage,
225
- initial_classifications, body)
158
+ self._async_create_glossary(display_name, description, language, usage, category, body)
226
159
  )
227
160
  return response
228
161
 
@@ -243,13 +176,9 @@ class GlossaryManager(GlossaryBrowser):
243
176
 
244
177
  """
245
178
 
246
- url = (
247
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
248
- f"{glossary_guid}/delete"
249
- )
179
+ await self._async_delete_collection(glossary_guid, body, cascade)
250
180
 
251
- await self._async_delete_request(url, body, cascade)
252
- logger.info(f"Deleted collection {glossary_guid} with cascade {cascade}")
181
+ logger.info(f"Deleted glossary {glossary_guid} with cascade {cascade}")
253
182
 
254
183
  def delete_glossary(self, glossary_guid: str, body: dict | DeleteRequestBody = None, cascade: bool = False) -> None:
255
184
  """Delete a new glossary.
@@ -273,7 +202,8 @@ class GlossaryManager(GlossaryBrowser):
273
202
  async def _async_update_glossary(
274
203
  self,
275
204
  glossary_guid: str,
276
- body: dict | UpdateElementRequestBody
205
+ body: dict | UpdateElementRequestBody,
206
+ merge_update: bool = True,
277
207
  ) -> None:
278
208
  """Update Glossary.
279
209
 
@@ -297,18 +227,16 @@ class GlossaryManager(GlossaryBrowser):
297
227
 
298
228
  """
299
229
 
300
- url = (
301
- f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
302
- f"{glossary_guid}/update"
303
- )
304
230
 
305
- await self._async_update_element_body_request(url, ["GlossaryProperties"], body)
231
+
232
+ await self._async_update_collection(glossary_guid, body, is_merge_update=merge_update)
306
233
  logger.info(f"Updated digital subscription {glossary_guid}")
307
234
 
308
235
  def update_glossary(
309
236
  self,
310
237
  glossary_guid: str,
311
- body: dict | UpdateElementRequestBody
238
+ body: dict | UpdateElementRequestBody,
239
+ merge_update: bool = True,
312
240
  ) -> None:
313
241
  """Update Glossary.
314
242
 
@@ -321,10 +249,6 @@ class GlossaryManager(GlossaryBrowser):
321
249
  is_merge_update: bool, optional, default = True
322
250
  If true, then only those properties specified in the body will be updated. If false, then all the
323
251
  properties of the glossary will be replaced with those of the body.
324
- for_lineage: bool, optional, default = False
325
- Normally false. Used when we want to retrieve elements that have been delete but have a Memento entry.
326
- for_duplicate_processing: bool, optional, default = False
327
- Normally false. Set true when Egeria is told to skip deduplication because another system will do it.
328
252
 
329
253
 
330
254
  Returns
@@ -342,7 +266,7 @@ class GlossaryManager(GlossaryBrowser):
342
266
  loop.run_until_complete(
343
267
  self._async_update_glossary(
344
268
  glossary_guid,
345
- body
269
+ body, merge_update
346
270
  )
347
271
  )
348
272
 
@@ -983,7 +907,7 @@ class GlossaryManager(GlossaryBrowser):
983
907
 
984
908
  return response
985
909
 
986
- async def _async_update_term(
910
+ async def _async_update_glossary_term(
987
911
  self,
988
912
  glossary_term_guid: str,
989
913
  body: dict | UpdateElementRequestBody,
@@ -1025,7 +949,7 @@ class GlossaryManager(GlossaryBrowser):
1025
949
  await self._async_update_element_body_request(url, ["GlossaryTermProperties"], body)
1026
950
  logger.info(f"Updated digital subscription {glossary_term_guid}")
1027
951
 
1028
- def update_term(
952
+ def update_glossary_term(
1029
953
  self,
1030
954
  glossary_term_guid: str,
1031
955
  body: dict | UpdateElementRequestBody,
@@ -1074,13 +998,102 @@ class GlossaryManager(GlossaryBrowser):
1074
998
  """
1075
999
  loop = asyncio.get_event_loop()
1076
1000
  loop.run_until_complete(
1077
- self._async_update_term(
1001
+ self._async_update_glossary_term(
1078
1002
  glossary_term_guid,
1079
1003
  body,
1080
1004
  )
1081
1005
  )
1082
1006
 
1083
1007
 
1008
+ @dynamic_catch
1009
+ async def _async_update_term_status(self, term_guid: str, status: str = None,
1010
+ body: dict | UpdateStatusRequestBody = None):
1011
+ """Update the status of a collection. Async version.
1012
+
1013
+ Parameters
1014
+ ----------
1015
+ collection_guid: str
1016
+ The guid of the collection to update.
1017
+ status: str, optional
1018
+ The new lifecycle status for the collection. Ignored, if the body is provided.
1019
+ body: dict | UpdateStatusRequestBody, optional
1020
+ A structure representing the details of the collection to create. If supplied, these details
1021
+ supersede the status parameter provided.
1022
+
1023
+ Returns
1024
+ -------
1025
+ Nothing
1026
+
1027
+ Raises
1028
+ ------
1029
+ InvalidParameterException
1030
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1031
+ PropertyServerException
1032
+ Raised by the server when an issue arises in processing a valid request
1033
+ NotAuthorizedException
1034
+ The principle specified by the user_id does not have authorization for the requested action
1035
+
1036
+ Notes
1037
+ -----
1038
+ JSON Structure looks like:
1039
+ {
1040
+ "class": "UpdateStatusRequestBody",
1041
+ "status": "APPROVED",
1042
+ "externalSourceGUID": "add guid here",
1043
+ "externalSourceName": "add qualified name here",
1044
+ "effectiveTime": "{{$isoTimestamp}}",
1045
+ "forLineage": false,
1046
+ "forDuplicateProcessing": false
1047
+ }
1048
+ """
1049
+
1050
+ url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/metadata-elements/{term_guid}/update-status"
1051
+ await self._async_update_status_request(url, status, body)
1052
+ logger.info(f"Updated status for term {term_guid}")
1053
+
1054
+ @dynamic_catch
1055
+ def update_term_status(self, term_guid: str, status: str = None,
1056
+ body: dict | UpdateStatusRequestBody = None):
1057
+ """Update the status of a DigitalProduct collection.
1058
+
1059
+ Parameters
1060
+ ----------
1061
+ collection_guid: str
1062
+ The guid of the collection to update.
1063
+ status: str, optional
1064
+ The new lifecycle status for the digital product. Ignored, if the body is provided.
1065
+ body: dict | UpdateStatusRequestBody, optional
1066
+ A structure representing the details of the collection to create. If supplied, these details
1067
+ supersede the status parameter provided.
1068
+
1069
+ Returns
1070
+ -------
1071
+ Nothing
1072
+
1073
+ Raises
1074
+ ------
1075
+ InvalidParameterException
1076
+ If the client passes incorrect parameters on the request - such as bad URLs or invalid values
1077
+ PropertyServerException
1078
+ Raised by the server when an issue arises in processing a valid request
1079
+ NotAuthorizedException
1080
+ The principle specified by the user_id does not have authorization for the requested action
1081
+
1082
+ Notes
1083
+ -----
1084
+ JSON Structure looks like:
1085
+ {
1086
+ "class": "UpdateStatusRequestBody",
1087
+ "status": "APPROVED",
1088
+ "externalSourceGUID": "add guid here",
1089
+ "externalSourceName": "add qualified name here",
1090
+ "effectiveTime": "{{$isoTimestamp}}",
1091
+ "forLineage": false,
1092
+ "forDuplicateProcessing": false
1093
+ }
1094
+ """
1095
+ loop = asyncio.get_event_loop()
1096
+ loop.run_until_complete(self._async_update_collection_status(term_guid, status, body))
1084
1097
 
1085
1098
 
1086
1099
  async def _async_delete_term(
@@ -1240,9 +1253,18 @@ class GlossaryManager(GlossaryBrowser):
1240
1253
 
1241
1254
 
1242
1255
  #
1243
- # To work with categories, use the collection manager
1256
+ # Categories are just Folders in collection manager
1257
+ #
1258
+
1259
+
1260
+ #
1261
+ # From glossary browser
1244
1262
  #
1245
1263
 
1264
+
1265
+
1266
+
1267
+
1246
1268
  async def _async_add_is_abstract_concepts(
1247
1269
  self, term_guid: str, body: dict | NewClassificationRequestBody = None,
1248
1270
  ) -> None:
@@ -1308,7 +1330,6 @@ class GlossaryManager(GlossaryBrowser):
1308
1330
  logger.info(f"Added AbstractConcept classification to {term_guid}")
1309
1331
 
1310
1332
 
1311
-
1312
1333
  def add_is_abstract_concept(
1313
1334
  self, term_guid: str, body: dict | NewClassificationRequestBody = None,
1314
1335
  ) -> None:
@@ -2517,6 +2538,356 @@ class GlossaryManager(GlossaryBrowser):
2517
2538
  body)
2518
2539
  )
2519
2540
 
2541
+ #
2542
+ # Integrated Glossary Browser methods
2543
+ #
2544
+
2545
+ def _extract_glossary_properties(self, element: dict, columns_struct: dict) -> dict:
2546
+ props = element.get('properties', {}) or {}
2547
+ normalized = {
2548
+ 'properties': props,
2549
+ 'elementHeader': element.get('elementHeader', {}),
2550
+ }
2551
+ col_data = populate_columns_from_properties(normalized, columns_struct)
2552
+ columns_list = col_data.get('formats', {}).get('columns', [])
2553
+ header_props = _extract_referenceable_properties(element)
2554
+ guid = header_props.get('GUID')
2555
+ for column in columns_list:
2556
+ key = column.get('key')
2557
+ if key in header_props:
2558
+ column['value'] = header_props.get(key)
2559
+ elif isinstance(key, str) and key.lower() == 'guid':
2560
+ column['value'] = guid
2561
+ if guid:
2562
+ categories = None
2563
+ try:
2564
+ categories = self.get_categories_for_glossary(guid)
2565
+ except Exception:
2566
+ categories = None
2567
+ cat_display_list = []
2568
+ cat_qn_list = []
2569
+ if isinstance(categories, list):
2570
+ for category in categories:
2571
+ gcp = category.get('glossaryCategoryProperties', {})
2572
+ dn = gcp.get('displayName', '') or ''
2573
+ qn = gcp.get('qualifiedName', '') or ''
2574
+ if dn:
2575
+ cat_display_list.append(dn)
2576
+ if qn:
2577
+ cat_qn_list.append(qn)
2578
+ cat_names_md = (", \n".join(cat_display_list)).rstrip(',') if cat_display_list else ''
2579
+ cat_qn_md = (", \n".join(cat_qn_list)).rstrip(',') if cat_qn_list else ''
2580
+ for column in columns_list:
2581
+ if column.get('key') == 'categories_names' and not column.get('value'):
2582
+ column['value'] = cat_names_md
2583
+ if column.get('key') == 'categories_qualified_names' and not column.get('value'):
2584
+ column['value'] = cat_qn_md
2585
+ for column in columns_list:
2586
+ if column.get('key') == 'mermaid' and not column.get('value'):
2587
+ column['value'] = element.get('mermaidGraph', '') or ''
2588
+ break
2589
+ return col_data
2590
+
2591
+ def _extract_term_properties(self, element: dict, columns_struct: dict) -> dict:
2592
+ col_data = populate_columns_from_properties(element, columns_struct)
2593
+ columns_list = col_data.get("formats", {}).get("columns", [])
2594
+ header_props = _extract_referenceable_properties(element)
2595
+ for column in columns_list:
2596
+ key = column.get('key')
2597
+ if key in header_props:
2598
+ column['value'] = header_props.get(key)
2599
+ elif isinstance(key, str) and key.lower() == 'guid':
2600
+ column['value'] = header_props.get('GUID')
2601
+ classification_names = ""
2602
+ classifications = element.get('elementHeader', {}).get("collectionCategories", [])
2603
+ for classification in classifications:
2604
+ classification_names += f"{classification['classificationName']}, "
2605
+ if classification_names:
2606
+ for column in columns_list:
2607
+ if column.get('key') == 'classifications':
2608
+ column['value'] = classification_names[:-2]
2609
+ break
2610
+ col_data = get_required_relationships(element, col_data)
2611
+ subject_area = element.get('elementHeader', {}).get("subjectArea", "") or ""
2612
+ subj_val = ""
2613
+ if isinstance(subject_area, dict):
2614
+ subj_val = subject_area.get("classificationProperties", {}).get("subjectAreaName", "")
2615
+ for column in columns_list:
2616
+ if column.get('key') == 'subject_area':
2617
+ column['value'] = subj_val
2618
+ break
2619
+ mermaid_val = element.get('mermaidGraph', "") or ""
2620
+ for column in columns_list:
2621
+ if column.get('key') == 'mermaid':
2622
+ column['value'] = mermaid_val
2623
+ break
2624
+ return col_data
2625
+
2626
+ def _get_term_additional_properties(self, element: dict, term_guid: str, output_format: str = None) -> dict:
2627
+ additional: dict = {}
2628
+ try:
2629
+ classifications = element.get('elementHeader', {}).get('otherClassifications', [])
2630
+ glossary_name = ''
2631
+ if classifications:
2632
+ cls_props = classifications[0].get('classificationProperties', {}) or {}
2633
+ g_guid = cls_props.get('anchorScopeGUID')
2634
+ if g_guid and hasattr(self, 'get_glossary_by_guid'):
2635
+ try:
2636
+ gl = self.get_glossary_by_guid(g_guid)
2637
+ if isinstance(gl, dict):
2638
+ if output_format == 'REPORT':
2639
+ glossary_name = gl.get('glossaryProperties', {}).get('displayName', '')
2640
+ else:
2641
+ glossary_name = gl.get('glossaryProperties', {}).get('qualifiedName', '')
2642
+ except Exception:
2643
+ pass
2644
+ if glossary_name:
2645
+ additional['in_glossary'] = glossary_name
2646
+ except Exception:
2647
+ pass
2648
+ try:
2649
+ if hasattr(self, 'get_categories_for_term') and term_guid:
2650
+ cats = self.get_categories_for_term(term_guid)
2651
+ names = []
2652
+ if isinstance(cats, list):
2653
+ for c in cats:
2654
+ gcp = c.get('glossaryCategoryProperties', {})
2655
+ val = gcp.get('displayName') if output_format in ['REPORT', 'LIST'] else gcp.get('qualifiedName')
2656
+ if val:
2657
+ names.append(val)
2658
+ if names:
2659
+ additional['categories'] = ", \n".join(names)
2660
+ except Exception:
2661
+ pass
2662
+ return additional
2663
+
2664
+ def _generate_glossary_output(self, elements: dict | list[dict], search_string: str,
2665
+ element_type_name: str | None,
2666
+ output_format: str = 'DICT',
2667
+ output_format_set: dict | str = None) -> str | list[dict]:
2668
+ entity_type = 'Glossary'
2669
+ if output_format_set:
2670
+ if isinstance(output_format_set, str):
2671
+ output_formats = select_output_format_set(output_format_set, output_format)
2672
+ elif isinstance(output_format_set, dict):
2673
+ output_formats = get_output_format_type_match(output_format_set, output_format)
2674
+ else:
2675
+ output_formats = None
2676
+ else:
2677
+ output_formats = select_output_format_set(entity_type, output_format)
2678
+ if output_formats is None:
2679
+ output_formats = select_output_format_set('Default', output_format)
2680
+ return generate_output(
2681
+ elements=elements,
2682
+ search_string=search_string,
2683
+ entity_type=entity_type,
2684
+ output_format=output_format,
2685
+ extract_properties_func=self._extract_glossary_properties,
2686
+ get_additional_props_func=None,
2687
+ columns_struct=output_formats,
2688
+ )
2689
+
2690
+ def _generate_term_output(self, elements: dict | list[dict], search_string: str,
2691
+ element_type_name: str | None,
2692
+ output_format: str = 'DICT',
2693
+ output_format_set: dict | str = None) -> str | list[dict]:
2694
+ entity_type = 'GlossaryTerm'
2695
+ if output_format_set:
2696
+ if isinstance(output_format_set, str):
2697
+ output_formats = select_output_format_set(output_format_set, output_format)
2698
+ elif isinstance(output_format_set, dict):
2699
+ output_formats = get_output_format_type_match(output_format_set, output_format)
2700
+ else:
2701
+ output_formats = None
2702
+ else:
2703
+ output_formats = select_output_format_set(entity_type, output_format)
2704
+ if output_formats is None:
2705
+ output_formats = select_output_format_set('Default', output_format)
2706
+ return generate_output(
2707
+ elements=elements,
2708
+ search_string=search_string,
2709
+ entity_type=entity_type,
2710
+ output_format=output_format,
2711
+ extract_properties_func=self._extract_term_properties,
2712
+ get_additional_props_func=self._get_term_additional_properties,
2713
+ columns_struct=output_formats,
2714
+ )
2715
+
2716
+ async def _async_get_glossary_term_statuses(self) -> [str]:
2717
+ url = (f"{self.platform_url}/servers/{self.view_server}"
2718
+ f"/api/open-metadata/glossary-manager/glossaries/terms/status-list")
2719
+ response = await self._async_make_request("GET", url)
2720
+ return response.json().get("statuses", [])
2721
+
2722
+ def get_glossary_term_statuses(self) -> [str]:
2723
+ loop = asyncio.get_event_loop()
2724
+ response = loop.run_until_complete(self._async_get_glossary_term_statuses())
2725
+ return response
2726
+
2727
+ async def _async_get_glossary_term_rel_statuses(self) -> [str]:
2728
+ url = (f"{self.platform_url}/servers/{self.view_server}"
2729
+ f"/api/open-metadata/glossary-manager/glossaries/terms/relationships/status-list")
2730
+ response = await self._async_make_request("GET", url)
2731
+ return response.json().get("statuses", [])
2732
+
2733
+ def get_glossary_term_rel_statuses(self) -> [str]:
2734
+ loop = asyncio.get_event_loop()
2735
+ response = loop.run_until_complete(self._async_get_glossary_term_rel_statuses())
2736
+ return response
2737
+
2738
+ async def _async_get_glossary_term_activity_types(self) -> [str]:
2739
+ url = (f"{self.platform_url}/servers/{self.view_server}"
2740
+ f"/api/open-metadata/glossary-manager/glossaries/terms/activity-types")
2741
+ response = await self._async_make_request("GET", url)
2742
+ return response.json().get("types", [])
2743
+
2744
+ def get_glossary_term_activity_types(self) -> [str]:
2745
+ loop = asyncio.get_event_loop()
2746
+ response = loop.run_until_complete(self._async_get_glossary_term_statuses())
2747
+ return response
2748
+
2749
+ async def _async_get_term_relationship_types(self) -> [str]:
2750
+ url = (f"{self.platform_url}/servers/{self.view_server}"
2751
+ f"/api/open-metadata/glossary-manager/glossaries/terms/relationships/type-names")
2752
+ response = await self._async_make_request("GET", url)
2753
+ return response.json().get("names", [])
2754
+
2755
+ def get_term_relationship_types(self) -> [str]:
2756
+ loop = asyncio.get_event_loop()
2757
+ response = loop.run_until_complete(self._async_get_term_relationship_types())
2758
+ return response
2759
+
2760
+ async def _async_find_glossaries(self, search_string: str = "*", classificaton_names: list[str] = None,
2761
+ metadata_element_types: list[str] = ["Glossary"],
2762
+ starts_with: bool = False, ends_with: bool = False, ignore_case: bool = False,
2763
+ start_from: int = 0,page_size: int = 0, output_format: str = 'JSON',
2764
+ output_format_set: str | dict = None,
2765
+ body: dict | SearchStringRequestBody = None) -> list | str:
2766
+
2767
+ response = await self._async_find_collections(search_string, classificaton_names,
2768
+ metadata_element_types, starts_with, ends_with, ignore_case,
2769
+ start_from, page_size, output_format, output_format_set, body)
2770
+ return response
2771
+
2772
+ def find_glossaries(self, search_string: str = "*", classificaton_names: list[str] = None,
2773
+ metadata_element_types: list[str] = ["Glossary"],
2774
+ starts_with: bool = False, ends_with: bool = False, ignore_case: bool = False,
2775
+ start_from: int = 0,page_size: int = 0, output_format: str = 'JSON',
2776
+ output_format_set: str | dict = None,
2777
+ body: dict | SearchStringRequestBody = None) -> list | str:
2778
+ loop = asyncio.get_event_loop()
2779
+ response = loop.run_until_complete(
2780
+ self._async_find_glossaries(search_string, classificaton_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body))
2781
+ return response
2782
+
2783
+ async def _async_get_glossaries_by_name(self, filter_string: str = None, classification_names: list[str] = None,
2784
+ body: dict | FilterRequestBody = None,
2785
+ start_from: int = 0, page_size: int = 0,
2786
+ output_format: str = 'JSON',
2787
+ output_format_set: str | dict = None) -> dict | str:
2788
+ return await self._async_get_collections_by_name(filter_string, classification_names, body, start_from, page_size, output_format, output_format_set)
2789
+
2790
+
2791
+ def get_glossaries_by_name(self, filter_string: str = None, classification_names: list[str] = None,
2792
+ body: dict | FilterRequestBody = None,
2793
+ start_from: int = 0, page_size: int = 0,
2794
+ output_format: str = 'JSON',
2795
+ output_format_set: str | dict = None) -> dict | str:
2796
+ loop = asyncio.get_event_loop()
2797
+ response = loop.run_until_complete(
2798
+ self._async_get_glossaries_by_name(filter_string, classification_names, body,start_from, page_size,
2799
+ output_format, output_format_set))
2800
+ return response
2801
+
2802
+ async def _async_get_glossary_by_guid(self, glossary_guid: str, element_type: str = "Glossary", body: dict | GetRequestBody = None,
2803
+ output_format: str = "JSON", output_format_set: str | dict = None) -> dict | str:
2804
+
2805
+ return await self._async_get_collection_by_guid(glossary_guid, element_type, body, output_format, output_format_set)
2806
+
2807
+
2808
+
2809
+ def get_glossary_by_guid(self, glossary_guid: str, element_type: str = "Glossary", body: dict| GetRequestBody=None,
2810
+ output_format: str = "JSON", output_format_set: str | dict = None) -> dict | str:
2811
+ loop = asyncio.get_event_loop()
2812
+ response = loop.run_until_complete(
2813
+ self._async_get_glossary_by_guid(glossary_guid, element_type, body,output_format, output_format_set))
2814
+ return response
2815
+
2816
+
2817
+
2818
+ async def _async_get_terms_by_name(self, filter_string: str = None, classification_names: list[str] = None,
2819
+ body: dict | FilterRequestBody = None,
2820
+ start_from: int = 0, page_size: int = 0,
2821
+ output_format: str = 'JSON',
2822
+ output_format_set: str | dict = None) -> list:
2823
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
2824
+ f"terms/by-name")
2825
+ response = await self._async_get_name_request(url, _type="GlossaryTerm",
2826
+ _gen_output=self._generate_term_output,
2827
+ filter_string=filter_string,
2828
+ classification_names=classification_names,
2829
+ start_from=start_from, page_size=page_size,
2830
+ output_format=output_format, output_format_set=output_format_set,
2831
+ body=body)
2832
+ return response
2833
+
2834
+ def get_terms_by_name(self, filter_string: str = None, classification_names: list[str] = None,
2835
+ body: dict | FilterRequestBody = None,
2836
+ start_from: int = 0, page_size: int = 0,
2837
+ output_format: str = 'JSON',
2838
+ output_format_set: str | dict = None) -> list:
2839
+ loop = asyncio.get_event_loop()
2840
+ response = loop.run_until_complete(
2841
+ self._async_get_terms_by_name(filter_string, classification_names, body,start_from, page_size,
2842
+ output_format, output_format_set))
2843
+ return response
2844
+
2845
+ async def _async_get_term_by_guid(self, term_guid: str, element_type: str = "GlossaryTerm", body: dict| GetRequestBody=None,
2846
+ output_format: str = "JSON", output_format_set: str | dict = None) -> dict | str:
2847
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/terms/"
2848
+ f"{term_guid}")
2849
+ response = await self._async_get_guid_request(url, _type=element_type,
2850
+ _gen_output=self._generate_term_output,
2851
+ output_format=output_format, output_format_set=output_format_set,
2852
+ body=body)
2853
+ return response
2854
+
2855
+ def get_term_by_guid(self, term_guid: str, element_type: str = "GlossaryTerm", body: dict| GetRequestBody=None,
2856
+ output_format: str = "JSON", output_format_set: str | dict = None) -> dict | str:
2857
+ loop = asyncio.get_event_loop()
2858
+ response = loop.run_until_complete(self._async_get_term_by_guid(term_guid, element_type, body, output_format, output_format_set))
2859
+ return response
2860
+
2861
+ async def _async_find_glossary_terms(self, search_string: str, starts_with: bool = False,
2862
+ ends_with: bool = False, ignore_case: bool = False, type_name: str = "GlossaryTerm",
2863
+ classification_names: list[str] = None, start_from: int = 0,
2864
+ page_size: int = 0, output_format: str = 'JSON',
2865
+ output_format_set: str | dict = None, body: dict = None) -> list | str:
2866
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/terms/"
2867
+ f"by-search-string")
2868
+ response = await self._async_find_request(url, _type= type_name,
2869
+ _gen_output=self._generate_term_output,
2870
+ search_string = search_string, classification_names = classification_names,
2871
+ metadata_element_types = ["GlossaryTerm"],
2872
+ starts_with = starts_with, ends_with = ends_with, ignore_case = ignore_case,
2873
+ start_from = start_from, page_size = page_size,
2874
+ output_format=output_format, output_format_set=output_format_set,
2875
+ body=body)
2876
+ return response
2877
+
2878
+ def find_glossary_terms(self, search_string: str, starts_with: bool = False,
2879
+ ends_with: bool = False, ignore_case: bool = False, type_name: str = "GlossaryTerm",
2880
+ classification_names: list[str] = None, start_from: int = 0,
2881
+ page_size: int = 0, output_format: str = 'JSON',
2882
+ output_format_set: str | dict = None, body: dict = None) -> list | str:
2883
+ loop = asyncio.get_event_loop()
2884
+ response = loop.run_until_complete(
2885
+ self._async_find_glossary_terms(search_string, starts_with,
2886
+ ends_with, ignore_case, type_name,classification_names,
2887
+ start_from,
2888
+ page_size, output_format, output_format_set, body))
2889
+ return response
2890
+
2520
2891
 
2521
2892
  if __name__ == "__main__":
2522
2893
  print("Main-Glossary Manager")