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