pyegeria 5.4.0.23__py3-none-any.whl → 5.4.0.25__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 (54) hide show
  1. commands/cat/debug_log +7967 -465
  2. commands/cat/debug_log.2025-08-15_09-14-07_444802.zip +0 -0
  3. commands/cat/debug_log.2025-08-16_10-21-59_388912.zip +0 -0
  4. commands/cat/debug_log.2025-08-17_11-34-27_981852.zip +0 -0
  5. commands/cat/dr_egeria_md.py +36 -6
  6. commands/cat/logs/pyegeria.log +3 -135
  7. md_processing/.DS_Store +0 -0
  8. md_processing/__init__.py +12 -6
  9. md_processing/data/commands.json +8523 -2234
  10. md_processing/dr_egeria_inbox/gov_def.md +76 -18
  11. md_processing/dr_egeria_inbox/img.png +0 -0
  12. md_processing/dr_egeria_inbox/product.md +185 -24
  13. md_processing/dr_egeria_outbox/.obsidian/workspace.json +5 -5
  14. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:05-product.md +426 -0
  15. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:56-product.md +212 -0
  16. md_processing/dr_egeria_outbox/monday/processed-2025-08-19 09:43-product.md +201 -0
  17. md_processing/dr_egeria_outbox/tuesday/processed-2025-08-19 10:55-product.md +209 -0
  18. md_processing/md_commands/governance_officer_commands.py +247 -178
  19. md_processing/md_commands/product_manager_commands.py +730 -580
  20. md_processing/md_processing_utils/common_md_proc_utils.py +170 -12
  21. md_processing/md_processing_utils/common_md_utils.py +126 -28
  22. md_processing/md_processing_utils/extraction_utils.py +2 -2
  23. md_processing/md_processing_utils/md_processing_constants.py +14 -10
  24. pyegeria/.DS_Store +0 -0
  25. pyegeria/__init__.py +1 -1
  26. pyegeria/_client_new.py +61 -12
  27. pyegeria/_exceptions_new.py +6 -0
  28. pyegeria/_output_formats.py +42 -2
  29. pyegeria/collection_manager.py +79 -14
  30. pyegeria/{data_designer_omvs.py → data_designer.py} +1171 -1675
  31. pyegeria/glossary_browser.py +1259 -0
  32. pyegeria/{glossary_manager_omvs.py → glossary_manager.py} +1181 -1099
  33. pyegeria/governance_officer.py +1 -3
  34. pyegeria/load_config.py +1 -1
  35. pyegeria/models.py +37 -4
  36. pyegeria/output_formatter.py +2 -1
  37. pyegeria/project_manager.py +1952 -0
  38. pyegeria/utils.py +5 -2
  39. {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/METADATA +1 -1
  40. {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/RECORD +43 -44
  41. md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:00-product.md +0 -62
  42. md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:13-product.md +0 -62
  43. md_processing/dr_egeria_outbox/friday/processed-2025-07-20 13:23-product.md +0 -47
  44. md_processing/dr_egeria_outbox/friday/processed-2025-08-01 11:55-data_test3.md +0 -503
  45. md_processing/dr_egeria_outbox/monday/processed-2025-07-14 12:38-data_designer_out.md +0 -663
  46. md_processing/dr_egeria_outbox/monday/processed-2025-07-21 10:52-generated_help_report.md +0 -2744
  47. md_processing/dr_egeria_outbox/monday/processed-2025-07-21 18:38-collections.md +0 -62
  48. md_processing/dr_egeria_outbox/monday/processed-2025-08-01 11:34-gov_def.md +0 -444
  49. md_processing/dr_egeria_outbox/processed-2025-08-03 16:05-glossary_list.md +0 -37
  50. pyegeria/glossary_browser_omvs.py +0 -3840
  51. pyegeria/governance_officer_omvs.py +0 -2367
  52. {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/LICENSE +0 -0
  53. {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/WHEEL +0 -0
  54. {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/entry_points.txt +0 -0
@@ -8,20 +8,21 @@ This module provides access to the data-designer OMVS module.
8
8
  """
9
9
 
10
10
  import asyncio
11
- from os import terminal_size
12
11
 
13
- from httpx import Response
14
12
  from loguru import logger
15
- from prompt_toolkit import data_structures
16
13
 
17
14
  from pyegeria import Client2
15
+ from pyegeria._client import max_paging_size
18
16
  from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
19
- from pyegeria._client import Client, max_paging_size
20
- from pyegeria._globals import NO_ELEMENTS_FOUND
21
- from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict, generate_output,
17
+ from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, GetRequestBody, NewElementRequestBody,
18
+ TemplateRequestBody,
19
+ UpdateElementRequestBody, NewRelationshipRequestBody,
20
+ DeleteRequestBody)
21
+ from pyegeria.output_formatter import (extract_mermaid_only, extract_basic_dict)
22
+ from pyegeria.output_formatter import (generate_output,
22
23
  _extract_referenceable_properties)
23
- from pyegeria.utils import body_slimmer
24
-
24
+ from pyegeria.output_formatter import (populate_columns_from_properties, get_required_relationships)
25
+ from pyegeria.utils import body_slimmer, dynamic_catch
25
26
 
26
27
 
27
28
  def query_seperator(current_string):
@@ -59,111 +60,22 @@ class DataDesigner(Client2):
59
60
  self.platform_url = platform_url
60
61
  self.user_id = user_id
61
62
  self.user_pwd = user_pwd
62
- self.metadata_explorer_command_root: str = (
63
+ self.data_designer_root: str = (
63
64
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/data-designer")
64
- Client.__init__(self, view_server_name, platform_url, user_id=user_id, user_pwd=user_pwd, token=token, )
65
+ Client2.__init__(self, view_server_name, platform_url, user_id=user_id, user_pwd=user_pwd, token=token, )
65
66
 
66
67
  #
67
68
  # Data Structures
68
69
  #
69
-
70
- async def _async_create_data_structure(self, name: str, description: str, qualified_name: str = None,
71
- namespace: str = None, version_id: str = None) -> str:
70
+ @dynamic_catch
71
+ async def _async_create_data_structure(self, body: dict | NewElementRequestBody) -> str:
72
72
  """
73
73
  Create a new data structure from a provided dict body. Async version.
74
74
 
75
75
  Parameters
76
76
  ----------
77
- name : str
78
- - unique name to search for
79
- description : str
80
- - description of the data structure
81
- qualified_name : str, optional
82
- - unique name of the data structure, if not provided, one will be generated from the name.
83
- namespace : str
84
- - a namespace for the data structure
85
- version_id : str, optional
86
- - a version identifier for the data structure
87
-
88
- Returns
89
- -------
90
- str
91
- The GUID of the element - or "No element found"
92
-
93
- Raises
94
- ------
95
- InvalidParameterException
96
- one of the parameters is null or invalid or
97
- PropertyServerException
98
- There is a problem adding the element properties to the metadata repository or
99
- UserNotAuthorizedException
100
- the requesting user is not authorized to issue this request.
101
- """
102
- if version_id is None:
103
- qualified_name = qualified_name or f"DataStructure::{name}"
104
- else:
105
- qualified_name = qualified_name or f"DataStructure::{name}::{version_id}"
106
- if namespace:
107
- qualified_name = f"{namespace}::{qualified_name}"
108
-
109
- body = {
110
- "properties": {
111
- "class": "DataStructureProperties", "qualifiedName": qualified_name, "displayName": name,
112
- "description": description, "namespace": namespace, "versionIdentifier": version_id
113
- }
114
- }
115
-
116
- url = f"{base_path(self, self.view_server)}/data-structures"
117
-
118
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
119
- return response.json().get("guid", NO_ELEMENTS_FOUND)
120
-
121
- def create_data_structure(self, name: str, description: str, qualified_name: str = None, namespace: str = None,
122
- version_id: str = None) -> str:
123
- """
124
- Create a new data structure from a provided dict body.
125
-
126
- Parameters
127
- ----------
128
- name : str
129
- - unique name to search for
130
- description : str
131
- - description of the data structure
132
- qualified_name : str, optional
133
- - unique name of the data structure, if not provided, one will be generated from the name.
134
- namespace : str
135
- - a namespace for the data structure
136
- version_id : str, optional
137
- - a version identifier for the data structure
138
-
139
- Returns
140
- -------
141
- str
142
- The GUID of the element - or "No element found"
143
-
144
- Raises
145
- ------
146
- InvalidParameterException
147
- one of the parameters is null or invalid or
148
- PropertyServerException
149
- There is a problem adding the element properties to the metadata repository or
150
- UserNotAuthorizedException
151
- the requesting user is not authorized to issue this request.
152
- """
153
-
154
- loop = asyncio.get_event_loop()
155
- response = loop.run_until_complete(
156
- self._async_create_data_structure(name, description, qualified_name, namespace, version_id, ))
157
- return response
158
-
159
- async def _async_create_data_structure_w_body(self, body: dict) -> str:
160
- """
161
- Create a new data structure with basic parameters. Async version.
162
-
163
- Parameters
164
- ----------
165
- body: dict
166
- - a dictionary containing the properties of the data structure to be created.
77
+ body : dict | NewElementRequestBody
78
+ - a dictionary or NewElementRequestBody object containing the data structure details
167
79
 
168
80
  Returns
169
81
  -------
@@ -179,64 +91,62 @@ class DataDesigner(Client2):
179
91
  UserNotAuthorizedException
180
92
  the requesting user is not authorized to issue this request.
181
93
 
182
- Note
183
- ----
184
-
185
- Full sample body:
186
-
187
- {
188
- "class" : "NewDataStructureRequestBody",
189
- "externalSourceGUID": "add guid here",
190
- "externalSourceName": "add qualified name here",
191
- "effectiveTime" : "{{$isoTimestamp}}",
192
- "forLineage" : false,
193
- "forDuplicateProcessing" : false,
194
- "anchorGUID" : "add guid here",
195
- "isOwnAnchor": false,
196
- "parentGUID": "add guid here",
197
- "parentRelationshipTypeName": "add type name here",
198
- "parentRelationshipProperties": {
199
- "class": "ElementProperties",
200
- "propertyValueMap" : {
201
- "description" : {
202
- "class": "PrimitiveTypePropertyValue",
203
- "typeName": "string",
204
- "primitiveValue" : "New description"
205
- }
206
- }
207
- },
208
- "parentAtEnd1": false,
209
- "properties": {
210
- "class" : "DataStructureProperties",
211
- "qualifiedName": "add unique name here",
212
- "displayName": "add short name here",
213
- "description": "add description here",
214
- "namespace": "add namespace for this structure",
215
- "versionIdentifier": "add version for this structure",
216
- "additionalProperties": {
217
- "property1" : "propertyValue1",
218
- "property2" : "propertyValue2"
219
- },
220
- "effectiveFrom": "{{$isoTimestamp}}",
221
- "effectiveTo": "{{$isoTimestamp}}"
94
+ Notes
95
+ -----
96
+ Sample body:
97
+ {
98
+ "class" : "NewElementRequestBody",
99
+ "anchorGUID" : "add guid here",
100
+ "isOwnAnchor": false,
101
+ "parentGUID": "add guid here",
102
+ "parentRelationshipTypeName": "add type name here",
103
+ "parentRelationshipProperties": {
104
+ "class": "RelationshipElementProperties",
105
+ "propertyValueMap" : {
106
+ "description" : {
107
+ "class": "PrimitiveTypePropertyValue",
108
+ "typeName": "string",
109
+ "primitiveValue" : "New description"
222
110
  }
223
111
  }
112
+ },
113
+ "parentAtEnd1": false,
114
+ "properties": {
115
+ "class" : "DataStructureProperties",
116
+ "qualifiedName": "add unique name here",
117
+ "displayName": "add short name here",
118
+ "description": "add description here",
119
+ "namespace": "add namespace for this structure",
120
+ "versionIdentifier": "add version for this structure",
121
+ "additionalProperties": {
122
+ "property1" : "propertyValue1",
123
+ "property2" : "propertyValue2"
124
+ },
125
+ "effectiveFrom": "{{$isoTimestamp}}",
126
+ "effectiveTo": "{{$isoTimestamp}}"
127
+ },
128
+ "externalSourceGUID": "add guid here",
129
+ "externalSourceName": "add qualified name here",
130
+ "effectiveTime" : "{{$isoTimestamp}}",
131
+ "forLineage" : false,
132
+ "forDuplicateProcessing" : false
133
+ }
224
134
 
225
135
  """
226
136
 
227
137
  url = f"{base_path(self, self.view_server)}/data-structures"
228
138
 
229
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
230
- return response.json().get("guid", NO_ELEMENTS_FOUND)
139
+ return await self._async_create_element_body_request(url, "DataStructure", body)
231
140
 
232
- def create_data_structure_w_body(self, body: dict) -> str:
141
+ @dynamic_catch
142
+ def create_data_structure(self, body: dict | NewElementRequestBody) -> str:
233
143
  """
234
- Create a new data structure with basic parameters.
144
+ Create a new data structure from a provided dict body.
235
145
 
236
146
  Parameters
237
147
  ----------
238
- body: dict
239
- - a dictionary containing the properties of the data structure to be created.
148
+ body : dict | NewElementRequestBody
149
+ - a dictionary or NewElementRequestBody object containing the data structure details
240
150
 
241
151
  Returns
242
152
  -------
@@ -252,56 +162,56 @@ class DataDesigner(Client2):
252
162
  UserNotAuthorizedException
253
163
  the requesting user is not authorized to issue this request.
254
164
 
255
- Note
256
- ----
257
-
258
- Full sample body:
259
-
260
- {
261
- "class" : "NewDataStructureRequestBody",
262
- "externalSourceGUID": "add guid here",
263
- "externalSourceName": "add qualified name here",
264
- "effectiveTime" : "{{$isoTimestamp}}",
265
- "forLineage" : false,
266
- "forDuplicateProcessing" : false,
267
- "anchorGUID" : "add guid here",
268
- "isOwnAnchor": false,
269
- "parentGUID": "add guid here",
270
- "parentRelationshipTypeName": "add type name here",
271
- "parentRelationshipProperties": {
272
- "class": "ElementProperties",
273
- "propertyValueMap" : {
274
- "description" : {
275
- "class": "PrimitiveTypePropertyValue",
276
- "typeName": "string",
277
- "primitiveValue" : "New description"
278
- }
279
- }
280
- },
281
- "parentAtEnd1": false,
282
- "properties": {
283
- "class" : "DataStructureProperties",
284
- "qualifiedName": "add unique name here",
285
- "displayName": "add short name here",
286
- "description": "add description here",
287
- "namespace": "add namespace for this structure",
288
- "versionIdentifier": "add version for this structure",
289
- "additionalProperties": {
290
- "property1" : "propertyValue1",
291
- "property2" : "propertyValue2"
292
- },
293
- "effectiveFrom": "{{$isoTimestamp}}",
294
- "effectiveTo": "{{$isoTimestamp}}"
165
+ Notes
166
+ -----
167
+ Sample body:
168
+ {
169
+ "class" : "NewElementRequestBody",
170
+ "anchorGUID" : "add guid here",
171
+ "isOwnAnchor": false,
172
+ "parentGUID": "add guid here",
173
+ "parentRelationshipTypeName": "add type name here",
174
+ "parentRelationshipProperties": {
175
+ "class": "RelationshipElementProperties",
176
+ "propertyValueMap" : {
177
+ "description" : {
178
+ "class": "PrimitiveTypePropertyValue",
179
+ "typeName": "string",
180
+ "primitiveValue" : "New description"
295
181
  }
296
182
  }
183
+ },
184
+ "parentAtEnd1": false,
185
+ "properties": {
186
+ "class" : "DataStructureProperties",
187
+ "qualifiedName": "add unique name here",
188
+ "displayName": "add short name here",
189
+ "description": "add description here",
190
+ "namespace": "add namespace for this structure",
191
+ "versionIdentifier": "add version for this structure",
192
+ "additionalProperties": {
193
+ "property1" : "propertyValue1",
194
+ "property2" : "propertyValue2"
195
+ },
196
+ "effectiveFrom": "{{$isoTimestamp}}",
197
+ "effectiveTo": "{{$isoTimestamp}}"
198
+ },
199
+ "externalSourceGUID": "add guid here",
200
+ "externalSourceName": "add qualified name here",
201
+ "effectiveTime" : "{{$isoTimestamp}}",
202
+ "forLineage" : false,
203
+ "forDuplicateProcessing" : false
204
+ }
297
205
 
298
206
  """
299
207
 
300
208
  loop = asyncio.get_event_loop()
301
- response = loop.run_until_complete(self._async_create_data_structure_w_body(body, ))
209
+ response = loop.run_until_complete(
210
+ self._async_create_data_structure(body))
302
211
  return response
303
212
 
304
- async def _async_create_data_structure_from_template(self, body: dict) -> str:
213
+ @dynamic_catch
214
+ async def _async_create_data_structure_from_template(self, body: dict | TemplateRequestBody) -> str:
305
215
  """
306
216
  Create a new metadata element to represent a data structure using an existing metadata element as a template.
307
217
  The template defines additional classifications and relationships that should be added to the new element.
@@ -319,12 +229,10 @@ class DataDesigner(Client2):
319
229
 
320
230
  Raises
321
231
  ------
322
- InvalidParameterException
323
- one of the parameters is null or invalid or
324
- PropertyServerException
325
- There is a problem adding the element properties to the metadata repository or
326
- UserNotAuthorizedException
327
- the requesting user is not authorized to issue this request.
232
+ PyegeriaException
233
+
234
+ ValidationError
235
+
328
236
 
329
237
  Note
330
238
  ----
@@ -371,13 +279,11 @@ class DataDesigner(Client2):
371
279
  }
372
280
 
373
281
  """
282
+ url = f"{self.data_designer_root}/data-structures/from-template"
283
+ return await self._async_create_element_from_template(url, body)
374
284
 
375
- url = f"{base_path(self, self.view_server)}/data-structures/from-template"
376
-
377
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
378
- return response.json().get("guid", NO_ELEMENTS_FOUND)
379
-
380
- def create_data_structure_from_template(self, body: dict) -> str:
285
+ @dynamic_catch
286
+ def create_data_structure_from_template(self, body: dict | TemplateRequestBody) -> str:
381
287
  """
382
288
  Create a new metadata element to represent a data structure using an existing metadata element as a template.
383
289
  The template defines additional classifications and relationships that should be added to the new element.
@@ -448,11 +354,11 @@ class DataDesigner(Client2):
448
354
  """
449
355
 
450
356
  loop = asyncio.get_event_loop()
451
- response = loop.run_until_complete(self._async_create_data_structure_from_template(body, ))
357
+ response = loop.run_until_complete(self._async_create_data_structure_from_template(body))
452
358
  return response
453
359
 
454
- async def _async_update_data_structure_w_body(self, data_struct_guid: str, body: dict,
455
- replace_all_properties: bool = False) -> None:
360
+ @dynamic_catch
361
+ async def _async_update_data_structure(self, data_struct_guid: str, body: dict | UpdateElementRequestBody) -> None:
456
362
  """
457
363
  Update the properties of a data structure. Async version.
458
364
 
@@ -462,34 +368,23 @@ class DataDesigner(Client2):
462
368
  - the GUID of the data structure to be updated.
463
369
  body: dict
464
370
  - a dictionary containing the properties of the data structure to be created.
465
- replace_all_properties: bool, default = False
466
- - if true, then all properties will be replaced with the new ones. Otherwise, only the specified ones
467
- will be replaced.
371
+
468
372
  Returns
469
373
  -------
470
374
  None
471
375
 
472
376
  Raises
473
377
  ------
474
- InvalidParameterException
475
- one of the parameters is null or invalid or
476
- PropertyServerException
477
- There is a problem adding the element properties to the metadata repository or
478
- UserNotAuthorizedException
479
- the requesting user is not authorized to issue this request.
378
+ PyegeriaException
379
+
380
+ ValidationError
480
381
 
481
382
  Note
482
383
  ----
483
-
484
384
  Full sample body:
485
-
486
385
  {
487
- "class" : "UpdateDataStructureRequestBody",
488
- "externalSourceGUID": "add guid here",
489
- "externalSourceName": "add qualified name here",
490
- "effectiveTime" : "{{$isoTimestamp}}",
491
- "forLineage" : false,
492
- "forDuplicateProcessing" : false,
386
+ "class" : "UpdateElementRequestBody",
387
+ "mergeUpdate": true,
493
388
  "properties": {
494
389
  "class" : "DataStructureProperties",
495
390
  "qualifiedName": "add unique name here",
@@ -503,19 +398,22 @@ class DataDesigner(Client2):
503
398
  },
504
399
  "effectiveFrom": "{{$isoTimestamp}}",
505
400
  "effectiveTo": "{{$isoTimestamp}}"
506
- }
401
+ },
402
+ "externalSourceGUID": "add guid here",
403
+ "externalSourceName": "add qualified name here",
404
+ "effectiveTime" : "{{$isoTimestamp}}",
405
+ "forLineage" : false,
406
+ "forDuplicateProcessing" : false
507
407
  }
508
408
 
509
409
  """
510
- replace_all_properties_s = str(replace_all_properties).lower()
511
-
512
- url = (f"{base_path(self, self.view_server)}/data-structures/{data_struct_guid}/update?"
513
- f"replaceAllProperties={replace_all_properties_s}")
514
410
 
515
- await self._async_make_request("POST", url, body_slimmer(body))
411
+ url = f"{base_path(self, self.view_server)}/data-structures/{data_struct_guid}/update"
412
+ await self._async_update_element_body_request(url, ["DataStructure"], body)
413
+ logger.info(f"Data structure {data_struct_guid} updated.")
516
414
 
517
- def update_data_structure_w_body(self, data_struct_guid: str, body: dict.get,
518
- replace_all_properties: bool = False) -> None:
415
+ @dynamic_catch
416
+ def update_data_structure(self, data_struct_guid: str, body: dict | UpdateElementRequestBody) -> None:
519
417
  """
520
418
  Update the properties of a data structure.
521
419
 
@@ -525,34 +423,23 @@ class DataDesigner(Client2):
525
423
  - the GUID of the data structure to be updated.
526
424
  body: dict
527
425
  - a dictionary containing the properties of the data structure to be created.
528
- r replace_all_properties: bool, default = False
529
- - if true, then all properties will be replaced with the new ones. Otherwise, only the specified ones
530
- will be replaced.
426
+
531
427
  Returns
532
428
  -------
533
429
  None
534
430
 
535
431
  Raises
536
432
  ------
537
- InvalidParameterException
538
- one of the parameters is null or invalid or
539
- PropertyServerException
540
- There is a problem adding the element properties to the metadata repository or
541
- UserNotAuthorizedException
542
- the requesting user is not authorized to issue this request.
433
+ PyegeriaException
434
+
435
+ ValidationError
543
436
 
544
437
  Note
545
438
  ----
546
-
547
439
  Full sample body:
548
-
549
- {
550
- "class" : "UpdateDataStructureRequestBody",
551
- "externalSourceGUID": "add guid here",
552
- "externalSourceName": "add qualified name here",
553
- "effectiveTime" : "{{$isoTimestamp}}",
554
- "forLineage" : false,
555
- "forDuplicateProcessing" : false,
440
+ {
441
+ "class" : "UpdateElementRequestBody",
442
+ "mergeUpdate": true,
556
443
  "properties": {
557
444
  "class" : "DataStructureProperties",
558
445
  "qualifiedName": "add unique name here",
@@ -566,260 +453,34 @@ r replace_all_properties: bool, default = False
566
453
  },
567
454
  "effectiveFrom": "{{$isoTimestamp}}",
568
455
  "effectiveTo": "{{$isoTimestamp}}"
569
- }
456
+ },
457
+ "externalSourceGUID": "add guid here",
458
+ "externalSourceName": "add qualified name here",
459
+ "effectiveTime" : "{{$isoTimestamp}}",
460
+ "forLineage" : false,
461
+ "forDuplicateProcessing" : false
570
462
  }
571
463
 
572
464
  """
573
465
 
574
466
  loop = asyncio.get_event_loop()
575
467
  loop.run_until_complete(
576
- self._async_update_data_structure_w_body(data_struct_guid, body, replace_all_properties))
577
-
578
- def get_data_memberships(self, data_get_fcn: callable, data_struct_guid: str) -> dict | None:
579
- data_structure_info = data_get_fcn(data_struct_guid, output_format="JSON")
580
- if data_structure_info == "No elements found":
581
- return None
582
- collection_list = {"DictList": [], "SpecList": [], "CollectionDetails": []}
583
- if isinstance(data_structure_info, (dict, list)):
584
- member_of_collections = data_structure_info.get('memberOfCollections',"")
585
- if isinstance(member_of_collections, list):
586
- for member_rel in member_of_collections:
587
- props = member_rel["relatedElement"]["properties"]
588
- qname = props.get('qualifiedName', None)
589
- guid = member_rel['relatedElement']['elementHeader']['guid']
590
- description = props.get('description', None)
591
- collection_type = props.get('collectionType', None)
592
- if collection_type == "Data Dictionary":
593
- collection_list["DictList"].append(guid)
594
- elif collection_type == "Data Specification":
595
- collection_list["SpecList"].append(guid)
596
- collection_list["CollectionDetails"].append({"guid":guid, "description":description,
597
- "collectionType":collection_type, "qualifiedName":qname})
598
- else:
599
- return None
600
- return collection_list
601
- else:
602
- return None
603
-
604
- def get_data_memberships_with_dict(self, data_field_elements: dict) -> dict:
605
- collection_list = {"DictList_guid": [], "DictList_qn": [], "SpecList_guid": [], "SpecList_qn": [], "CollectionDetails": []}
606
- if isinstance(data_field_elements, (dict, list)):
468
+ self._async_update_data_structure(data_struct_guid, body))
607
469
 
608
- for member_rel in data_field_elements:
609
- type_name = ""
610
- props = member_rel["relatedElement"]["properties"]
611
- qname = props.get('qualifiedName', None)
612
- guid = member_rel['relatedElement']['elementHeader']['guid']
613
- description = props.get('description', None)
614
- collection_type = props.get('collectionType', None)
615
- classifications = member_rel["relatedElement"]["elementHeader"]["classifications"]
616
- for classification in classifications:
617
- type_name = classification["type"]['typeName']
618
- if type_name == "DataDictionary":
619
- collection_list["DictList_guid"].append(guid)
620
- collection_list["DictList_qn"].append(qname)
621
- elif type_name == "DataSpec":
622
- collection_list["SpecList_guid"].append(guid)
623
- collection_list["SpecList_qn"].append(qname)
624
- collection_list["CollectionDetails"].append({"typeName":type_name, "guid":guid, "description":description,
625
- "collectionType": collection_type,
626
- "qualifiedName": qname
627
- })
628
- return collection_list
470
+ @dynamic_catch
471
+ async def _async_link_member_data_field(self, parent_data_struct_guid: str, member_data_field_guid: str,
472
+ body: dict | NewRelationshipRequestBody = None) -> None:
473
+ """
474
+ Connect a data structure to a data field. Async version.
629
475
 
630
-
631
- def get_data_rel_elements_dict(self, el_struct: dict)-> dict | str:
632
- """return the lists of objects related to a data field"""
633
-
634
- parent_guids = []
635
- parent_names = []
636
- parent_qnames = []
637
-
638
- data_structure_guids = []
639
- data_structure_names = []
640
- data_structure_qnames = []
641
-
642
- assigned_meanings_guids = []
643
- assigned_meanings_names = []
644
- assigned_meanings_qnames = []
645
-
646
- data_class_guids = []
647
- data_class_names = []
648
- data_class_qnames = []
649
-
650
- external_references_guids = []
651
- external_references_names = []
652
- external_references_qnames = []
653
-
654
- member_of_data_dicts_guids = []
655
- member_of_data_dicts_names = []
656
- member_of_data_dicts_qnames = []
657
-
658
- member_of_data_spec_guids = []
659
- member_of_data_spec_names = []
660
- member_of_data_spec_qnames = []
661
-
662
- member_data_field_guids = []
663
- member_data_field_names = []
664
- member_data_field_qnames = []
665
-
666
- nested_data_classes_guids = []
667
- nested_data_classes_names = []
668
- nested_data_classes_qnames = []
669
-
670
- specialized_data_classes_guids = []
671
- specialized_data_classes_names = []
672
- specialized_data_classes_qnames = []
673
-
674
-
675
-
676
- # terms
677
- assigned_meanings = el_struct.get("assignedMeanings", {})
678
- for meaning in assigned_meanings:
679
- assigned_meanings_guids.append(meaning['relatedElement']['elementHeader']['guid'])
680
- assigned_meanings_names.append(meaning['relatedElement']['properties']['displayName'])
681
- assigned_meanings_qnames.append(meaning['relatedElement']['properties']['qualifiedName'])
682
-
683
-
684
- # extract existing related data structure and data field elements
685
- other_related_elements = el_struct.get("otherRelatedElements",None)
686
- if other_related_elements:
687
- for rel in other_related_elements:
688
- related_element = rel["relatedElement"]
689
- type = related_element["elementHeader"]["type"]["typeName"]
690
- guid = related_element["elementHeader"]["guid"]
691
- qualified_name = related_element["properties"].get("qualifiedName","") or ""
692
- display_name = related_element["properties"].get("displayName","") or ""
693
- if type == "DataStructure":
694
- data_structure_guids.append(guid)
695
- data_structure_names.append(display_name)
696
- data_structure_qnames.append(qualified_name)
697
-
698
- elif type == "DataField":
699
- parent_guids.append(guid)
700
- parent_names.append(display_name)
701
- parent_qnames.append(qualified_name)
702
-
703
-
704
- member_of_collections = el_struct.get("memberOfCollections",{})
705
- for collection in member_of_collections:
706
- c_type = collection["relatedElement"]["properties"].get("collectionType","") or ""
707
- guid = collection["relatedElement"]["elementHeader"]["guid"]
708
- name = collection["relatedElement"]["properties"].get("name","") or ""
709
- qualifiedName = collection['relatedElement']["properties"].get("qualifiedName","") or ""
710
- classifications = collection["relatedElement"]["elementHeader"]["classifications"]
711
- for classification in classifications:
712
- type_name = classification["type"]['typeName']
713
- if type_name == "DataDictionary":
714
- member_of_data_dicts_guids.append(guid)
715
- member_of_data_dicts_names.append(name)
716
- member_of_data_dicts_qnames.append(qualifiedName)
717
- elif type_name == "DataSpec":
718
- member_of_data_spec_guids.append(guid)
719
- member_of_data_spec_names.append(name)
720
- member_of_data_spec_qnames.append(qualifiedName)
721
-
722
- member_data_fields = el_struct.get("memberDataFields", {})
723
- for data_field in member_data_fields:
724
- member_data_field_guids.append(data_field["elementHeader"]["guid"])
725
- member_data_field_names.append(data_field["properties"]["displayName"])
726
- member_data_field_qnames.append(data_field["properties"]["qualifiedName"])
727
-
728
- data_classes = el_struct.get("assignedDataClasses", {})
729
- for data_class in data_classes:
730
- data_class_guids.append(data_class['relatedElement']["elementHeader"]["guid"])
731
- data_class_names.append(data_class['relatedElement']["properties"]["displayName"])
732
- data_class_qnames.append(data_class['relatedElement']["properties"]["qualifiedName"])
733
-
734
- nested_data_classes = el_struct.get("nestedDataClasses", {})
735
- for nested_data_class in nested_data_classes:
736
- nested_data_classes_guids.append(nested_data_class['relatedElement']["elementHeader"]["guid"])
737
- nested_data_classes_names.append(nested_data_class['relatedElement']["properties"]["displayName"])
738
- nested_data_classes_qnames.append(nested_data_class['relatedElement']["properties"]["qualifiedName"])
739
-
740
- specialized_data_classes = el_struct.get("specializedDataClasses", {})
741
- for nested_data_class in specialized_data_classes:
742
- specialized_data_classes_guids.append(nested_data_class['relatedElement']["elementHeader"]["guid"])
743
- specialized_data_classes_names.append(nested_data_class['relatedElement']["properties"]["displayName"])
744
- specialized_data_classes_qnames.append(nested_data_class['relatedElement']["properties"]["qualifiedName"])
745
-
746
- mermaid = el_struct.get("mermaidGraph", {})
747
-
748
- return {"parent_guids": parent_guids,
749
- "parent_names": parent_names,
750
- "parent_qnames": parent_qnames,
751
-
752
- "data_structure_guids": data_structure_guids,
753
- "data_structure_names": data_structure_names,
754
- "data_structure_qnames": data_structure_qnames,
755
-
756
- "assigned_meanings_guids": assigned_meanings_guids,
757
- "assigned_meanings_names": assigned_meanings_names,
758
- "assigned_meanings_qnames": assigned_meanings_qnames,
759
-
760
- "data_class_guids": data_class_guids,
761
- "data_class_names": data_class_names,
762
- "data_class_qnames": data_class_qnames,
763
-
764
- "nested_data_class_guids": nested_data_classes_guids,
765
- "nested_data_class_names": nested_data_classes_names,
766
- "nested_data_class_qnames": nested_data_classes_qnames,
767
-
768
- "specialized_data_class_guids": specialized_data_classes_guids,
769
- "specialized_data_class_names": specialized_data_classes_names,
770
- "specialized_data_class_qnames": specialized_data_classes_qnames,
771
-
772
- "external_references_guids": external_references_guids,
773
- "external_references_names": external_references_names,
774
- "external_references_qnames": external_references_qnames,
775
-
776
- "member_of_data_dicts_guids": member_of_data_dicts_guids,
777
- "member_of_data_dicts_names": member_of_data_dicts_names,
778
- "member_of_data_dicts_qnames": member_of_data_dicts_qnames,
779
-
780
- "member_of_data_spec_guids": member_of_data_spec_guids,
781
- "member_of_data_spec_names": member_of_data_spec_names,
782
- "member_of_data_spec_qnames": member_of_data_spec_qnames,
783
-
784
- "member_data_field_guids": member_data_field_guids,
785
- "member_data_field_names": member_data_field_names,
786
- "member_data_field_qnames": member_data_field_qnames,
787
-
788
- "mermaid" : mermaid,
789
- }
790
-
791
-
792
- def get_data_field_rel_elements(self, guid:str)-> dict | str:
793
- """return the lists of objects related to a data field"""
794
-
795
- data_field_entry = self.get_data_field_by_guid(guid, output_format="JSON")
796
- if isinstance(data_field_entry, str):
797
- return None
798
- return self.get_data_rel_elements_dict(data_field_entry)
799
-
800
- def get_data_class_rel_elements(self, guid:str)-> dict | str:
801
- """return the lists of objects related to a data class"""
802
-
803
- data_class_entry = self.get_data_class_by_guid(guid, output_format="JSON")
804
- if isinstance(data_class_entry, str):
805
- return None
806
- return self.get_data_rel_elements_dict(data_class_entry)
807
-
808
-
809
-
810
- async def _async_link_member_data_field(self, parent_data_struct_guid: str, member_data_field_guid: str,
811
- body: dict = None) -> None:
812
- """
813
- Connect a data structure to a data field. Async version.
814
-
815
- Parameters
816
- ----------
817
- parent_data_struct_guid: str
818
- - the GUID of the parent data structure the data class will be connected to.
819
- member_data_field_guid: str
820
- - the GUID of the data class to be connected.
821
- body: dict, optional
822
- - a dictionary containing additional properties.
476
+ Parameters
477
+ ----------
478
+ parent_data_struct_guid: str
479
+ - the GUID of the parent data structure the data class will be connected to.
480
+ member_data_field_guid: str
481
+ - the GUID of the data class to be connected.
482
+ body: dict, optional
483
+ - a dictionary containing additional properties.
823
484
 
824
485
  Returns
825
486
  -------
@@ -838,14 +499,8 @@ r replace_all_properties: bool, default = False
838
499
  ----
839
500
 
840
501
  Full sample body:
841
-
842
502
  {
843
- "class" : "MemberDataFieldRequestBody",
844
- "externalSourceGUID": "add guid here",
845
- "externalSourceName": "add qualified name here",
846
- "effectiveTime" : "{{$isoTimestamp}}",
847
- "forLineage" : false,
848
- "forDuplicateProcessing" : false,
503
+ "class" : "NewRelationshipRequestBody",
849
504
  "properties": {
850
505
  "class": "MemberDataFieldProperties",
851
506
  "dataFieldPosition": 0,
@@ -853,76 +508,80 @@ r replace_all_properties: bool, default = False
853
508
  "maxCardinality": 0,
854
509
  "effectiveFrom": "{{$isoTimestamp}}",
855
510
  "effectiveTo": "{{$isoTimestamp}}"
856
- }
511
+ },
512
+ "externalSourceGUID": "add guid here",
513
+ "externalSourceName": "add qualified name here",
514
+ "effectiveTime" : "{{$isoTimestamp}}",
515
+ "forLineage" : false,
516
+ "forDuplicateProcessing" : false
857
517
  }
858
518
 
859
519
  """
860
520
 
861
521
  url = (f"{base_path(self, self.view_server)}/data-structures/{parent_data_struct_guid}"
862
522
  f"/member-data-fields/{member_data_field_guid}/attach")
523
+ await self._async_new_relationship_request(url, ["MemberDataFieldProperties"], body)
524
+ logger.info(f"Data field {member_data_field_guid} attached to Data structure {parent_data_struct_guid}.")
863
525
 
864
- if body is None:
865
- await self._async_make_request("POST", url)
866
- else:
867
- await self._async_make_request("POST", url, body_slimmer(body))
868
-
526
+ @dynamic_catch
869
527
  def link_member_data_field(self, parent_data_struct_guid: str, member_data_field_guid: str,
870
- body: dict = None) -> None:
871
- """
872
- Connect a data structure to a data field.
873
-
874
- Parameters
875
- ----------
876
- parent_data_struct_guid: str
877
- - the GUID of the parent data structure the data class will be connected to.
878
- member_data_field_guid: str
879
- - the GUID of the data class to be connected.
880
- body: dict, optional
881
- - a dictionary containing additional properties.
882
-
883
- Returns
884
- -------
885
- None
886
-
887
- Raises
888
- ------
889
- InvalidParameterException
890
- one of the parameters is null or invalid or
891
- PropertyServerException
892
- There is a problem adding the element properties to the metadata repository or
893
- UserNotAuthorizedException
894
- the requesting user is not authorized to issue this request.
895
-
896
- Note
897
- ----
898
-
899
- Full sample body:
900
-
901
- {
902
- "class" : "MemberDataFieldRequestBody",
903
- "externalSourceGUID": "add guid here",
904
- "externalSourceName": "add qualified name here",
905
- "effectiveTime" : "{{$isoTimestamp}}",
906
- "forLineage" : false,
907
- "forDuplicateProcessing" : false,
908
- "properties": {
909
- "class": "MemberDataFieldProperties",
910
- "dataFieldPosition": 0,
911
- "minCardinality": 0,
912
- "maxCardinality": 0,
913
- "effectiveFrom": "{{$isoTimestamp}}",
914
- "effectiveTo": "{{$isoTimestamp}}"
915
- }
916
- }
917
-
918
- """
528
+ body: dict | NewRelationshipRequestBody = None) -> None:
529
+ """
530
+ Connect a data structure to a data field.
531
+
532
+ Parameters
533
+ ----------
534
+ parent_data_struct_guid: str
535
+ - the GUID of the parent data structure the data class will be connected to.
536
+ member_data_field_guid: str
537
+ - the GUID of the data class to be connected.
538
+ body: dict, optional
539
+ - a dictionary containing additional properties.
540
+
541
+ Returns
542
+ -------
543
+ None
544
+
545
+ Raises
546
+ ------
547
+ InvalidParameterException
548
+ one of the parameters is null or invalid or
549
+ PropertyServerException
550
+ There is a problem adding the element properties to the metadata repository or
551
+ UserNotAuthorizedException
552
+ the requesting user is not authorized to issue this request.
553
+
554
+ Note
555
+ ----
556
+
557
+ Full sample body:
558
+ {
559
+ "class" : "NewRelationshipRequestBody",
560
+ "properties": {
561
+ "class": "MemberDataFieldProperties",
562
+ "dataFieldPosition": 0,
563
+ "minCardinality": 0,
564
+ "maxCardinality": 0,
565
+ "effectiveFrom": "{{$isoTimestamp}}",
566
+ "effectiveTo": "{{$isoTimestamp}}"
567
+ },
568
+ "externalSourceGUID": "add guid here",
569
+ "externalSourceName": "add qualified name here",
570
+ "effectiveTime" : "{{$isoTimestamp}}",
571
+ "forLineage" : false,
572
+ "forDuplicateProcessing" : false
573
+ }
574
+
575
+ """
919
576
 
920
577
  loop = asyncio.get_event_loop()
921
578
  loop.run_until_complete(
922
579
  self._async_link_member_data_field(parent_data_struct_guid, member_data_field_guid, body))
923
580
 
581
+ @dynamic_catch
924
582
  async def _async_detach_member_data_field(self, parent_data_struct_guid: str, member_data_field_guid: str,
925
- body: dict = None) -> None:
583
+ body: dict | DeleteRequestBody = None,
584
+ cascade_delete: bool = False) -> None:
926
585
  """
927
586
  Detach a data class from a data structure. Request body is optional. Async version.
928
587
 
@@ -935,6 +594,7 @@ r replace_all_properties: bool, default = False
935
594
  body: dict, optional
936
595
  - a dictionary containing additional properties.
937
596
 
597
+
938
598
  Returns
939
599
  -------
940
600
  None
@@ -952,9 +612,10 @@ r replace_all_properties: bool, default = False
952
612
  ----
953
613
 
954
614
  Full sample body:
955
-
956
- {
957
- "class": "MetadataSourceRequestBody",
615
+ {
616
+ "class": "DeleteRequestBody",
617
+ "cascadedDelete": false,
618
+ "deleteMethod": "LOOK_FOR_LINEAGE",
958
619
  "externalSourceGUID": "add guid here",
959
620
  "externalSourceName": "add qualified name here",
960
621
  "effectiveTime": "{{$isoTimestamp}}",
@@ -965,23 +626,22 @@ r replace_all_properties: bool, default = False
965
626
 
966
627
  """
967
628
 
968
- url = (f"{base_path(self, self.view_server)}/data-structures/{parent_data_struct_guid}"
629
+ url = (f"{self.data_designer_root}/data-structures/{parent_data_struct_guid}"
969
630
  f"/member-data-fields/{member_data_field_guid}/detach")
970
631
 
971
- if body is None:
972
- await self._async_make_request("POST", url)
973
- else:
974
- await self._async_make_request("POST", url, body_slimmer(body))
632
+ await self._async_delete_request(url, body, cascade_delete)
633
+ logger.info(f"Data field {member_data_field_guid} detached from data structure {parent_data_struct_guid}.")
975
634
 
635
+ @dynamic_catch
976
636
  def detach_member_data_field(self, parent_data_struct_guid: str, member_data_field_guid: str,
977
- body: dict = None) -> None:
637
+ body: dict = None | DeleteRequestBody, cascade_delete: bool = False) -> None:
978
638
  """
979
639
  Detach a data class from a data structure. Request body is optional.
980
640
 
981
641
  Parameters
982
642
  ----------
983
643
  parent_data_struct_guid: str
984
- - the GUID of the parent data structure the data class will be detached fromo.
644
+ - the GUID of the parent data structure the data class will be detached from..
985
645
  member_data_field_guid: str
986
646
  - the GUID of the data class to be disconnected.
987
647
  body: dict, optional
@@ -1004,9 +664,10 @@ r replace_all_properties: bool, default = False
1004
664
  ----
1005
665
 
1006
666
  Full sample body:
1007
-
1008
667
  {
1009
- "class": "MetadataSourceRequestBody",
668
+ "class": "DeleteRequestBody",
669
+ "cascadedDelete": false,
670
+ "deleteMethod": "LOOK_FOR_LINEAGE",
1010
671
  "externalSourceGUID": "add guid here",
1011
672
  "externalSourceName": "add qualified name here",
1012
673
  "effectiveTime": "{{$isoTimestamp}}",
@@ -1014,23 +675,26 @@ r replace_all_properties: bool, default = False
1014
675
  "forDuplicateProcessing": false
1015
676
  }
1016
677
 
678
+
1017
679
  """
1018
680
 
1019
681
  loop = asyncio.get_event_loop()
1020
682
  loop.run_until_complete(
1021
- self._async_detach_member_data_field(parent_data_struct_guid, member_data_field_guid, body))
683
+ self._async_detach_member_data_field(parent_data_struct_guid, member_data_field_guid, body, cascade_delete))
1022
684
 
1023
- async def _async_delete_data_structure(self, data_struct_guid: str, body: dict = None, cascade: bool=False) -> None:
685
+ @dynamic_catch
686
+ async def _async_delete_data_structure(self, data_struct_guid: str, body: dict = None,
687
+ cascade_delete: bool = False) -> None:
1024
688
  """
1025
689
  Delete a data structure. Request body is optional. Async version.
1026
690
 
1027
691
  Parameters
1028
692
  ----------
1029
- data_struct_guid: str
693
+ data_struct_guid: str
1030
694
  - the GUID of the parent data structure to delete.
1031
695
  body: dict, optional
1032
696
  - a dictionary containing additional properties.
1033
- cascade: bool, optional
697
+ cascade_delete: bool, optional
1034
698
  - if True, then all child data structures will be deleted as well. Otherwise, only the data structure
1035
699
 
1036
700
  Returns
@@ -1051,8 +715,10 @@ r replace_all_properties: bool, default = False
1051
715
 
1052
716
  Full sample body:
1053
717
 
1054
- {
1055
- "class": "MetadataSourceRequestBody",
718
+ {
719
+ "class": "DeleteRequestBody",
720
+ "cascadedDelete": false,
721
+ "deleteMethod": "LOOK_FOR_LINEAGE",
1056
722
  "externalSourceGUID": "add guid here",
1057
723
  "externalSourceName": "add qualified name here",
1058
724
  "effectiveTime": "{{$isoTimestamp}}",
@@ -1060,30 +726,27 @@ r replace_all_properties: bool, default = False
1060
726
  "forDuplicateProcessing": false
1061
727
  }
1062
728
 
1063
-
1064
729
  """
1065
- cascaded_s = str(cascade).lower()
1066
- url = f"{base_path(self, self.view_server)}/data-structures/{data_struct_guid}/delete?cascadedDelete={cascaded_s}"
1067
730
 
1068
- if body is None:
1069
- await self._async_make_request("POST", url)
1070
- else:
1071
- await self._async_make_request("POST", url, body_slimmer(body))
731
+ url = f"{self.data_designer_root}/data-structures/{data_struct_guid}/delete"
1072
732
 
1073
- def delete_data_structure(self, data_struct_guid: str, body: dict = None, cascade: bool = False) -> None:
733
+ await self._async_delete_request(url, body, cascade_delete)
734
+ logger.info(f"Data structure {data_struct_guid} deleted.")
735
+
736
+ @dynamic_catch
737
+ def delete_data_structure(self, data_struct_guid: str, body: dict = None, cascade_delete: bool = False) -> None:
1074
738
  """
1075
- Delete a data structure. Request body is optional.
739
+ Delete a data structure. Request body is optional. Async version.
1076
740
 
1077
741
  Parameters
1078
742
  ----------
1079
743
  data_struct_guid: str
1080
- - the GUID of the data structure to delete.
744
+ - the GUID of the parent data structure to delete.
1081
745
  body: dict, optional
1082
746
  - a dictionary containing additional properties.
1083
- cascade: bool, optional
747
+ cascade_delete: bool, optional
1084
748
  - if True, then all child data structures will be deleted as well. Otherwise, only the data structure
1085
749
 
1086
-
1087
750
  Returns
1088
751
  -------
1089
752
  None
@@ -1103,7 +766,9 @@ r replace_all_properties: bool, default = False
1103
766
  Full sample body:
1104
767
 
1105
768
  {
1106
- "class": "MetadataSourceRequestBody",
769
+ "class": "DeleteRequestBody",
770
+ "cascadedDelete": false,
771
+ "deleteMethod": "LOOK_FOR_LINEAGE",
1107
772
  "externalSourceGUID": "add guid here",
1108
773
  "externalSourceName": "add qualified name here",
1109
774
  "effectiveTime": "{{$isoTimestamp}}",
@@ -1114,18 +779,15 @@ r replace_all_properties: bool, default = False
1114
779
  """
1115
780
 
1116
781
  loop = asyncio.get_event_loop()
1117
- loop.run_until_complete(self._async_delete_data_field(data_struct_guid, body, cascade))
782
+ loop.run_until_complete(self._async_delete_data_field(data_struct_guid, body, cascade_delete))
1118
783
 
1119
- async def _async_find_all_data_structures(self, start_from: int = 0, page_size: int = max_paging_size,
1120
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
784
+ @dynamic_catch
785
+ def find_all_data_structures(self, output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1121
786
  """Returns a list of all known data structures. Async version.
1122
787
 
1123
788
  Parameters
1124
789
  ----------
1125
- start_from: int, default = 0
1126
- - index of the list to start from (0 for start).
1127
- page_size
1128
- - maximum number of elements to return.
790
+
1129
791
  output_format: str, default = "DICT"
1130
792
  - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
1131
793
  output_format_set: dict, optional, default = None
@@ -1146,41 +808,40 @@ r replace_all_properties: bool, default = False
1146
808
 
1147
809
  """
1148
810
 
1149
- possible_query_params = query_string(
1150
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", 'false'), ("endsWith", 'false'),
1151
- ("ignoreCase", 'true')])
1152
-
1153
- url = (f"{base_path(self, self.view_server)}/data-structures/by-search-string"
1154
- f"{possible_query_params}")
811
+ return self.find_data_structures(search_string="*", output_format=output_format,
812
+ output_format_set=output_format_set)
1155
813
 
1156
- response: Response = await self._async_make_request("POST", url)
1157
-
1158
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1159
- if type(elements) is str:
1160
- return NO_ELEMENTS_FOUND
1161
- if output_format != 'JSON': # return other representations
1162
- return self._generate_data_structure_output(elements, filter, output_format, output_format_set)
1163
- return elements
1164
-
1165
- def find_all_data_structures(self, start_from: int = 0, page_size: int = max_paging_size,
1166
- output_format: str = 'JSON', output_format_set: dict = None) -> list | str:
1167
- """ Returns a list of all known data structures.
814
+ @dynamic_catch
815
+ async def _async_find_data_structures(self, search_string: str, start_from: int = 0, page_size: int = 0,
816
+ starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
817
+ body: dict | SearchStringRequestBody = None,
818
+ output_format: str = 'JSON',
819
+ output_format_set: str | dict = None) -> list | str:
820
+ """ Find the list of data structure metadata elements that contain the search string.
821
+ Async version.
1168
822
 
1169
823
  Parameters
1170
824
  ----------
825
+ search_string: str
826
+ - search string to filter on.
1171
827
  start_from: int, default = 0
1172
828
  - index of the list to start from (0 for start).
1173
829
  page_size
1174
830
  - maximum number of elements to return.
1175
- output_format: str, default = "DICT"
1176
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
1177
- columns_struct: dict, optional, default = None
1178
- - The desired output columns/field options.
1179
-
1180
- Returns
831
+ starts_with: bool, default = True
832
+ - if True, the search string filters from the beginning of the string.
833
+ ends_with: bool, default = False
834
+ - if True, the search string filters from the end of the string.
835
+ ignore_case: bool, default = True
836
+ - If True, the case of the search string is ignored.
837
+ output_format: str, default = "DICT"
838
+ - one of "DICT", "MERMAID" or "JSON"
839
+ output_format_set: dict|str, optional, default = None
840
+ - The desired output columns/field options.
841
+ Returns
1181
842
  -------
1182
843
  [dict] | str
1183
- Returns a string if no elements are found and a list of dict elements with the results.
844
+ Returns a string if no elements are found and a list of dict with the results.
1184
845
 
1185
846
  Raises
1186
847
  ------
@@ -1191,23 +852,46 @@ r replace_all_properties: bool, default = False
1191
852
  UserNotAuthorizedException
1192
853
  the requesting user is not authorized to issue this request.
1193
854
 
855
+ Notes:
856
+ _____
857
+ Sample Body:
858
+ {
859
+ "class" : "SearchStringRequestBody",
860
+ "startsWith" : false,
861
+ "endsWith" : false,
862
+ "ignoreCase" : true,
863
+ "startFrom" : 0,
864
+ "pageSize": 0,
865
+ "asOfTime" : "{{$isoTimestamp}}",
866
+ "effectiveTime" : "{{$isoTimestamp}}",
867
+ "forLineage" : false,
868
+ "forDuplicateProcessing" : false,
869
+ "limitResultsByStatus" : ["ACTIVE"],
870
+ "sequencingOrder" : "PROPERTY_ASCENDING",
871
+ "sequencingProperty" : "qualifiedName"
872
+ }
873
+
1194
874
  """
1195
875
 
1196
- loop = asyncio.get_event_loop()
1197
- response = loop.run_until_complete(self._async_find_all_data_structures(start_from, page_size, output_format, output_format_set))
1198
- return response
876
+ url = f"{base_path(self, self.view_server)}/data-structures/by-search-string"
1199
877
 
1200
- async def _async_find_data_structures_w_body(self, body: dict, start_from: int = 0,
1201
- page_size: int = max_paging_size, starts_with: bool = True,
1202
- ends_with: bool = False, ignore_case: bool = True,
1203
- output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1204
- """ Retrieve the list of data structure metadata elements that contain the search string.
1205
- Async version.
878
+ return await self._async_find_request(url, "DataStructure", self._generate_data_structure_output,
879
+ search_string, start_from=start_from, page_size=page_size,
880
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
881
+ body=body, output_format=output_format,
882
+ output_format_set=output_format_set)
883
+
884
+ @dynamic_catch
885
+ def find_data_structures(self, search_string: str, start_from: int = 0, page_size: int = 0,
886
+ starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
887
+ body: dict | SearchStringRequestBody = None,
888
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
889
+ """ Find the list of data structure metadata elements that contain the search string.
1206
890
 
1207
891
  Parameters
1208
892
  ----------
1209
- body: dict
1210
- - A structure containing the search criteria. (example below)
893
+ search_string: str
894
+ - search string to filter on.
1211
895
  start_from: int, default = 0
1212
896
  - index of the list to start from (0 for start).
1213
897
  page_size
@@ -1219,10 +903,9 @@ r replace_all_properties: bool, default = False
1219
903
  ignore_case: bool, default = True
1220
904
  - If True, the case of the search string is ignored.
1221
905
  output_format: str, default = "DICT"
1222
- - output format of the data structure. Possible values: "DICT", 'REPORT', 'FORM', "JSON", "MERMAID".
1223
- output_format_set: str | dict, optional, default = None
906
+ - one of "DICT", "MERMAID" or "JSON"
907
+ output_format_set: dict|str, optional, default = None
1224
908
  - The desired output columns/field options.
1225
-
1226
909
  Returns
1227
910
  -------
1228
911
  [dict] | str
@@ -1238,62 +921,56 @@ r replace_all_properties: bool, default = False
1238
921
  the requesting user is not authorized to issue this request.
1239
922
 
1240
923
  Notes:
1241
-
1242
- {
1243
- "class": "FilterRequestBody",
1244
- "asOfTime": "{{$isoTimestamp}}",
1245
- "effectiveTime": "{{$isoTimestamp}}",
1246
- "forLineage": false,
1247
- "forDuplicateProcessing": false,
1248
- "limitResultsByStatus": ["ACTIVE"],
1249
- "sequencingOrder": "PROPERTY_ASCENDING",
1250
- "sequencingProperty": "qualifiedName",
1251
- "filter": ""
1252
- }
924
+ _____
925
+ Sample Body:
926
+ {
927
+ "class" : "SearchStringRequestBody",
928
+ "startsWith" : false,
929
+ "endsWith" : false,
930
+ "ignoreCase" : true,
931
+ "startFrom" : 0,
932
+ "pageSize": 0,
933
+ "asOfTime" : "{{$isoTimestamp}}",
934
+ "effectiveTime" : "{{$isoTimestamp}}",
935
+ "forLineage" : false,
936
+ "forDuplicateProcessing" : false,
937
+ "limitResultsByStatus" : ["ACTIVE"],
938
+ "sequencingOrder" : "PROPERTY_ASCENDING",
939
+ "sequencingProperty" : "qualifiedName"
940
+ }
1253
941
 
1254
942
  """
1255
- starts_with_s = str(starts_with).lower()
1256
- ends_with_s = str(ends_with).lower()
1257
- ignore_case_s = str(ignore_case).lower()
1258
- possible_query_params = query_string(
1259
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", starts_with_s),
1260
- ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
1261
-
1262
- url = (f"{base_path(self, self.view_server)}/data-structures/by-search-string"
1263
- f"{possible_query_params}")
1264
943
 
1265
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1266
-
1267
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1268
- if type(elements) is list and len(elements) == 0:
1269
- return NO_ELEMENTS_FOUND
1270
- if output_format != 'JSON': # return other representations
1271
- return self._generate_data_structure_output(elements, filter, output_format, output_format_set)
1272
- return elements
944
+ loop = asyncio.get_event_loop()
945
+ response = loop.run_until_complete(
946
+ self._async_find_data_structures(search_string, start_from, page_size, starts_with, ends_with, ignore_case,
947
+ body, output_format, output_format_set))
948
+ return response
1273
949
 
1274
- def find_data_structures_w_body(self, body: dict, start_from: int = 0, page_size: int = max_paging_size,
1275
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
1276
- output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1277
- """ Retrieve the list of data structure metadata elements that contain the search string.
950
+ @dynamic_catch
951
+ async def _async_get_data_structures_by_name(self, filter_string: str, classification_names: list[str] = None,
952
+ body: dict | FilterRequestBody = None, start_from: int = 0,
953
+ page_size: int = 0,
954
+ output_format: str = 'JSON',
955
+ output_format_set: str | dict = None) -> list | str:
956
+ """ Get the list of data structure metadata elements with a matching name to the search string filter.
957
+ Async version.
1278
958
 
1279
959
  Parameters
1280
960
  ----------
1281
- body: dict
1282
- - A structure containing the search criteria. (example below)
961
+ filter: str
962
+ - search string to filter on.
963
+ body: dict, optional
964
+ - a dictionary containing additional properties for the request.
1283
965
  start_from: int, default = 0
1284
966
  - index of the list to start from (0 for start).
1285
967
  page_size
1286
968
  - maximum number of elements to return.
1287
- starts_with: bool, default = True
1288
- - if True, the search string filters from the beginning of the string.
1289
- ends_with: bool, default = False
1290
- - if True, the search string filters from the end of the string.
1291
- ignore_case: bool, default = True
1292
- - If True, the case of the search string is ignored.
1293
969
  output_format: str, default = "DICT"
1294
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
970
+ - one of "DICT", "MERMAID" or "JSON"
1295
971
  output_format_set: str | dict, optional, default = None
1296
972
  - The desired output columns/field options.
973
+
1297
974
  Returns
1298
975
  -------
1299
976
  [dict] | str
@@ -1308,52 +985,54 @@ r replace_all_properties: bool, default = False
1308
985
  UserNotAuthorizedException
1309
986
  the requesting user is not authorized to issue this request.
1310
987
 
1311
- Notes:
1312
-
1313
- {
1314
- "class": "FilterRequestBody",
1315
- "asOfTime": "{{$isoTimestamp}}",
1316
- "effectiveTime": "{{$isoTimestamp}}",
1317
- "forLineage": false,
1318
- "forDuplicateProcessing : false,
1319
- "limitResultsByStatus": ["ACTIVE"],
1320
- "sequencingOrder": "PROPERTY_ASCENDING",
1321
- "sequencingProperty": "qualifiedName",
1322
- "filter": ""
1323
- }
988
+ Notes
989
+ -----
990
+ {
991
+ "class": "FilterRequestBody",
992
+ "asOfTime": "{{$isoTimestamp}}",
993
+ "effectiveTime": "{{$isoTimestamp}}",
994
+ "forLineage": false,
995
+ "forDuplicateProcessing": false,
996
+ "limitResultsByStatus": ["ACTIVE"],
997
+ "sequencingOrder": "PROPERTY_ASCENDING",
998
+ "sequencingProperty": "qualifiedName",
999
+ "filter": "Add name here"
1000
+ }
1001
+ """
1324
1002
 
1325
- """
1003
+ url = f"{base_path(self, self.view_server)}/data-structures/by-name"
1004
+ response = await self._async_get_name_request(url, _type="DataStructure",
1005
+ _gen_output=self._generate_data_structure_output,
1006
+ filter_string=filter_string,
1007
+ classification_names=classification_names,
1008
+ start_from=start_from, page_size=page_size,
1009
+ output_format=output_format, output_format_set=output_format_set,
1010
+ body=body)
1326
1011
 
1327
- loop = asyncio.get_event_loop()
1328
- response = loop.run_until_complete(
1329
- self._async_find_data_structures_w_body(body, start_from, page_size, starts_with, ends_with, ignore_case,
1330
- output_format, output_format_set))
1331
1012
  return response
1332
1013
 
1333
- async def _async_find_data_structures(self, search_string: str, start_from: int = 0, page_size: int = max_paging_size,
1334
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
1335
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
1336
- """ Find the list of data structure metadata elements that contain the search string.
1337
- Async version.
1014
+ @dynamic_catch
1015
+ def get_data_structures_by_name(self, filter: str, classification_names: list[str] = None,
1016
+ body: dict | FilterRequestBody = None, start_from: int = 0,
1017
+ page_size: int = max_paging_size, output_format: str = 'JSON',
1018
+ output_format_set: str | dict = None) -> list | str:
1019
+ """ Get the list of data structure metadata elements with a matching name to the search string filter.
1338
1020
 
1339
1021
  Parameters
1340
1022
  ----------
1341
- search_string: str
1023
+ filter: str
1342
1024
  - search string to filter on.
1025
+ body: dict, optional
1026
+ - a dictionary containing additional properties for the request.
1343
1027
  start_from: int, default = 0
1344
1028
  - index of the list to start from (0 for start).
1345
1029
  page_size
1346
1030
  - maximum number of elements to return.
1347
- starts_with: bool, default = True
1348
- - if True, the search string filters from the beginning of the string.
1349
- ends_with: bool, default = False
1350
- - if True, the search string filters from the end of the string.
1351
- ignore_case: bool, default = True
1352
- - If True, the case of the search string is ignored.
1353
1031
  output_format: str, default = "DICT"
1354
- - one of "DICT", "MERMAID" or "JSON"
1355
- output_format_set: dict|str, optional, default = None
1032
+ - one of "DICT", "MERMAID" or "JSON"
1033
+ output_format_set: str | dict, optional, default = None
1356
1034
  - The desired output columns/field options.
1035
+
1357
1036
  Returns
1358
1037
  -------
1359
1038
  [dict] | str
@@ -1368,55 +1047,34 @@ r replace_all_properties: bool, default = False
1368
1047
  UserNotAuthorizedException
1369
1048
  the requesting user is not authorized to issue this request.
1370
1049
 
1371
- """
1372
- if search_string == "*":
1373
- search_string = None
1374
-
1375
- body = {"filter": search_string}
1376
- starts_with_s = str(starts_with).lower()
1377
- ends_with_s = str(ends_with).lower()
1378
- ignore_case_s = str(ignore_case).lower()
1379
-
1380
- possible_query_params = query_string(
1381
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", ends_with_s), ("endsWith", ends_with_s),
1382
- ("ignoreCase", ignore_case_s),])
1383
1050
 
1384
- url = (f"{base_path(self, self.view_server)}/data-structures/by-search-string"
1385
- f"{possible_query_params}")
1386
-
1387
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1388
-
1389
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1390
- if type(elements) is str:
1391
- return NO_ELEMENTS_FOUND
1051
+ """
1392
1052
 
1393
- if output_format != 'JSON': # return a simplified markdown representation
1394
- return self._generate_data_structure_output(elements, filter, output_format, output_format_set)
1395
- return elements
1053
+ loop = asyncio.get_event_loop()
1054
+ response = loop.run_until_complete(
1055
+ self._async_get_data_structures_by_name(filter, classification_names, body, start_from, page_size,
1056
+ output_format, output_format_set))
1057
+ return response
1396
1058
 
1397
- def find_data_structures(self, search_string: str, start_from: int = 0, page_size: int = max_paging_size,
1398
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
1399
- output_format: str = 'JSON', output_format_set:str| dict = None) -> list | str:
1400
- """ Retrieve the list of data structure metadata elements that contain the search string filter.
1059
+ @dynamic_catch
1060
+ async def _async_get_data_structure_by_guid(self, guid: str, element_type: str = None,
1061
+ body: dict | GetRequestBody = None,
1062
+ output_format: str = 'JSON',
1063
+ output_format_set: str | dict = None) -> list | str:
1064
+ """ Get the data structure metadata elements for the specified GUID.
1065
+ Async version.
1401
1066
 
1402
1067
  Parameters
1403
1068
  ----------
1404
- search_string: str
1405
- - search string to filter on.
1406
- start_from: int, default = 0
1407
- - index of the list to start from (0 for start).
1408
- page_size
1409
- - maximum number of elements to return.
1410
- starts_with: bool, default = True
1411
- - if True, the search string filters from the beginning of the string.
1412
- ends_with: bool, default = False
1413
- - if True, the search string filters from the end of the string.
1414
- ignore_case: bool, default = True
1415
- - If True, the case of the search string is ignored.
1069
+ guid: str
1070
+ - unique identifier of the data structure metadata element.
1071
+ element_type: str, optional
1072
+ - optional element type.
1073
+ body: dict | GetRequestBody, optional
1074
+ - optional request body.
1416
1075
  output_format: str, default = "DICT"
1417
- output_format: str, default = "DICT"
1418
- - one of "DICT", "MERMAID" or "JSON"
1419
- output_format_set: dict|str, optional, default = None
1076
+ - one of "DICT", "MERMAID" or "JSON"
1077
+ output_format_set: str | dict, optional, default = None
1420
1078
  - The desired output columns/field options.
1421
1079
 
1422
1080
  Returns
@@ -1433,33 +1091,46 @@ r replace_all_properties: bool, default = False
1433
1091
  UserNotAuthorizedException
1434
1092
  the requesting user is not authorized to issue this request.
1435
1093
 
1094
+ Notes
1095
+ ----
1436
1096
 
1437
- """
1097
+ Optional request body:
1098
+ {
1099
+ "class" : "GetRequestBody",
1100
+ "asOfTime" : "{{$isoTimestamp}}",
1101
+ "effectiveTime" : "{{$isoTimestamp}}",
1102
+ "forLineage" : false,
1103
+ "forDuplicateProcessing" : false
1104
+ }
1105
+
1106
+
1107
+ """
1108
+
1109
+ url = (f"{base_path(self, self.view_server)}/data-structures/{guid}/retrieve")
1110
+ type = element_type if element_type else "DataStructure"
1111
+
1112
+ response = await self._async_get_guid_request(url, _type=type,
1113
+ _gen_output=self._generate_data_structure_output,
1114
+ output_format=output_format, output_format_set=output_format_set,
1115
+ body=body)
1438
1116
 
1439
- loop = asyncio.get_event_loop()
1440
- response = loop.run_until_complete(
1441
- self._async_find_data_structures(search_string, start_from, page_size, starts_with, ends_with, ignore_case,
1442
- output_format, output_format_set))
1443
1117
  return response
1444
1118
 
1445
- async def _async_get_data_structures_by_name(self, filter: str, body: dict = None, start_from: int = 0,
1446
- page_size: int = max_paging_size,
1447
- output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1448
- """ Get the list of data structure metadata elements with a matching name to the search string filter.
1449
- Async version.
1119
+ @dynamic_catch
1120
+ def get_data_structure_by_guid(self, guid: str, element_type: str = None, body: str = None,
1121
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1122
+ """ Get the data structure metadata element with the specified unique identifier..
1450
1123
 
1451
1124
  Parameters
1452
1125
  ----------
1453
- filter: str
1454
- - search string to filter on.
1126
+ guid: str
1127
+ - unique identifier of the data structure metadata element.
1128
+ element_type: str, optional
1129
+ - optional element type.
1455
1130
  body: dict, optional
1456
- - a dictionary containing additional properties for the request.
1457
- start_from: int, default = 0
1458
- - index of the list to start from (0 for start).
1459
- page_size
1460
- - maximum number of elements to return.
1131
+ - optional request body.
1461
1132
  output_format: str, default = "DICT"
1462
- - one of "DICT", "MERMAID" or "JSON"
1133
+ - one of "DICT", "MERMAID" or "JSON"
1463
1134
  output_format_set: str | dict, optional, default = None
1464
1135
  - The desired output columns/field options.
1465
1136
 
@@ -1478,185 +1149,262 @@ r replace_all_properties: bool, default = False
1478
1149
  the requesting user is not authorized to issue this request.
1479
1150
 
1480
1151
  Notes
1481
- -----
1152
+ ----
1153
+
1154
+ Optional request body:
1482
1155
  {
1483
- "class": "FilterRequestBody",
1156
+ "class": "GetRequestBody",
1484
1157
  "asOfTime": "{{$isoTimestamp}}",
1485
1158
  "effectiveTime": "{{$isoTimestamp}}",
1486
1159
  "forLineage": false,
1487
- "forDuplicateProcessing": false,
1488
- "limitResultsByStatus": ["ACTIVE"],
1489
- "sequencingOrder": "PROPERTY_ASCENDING",
1490
- "sequencingProperty": "qualifiedName",
1491
- "filter": "Add name here"
1160
+ "forDuplicateProcessing": false
1492
1161
  }
1493
- """
1494
- if body is None:
1495
- body = {"filter": filter}
1496
1162
 
1497
- possible_query_params = query_string([("startFrom", start_from), ("pageSize", page_size), ])
1163
+ """
1164
+
1165
+ loop = asyncio.get_event_loop()
1166
+ response = loop.run_until_complete(
1167
+ self._async_get_data_structure_by_guid(guid, element_type, body, output_format, output_format_set))
1168
+ return response
1169
+
1170
+ def get_data_memberships(self, data_get_fcn: callable, data_struct_guid: str) -> dict | None:
1171
+ data_structure_info = data_get_fcn(data_struct_guid, output_format="JSON")
1172
+ if data_structure_info == "No elements found":
1173
+ return None
1174
+ collection_list = {"DictList": [], "SpecList": [], "CollectionDetails": []}
1175
+ if isinstance(data_structure_info, (dict, list)):
1176
+ member_of_collections = data_structure_info.get('memberOfCollections', "")
1177
+ if isinstance(member_of_collections, list):
1178
+ for member_rel in member_of_collections:
1179
+ props = member_rel["relatedElement"]["properties"]
1180
+ qname = props.get('qualifiedName', None)
1181
+ guid = member_rel['relatedElement']['elementHeader']['guid']
1182
+ description = props.get('description', None)
1183
+ collection_type = props.get('collectionType', None)
1184
+ if collection_type == "Data Dictionary":
1185
+ collection_list["DictList"].append(guid)
1186
+ elif collection_type == "Data Specification":
1187
+ collection_list["SpecList"].append(guid)
1188
+ collection_list["CollectionDetails"].append({
1189
+ "guid": guid, "description": description,
1190
+ "collectionType": collection_type,
1191
+ "qualifiedName": qname
1192
+ })
1193
+ else:
1194
+ return None
1195
+ return collection_list
1196
+ else:
1197
+ return None
1198
+
1199
+ def get_data_memberships_with_dict(self, data_field_elements: dict) -> dict:
1200
+ collection_list = {
1201
+ "DictList_guid": [], "DictList_qn": [], "SpecList_guid": [], "SpecList_qn": [], "CollectionDetails": []
1202
+ }
1203
+ if isinstance(data_field_elements, (dict, list)):
1204
+
1205
+ for member_rel in data_field_elements:
1206
+ type_name = ""
1207
+ props = member_rel["relatedElement"]["properties"]
1208
+ qname = props.get('qualifiedName', None)
1209
+ guid = member_rel['relatedElement']['elementHeader']['guid']
1210
+ description = props.get('description', None)
1211
+ collection_type = props.get('collectionType', None)
1212
+ classifications = member_rel["relatedElement"]["elementHeader"]["classifications"]
1213
+ for classification in classifications:
1214
+ type_name = classification["type"]['typeName']
1215
+ if type_name == "DataDictionary":
1216
+ collection_list["DictList_guid"].append(guid)
1217
+ collection_list["DictList_qn"].append(qname)
1218
+ elif type_name == "DataSpec":
1219
+ collection_list["SpecList_guid"].append(guid)
1220
+ collection_list["SpecList_qn"].append(qname)
1221
+ collection_list["CollectionDetails"].append({
1222
+ "typeName": type_name, "guid": guid,
1223
+ "description": description,
1224
+ "collectionType": collection_type,
1225
+ "qualifiedName": qname
1226
+ })
1227
+ return collection_list
1498
1228
 
1499
- url = (f"{base_path(self, self.view_server)}/data-structures/by-name"
1500
- f"{possible_query_params}")
1229
+ def get_data_rel_elements_dict(self, el_struct: dict) -> dict | str:
1230
+ """return the lists of objects related to a data field"""
1501
1231
 
1502
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1232
+ parent_guids = []
1233
+ parent_names = []
1234
+ parent_qnames = []
1235
+
1236
+ data_structure_guids = []
1237
+ data_structure_names = []
1238
+ data_structure_qnames = []
1239
+
1240
+ assigned_meanings_guids = []
1241
+ assigned_meanings_names = []
1242
+ assigned_meanings_qnames = []
1243
+
1244
+ data_class_guids = []
1245
+ data_class_names = []
1246
+ data_class_qnames = []
1247
+
1248
+ external_references_guids = []
1249
+ external_references_names = []
1250
+ external_references_qnames = []
1251
+
1252
+ member_of_data_dicts_guids = []
1253
+ member_of_data_dicts_names = []
1254
+ member_of_data_dicts_qnames = []
1255
+
1256
+ member_of_data_spec_guids = []
1257
+ member_of_data_spec_names = []
1258
+ member_of_data_spec_qnames = []
1259
+
1260
+ member_data_field_guids = []
1261
+ member_data_field_names = []
1262
+ member_data_field_qnames = []
1263
+
1264
+ nested_data_classes_guids = []
1265
+ nested_data_classes_names = []
1266
+ nested_data_classes_qnames = []
1503
1267
 
1504
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
1505
- if type(elements) is str:
1506
- return NO_ELEMENTS_FOUND
1507
- if output_format != 'JSON': # return other representations
1508
- return self._generate_data_structure_output(elements, filter, output_format, output_format_set)
1509
- return elements
1268
+ specialized_data_classes_guids = []
1269
+ specialized_data_classes_names = []
1270
+ specialized_data_classes_qnames = []
1510
1271
 
1511
- def get_data_structures_by_name(self, filter: str, body: dict = None, start_from: int = 0,
1512
- page_size: int = max_paging_size, output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1513
- """ Get the list of data structure metadata elements with a matching name to the search string filter.
1272
+ # terms
1273
+ assigned_meanings = el_struct.get("assignedMeanings", {})
1274
+ for meaning in assigned_meanings:
1275
+ assigned_meanings_guids.append(meaning['relatedElement']['elementHeader']['guid'])
1276
+ assigned_meanings_names.append(meaning['relatedElement']['properties']['displayName'])
1277
+ assigned_meanings_qnames.append(meaning['relatedElement']['properties']['qualifiedName'])
1514
1278
 
1515
- Parameters
1516
- ----------
1517
- filter: str
1518
- - search string to filter on.
1519
- body: dict, optional
1520
- - a dictionary containing additional properties for the request.
1521
- start_from: int, default = 0
1522
- - index of the list to start from (0 for start).
1523
- page_size
1524
- - maximum number of elements to return.
1525
- output_format: str, default = "DICT"
1526
- - one of "DICT", "MERMAID" or "JSON"
1527
- output_format_set: str | dict, optional, default = None
1528
- - The desired output columns/field options.
1279
+ # extract existing related data structure and data field elements
1280
+ other_related_elements = el_struct.get("otherRelatedElements", None)
1281
+ if other_related_elements:
1282
+ for rel in other_related_elements:
1283
+ related_element = rel["relatedElement"]
1284
+ type = related_element["elementHeader"]["type"]["typeName"]
1285
+ guid = related_element["elementHeader"]["guid"]
1286
+ qualified_name = related_element["properties"].get("qualifiedName", "") or ""
1287
+ display_name = related_element["properties"].get("displayName", "") or ""
1288
+ if type == "DataStructure":
1289
+ data_structure_guids.append(guid)
1290
+ data_structure_names.append(display_name)
1291
+ data_structure_qnames.append(qualified_name)
1529
1292
 
1530
- Returns
1531
- -------
1532
- [dict] | str
1533
- Returns a string if no elements are found and a list of dict with the results.
1293
+ elif type == "DataField":
1294
+ parent_guids.append(guid)
1295
+ parent_names.append(display_name)
1296
+ parent_qnames.append(qualified_name)
1534
1297
 
1535
- Raises
1536
- ------
1537
- InvalidParameterException
1538
- one of the parameters is null or invalid or
1539
- PropertyServerException
1540
- There is a problem adding the element properties to the metadata repository or
1541
- UserNotAuthorizedException
1542
- the requesting user is not authorized to issue this request.
1298
+ member_of_collections = el_struct.get("memberOfCollections", {})
1299
+ for collection in member_of_collections:
1300
+ c_type = collection["relatedElement"]["properties"].get("collectionType", "") or ""
1301
+ guid = collection["relatedElement"]["elementHeader"]["guid"]
1302
+ name = collection["relatedElement"]["properties"].get("name", "") or ""
1303
+ qualifiedName = collection['relatedElement']["properties"].get("qualifiedName", "") or ""
1304
+ classifications = collection["relatedElement"]["elementHeader"]["classifications"]
1305
+ for classification in classifications:
1306
+ type_name = classification["type"]['typeName']
1307
+ if type_name == "DataDictionary":
1308
+ member_of_data_dicts_guids.append(guid)
1309
+ member_of_data_dicts_names.append(name)
1310
+ member_of_data_dicts_qnames.append(qualifiedName)
1311
+ elif type_name == "DataSpec":
1312
+ member_of_data_spec_guids.append(guid)
1313
+ member_of_data_spec_names.append(name)
1314
+ member_of_data_spec_qnames.append(qualifiedName)
1543
1315
 
1316
+ member_data_fields = el_struct.get("memberDataFields", {})
1317
+ for data_field in member_data_fields:
1318
+ member_data_field_guids.append(data_field["elementHeader"]["guid"])
1319
+ member_data_field_names.append(data_field["properties"]["displayName"])
1320
+ member_data_field_qnames.append(data_field["properties"]["qualifiedName"])
1544
1321
 
1545
- """
1322
+ data_classes = el_struct.get("assignedDataClasses", {})
1323
+ for data_class in data_classes:
1324
+ data_class_guids.append(data_class['relatedElement']["elementHeader"]["guid"])
1325
+ data_class_names.append(data_class['relatedElement']["properties"]["displayName"])
1326
+ data_class_qnames.append(data_class['relatedElement']["properties"]["qualifiedName"])
1546
1327
 
1547
- loop = asyncio.get_event_loop()
1548
- response = loop.run_until_complete(
1549
- self._async_get_data_structures_by_name(filter, body, start_from, page_size, output_format, output_format_set))
1550
- return response
1328
+ nested_data_classes = el_struct.get("nestedDataClasses", {})
1329
+ for nested_data_class in nested_data_classes:
1330
+ nested_data_classes_guids.append(nested_data_class['relatedElement']["elementHeader"]["guid"])
1331
+ nested_data_classes_names.append(nested_data_class['relatedElement']["properties"]["displayName"])
1332
+ nested_data_classes_qnames.append(nested_data_class['relatedElement']["properties"]["qualifiedName"])
1551
1333
 
1552
- async def _async_get_data_structure_by_guid(self, guid: str, body: dict = None,
1553
- output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1554
- """ Get the data structure metadata elements for the specified GUID.
1555
- Async version.
1334
+ specialized_data_classes = el_struct.get("specializedDataClasses", {})
1335
+ for nested_data_class in specialized_data_classes:
1336
+ specialized_data_classes_guids.append(nested_data_class['relatedElement']["elementHeader"]["guid"])
1337
+ specialized_data_classes_names.append(nested_data_class['relatedElement']["properties"]["displayName"])
1338
+ specialized_data_classes_qnames.append(nested_data_class['relatedElement']["properties"]["qualifiedName"])
1556
1339
 
1557
- Parameters
1558
- ----------
1559
- guid: str
1560
- - unique identifier of the data structure metadata element.
1561
- body: dict, optional
1562
- - optional request body.
1563
- output_format: str, default = "DICT"
1564
- - one of "DICT", "MERMAID" or "JSON"
1565
- output_format_set: str | dict, optional, default = None
1566
- - The desired output columns/field options.
1340
+ mermaid = el_struct.get("mermaidGraph", {})
1567
1341
 
1568
- Returns
1569
- -------
1570
- [dict] | str
1571
- Returns a string if no elements are found and a list of dict with the results.
1342
+ return {
1343
+ "parent_guids": parent_guids,
1344
+ "parent_names": parent_names,
1345
+ "parent_qnames": parent_qnames,
1572
1346
 
1573
- Raises
1574
- ------
1575
- InvalidParameterException
1576
- one of the parameters is null or invalid or
1577
- PropertyServerException
1578
- There is a problem adding the element properties to the metadata repository or
1579
- UserNotAuthorizedException
1580
- the requesting user is not authorized to issue this request.
1347
+ "data_structure_guids": data_structure_guids,
1348
+ "data_structure_names": data_structure_names,
1349
+ "data_structure_qnames": data_structure_qnames,
1581
1350
 
1582
- Notes
1583
- ----
1351
+ "assigned_meanings_guids": assigned_meanings_guids,
1352
+ "assigned_meanings_names": assigned_meanings_names,
1353
+ "assigned_meanings_qnames": assigned_meanings_qnames,
1584
1354
 
1585
- Optional request body:
1586
- {
1587
- "class": "AnyTimeRequestBody",
1588
- "asOfTime": "{{$isoTimestamp}}",
1589
- "effectiveTime": "{{$isoTimestamp}}",
1590
- "forLineage": false,
1591
- "forDuplicateProcessing": false
1592
- }
1355
+ "data_class_guids": data_class_guids,
1356
+ "data_class_names": data_class_names,
1357
+ "data_class_qnames": data_class_qnames,
1593
1358
 
1594
- """
1359
+ "nested_data_class_guids": nested_data_classes_guids,
1360
+ "nested_data_class_names": nested_data_classes_names,
1361
+ "nested_data_class_qnames": nested_data_classes_qnames,
1595
1362
 
1596
- url = (f"{base_path(self, self.view_server)}/data-structures/{guid}/retrieve")
1597
- if body:
1598
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1599
- else:
1600
- response: Response = await self._async_make_request("POST", url)
1363
+ "specialized_data_class_guids": specialized_data_classes_guids,
1364
+ "specialized_data_class_names": specialized_data_classes_names,
1365
+ "specialized_data_class_qnames": specialized_data_classes_qnames,
1601
1366
 
1602
- element = response.json().get("element", NO_ELEMENTS_FOUND)
1603
- if type(element) is str:
1604
- return NO_ELEMENTS_FOUND
1605
- if output_format != 'JSON': # return other representations
1606
- return self._generate_data_structure_output(element, filter, output_format, output_format_set)
1607
- return element
1367
+ "external_references_guids": external_references_guids,
1368
+ "external_references_names": external_references_names,
1369
+ "external_references_qnames": external_references_qnames,
1608
1370
 
1609
- def get_data_structure_by_guid(self, guid: str, body: str = None, output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
1610
- """ Get the data structure metadata element with the specified unique identifier..
1371
+ "member_of_data_dicts_guids": member_of_data_dicts_guids,
1372
+ "member_of_data_dicts_names": member_of_data_dicts_names,
1373
+ "member_of_data_dicts_qnames": member_of_data_dicts_qnames,
1611
1374
 
1612
- Parameters
1613
- ----------
1614
- guid: str
1615
- - unique identifier of the data structure metadata element.
1616
- body: dict, optional
1617
- - optional request body.
1618
- output_format: str, default = "DICT"
1619
- - one of "DICT", "MERMAID" or "JSON"
1620
- output_format_set: str | dict, optional, default = None
1621
- - The desired output columns/field options.
1375
+ "member_of_data_spec_guids": member_of_data_spec_guids,
1376
+ "member_of_data_spec_names": member_of_data_spec_names,
1377
+ "member_of_data_spec_qnames": member_of_data_spec_qnames,
1622
1378
 
1623
- Returns
1624
- -------
1625
- [dict] | str
1626
- Returns a string if no elements are found and a list of dict with the results.
1379
+ "member_data_field_guids": member_data_field_guids,
1380
+ "member_data_field_names": member_data_field_names,
1381
+ "member_data_field_qnames": member_data_field_qnames,
1627
1382
 
1628
- Raises
1629
- ------
1630
- InvalidParameterException
1631
- one of the parameters is null or invalid or
1632
- PropertyServerException
1633
- There is a problem adding the element properties to the metadata repository or
1634
- UserNotAuthorizedException
1635
- the requesting user is not authorized to issue this request.
1383
+ "mermaid": mermaid,
1384
+ }
1636
1385
 
1637
- Notes
1638
- ----
1386
+ def get_data_field_rel_elements(self, guid: str) -> dict | str:
1387
+ """return the lists of objects related to a data field"""
1639
1388
 
1640
- Optional request body:
1641
- {
1642
- "class": "AnyTimeRequestBody",
1643
- "asOfTime": "{{$isoTimestamp}}",
1644
- "effectiveTime": "{{$isoTimestamp}}",
1645
- "forLineage": false,
1646
- "forDuplicateProcessing": false
1647
- }
1389
+ data_field_entry = self.get_data_field_by_guid(guid, output_format="JSON")
1390
+ if isinstance(data_field_entry, str):
1391
+ return None
1392
+ return self.get_data_rel_elements_dict(data_field_entry)
1648
1393
 
1649
- """
1394
+ def get_data_class_rel_elements(self, guid: str) -> dict | str:
1395
+ """return the lists of objects related to a data class"""
1650
1396
 
1651
- loop = asyncio.get_event_loop()
1652
- response = loop.run_until_complete(self._async_get_data_structure_by_guid(guid, body, output_format, output_format_set))
1653
- return response
1397
+ data_class_entry = self.get_data_class_by_guid(guid, output_format="JSON")
1398
+ if isinstance(data_class_entry, str):
1399
+ return None
1400
+ return self.get_data_rel_elements_dict(data_class_entry)
1654
1401
 
1655
1402
  #
1656
1403
  # Work with Data Fields
1657
1404
  # https://egeria-project.org/concepts/data-class
1658
1405
  #
1659
- async def _async_create_data_field(self, body: dict) -> str:
1406
+ @dynamic_catch
1407
+ async def _async_create_data_field(self, body: dict | NewElementRequestBody) -> str:
1660
1408
  """
1661
1409
  Create a new data class with parameters defined in the body. Async version.
1662
1410
 
@@ -1684,7 +1432,7 @@ r replace_all_properties: bool, default = False
1684
1432
  Sample bodies:
1685
1433
 
1686
1434
  {
1687
- "class" : "NewDataFieldRequestBody",
1435
+ "class" : "NewElementRequestBody",
1688
1436
  "externalSourceGUID": "add guid here",
1689
1437
  "externalSourceName": "add qualified name here",
1690
1438
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1765,10 +1513,10 @@ r replace_all_properties: bool, default = False
1765
1513
 
1766
1514
  url = f"{base_path(self, self.view_server)}/data-fields"
1767
1515
 
1768
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1769
- return response.json().get("guid", NO_ELEMENTS_FOUND)
1516
+ return await self._async_create_element_body_request(url, "DataField", body)
1770
1517
 
1771
- def create_data_field(self, body: dict) -> str:
1518
+ @dynamic_catch
1519
+ def create_data_field(self, body: dict | NewElementRequestBody) -> str:
1772
1520
  """
1773
1521
  Create a new data class with parameters defined in the body..
1774
1522
 
@@ -1880,7 +1628,8 @@ r replace_all_properties: bool, default = False
1880
1628
  response = loop.run_until_complete(self._async_create_data_field(body))
1881
1629
  return response
1882
1630
 
1883
- async def _async_create_data_field_from_template(self, body: dict) -> str:
1631
+ @dynamic_catch
1632
+ async def _async_create_data_field_from_template(self, body: dict | TemplateRequestBody) -> str:
1884
1633
  """
1885
1634
  Create a new metadata element to represent a data class using an existing metadata element as a template.
1886
1635
  The template defines additional classifications and relationships that should be added to the new element.
@@ -1950,10 +1699,10 @@ r replace_all_properties: bool, default = False
1950
1699
 
1951
1700
  url = f"{base_path(self, self.view_server)}/data-fields/from-template"
1952
1701
 
1953
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1954
- return response.json().get("guid", NO_ELEMENTS_FOUND)
1702
+ return await self._async_create_element_from_template(url, body)
1955
1703
 
1956
- def create_data_field_from_template(self, body: dict) -> str:
1704
+ @dynamic_catch
1705
+ def create_data_field_from_template(self, body: dict | TemplateRequestBody) -> str:
1957
1706
  """
1958
1707
  Create a new metadata element to represent a data class using an existing metadata element as a template.
1959
1708
  The template defines additional classifications and relationships that should be added to the new element.
@@ -2025,8 +1774,8 @@ r replace_all_properties: bool, default = False
2025
1774
  response = loop.run_until_complete(self._async_create_data_field_from_template(body))
2026
1775
  return response
2027
1776
 
2028
- async def _async_update_data_field(self, data_field_guid: str, body: dict,
2029
- replace_all_properties: bool = False) -> None:
1777
+ @dynamic_catch
1778
+ async def _async_update_data_field(self, data_field_guid: str, body: dict | UpdateElementRequestBody) -> None:
2030
1779
  """
2031
1780
  Update the properties of a data class. Async version.
2032
1781
 
@@ -2036,9 +1785,7 @@ r replace_all_properties: bool, default = False
2036
1785
  - the GUID of the data class to be updated.
2037
1786
  body: dict
2038
1787
  - a dictionary containing the properties of the data structure to be created.
2039
- replace_all_properties: bool, default = False
2040
- - if true, then all properties will be replaced with the new ones. Otherwise, only the specified ones
2041
- will be replaced.
1788
+
2042
1789
  Returns
2043
1790
  -------
2044
1791
  None
@@ -2092,14 +1839,14 @@ r replace_all_properties: bool, default = False
2092
1839
  }
2093
1840
 
2094
1841
  """
2095
- replace_all_properties_s = str(replace_all_properties).lower()
2096
1842
 
2097
- url = (f"{base_path(self, self.view_server)}/data-fields/{data_field_guid}/update?"
2098
- f"replaceAllProperties={replace_all_properties_s}")
1843
+ url = f"{base_path(self, self.view_server)}/data-fields/{data_field_guid}/update"
2099
1844
 
2100
- await self._async_make_request("POST", url, body_slimmer(body))
1845
+ await self._async_update_element_body_request(url, ["DataField"], body)
1846
+ logger.info(f"Data Field {data_field_guid} updated.")
2101
1847
 
2102
- def update_data_field(self, data_field_guid: str, body: dict.get, replace_all_properties: bool = False) -> None:
1848
+ @dynamic_catch
1849
+ def update_data_field(self, data_field_guid: str, body: dict | UpdateElementRequestBody) -> None:
2103
1850
  """
2104
1851
  Update the properties of a data class.
2105
1852
 
@@ -2166,10 +1913,11 @@ r replace_all_properties: bool, default = False
2166
1913
  """
2167
1914
 
2168
1915
  loop = asyncio.get_event_loop()
2169
- loop.run_until_complete(self._async_update_data_field(data_field_guid, body, replace_all_properties))
1916
+ loop.run_until_complete(self._async_update_data_field(data_field_guid, body))
2170
1917
 
1918
+ @dynamic_catch
2171
1919
  async def _async_link_nested_data_field(self, parent_data_field_guid: str, nested_data_field_guid: str,
2172
- body: dict = None) -> None:
1920
+ body: dict | NewRelationshipRequestBody = None) -> None:
2173
1921
  """
2174
1922
  Connect a nested data field to a data field. Request body is optional. Async version.
2175
1923
 
@@ -2222,13 +1970,12 @@ r replace_all_properties: bool, default = False
2222
1970
  url = (f"{base_path(self, self.view_server)}/data-fields/{parent_data_field_guid}"
2223
1971
  f"/nested-data-fields/{nested_data_field_guid}/attach")
2224
1972
 
2225
- if body is None:
2226
- await self._async_make_request("POST", url)
2227
- else:
2228
- await self._async_make_request("POST", url, body_slimmer(body))
1973
+ await self._async_new_relationship_request(url, ["NestedDataFieldProperties"], body)
1974
+ logger.info(f"Data field {parent_data_field_guid} attached to Data structure {nested_data_field_guid}.")
2229
1975
 
1976
+ @dynamic_catch
2230
1977
  def link_nested_data_field(self, parent_data_field_guid: str, nested_data_field_guid: str,
2231
- body: dict = None) -> None:
1978
+ body: dict | NewRelationshipRequestBody = None) -> None:
2232
1979
  """
2233
1980
  Connect a nested data class to a data class. Request body is optional.
2234
1981
 
@@ -2282,8 +2029,9 @@ r replace_all_properties: bool, default = False
2282
2029
  loop.run_until_complete(
2283
2030
  self._async_link_nested_data_field(parent_data_field_guid, nested_data_field_guid, body))
2284
2031
 
2032
+ @dynamic_catch
2285
2033
  async def _async_detach_nested_data_field(self, parent_data_field_guid: str, nested_data_field_guid: str,
2286
- body: dict = None) -> None:
2034
+ body: dict | DeleteRequestBody = None) -> None:
2287
2035
  """
2288
2036
  Detach a nested data class from a data class. Request body is optional. Async version.
2289
2037
 
@@ -2329,13 +2077,12 @@ r replace_all_properties: bool, default = False
2329
2077
  url = (f"{base_path(self, self.view_server)}/data-fields/{parent_data_field_guid}"
2330
2078
  f"/member-data-fields/{nested_data_field_guid}/detach")
2331
2079
 
2332
- if body is None:
2333
- await self._async_make_request("POST", url)
2334
- else:
2335
- await self._async_make_request("POST", url, body_slimmer(body))
2080
+ await self._async_delete_request(url, body)
2081
+ logger.info(f"Data field {parent_data_field_guid} detached from data structure {nested_data_field_guid}.")
2336
2082
 
2083
+ @dynamic_catch
2337
2084
  def detach_nested_data_field(self, parent_data_field_guid: str, nested_data_field_guid: str,
2338
- body: dict = None) -> None:
2085
+ body: dict | DeleteRequestBody = None) -> None:
2339
2086
  """
2340
2087
  Detach a nested data class from a data class. Request body is optional.
2341
2088
 
@@ -2381,7 +2128,9 @@ r replace_all_properties: bool, default = False
2381
2128
  loop.run_until_complete(
2382
2129
  self._async_detach_nested_data_field(parent_data_field_guid, nested_data_field_guid, body))
2383
2130
 
2384
- async def _async_delete_data_field(self, data_field_guid: str, body: dict = None, cascade:bool = False) -> None:
2131
+ @dynamic_catch
2132
+ async def _async_delete_data_field(self, data_field_guid: str, body: dict | DeleteRequestBody = None,
2133
+ cascade_delete: bool = False) -> None:
2385
2134
  """
2386
2135
  Delete a data class. Request body is optional. Async version.
2387
2136
 
@@ -2424,126 +2173,31 @@ r replace_all_properties: bool, default = False
2424
2173
 
2425
2174
 
2426
2175
  """
2427
- cascade_s = str(cascade).lower()
2428
- url = f"{base_path(self, self.view_server)}/data-fields/{data_field_guid}/delete?cascadedDelete={cascade_s}"
2429
-
2430
- if body is None:
2431
- await self._async_make_request("POST", url)
2432
- else:
2433
- await self._async_make_request("POST", url, body_slimmer(body))
2434
-
2435
- def delete_data_field(self, data_field_guid: str, body: dict = None, cascade:bool = False) -> None:
2436
- """
2437
- Delete a data class. Request body is optional.
2438
-
2439
- Parameters
2440
- ----------
2441
- data_field_guid: str
2442
- - the GUID of the data class the data class to delete.
2443
- body: dict, optional
2444
- - a dictionary containing additional properties.
2445
- cascade: bool, optional
2446
- - if True, then all child data fields will be deleted as well.
2447
-
2448
-
2449
- Returns
2450
- -------
2451
- None
2452
-
2453
- Raises
2454
- ------
2455
- InvalidParameterException
2456
- one of the parameters is null or invalid or
2457
- PropertyServerException
2458
- There is a problem adding the element properties to the metadata repository or
2459
- UserNotAuthorizedException
2460
- the requesting user is not authorized to issue this request.
2461
-
2462
- Note
2463
- ----
2464
-
2465
- Full sample body:
2466
-
2467
- {
2468
- "class": "MetadataSourceRequestBody",
2469
- "externalSourceGUID": "add guid here",
2470
- "externalSourceName": "add qualified name here",
2471
- "effectiveTime": "{{$isoTimestamp}}",
2472
- "forLineage": false,
2473
- "forDuplicateProcessing": false
2474
- }
2475
-
2476
- """
2477
-
2478
- loop = asyncio.get_event_loop()
2479
- loop.run_until_complete(self._async_delete_data_field(data_field_guid, body, cascade))
2480
2176
 
2481
- async def _async_find_all_data_fields(self, start_from: int = 0, page_size: int = max_paging_size,
2482
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2483
- """Returns a list of all known data fields. Async version.
2484
-
2485
- Parameters
2486
- ----------
2487
- start_from: int, default = 0
2488
- - index of the list to start from (0 for start).
2489
- page_size
2490
- - maximum number of elements to return.
2491
- output_format: str, default = "DICT"
2492
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
2493
- output_format_set: str|dict, optional, default = None
2494
- - The desired output columns/field options.
2495
-
2496
- Returns
2497
- -------
2498
- [dict] | str
2499
- Returns a string if no elements are found and a list of dict elements with the results.
2177
+ url = f"{base_path(self, self.view_server)}/data-fields/{data_field_guid}/delete"
2500
2178
 
2501
- Raises
2502
- ------
2503
- InvalidParameterException
2504
- one of the parameters is null or invalid or
2505
- PropertyServerException
2506
- There is a problem adding the element properties to the metadata repository or
2507
- UserNotAuthorizedException
2508
- the requesting user is not authorized to issue this request.
2179
+ await self._async_delete_request(url, body, cascade_delete)
2180
+ logger.info(f"Data Field {data_field_guid} deleted.")
2509
2181
 
2182
+ @dynamic_catch
2183
+ def delete_data_field(self, data_field_guid: str, body: dict | DeleteRequestBody = None,
2184
+ cascade_delete: bool = False) -> None:
2510
2185
  """
2511
-
2512
- possible_query_params = query_string(
2513
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", 'false'), ("endsWith", 'false'),
2514
- ("ignoreCase", 'true')])
2515
-
2516
- url = (f"{base_path(self, self.view_server)}/data-fields/by-search-string"
2517
- f"{possible_query_params}")
2518
-
2519
- response: Response = await self._async_make_request("POST", url)
2520
-
2521
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
2522
- if type(elements) is str:
2523
- return NO_ELEMENTS_FOUND
2524
- if output_format != 'JSON': # return other representations
2525
- return self._generate_data_field_output(elements, filter, output_format, output_format_set)
2526
- return elements
2527
-
2528
- def find_all_data_fields(self, start_from: int = 0, page_size: int = max_paging_size,
2529
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2530
- """ Returns a list of all known data fields.
2186
+ Delete a data class. Request body is optional.
2531
2187
 
2532
2188
  Parameters
2533
2189
  ----------
2534
- start_from: int, default = 0
2535
- - index of the list to start from (0 for start).
2536
- page_size
2537
- - maximum number of elements to return.
2538
- output_format: str, default = "DICT"
2539
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
2540
- output_format_set: str|dict, optional, default = None
2541
- - The desired output columns/field options.
2190
+ data_field_guid: str
2191
+ - the GUID of the data class the data class to delete.
2192
+ body: dict, optional
2193
+ - a dictionary containing additional properties.
2194
+ cascade: bool, optional
2195
+ - if True, then all child data fields will be deleted as well.
2196
+
2542
2197
 
2543
2198
  Returns
2544
2199
  -------
2545
- [dict] | str
2546
- Returns a string if no elements are found and a list of dict elements with the results.
2200
+ None
2547
2201
 
2548
2202
  Raises
2549
2203
  ------
@@ -2554,42 +2208,45 @@ r replace_all_properties: bool, default = False
2554
2208
  UserNotAuthorizedException
2555
2209
  the requesting user is not authorized to issue this request.
2556
2210
 
2211
+ Note
2212
+ ----
2213
+
2214
+ Full sample body:
2215
+
2216
+ {
2217
+ "class": "MetadataSourceRequestBody",
2218
+ "externalSourceGUID": "add guid here",
2219
+ "externalSourceName": "add qualified name here",
2220
+ "effectiveTime": "{{$isoTimestamp}}",
2221
+ "forLineage": false,
2222
+ "forDuplicateProcessing": false
2223
+ }
2224
+
2557
2225
  """
2558
2226
 
2559
2227
  loop = asyncio.get_event_loop()
2560
- response = loop.run_until_complete(self._async_find_all_data_fields(start_from, page_size, output_format, output_format_set))
2561
- return response
2228
+ loop.run_until_complete(self._async_delete_data_field(data_field_guid, body, cascade_delete))
2562
2229
 
2563
- async def _async_find_data_fields_w_body(self, body: dict, start_from: int = 0, page_size: int = max_paging_size,
2564
- starts_with: bool = True, ends_with: bool = False,
2565
- ignore_case: bool = True, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2566
- """ Retrieve the list of data class metadata elements that contain the search string.
2567
- Async version.
2230
+ @dynamic_catch
2231
+ async def _async_find_all_data_fields(self, output_format: str = 'JSON',
2232
+ output_format_set: str | dict = None) -> list | str:
2233
+ """Returns a list of all known data fields. Async version.
2568
2234
 
2569
2235
  Parameters
2570
2236
  ----------
2571
- body: dict
2572
- - A structure containing the search criteria. (example below)
2573
2237
  start_from: int, default = 0
2574
2238
  - index of the list to start from (0 for start).
2575
2239
  page_size
2576
2240
  - maximum number of elements to return.
2577
- starts_with: bool, default = True
2578
- - if True, the search string filters from the beginning of the string.
2579
- ends_with: bool, default = False
2580
- - if True, the search string filters from the end of the string.
2581
- ignore_case: bool, default = True
2582
- - If True, the case of the search string is ignored.
2583
2241
  output_format: str, default = "DICT"
2584
2242
  - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
2585
2243
  output_format_set: str|dict, optional, default = None
2586
2244
  - The desired output columns/field options.
2587
2245
 
2588
-
2589
2246
  Returns
2590
2247
  -------
2591
2248
  [dict] | str
2592
- Returns a string if no elements are found and a list of dict with the results.
2249
+ Returns a string if no elements are found and a list of dict elements with the results.
2593
2250
 
2594
2251
  Raises
2595
2252
  ------
@@ -2600,71 +2257,30 @@ r replace_all_properties: bool, default = False
2600
2257
  UserNotAuthorizedException
2601
2258
  the requesting user is not authorized to issue this request.
2602
2259
 
2603
- Notes:
2604
-
2605
- {
2606
- "class": "FilterRequestBody",
2607
- "asOfTime": "{{$isoTimestamp}}",
2608
- "effectiveTime": "{{$isoTimestamp}}",
2609
- "forLineage": false,
2610
- "forDuplicateProcessing : false,
2611
- "limitResultsByStatus": ["ACTIVE"],
2612
- "sequencingOrder": "PROPERTY_ASCENDING",
2613
- "sequencingProperty": "qualifiedName",
2614
- "filter": ""
2615
- }
2616
-
2617
2260
  """
2618
- if body['filter'] == "*":
2619
- body['filter'] = None
2620
- starts_with_s = str(starts_with).lower()
2621
- ends_with_s = str(ends_with).lower()
2622
- ignore_case_s = str(ignore_case).lower()
2623
- possible_query_params = query_string(
2624
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", starts_with_s),
2625
- ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
2626
2261
 
2627
- url = (f"{base_path(self, self.view_server)}/data-fields/by-search-string"
2628
- f"{possible_query_params}")
2262
+ return self.find_data_fields(search_string="*", output_format=output_format,
2263
+ output_format_set=output_format_set)
2629
2264
 
2630
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
2631
-
2632
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
2633
- if type(elements) is str:
2634
- return NO_ELEMENTS_FOUND
2635
- if output_format != 'JSON': # return other representations
2636
- return self._generate_data_field_output(elements, filter, output_format, output_format_set)
2637
- return elements
2638
-
2639
- def find_data_fields_w_body(self, body: dict, start_from: int = 0, page_size: int = max_paging_size,
2640
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
2641
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2642
- """ Retrieve the list of data class metadata elements that contain the search string.
2265
+ @dynamic_catch
2266
+ def find_all_data_fields(self, output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
2267
+ """ Returns a list of all known data fields.
2643
2268
 
2644
2269
  Parameters
2645
2270
  ----------
2646
- body: dict
2647
- - A structure containing the search criteria. (example below)
2648
2271
  start_from: int, default = 0
2649
2272
  - index of the list to start from (0 for start).
2650
2273
  page_size
2651
2274
  - maximum number of elements to return.
2652
- starts_with: bool, default = True
2653
- - if True, the search string filters from the beginning of the string.
2654
- ends_with: bool, default = False
2655
- - if True, the search string filters from the end of the string.
2656
- ignore_case: bool, default = True
2657
- - If True, the case of the search string is ignored.
2658
2275
  output_format: str, default = "DICT"
2659
2276
  - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
2660
2277
  output_format_set: str|dict, optional, default = None
2661
2278
  - The desired output columns/field options.
2662
2279
 
2663
-
2664
2280
  Returns
2665
2281
  -------
2666
2282
  [dict] | str
2667
- Returns a string if no elements are found and a list of dict with the results.
2283
+ Returns a string if no elements are found and a list of dict elements with the results.
2668
2284
 
2669
2285
  Raises
2670
2286
  ------
@@ -2675,31 +2291,18 @@ r replace_all_properties: bool, default = False
2675
2291
  UserNotAuthorizedException
2676
2292
  the requesting user is not authorized to issue this request.
2677
2293
 
2678
- Notes:
2679
-
2680
- {
2681
- "class": "FilterRequestBody",
2682
- "asOfTime": "{{$isoTimestamp}}",
2683
- "effectiveTime": "{{$isoTimestamp}}",
2684
- "forLineage": false,
2685
- "forDuplicateProcessing : false,
2686
- "limitResultsByStatus": ["ACTIVE"],
2687
- "sequencingOrder": "PROPERTY_ASCENDING",
2688
- "sequencingProperty": "qualifiedName",
2689
- "filter": ""
2690
- }
2691
-
2692
- """
2294
+ """
2693
2295
 
2694
2296
  loop = asyncio.get_event_loop()
2695
2297
  response = loop.run_until_complete(
2696
- self._async_find_data_fields_w_body(body, start_from, page_size, starts_with, ends_with, ignore_case,
2697
- output_format,output_format_set))
2298
+ self._async_find_all_data_fields(output_format, output_format_set))
2698
2299
  return response
2699
2300
 
2700
- async def _async_find_data_fields(self, filter: str, start_from: int = 0, page_size: int = max_paging_size,
2301
+ @dynamic_catch
2302
+ async def _async_find_data_fields(self, search_string: str, start_from: int = 0, page_size: int = 0,
2701
2303
  starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
2702
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2304
+ body: dict | SearchStringRequestBody = None,
2305
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
2703
2306
  """ Find the list of data class elements that contain the search string.
2704
2307
  Async version.
2705
2308
 
@@ -2737,31 +2340,20 @@ r replace_all_properties: bool, default = False
2737
2340
  the requesting user is not authorized to issue this request.
2738
2341
 
2739
2342
  """
2740
- if filter == "*":
2741
- filter = None
2742
- body = {"filter": filter}
2743
- starts_with_s = str(starts_with).lower()
2744
- ends_with_s = str(ends_with).lower()
2745
- ignore_case_s = str(ignore_case).lower()
2746
-
2747
- possible_query_params = query_string(
2748
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith",ends_with_s), ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s) ])
2749
-
2750
- url = (f"{base_path(self, self.view_server)}/data-fields/by-search-string"
2751
- f"{possible_query_params}")
2752
2343
 
2753
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
2344
+ url = f"{base_path(self, self.view_server)}/data-fields/by-search-string"
2754
2345
 
2755
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
2756
- if type(elements) is str:
2757
- return NO_ELEMENTS_FOUND
2758
- if output_format != 'JSON': # return other representations
2759
- return self._generate_data_field_output(elements, filter, output_format, output_format_set)
2760
- return elements
2346
+ return await self._async_find_request(url, "DataField", self._generate_data_field_output,
2347
+ search_string, start_from=start_from, page_size=page_size,
2348
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
2349
+ body=body, output_format=output_format,
2350
+ output_format_set=output_format_set)
2761
2351
 
2762
- def find_data_fields(self, filter: str, start_from: int = 0, page_size: int = max_paging_size,
2352
+ @dynamic_catch
2353
+ def find_data_fields(self, search_string: str, start_from: int = 0, page_size: int = max_paging_size,
2763
2354
  starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
2764
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2355
+ body: dict | SearchStringRequestBody = None,
2356
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
2765
2357
  """ Retrieve the list of data fields elements that contain the search string filter.
2766
2358
 
2767
2359
  Parameters
@@ -2802,13 +2394,16 @@ r replace_all_properties: bool, default = False
2802
2394
 
2803
2395
  loop = asyncio.get_event_loop()
2804
2396
  response = loop.run_until_complete(
2805
- self._async_find_data_fields(filter, start_from, page_size, starts_with, ends_with, ignore_case,
2806
- output_format, output_format_set))
2397
+ self._async_find_data_fields(search_string, start_from, page_size, starts_with, ends_with, ignore_case,
2398
+ body, output_format, output_format_set))
2807
2399
  return response
2808
2400
 
2809
- async def _async_get_data_fields_by_name(self, filter: str, body: dict = None, start_from: int = 0,
2810
- page_size: int = max_paging_size,
2811
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2401
+ @dynamic_catch
2402
+ async def _async_get_data_fields_by_name(self, filter_string: str, classification_names: list[str] = None,
2403
+ body: dict = None | FilterRequestBody, start_from: int = 0,
2404
+ page_size: int = 0,
2405
+ output_format: str = 'JSON',
2406
+ output_format_set: str | dict = None) -> list | str:
2812
2407
  """ Get the list of data class metadata elements with a matching name to the search string filter.
2813
2408
  Async version.
2814
2409
 
@@ -2855,25 +2450,24 @@ r replace_all_properties: bool, default = False
2855
2450
  "filter": "Add name here"
2856
2451
  }
2857
2452
  """
2858
- if body is None:
2859
- body = {"filter": filter}
2860
2453
 
2861
- possible_query_params = query_string([("startFrom", start_from), ("pageSize", page_size), ])
2454
+ url = f"{base_path(self, self.view_server)}/data-fields/by-name"
2862
2455
 
2863
- url = (f"{base_path(self, self.view_server)}/data-fields/by-name"
2864
- f"{possible_query_params}")
2456
+ response = await self._async_get_name_request(url, _type="DataField",
2457
+ _gen_output=self._generate_data_field_output,
2458
+ filter_string=filter_string,
2459
+ classification_names=classification_names,
2460
+ start_from=start_from, page_size=page_size,
2461
+ output_format=output_format, output_format_set=output_format_set,
2462
+ body=body)
2865
2463
 
2866
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
2867
-
2868
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
2869
- if type(elements) is str:
2870
- return NO_ELEMENTS_FOUND
2871
- if output_format != 'JSON': # return other representations
2872
- return self._generate_data_field_output(elements, filter, output_format, output_format_set)
2873
- return elements
2464
+ return response
2874
2465
 
2875
- def get_data_fields_by_name(self, filter: str, body: dict = None, start_from: int = 0,
2876
- page_size: int = max_paging_size, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2466
+ @dynamic_catch
2467
+ def get_data_fields_by_name(self, filter_string: str, classification_names: list[str] = None, body: dict = None,
2468
+ start_from: int = 0,
2469
+ page_size: int = max_paging_size, output_format: str = 'JSON',
2470
+ output_format_set: str | dict = None) -> list | str:
2877
2471
  """ Get the list of data class elements with a matching name to the search string filter.
2878
2472
 
2879
2473
  Parameters
@@ -2924,11 +2518,15 @@ r replace_all_properties: bool, default = False
2924
2518
 
2925
2519
  loop = asyncio.get_event_loop()
2926
2520
  response = loop.run_until_complete(
2927
- self._async_get_data_fields_by_name(filter, body, start_from, page_size, output_format, output_format_set))
2521
+ self._async_get_data_fields_by_name(filter, classification_names, body, start_from, page_size,
2522
+ output_format, output_format_set))
2928
2523
  return response
2929
2524
 
2930
- async def _async_get_data_field_by_guid(self, guid: str, body: dict = None,
2931
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2525
+ @dynamic_catch
2526
+ async def _async_get_data_field_by_guid(self, guid: str, element_type: str = None,
2527
+ body: dict | GetRequestBody = None,
2528
+ output_format: str = 'JSON',
2529
+ output_format_set: str | dict = None) -> list | str:
2932
2530
  """ Get the data class elements for the specified GUID.
2933
2531
  Async version.
2934
2532
 
@@ -2973,19 +2571,17 @@ r replace_all_properties: bool, default = False
2973
2571
  """
2974
2572
 
2975
2573
  url = (f"{base_path(self, self.view_server)}/data-fields/{guid}/retrieve")
2976
- if body:
2977
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
2978
- else:
2979
- response: Response = await self._async_make_request("POST", url)
2574
+ type = element_type if element_type else "DataField"
2575
+ response = await self._async_get_guid_request(url, _type=type,
2576
+ _gen_output=self._generate_data_field_output,
2577
+ output_format=output_format, output_format_set=output_format_set,
2578
+ body=body)
2980
2579
 
2981
- elements = response.json().get("element", NO_ELEMENTS_FOUND)
2982
- if type(elements) is str:
2983
- return NO_ELEMENTS_FOUND
2984
- if output_format != 'JSON': # return other representations
2985
- return self._generate_data_field_output(elements, None, output_format, output_format_set)
2986
- return elements
2580
+ return response
2987
2581
 
2988
- def get_data_field_by_guid(self, guid: str, body: str = None, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
2582
+ @dynamic_catch
2583
+ def get_data_field_by_guid(self, guid: str, element_type: str = None, body: str | GetRequestBody = None,
2584
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
2989
2585
  """ Get the data structure metadata element with the specified unique identifier..
2990
2586
 
2991
2587
  Parameters
@@ -3028,7 +2624,8 @@ r replace_all_properties: bool, default = False
3028
2624
  """
3029
2625
 
3030
2626
  loop = asyncio.get_event_loop()
3031
- response = loop.run_until_complete(self._async_get_data_field_by_guid(guid, body, output_format, output_format_set))
2627
+ response = loop.run_until_complete(self._async_get_data_field_by_guid(guid, element_type,
2628
+ body, output_format, output_format_set))
3032
2629
  return response
3033
2630
 
3034
2631
  ###
@@ -3037,7 +2634,8 @@ r replace_all_properties: bool, default = False
3037
2634
  # https://egeria-project.org/concepts/data-class
3038
2635
  #
3039
2636
  #
3040
- async def _async_create_data_class(self, body: dict) -> str:
2637
+ @dynamic_catch
2638
+ async def _async_create_data_class(self, body: dict | NewElementRequestBody) -> str:
3041
2639
  """
3042
2640
  Create a new data class with parameters defined in the body. Async version.
3043
2641
 
@@ -3156,10 +2754,10 @@ r replace_all_properties: bool, default = False
3156
2754
 
3157
2755
  url = f"{base_path(self, self.view_server)}/data-classes"
3158
2756
 
3159
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
3160
- return response.json().get("guid", NO_ELEMENTS_FOUND)
2757
+ return await self._async_create_element_body_request(url, "DataClass", body)
3161
2758
 
3162
- def create_data_class(self, body: dict) -> str:
2759
+ @dynamic_catch
2760
+ def create_data_class(self, body: dict | NewElementRequestBody) -> str:
3163
2761
  """
3164
2762
  Create a new data class with parameters defined in the body..
3165
2763
 
@@ -3280,7 +2878,8 @@ r replace_all_properties: bool, default = False
3280
2878
  response = loop.run_until_complete(self._async_create_data_class(body))
3281
2879
  return response
3282
2880
 
3283
- async def _async_create_data_class_from_template(self, body: dict) -> str:
2881
+ @dynamic_catch
2882
+ async def _async_create_data_class_from_template(self, body: dict | TemplateRequestBody) -> str:
3284
2883
  """
3285
2884
  Create a new metadata element to represent a data class using an existing metadata element as a template.
3286
2885
  The template defines additional classifications and relationships that should be added to the new element.
@@ -3349,11 +2948,10 @@ r replace_all_properties: bool, default = False
3349
2948
  """
3350
2949
 
3351
2950
  url = f"{base_path(self, self.view_server)}/data-classes/from-template"
2951
+ return await self._async_create_element_from_template(url, body)
3352
2952
 
3353
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
3354
- return response.json().get("guid", NO_ELEMENTS_FOUND)
3355
-
3356
- def create_data_class_from_template(self, body: dict) -> str:
2953
+ @dynamic_catch
2954
+ def create_data_class_from_template(self, body: dict | TemplateRequestBody) -> str:
3357
2955
  """
3358
2956
  Create a new metadata element to represent a data class using an existing metadata element as a template.
3359
2957
  The template defines additional classifications and relationships that should be added to the new element.
@@ -3424,8 +3022,9 @@ r replace_all_properties: bool, default = False
3424
3022
  response = loop.run_until_complete(self._async_create_data_class_from_template(body))
3425
3023
  return response
3426
3024
 
3427
- async def _async_update_data_class(self, data_class_guid: str, body: dict,
3428
- replace_all_properties: bool = False) -> None:
3025
+ @dynamic_catch
3026
+ async def _async_update_data_class(self, data_class_guid: str, body: dict | UpdateElementRequestBody,
3027
+ ) -> None:
3429
3028
  """
3430
3029
  Update the properties of a data class. Async version.
3431
3030
 
@@ -3435,9 +3034,7 @@ r replace_all_properties: bool, default = False
3435
3034
  - the GUID of the data class to be updated.
3436
3035
  body: dict
3437
3036
  - a dictionary containing the properties of the data structure to be created.
3438
- replace_all_properties: bool, default = False
3439
- - if true, then all properties will be replaced with the new ones. Otherwise, only the specified ones
3440
- will be replaced.
3037
+
3441
3038
  Returns
3442
3039
  -------
3443
3040
  None
@@ -3491,14 +3088,13 @@ r replace_all_properties: bool, default = False
3491
3088
  }
3492
3089
  }
3493
3090
  """
3494
- replace_all_properties_s = str(replace_all_properties).lower()
3495
3091
 
3496
- url = (f"{base_path(self, self.view_server)}/data-classes/{data_class_guid}/update?"
3497
- f"replaceAllProperties={replace_all_properties_s}")
3092
+ url = f"{base_path(self, self.view_server)}/data-classes/{data_class_guid}/update"
3093
+ await self._async_update_element_body_request(url, ["DataClass"], body)
3094
+ logger.info(f"Data class {data_class_guid} updated.")
3498
3095
 
3499
- await self._async_make_request("POST", url, body_slimmer(body))
3500
-
3501
- def update_data_class(self, data_class_guid: str, body: dict.get, replace_all_properties: bool = False) -> None:
3096
+ @dynamic_catch
3097
+ def update_data_class(self, data_class_guid: str, body: dict | UpdateElementRequestBody) -> None:
3502
3098
  """
3503
3099
  Update the properties of a data class.
3504
3100
 
@@ -3508,9 +3104,7 @@ r replace_all_properties: bool, default = False
3508
3104
  - the GUID of the data class to be updated.
3509
3105
  body: dict
3510
3106
  - a dictionary containing the properties of the data structure to be created.
3511
- replace_all_properties: bool, default = False
3512
- - if true, then all properties will be replaced with the new ones. Otherwise, only the specified ones
3513
- will be replaced.
3107
+
3514
3108
  Returns
3515
3109
  -------
3516
3110
  None
@@ -3566,10 +3160,11 @@ r replace_all_properties: bool, default = False
3566
3160
  """
3567
3161
 
3568
3162
  loop = asyncio.get_event_loop()
3569
- loop.run_until_complete(self._async_update_data_class(data_class_guid, body, replace_all_properties))
3163
+ loop.run_until_complete(self._async_update_data_class(data_class_guid, body))
3570
3164
 
3165
+ @dynamic_catch
3571
3166
  async def _async_link_nested_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3572
- body: dict = None) -> None:
3167
+ body: dict | NewRelationshipRequestBody = None) -> None:
3573
3168
  """
3574
3169
  Connect two data classes to show that one is used by the other when it is validating (typically a complex
3575
3170
  data item). Request body is optional. Async version.
@@ -3615,13 +3210,12 @@ r replace_all_properties: bool, default = False
3615
3210
  url = (f"{base_path(self, self.view_server)}/data-classes/{parent_data_class_guid}"
3616
3211
  f"/nested-data-classes/{child_data_class_guid}/attach")
3617
3212
 
3618
- if body is None:
3619
- await self._async_make_request("POST", url)
3620
- else:
3621
- await self._async_make_request("POST", url, body_slimmer(body))
3213
+ await self._async_new_relationship_request(url, ["MemberDataClassProperties"], body)
3214
+ logger.info(f"Data field {child_data_class_guid} attached to Data structure {parent_data_class_guid}.")
3622
3215
 
3216
+ @dynamic_catch
3623
3217
  def link_nested_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3624
- body: dict = None) -> None:
3218
+ body: dict | NewRelationshipRequestBody = None) -> None:
3625
3219
  """
3626
3220
  Connect a nested data class to a data class. Request body is optional.
3627
3221
 
@@ -3666,8 +3260,10 @@ r replace_all_properties: bool, default = False
3666
3260
  loop = asyncio.get_event_loop()
3667
3261
  loop.run_until_complete(self._async_link_nested_data_class(parent_data_class_guid, child_data_class_guid, body))
3668
3262
 
3263
+ @dynamic_catch
3669
3264
  async def _async_detach_nested_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3670
- body: dict = None) -> None:
3265
+ body: dict | DeleteRequestBody = None,
3266
+ cascade_delete: bool = False) -> None:
3671
3267
  """
3672
3268
  Detach two nested data classes from each other. Request body is optional. Async version.
3673
3269
 
@@ -3713,13 +3309,12 @@ r replace_all_properties: bool, default = False
3713
3309
  url = (f"{base_path(self, self.view_server)}/data-classes/{parent_data_class_guid}"
3714
3310
  f"/nested-data-classes/{child_data_class_guid}/detach")
3715
3311
 
3716
- if body is None:
3717
- await self._async_make_request("POST", url)
3718
- else:
3719
- await self._async_make_request("POST", url, body_slimmer(body))
3312
+ await self._async_delete_request(url, body, cascade_delete)
3313
+ logger.info(f"Data Class {child_data_class_guid} detached from data structure {parent_data_class_guid}.")
3720
3314
 
3315
+ @dynamic_catch
3721
3316
  def detach_nested_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3722
- body: dict = None) -> None:
3317
+ body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
3723
3318
  """
3724
3319
  Detach two nested data classes from each other. Request body is optional.
3725
3320
 
@@ -3763,10 +3358,11 @@ r replace_all_properties: bool, default = False
3763
3358
 
3764
3359
  loop = asyncio.get_event_loop()
3765
3360
  loop.run_until_complete(
3766
- self._async_detach_nested_data_class(parent_data_class_guid, child_data_class_guid, body))
3361
+ self._async_detach_nested_data_class(parent_data_class_guid, child_data_class_guid, body, cascade_delete))
3767
3362
 
3768
- async def _async_link_specialist_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3769
- body: dict = None) -> None:
3363
+ @dynamic_catch
3364
+ async def _async_link_specialized_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3365
+ body: dict | NewRelationshipRequestBody = None, ) -> None:
3770
3366
  """
3771
3367
  Connect two data classes to show that one provides a more specialist evaluation. Request body is optional.
3772
3368
  Async version.
@@ -3812,13 +3408,12 @@ r replace_all_properties: bool, default = False
3812
3408
  url = (f"{base_path(self, self.view_server)}/data-classes/{parent_data_class_guid}"
3813
3409
  f"/specialized-data-classes/{child_data_class_guid}/attach")
3814
3410
 
3815
- if body is None:
3816
- await self._async_make_request("POST", url)
3817
- else:
3818
- await self._async_make_request("POST", url, body_slimmer(body))
3411
+ await self._async_new_relationship_request(url, ["DataClassHierarchyProperties"], body)
3412
+ logger.info(f"Data field {child_data_class_guid} attached to Data structure {parent_data_class_guid}.")
3819
3413
 
3820
- def link_specialist_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3821
- body: dict = None) -> None:
3414
+ @dynamic_catch
3415
+ def link_specialized_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3416
+ body: dict | NewRelationshipRequestBody = None) -> None:
3822
3417
  """
3823
3418
  Connect two data classes to show that one provides a more specialist evaluation. Request body is optional.
3824
3419
 
@@ -3862,10 +3457,12 @@ r replace_all_properties: bool, default = False
3862
3457
 
3863
3458
  loop = asyncio.get_event_loop()
3864
3459
  loop.run_until_complete(
3865
- self._async_link_specialist_data_class(parent_data_class_guid, child_data_class_guid, body))
3460
+ self._async_link_specialized_data_class(parent_data_class_guid, child_data_class_guid, body))
3866
3461
 
3867
- async def _async_detach_specialist_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3868
- body: dict = None) -> None:
3462
+ @dynamic_catch
3463
+ async def _async_detach_specialized_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3464
+ body: dict | DeleteRequestBody = None,
3465
+ cascade_delete: bool = False) -> None:
3869
3466
  """
3870
3467
  Detach two data classes from each other. Request body is optional. Async version.
3871
3468
 
@@ -3911,13 +3508,12 @@ r replace_all_properties: bool, default = False
3911
3508
  url = (f"{base_path(self, self.view_server)}/data-classes/{parent_data_class_guid}"
3912
3509
  f"/specialized-data-classes/{child_data_class_guid}/detach")
3913
3510
 
3914
- if body is None:
3915
- await self._async_make_request("POST", url)
3916
- else:
3917
- await self._async_make_request("POST", url, body_slimmer(body))
3511
+ await self._async_delete_request(url, body, cascade_delete)
3512
+ logger.info(f"Data field {child_data_class_guid} detached from data structure {parent_data_class_guid}.")
3918
3513
 
3919
- def detach_specialist_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3920
- body: dict = None) -> None:
3514
+ @dynamic_catch
3515
+ def detach_specialized_data_class(self, parent_data_class_guid: str, child_data_class_guid: str,
3516
+ body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
3921
3517
  """
3922
3518
  Detach two data classes from each other. Request body is optional.
3923
3519
 
@@ -3961,9 +3557,12 @@ r replace_all_properties: bool, default = False
3961
3557
 
3962
3558
  loop = asyncio.get_event_loop()
3963
3559
  loop.run_until_complete(
3964
- self._async_detach_specialist_data_class(parent_data_class_guid, child_data_class_guid, body))
3560
+ self._async_detach_specialized_data_class(parent_data_class_guid, child_data_class_guid, body,
3561
+ cascade_delete))
3965
3562
 
3966
- async def _async_delete_data_class(self, data_class_guid: str, body: dict = None, cascade:bool= False) -> None:
3563
+ @dynamic_catch
3564
+ async def _async_delete_data_class(self, data_class_guid: str, body: dict | DeleteRequestBody = None,
3565
+ cascade_delete: bool = False) -> None:
3967
3566
  """
3968
3567
  Delete a data class. Request body is optional. Async version.
3969
3568
 
@@ -4006,15 +3605,17 @@ r replace_all_properties: bool, default = False
4006
3605
 
4007
3606
 
4008
3607
  """
4009
- cascade_s = str(cascade).lower()
4010
- url = f"{base_path(self, self.view_server)}/data-classes/{data_class_guid}/delete?cascadedDelete={cascade_s}"
4011
3608
 
4012
- if body is None:
4013
- await self._async_make_request("POST", url)
4014
- else:
4015
- await self._async_make_request("POST", url, body_slimmer(body))
3609
+ url = f"{base_path(self, self.view_server)}/data-classes/{data_class_guid}/delete"
4016
3610
 
4017
- def delete_data_class(self, data_class_guid: str, body: dict = None, cascade:bool= False) -> None:
3611
+ await self._async_delete_request(url, body, cascade_delete)
3612
+ logger.info(f"Data structure {data_class_guid} deleted.")
3613
+
3614
+ @dynamic_catch
3615
+ def delete_data_class(self,
3616
+ data_class_guid: str,
3617
+ body: dict | DeleteRequestBody = None,
3618
+ cascade_delete: bool = False) -> None:
4018
3619
  """
4019
3620
  Delete a data class. Request body is optional.
4020
3621
 
@@ -4058,10 +3659,12 @@ r replace_all_properties: bool, default = False
4058
3659
  """
4059
3660
 
4060
3661
  loop = asyncio.get_event_loop()
4061
- loop.run_until_complete(self._async_delete_data_class(data_class_guid, body, cascade))
3662
+ loop.run_until_complete(self._async_delete_data_class(data_class_guid, body, cascade_delete))
4062
3663
 
4063
- async def _async_find_all_data_classes(self, start_from: int = 0, page_size: int = max_paging_size,
4064
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3664
+ @dynamic_catch
3665
+ async def _async_find_all_data_classes(self,
3666
+ output_format: str = 'JSON',
3667
+ output_format_set: str | dict = None) -> list | str:
4065
3668
  """ Returns a list of all data classes. Async version.
4066
3669
 
4067
3670
  Parameters
@@ -4092,24 +3695,14 @@ r replace_all_properties: bool, default = False
4092
3695
 
4093
3696
  """
4094
3697
 
4095
- possible_query_params = query_string(
4096
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", 'false'), ("endsWith", 'false'),
4097
- ("ignoreCase", 'true')])
4098
-
4099
- url = (f"{base_path(self, self.view_server)}/data-classes/by-search-string"
4100
- f"{possible_query_params}")
3698
+ url = f"{base_path(self, self.view_server)}/data-classes/by-search-string"
4101
3699
 
4102
- response: Response = await self._async_make_request("POST", url)
3700
+ return self.find_data_classes(search_string="*", output_format=output_format,
3701
+ output_format_set=output_format_set)
4103
3702
 
4104
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
4105
- if type(elements) is str:
4106
- return NO_ELEMENTS_FOUND
4107
- if output_format != 'JSON': # return other representations
4108
- return self._generate_data_class_output(elements, filter, output_format, output_format_set)
4109
- return elements
4110
-
4111
- def find_all_data_classes(self, start_from: int = 0, page_size: int = max_paging_size,
4112
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3703
+ @dynamic_catch
3704
+ def find_all_data_classes(self,
3705
+ output_format: str = 'JSON', output_format_set: str | dict = None) -> list | str:
4113
3706
  """ Returns a list of all data classes.
4114
3707
 
4115
3708
  Parameters
@@ -4139,149 +3732,16 @@ r replace_all_properties: bool, default = False
4139
3732
 
4140
3733
  """
4141
3734
 
4142
- loop = asyncio.get_event_loop()
4143
- response = loop.run_until_complete(self._async_find_all_data_classes(start_from, page_size, output_format, output_format_set))
4144
- return response
4145
-
4146
- async def _async_find_data_classes_w_body(self, body: dict, start_from: int = 0, page_size: int = max_paging_size,
4147
- starts_with: bool = True, ends_with: bool = False,
4148
- ignore_case: bool = True, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
4149
- """ Retrieve the list of data class metadata elements that contain the search string.
4150
- Async version.
4151
-
4152
- Parameters
4153
- ----------
4154
- body: dict
4155
- - A structure containing the search criteria. (example below)
4156
- start_from: int, default = 0
4157
- - index of the list to start from (0 for start).
4158
- page_size
4159
- - maximum number of elements to return.
4160
- starts_with: bool, default = True
4161
- - if True, the search string filters from the beginning of the string.
4162
- ends_with: bool, default = False
4163
- - if True, the search string filters from the end of the string.
4164
- ignore_case: bool, default = True
4165
- - If True, the case of the search string is ignored.
4166
- output_format: str, default = "DICT"
4167
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
4168
- output_format_set: str|dict, optional, default = None
4169
- - The desired output columns/field options.
4170
-
4171
-
4172
- Returns
4173
- -------
4174
- [dict] | str
4175
- Returns a string if no elements are found and a list of dict with the results.
4176
-
4177
- Raises
4178
- ------
4179
- InvalidParameterException
4180
- one of the parameters is null or invalid or
4181
- PropertyServerException
4182
- There is a problem adding the element properties to the metadata repository or
4183
- UserNotAuthorizedException
4184
- the requesting user is not authorized to issue this request.
4185
-
4186
- Notes:
4187
-
4188
- {
4189
- "class": "FilterRequestBody",
4190
- "asOfTime": "{{$isoTimestamp}}",
4191
- "effectiveTime": "{{$isoTimestamp}}",
4192
- "forLineage": false,
4193
- "forDuplicateProcessing : false,
4194
- "limitResultsByStatus": ["ACTIVE"],
4195
- "sequencingOrder": "PROPERTY_ASCENDING",
4196
- "sequencingProperty": "qualifiedName",
4197
- "filter": ""
4198
- }
4199
-
4200
- """
4201
-
4202
- starts_with_s = str(starts_with).lower()
4203
- ends_with_s = str(ends_with).lower()
4204
- ignore_case_s = str(ignore_case).lower()
4205
- possible_query_params = query_string(
4206
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", starts_with_s),
4207
- ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
4208
-
4209
- url = (f"{base_path(self, self.view_server)}/data-classes/by-search-string"
4210
- f"{possible_query_params}")
4211
-
4212
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
4213
-
4214
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
4215
- if type(elements) is str:
4216
- return NO_ELEMENTS_FOUND
4217
- if output_format != 'JSON': # return other representations
4218
- return self._generate_data_class_output(elements, filter, output_format, output_format_set)
4219
- return elements
4220
-
4221
- def find_data_classes_w_body(self, body: dict, start_from: int = 0, page_size: int = max_paging_size,
4222
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
4223
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
4224
- """ Retrieve the list of data class metadata elements that contain the search string.
4225
-
4226
- Parameters
4227
- ----------
4228
- body: dict
4229
- - A structure containing the search criteria. (example below)
4230
- start_from: int, default = 0
4231
- - index of the list to start from (0 for start).
4232
- page_size
4233
- - maximum number of elements to return.
4234
- starts_with: bool, default = True
4235
- - if True, the search string filters from the beginning of the string.
4236
- ends_with: bool, default = False
4237
- - if True, the search string filters from the end of the string.
4238
- ignore_case: bool, default = True
4239
- - If True, the case of the search string is ignored.
4240
- output_format: str, default = "DICT"
4241
- - output format of the data structure. Possible values: "DICT", "JSON", "MERMAID".
4242
- output_format_set: str|dict, optional, default = None
4243
- - The desired output columns/field options.
4244
-
4245
-
4246
- Returns
4247
- -------
4248
- [dict] | str
4249
- Returns a string if no elements are found and a list of dict with the results.
4250
-
4251
- Raises
4252
- ------
4253
- InvalidParameterException
4254
- one of the parameters is null or invalid or
4255
- PropertyServerException
4256
- There is a problem adding the element properties to the metadata repository or
4257
- UserNotAuthorizedException
4258
- the requesting user is not authorized to issue this request.
4259
-
4260
- Notes:
4261
-
4262
- {
4263
- "class": "FilterRequestBody",
4264
- "asOfTime": "{{$isoTimestamp}}",
4265
- "effectiveTime": "{{$isoTimestamp}}",
4266
- "forLineage": false,
4267
- "forDuplicateProcessing : false,
4268
- "limitResultsByStatus": ["ACTIVE"],
4269
- "sequencingOrder": "PROPERTY_ASCENDING",
4270
- "sequencingProperty": "qualifiedName",
4271
- "filter": ""
4272
- }
4273
-
4274
- """
4275
-
4276
3735
  loop = asyncio.get_event_loop()
4277
3736
  response = loop.run_until_complete(
4278
- self._async_find_data_classes_w_body(body, start_from, page_size, starts_with, ends_with, ignore_case,
4279
- output_format, output_format_set))
3737
+ self._async_find_all_data_classes(output_format, output_format_set))
4280
3738
  return response
4281
3739
 
4282
- async def _async_find_data_classes(self, filter: str, start_from: int = 0, page_size: int = max_paging_size,
3740
+ @dynamic_catch
3741
+ async def _async_find_data_classes(self, search_string: str, start_from: int = 0, page_size: int = max_paging_size,
4283
3742
  starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
4284
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3743
+ output_format: str = 'JSON', output_format_set: str | dict = None,
3744
+ body: dict | SearchStringRequestBody = None) -> list | str:
4285
3745
  """ Find the list of data class elements that contain the search string.
4286
3746
  Async version.
4287
3747
 
@@ -4320,33 +3780,19 @@ r replace_all_properties: bool, default = False
4320
3780
  the requesting user is not authorized to issue this request.
4321
3781
 
4322
3782
  """
4323
- if filter == "*":
4324
- filter = None
4325
- body = {"filter": filter}
4326
-
4327
- starts_with_s = str(starts_with).lower()
4328
- ends_with_s = str(ends_with).lower()
4329
- ignore_case_s = str(ignore_case).lower()
4330
3783
 
4331
- possible_query_params = query_string(
4332
- [("startFrom", start_from), ("pageSize", page_size), ("startsWith", starts_with_s), ("endsWith", ends_with_s),
4333
- ("ignoreCase", ignore_case_s)])
3784
+ url = f"{base_path(self, self.view_server)}/data-classes/by-search-string"
3785
+ return await self._async_find_request(url, "DataClass", self._generate_data_class_output,
3786
+ search_string, start_from=start_from, page_size=page_size,
3787
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
3788
+ body=body, output_format=output_format,
3789
+ output_format_set=output_format_set)
4334
3790
 
4335
- url = (f"{base_path(self, self.view_server)}/data-classes/by-search-string"
4336
- f"{possible_query_params}")
4337
-
4338
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
4339
-
4340
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
4341
- if type(elements) is str:
4342
- return NO_ELEMENTS_FOUND
4343
- if output_format != 'JSON': # return other representations
4344
- return self._generate_data_class_output(elements, filter, output_format, output_format_set)
4345
- return elements
4346
-
4347
- def find_data_classes(self, filter: str, start_from: int = 0, page_size: int = max_paging_size,
3791
+ @dynamic_catch
3792
+ def find_data_classes(self, search_string: str, start_from: int = 0, page_size: int = max_paging_size,
4348
3793
  starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True,
4349
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3794
+ output_format: str = 'JSON', output_format_set: str | dict = None,
3795
+ body: dict | SearchStringRequestBody = None) -> list | str:
4350
3796
  """ Retrieve the list of data fields elements that contain the search string filter.
4351
3797
 
4352
3798
  Parameters
@@ -4388,13 +3834,16 @@ r replace_all_properties: bool, default = False
4388
3834
 
4389
3835
  loop = asyncio.get_event_loop()
4390
3836
  response = loop.run_until_complete(
4391
- self._async_find_data_classes(filter, start_from, page_size, starts_with, ends_with, ignore_case,
4392
- output_format, output_format_set))
3837
+ self._async_find_data_classes(search_string, start_from, page_size, starts_with, ends_with, ignore_case,
3838
+ output_format, output_format_set, body))
4393
3839
  return response
4394
3840
 
4395
- async def _async_get_data_classes_by_name(self, filter: str, body: dict = None, start_from: int = 0,
4396
- page_size: int = max_paging_size,
4397
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3841
+ @dynamic_catch
3842
+ async def _async_get_data_classes_by_name(self, filter_string: str, classification_names: list[str],
3843
+ body: dict | FilterRequestBody = None, start_from: int = 0,
3844
+ page_size: int = 0,
3845
+ output_format: str = 'JSON',
3846
+ output_format_set: str | dict = None) -> list | str:
4398
3847
  """ Get the list of data class metadata elements with a matching name to the search string filter.
4399
3848
  Async version.
4400
3849
 
@@ -4441,25 +3890,24 @@ r replace_all_properties: bool, default = False
4441
3890
  "filter": "Add name here"
4442
3891
  }
4443
3892
  """
4444
- if body is None:
4445
- body = {"filter": filter}
4446
-
4447
- possible_query_params = query_string([("startFrom", start_from), ("pageSize", page_size), ])
4448
3893
 
4449
- url = (f"{base_path(self, self.view_server)}/data-classes/by-name"
4450
- f"{possible_query_params}")
3894
+ url = f"{base_path(self, self.view_server)}/data-classes/by-name"
4451
3895
 
4452
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
3896
+ response = await self._async_get_name_request(url, _type="DataClass",
3897
+ _gen_output=self._generate_data_class_output,
3898
+ filter_string=filter_string,
3899
+ classification_names=classification_names,
3900
+ start_from=start_from, page_size=page_size,
3901
+ output_format=output_format, output_format_set=output_format_set,
3902
+ body=body)
4453
3903
 
4454
- elements = response.json().get("elements", NO_ELEMENTS_FOUND)
4455
- if type(elements) is str:
4456
- return NO_ELEMENTS_FOUND
4457
- if output_format != 'JSON': # return other representations
4458
- return self._generate_data_class_output(elements, filter, output_format, output_format_set)
4459
- return elements
3904
+ return response
4460
3905
 
4461
- def get_data_classes_by_name(self, filter: str, body: dict = None, start_from: int = 0,
4462
- page_size: int = max_paging_size, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3906
+ @dynamic_catch
3907
+ def get_data_classes_by_name(self, filter_string: str, classification_names: list[str] = None,
3908
+ body: dict | FilterRequestBody = None, start_from: int = 0,
3909
+ page_size: int = max_paging_size, output_format: str = 'JSON',
3910
+ output_format_set: str | dict = None) -> list | str:
4463
3911
  """ Get the list of data class elements with a matching name to the search string filter.
4464
3912
 
4465
3913
  Parameters
@@ -4510,11 +3958,16 @@ r replace_all_properties: bool, default = False
4510
3958
 
4511
3959
  loop = asyncio.get_event_loop()
4512
3960
  response = loop.run_until_complete(
4513
- self._async_get_data_classes_by_name(filter, body, start_from, page_size, output_format, output_format_set))
3961
+ self._async_get_data_classes_by_name(filter_string, classification_names, body,
3962
+ start_from, page_size, output_format, output_format_set
3963
+ ))
4514
3964
  return response
4515
3965
 
4516
- async def _async_get_data_class_by_guid(self, guid: str, body: dict = None,
4517
- output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
3966
+ @dynamic_catch
3967
+ async def _async_get_data_class_by_guid(self, guid: str, element_type: str = None,
3968
+ body: dict | GetRequestBody = None,
3969
+ output_format: str = 'JSON',
3970
+ output_format_set: str | dict = None) -> list | str:
4518
3971
  """ Get the data class elements for the specified GUID.
4519
3972
  Async version.
4520
3973
 
@@ -4558,19 +4011,18 @@ r replace_all_properties: bool, default = False
4558
4011
  """
4559
4012
 
4560
4013
  url = (f"{base_path(self, self.view_server)}/data-classes/{guid}/retrieve")
4561
- if body:
4562
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
4563
- else:
4564
- response: Response = await self._async_make_request("POST", url)
4014
+ type = element_type if element_type else "DataClass"
4565
4015
 
4566
- elements = response.json().get("element", NO_ELEMENTS_FOUND)
4567
- if type(elements) is str:
4568
- return NO_ELEMENTS_FOUND
4569
- if output_format != 'JSON': # return other representations
4570
- return self._generate_data_class_output(elements, filter, output_format, output_format_set)
4571
- return elements
4016
+ response = await self._async_get_guid_request(url, _type=type,
4017
+ _gen_output=self._generate_data_class_output,
4018
+ output_format=output_format, output_format_set=output_format_set,
4019
+ body=body)
4020
+ return response
4572
4021
 
4573
- def get_data_class_by_guid(self, guid: str, body: str = None, output_format: str = 'JSON', output_format_set: str|dict = None) -> list | str:
4022
+ @dynamic_catch
4023
+ def get_data_class_by_guid(self, guid: str, element_type: str = None, body: dict | FilterRequestBody = None,
4024
+ output_format: str = 'JSON',
4025
+ output_format_set: str | dict = None) -> list | str:
4574
4026
  """ Get the data structure metadata element with the specified unique identifier..
4575
4027
 
4576
4028
  Parameters
@@ -4613,7 +4065,8 @@ r replace_all_properties: bool, default = False
4613
4065
  """
4614
4066
 
4615
4067
  loop = asyncio.get_event_loop()
4616
- response = loop.run_until_complete(self._async_get_data_class_by_guid(guid, body, output_format, output_format_set))
4068
+ response = loop.run_until_complete(
4069
+ self._async_get_data_class_by_guid(guid, element_type, body, output_format, output_format_set))
4617
4070
  return response
4618
4071
 
4619
4072
  ###
@@ -4621,8 +4074,9 @@ r replace_all_properties: bool, default = False
4621
4074
  # Assembling a data specification
4622
4075
  # https://egeria-project.org/concepts/data-specification
4623
4076
  #
4077
+ @dynamic_catch
4624
4078
  async def _async_link_data_class_definition(self, data_definition_guid: str, data_class_guid: str,
4625
- body: dict = None) -> None:
4079
+ body: dict | NewRelationshipRequestBody = None) -> None:
4626
4080
  """
4627
4081
  Connect an element that is part of a data design to a data class to show that the data class should be used as
4628
4082
  the specification for the data values when interpreting the data definition. Request body is optional.
@@ -4668,12 +4122,12 @@ r replace_all_properties: bool, default = False
4668
4122
  url = (f"{base_path(self, self.view_server)}/data-definitions/{data_definition_guid}"
4669
4123
  f"/data-class-definition/{data_class_guid}/attach")
4670
4124
 
4671
- if body is None:
4672
- await self._async_make_request("POST", url)
4673
- else:
4674
- await self._async_make_request("POST", url, body_slimmer(body))
4125
+ await self._async_new_relationship_request(url, ["DataClassDefinitionProperties"], body)
4126
+ logger.info(f"Data class {data_class_guid} attached to Data definition {data_definition_guid}.")
4675
4127
 
4676
- def link_data_class_definition(self, data_definition_guid: str, data_class_guid: str, body: dict = None) -> None:
4128
+ @dynamic_catch
4129
+ def link_data_class_definition(self, data_definition_guid: str, data_class_guid: str,
4130
+ body: dict | NewRelationshipRequestBody = None) -> None:
4677
4131
  """
4678
4132
  Connect an element that is part of a data design to a data class to show that the data class should be used as
4679
4133
  the specification for the data values when interpreting the data definition. Request body is optional.
@@ -4719,8 +4173,10 @@ r replace_all_properties: bool, default = False
4719
4173
  loop = asyncio.get_event_loop()
4720
4174
  loop.run_until_complete(self._async_link_data_class_definition(data_definition_guid, data_class_guid, body))
4721
4175
 
4176
+ @dynamic_catch
4722
4177
  async def _async_detach_data_class_definition(self, data_definition_guid: str, data_class_guid: str,
4723
- body: dict = None) -> None:
4178
+ body: dict | DeleteRequestBody = None,
4179
+ cascade_delete: bool = False) -> None:
4724
4180
  """
4725
4181
  Detach a data definition from a data class. Request body is optional. Async version.
4726
4182
 
@@ -4766,12 +4222,12 @@ r replace_all_properties: bool, default = False
4766
4222
  url = (f"{base_path(self, self.view_server)}/data-definitions/{data_definition_guid}"
4767
4223
  f"/data-class-definition/{data_class_guid}/detach")
4768
4224
 
4769
- if body is None:
4770
- await self._async_make_request("POST", url)
4771
- else:
4772
- await self._async_make_request("POST", url, body_slimmer(body))
4225
+ await self._async_delete_request(url, body, cascade_delete)
4226
+ logger.info(f"Data class {data_class_guid} detached from data definition {data_definition_guid}.")
4773
4227
 
4774
- def detach_data_class_definition(self, data_definition_guid: str, data_class_guid: str, body: dict = None) -> None:
4228
+ @dynamic_catch
4229
+ def detach_data_class_definition(self, data_definition_guid: str, data_class_guid: str,
4230
+ body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
4775
4231
  """
4776
4232
  Detach a data definition from a data class. Request body is optional.
4777
4233
 
@@ -4815,10 +4271,12 @@ r replace_all_properties: bool, default = False
4815
4271
  """
4816
4272
 
4817
4273
  loop = asyncio.get_event_loop()
4818
- loop.run_until_complete(self._async_detach_data_class_definition(data_definition_guid, data_class_guid, body))
4274
+ loop.run_until_complete(
4275
+ self._async_detach_data_class_definition(data_definition_guid, data_class_guid, body, cascade_delete))
4819
4276
 
4277
+ @dynamic_catch
4820
4278
  async def _async_link_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str,
4821
- body: dict = None) -> None:
4279
+ body: dict | NewRelationshipRequestBody = None) -> None:
4822
4280
  """
4823
4281
  Connect an element that is part of a data design to a glossary term to show that the term should be used as
4824
4282
  the semantic definition for the data values when interpreting the data definition. Request body is optional.
@@ -4865,12 +4323,12 @@ r replace_all_properties: bool, default = False
4865
4323
  url = (f"{base_path(self, self.view_server)}/data-definitions/{data_definition_guid}"
4866
4324
  f"/semantic-definition/{glossary_term_guid}/attach")
4867
4325
 
4868
- if body is None:
4869
- await self._async_make_request("POST", url)
4870
- else:
4871
- await self._async_make_request("POST", url, body_slimmer(body))
4326
+ await self._async_new_relationship_request(url, ["SemanticDefinitionProperties"], body)
4327
+ logger.info(f"Data class {data_definition_guid} attached to term definition {glossary_term_guid}.")
4872
4328
 
4873
- def link_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str, body: dict = None) -> None:
4329
+ @dynamic_catch
4330
+ def link_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str,
4331
+ body: dict | NewRelationshipRequestBody = None) -> None:
4874
4332
  """
4875
4333
  Connect an element that is part of a data design to a glossary term to show that the term should be used as
4876
4334
  the semantic definition for the data values when interpreting the data definition. Request body is optional.
@@ -4917,8 +4375,10 @@ r replace_all_properties: bool, default = False
4917
4375
  loop = asyncio.get_event_loop()
4918
4376
  loop.run_until_complete(self._async_link_semantic_definition(data_definition_guid, glossary_term_guid, body))
4919
4377
 
4378
+ @dynamic_catch
4920
4379
  async def _async_detach_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str,
4921
- body: dict = None) -> None:
4380
+ body: dict | DeleteRequestBody = None,
4381
+ cascade_delete: bool = False) -> None:
4922
4382
  """
4923
4383
  Detach a data definition from a glossary term. Request body is optional. Async version.
4924
4384
 
@@ -4963,13 +4423,12 @@ r replace_all_properties: bool, default = False
4963
4423
 
4964
4424
  url = (f"{base_path(self, self.view_server)}/data-definitions/{data_definition_guid}"
4965
4425
  f"/semantic-definition/{glossary_term_guid}/detach")
4426
+ await self._async_delete_request(url, body, cascade_delete)
4427
+ logger.info(f"Data definition {data_definition_guid} detached from term {glossary_term_guid}.")
4966
4428
 
4967
- if body is None:
4968
- await self._async_make_request("POST", url)
4969
- else:
4970
- await self._async_make_request("POST", url, body_slimmer(body))
4971
-
4972
- def detach_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str, body: dict = None) -> None:
4429
+ @dynamic_catch
4430
+ def detach_semantic_definition(self, data_definition_guid: str, glossary_term_guid: str,
4431
+ body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
4973
4432
  """
4974
4433
  Detach a data definition from a glossary term. Request body is optional.
4975
4434
 
@@ -5013,10 +4472,13 @@ r replace_all_properties: bool, default = False
5013
4472
  """
5014
4473
 
5015
4474
  loop = asyncio.get_event_loop()
5016
- loop.run_until_complete(self._async_detach_semantic_definition(data_definition_guid, glossary_term_guid, body))
4475
+ loop.run_until_complete(
4476
+ self._async_detach_semantic_definition(data_definition_guid, glossary_term_guid, body, cascade_delete))
4477
+
4478
+
5017
4479
 
5018
4480
  async def _async_link_certification_type_to_data_structure(self, certification_type_guid: str,
5019
- data_structure_guid: str, body: dict = None) -> None:
4481
+ data_structure_guid: str, body: dict | NewRelationshipRequestBody = None) -> None:
5020
4482
  """
5021
4483
  Connect a certification type to a data structure to guide the survey action service (that checks the data
5022
4484
  quality of a data resource as part of certifying it with the supplied certification type) to the definition
@@ -5065,14 +4527,12 @@ r replace_all_properties: bool, default = False
5065
4527
 
5066
4528
  url = (f"{base_path(self, self.view_server)}/certification-types/{certification_type_guid}"
5067
4529
  f"/data-structure-definition/{data_structure_guid}/attach")
4530
+ await self._async_new_relationship_request(url, ["CertificationTypeProperties"], body)
4531
+ logger.info(f"Certification type {certification_type_guid} linked to {data_structure_guid}.")
5068
4532
 
5069
- if body is None:
5070
- await self._async_make_request("POST", url)
5071
- else:
5072
- await self._async_make_request("POST", url, body_slimmer(body))
5073
4533
 
5074
4534
  def link_certification_type_to_data_structure(self, certification_type_guid: str, data_structure_guid: str,
5075
- body: dict = None) -> None:
4535
+ body: dict |NewRelationshipRequestBody = None) -> None:
5076
4536
  """
5077
4537
  Connect a certification type to a data structure to guide the survey action service (that checks the data
5078
4538
  quality of a data resource as part of certifying it with the supplied certification type) to the definition
@@ -5123,7 +4583,7 @@ r replace_all_properties: bool, default = False
5123
4583
  self._async_link_certification_type_to_data_structure(certification_type_guid, data_structure_guid, body))
5124
4584
 
5125
4585
  async def _async_detach_certification_type_from_data_structure(self, certification_type_guid: str,
5126
- data_structure_guid: str, body: dict = None) -> None:
4586
+ data_structure_guid: str, body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
5127
4587
  """
5128
4588
  Detach a data structure from a certification type. Request body is optional. Async version.
5129
4589
 
@@ -5168,13 +4628,12 @@ r replace_all_properties: bool, default = False
5168
4628
  url = (f"{base_path(self, self.view_server)}/certification-stypes/{certification_type_guid}"
5169
4629
  f"/data-structure-definition/{data_structure_guid}/detach")
5170
4630
 
5171
- if body is None:
5172
- await self._async_make_request("POST", url)
5173
- else:
5174
- await self._async_make_request("POST", url, body_slimmer(body))
4631
+ await self._async_delete_request(url, body, cascade_delete)
4632
+ logger.info(f"Certification type {certification_type_guid} detached from data structure {data_structure_guid}.")
4633
+
5175
4634
 
5176
4635
  def detach_certification_type_from_data_structure(self, certification_type_guid: str, data_structure_guid: str,
5177
- body: dict = None) -> None:
4636
+ body: dict | DeleteRequestBody= None, cascade_delete: bool = False) -> None:
5178
4637
  """
5179
4638
  Detach a data structure from a certification type. Request body is optional.
5180
4639
 
@@ -5219,125 +4678,144 @@ r replace_all_properties: bool, default = False
5219
4678
  loop = asyncio.get_event_loop()
5220
4679
  loop.run_until_complete(
5221
4680
  self._async_detach_certification_type_from_data_structure(certification_type_guid, data_structure_guid,
5222
- body))
5223
-
5224
- def _extract_data_structure_properties(self, element: dict) -> dict:
5225
- """
5226
- Extract common properties from a data structure element.
5227
-
5228
- Args:
5229
- element (dict): The data structure element
5230
-
5231
- Returns:
5232
- dict: Dictionary of extracted properties
5233
- """
5234
- props = _extract_referenceable_properties(element)
5235
-
5236
- props['properties'] = element.get('properties', {})
5237
-
5238
- props['namespace'] = props['properties'].get("namespace", "") or ""
5239
-
5240
- classification_names = []
5241
- for c in props['classifications']:
5242
- classification_names.append(c.get("classificationName", None))
5243
- props['classifications'] = classification_names
5244
-
5245
- # Now lets get the related elements
5246
- associated_elements = self.get_data_rel_elements_dict(element)
5247
- props['data_specs'] = associated_elements.get("member_of_data_spec_qnames", [])
5248
-
5249
- # data_structures = associated_elements.get("member_of_data_struct_qnames", [])
5250
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames", [])
5251
- props['parent_names'] = associated_elements.get("parent_qnames", [])
5252
- props['member_data_fields'] = associated_elements.get("member_data_field_qnames", [])
4681
+ body, cascade_delete))
5253
4682
 
5254
- props['mermaid'] = element.get('mermaidGraph', "") or ""
5255
4683
 
5256
- return props
5257
4684
 
5258
- def _extract_data_class_properties(self, element: dict) -> dict:
5259
- """
5260
- Extract common properties from a data class element.
5261
-
5262
- Args:
5263
- element (dict): The data class element
5264
-
5265
- Returns:
5266
- dict: Dictionary of extracted properties
5267
- """
5268
- props = _extract_referenceable_properties(element)
5269
- properties = element.get('properties', {})
5270
- props['properties'] = properties
5271
-
5272
- classification_names = []
5273
- for c in props['classifications']:
5274
- classification_names.append(c.get("classificationName", None))
5275
- props['classifications'] = classification_names
5276
-
5277
- props['namespace'] = props['properties'].get("namespace", "") or ""
5278
-
5279
- props['data_type'] = properties.get('dataType', "") or ""
5280
- props['match_property_names'] = properties.get('matchPropertyNames', []) or []
5281
- props['match_threshold'] = properties.get('matchThreshold', 0)
5282
- props['allow_duplicate_values'] = properties.get('allowDuplicateValues', False)
5283
- props['is_case_sensitive'] = properties.get('isCaseSensitive', False)
5284
- props['is_nullable'] = properties.get('isNullable', False)
5285
-
5286
-
5287
- # Now lets get the related elements
5288
- associated_elements = self.get_data_rel_elements_dict(element)
5289
- props['data_dictionaries'] = associated_elements.get("member_of_data_dicts_qnames", [])
5290
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames", [])
5291
- props['parent_names'] = associated_elements.get("parent_qnames", [])
5292
- props['nested_data_classes'] = associated_elements.get("nested_data_class_qnames", [])
5293
- props['specialized_data_classes'] = associated_elements.get("specialized_data_class_qnames", [])
5294
- props['mermaid'] = element.get('mermaidGraph', "") or ""
5295
-
5296
- return props
5297
-
5298
- def _extract_data_field_properties(self, element: dict) -> dict:
5299
- """
5300
- Extract common properties from a data field element.
5301
-
5302
- Args:
5303
- element (dict): The data field element
5304
4685
 
5305
- Returns:
5306
- dict: Dictionary of extracted properties
4686
+ def _extract_data_structure_properties(self, element: dict, columns_struct: dict) -> dict:
5307
4687
  """
5308
- props = _extract_referenceable_properties(element)
5309
-
5310
- props['properties'] = element.get('properties', {})
5311
- props['namespace'] = props['properties'].get("namespace", "") or ""
5312
- properties = element.get('properties', {})
5313
-
5314
- classification_names = []
5315
- for c in props['classifications']:
5316
- classification_names.append(c.get("classificationName", None))
5317
- props['classifications'] = classification_names
5318
-
5319
- props['is_nullable'] = properties.get('isNullable', False)
5320
- props['data_type'] = properties.get('dataType', "") or ""
5321
- props['minimum_length'] = properties.get('minimumLength', 0)
5322
- props['length'] = properties.get('length', 0)
5323
- props['precision'] = properties.get('precision', 0)
5324
- props['ordered_values'] = properties.get('orderedValues', False)
5325
- props['sort_order'] = properties.get('sortOrder', "") or ""
4688
+ Populate columns_struct values for a Data Structure element using a standardized approach.
5326
4689
 
4690
+ - Populate values from element.properties via populate_columns_from_properties
4691
+ - Overlay header-derived values using _extract_referenceable_properties
4692
+ - Derive classifications as a comma-separated list
4693
+ - Populate relationship-based columns using get_required_relationships
4694
+ - Populate mermaid graph if requested
5327
4695
 
5328
- # Now lets get the related elements
5329
- associated_elements = self.get_data_rel_elements_dict(element)
5330
- props['data_dictionaries'] = associated_elements.get("member_of_data_dicts_qnames",[])
5331
- props['data_structures'] = associated_elements.get("data_structure_qnames",[])
5332
- props['assigned_meanings'] = associated_elements.get("assigned_meanings_qnames",[])
5333
- props['parent_names'] = associated_elements.get("parent_qnames",[])
5334
- props['data_class'] = associated_elements.get("data_class_qnames",[])
5335
- props['mermaid'] = element.get('mermaidGraph', "") or ""
5336
-
5337
- return props
4696
+ Returns the updated columns_struct.
4697
+ """
4698
+ # Start with properties-based values
4699
+ col_data = populate_columns_from_properties(element, columns_struct)
4700
+ columns_list = col_data.get("formats", {}).get("columns", [])
4701
+
4702
+ # Header-derived values
4703
+ header_props = _extract_referenceable_properties(element)
4704
+ for column in columns_list:
4705
+ key = column.get('key')
4706
+ if key in header_props:
4707
+ column['value'] = header_props.get(key)
4708
+ elif isinstance(key, str) and key.lower() == 'guid':
4709
+ column['value'] = header_props.get('GUID')
4710
+
4711
+ # Classifications (names only)
4712
+ cl_names = []
4713
+ for c in element.get('elementHeader', {}).get('classifications', []) or []:
4714
+ nm = c.get('classificationName')
4715
+ if nm:
4716
+ cl_names.append(nm)
4717
+ if cl_names:
4718
+ for column in columns_list:
4719
+ if column.get('key') == 'classifications':
4720
+ column['value'] = ", ".join(cl_names)
4721
+ break
4722
+
4723
+ # Relationship-derived values (generic)
4724
+ col_data = get_required_relationships(element, col_data)
4725
+
4726
+ # Mermaid graph
4727
+ mermaid_val = element.get('mermaidGraph', "") or ""
4728
+ for column in columns_list:
4729
+ if column.get('key') == 'mermaid':
4730
+ column['value'] = mermaid_val
4731
+ break
4732
+
4733
+ return col_data
4734
+
4735
+ def _extract_data_class_properties(self, element: dict, columns_struct: dict) -> dict:
4736
+ """
4737
+ Populate columns_struct values for a Data Class element using the standardized approach.
4738
+
4739
+ Uses properties population, header overlay, classifications, generic relationships,
4740
+ and mermaid graph assignment similar to collection_manager.
4741
+ """
4742
+ col_data = populate_columns_from_properties(element, columns_struct)
4743
+ columns_list = col_data.get("formats", {}).get("columns", [])
4744
+
4745
+ header_props = _extract_referenceable_properties(element)
4746
+ for column in columns_list:
4747
+ key = column.get('key')
4748
+ if key in header_props:
4749
+ column['value'] = header_props.get(key)
4750
+ elif isinstance(key, str) and key.lower() == 'guid':
4751
+ column['value'] = header_props.get('GUID')
4752
+
4753
+ # Classifications from header
4754
+ cl_names = []
4755
+ for c in element.get('elementHeader', {}).get('classifications', []) or []:
4756
+ nm = c.get('classificationName')
4757
+ if nm:
4758
+ cl_names.append(nm)
4759
+ if cl_names:
4760
+ for column in columns_list:
4761
+ if column.get('key') == 'classifications':
4762
+ column['value'] = ", ".join(cl_names)
4763
+ break
4764
+
4765
+ # Relationships and mermaid
4766
+ col_data = get_required_relationships(element, col_data)
4767
+
4768
+ mermaid_val = element.get('mermaidGraph', "") or ""
4769
+ for column in columns_list:
4770
+ if column.get('key') == 'mermaid':
4771
+ column['value'] = mermaid_val
4772
+ break
4773
+
4774
+ return col_data
4775
+
4776
+ def _extract_data_field_properties(self, element: dict, columns_struct: dict) -> dict:
4777
+ """
4778
+ Populate columns_struct values for a Data Field element using the standardized approach.
4779
+
4780
+ Populates from properties, overlays header values, derives classifications, uses
4781
+ get_required_relationships for relationships, and adds mermaid graph.
4782
+ """
4783
+ col_data = populate_columns_from_properties(element, columns_struct)
4784
+ columns_list = col_data.get("formats", {}).get("columns", [])
4785
+
4786
+ header_props = _extract_referenceable_properties(element)
4787
+ for column in columns_list:
4788
+ key = column.get('key')
4789
+ if key in header_props:
4790
+ column['value'] = header_props.get(key)
4791
+ elif isinstance(key, str) and key.lower() == 'guid':
4792
+ column['value'] = header_props.get('GUID')
4793
+
4794
+ # Classifications from header
4795
+ cl_names = []
4796
+ for c in element.get('elementHeader', {}).get('classifications', []) or []:
4797
+ nm = c.get('classificationName')
4798
+ if nm:
4799
+ cl_names.append(nm)
4800
+ if cl_names:
4801
+ for column in columns_list:
4802
+ if column.get('key') == 'classifications':
4803
+ column['value'] = ", ".join(cl_names)
4804
+ break
4805
+
4806
+ # Relationships and mermaid
4807
+ col_data = get_required_relationships(element, col_data)
4808
+
4809
+ mermaid_val = element.get('mermaidGraph', "") or ""
4810
+ for column in columns_list:
4811
+ if column.get('key') == 'mermaid':
4812
+ column['value'] = mermaid_val
4813
+ break
4814
+
4815
+ return col_data
5338
4816
 
5339
4817
  def _generate_basic_structured_output(self, elements: dict, filter: str, output_format: str,
5340
- columns_struct: dict = None) -> str | list:
4818
+ columns_struct: dict = None) -> str | list:
5341
4819
  """
5342
4820
  Generate output in the specified format for the given elements.
5343
4821
 
@@ -5357,19 +4835,18 @@ r replace_all_properties: bool, default = False
5357
4835
  return extract_basic_dict(elements)
5358
4836
  elif output_format == "HTML":
5359
4837
  return generate_output(
5360
- elements=elements,
5361
- search_string=filter,
4838
+ elements=elements,
4839
+ search_string=filter,
5362
4840
  entity_type="Data Element",
5363
4841
  columns_struct=columns_struct,
5364
4842
  output_format="HTML",
5365
4843
  extract_properties_func=self._extract_data_structure_properties
5366
- )
4844
+ )
5367
4845
 
5368
4846
  # For other formats (MD, FORM, REPORT, LIST), use generate_output
5369
4847
  elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
5370
4848
  # Define columns for LIST format
5371
4849
 
5372
-
5373
4850
  return generate_output(elements,
5374
4851
  filter,
5375
4852
  "Data Element",
@@ -5379,83 +4856,102 @@ r replace_all_properties: bool, default = False
5379
4856
  columns_struct,
5380
4857
  )
5381
4858
 
5382
-
5383
- def _generate_data_structure_output(self, elements: dict|list[dict], filter:str = None,
5384
- output_format: str = "DICT", output_format_set: str|dict = None) -> str | list:
4859
+ def _generate_data_structure_output(self, elements: dict | list[dict], filter: str = None,
4860
+ element_type_name: str | None = None,
4861
+ output_format: str = "DICT",
4862
+ output_format_set: str | dict = None) -> str | list:
5385
4863
  """
5386
4864
  Generate output for data structures in the specified format.
5387
4865
 
5388
4866
  Args:
5389
4867
  elements: Dictionary or list of dictionaries containing data structure elements
5390
4868
  filter: The search string used to find the elements
4869
+ element_type_name: Optional specific subtype name to drive output format selection
5391
4870
  output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5392
4871
 
5393
4872
  Returns:
5394
4873
  Formatted output as string or list of dictionaries
5395
4874
  """
5396
- entity_type = "Data Structure"
5397
- if output_format_set is None:
5398
- output_format_set = select_output_format_set(entity_type, output_format)
4875
+ entity_type = element_type_name or "Data Structure"
5399
4876
 
4877
+ # First see if the user has specified an output_format_set - either a label or a dict
5400
4878
  if output_format_set:
5401
4879
  if isinstance(output_format_set, str):
5402
4880
  output_formats = select_output_format_set(output_format_set, output_format)
5403
- if isinstance(output_format_set, dict):
4881
+ elif isinstance(output_format_set, dict):
5404
4882
  output_formats = get_output_format_type_match(output_format_set, output_format)
4883
+ # If no output_format was set, then use the element_type_name to lookup the output format
4884
+ elif element_type_name:
4885
+ output_formats = select_output_format_set(element_type_name, output_format)
5405
4886
  else:
5406
- output_formats = None
5407
- logger.trace(f"Executing _generate_data_structure_output for {entity_type}: {output_formats}")
5408
- return generate_output(elements,
5409
- filter,
5410
- entity_type,
5411
- output_format,
5412
- self._extract_data_structure_properties,
5413
- None,
5414
- output_formats,
5415
- )
4887
+ # fallback to entity type
4888
+ output_formats = select_output_format_set(entity_type, output_format)
4889
+ if output_formats is None:
4890
+ output_formats = select_output_format_set("Default", output_format)
5416
4891
 
5417
- def _generate_data_class_output(self, elements: dict|list[dict], filter: str = None, output_format: str = "DICT", output_format_set: str|dict = None) -> str | list:
4892
+ logger.trace(f"Executing _generate_data_structure_output for {entity_type}: {output_formats}")
4893
+ return generate_output(
4894
+ elements,
4895
+ filter,
4896
+ entity_type,
4897
+ output_format,
4898
+ self._extract_data_structure_properties,
4899
+ None,
4900
+ output_formats,
4901
+ )
4902
+
4903
+ def _generate_data_class_output(self, elements: dict | list[dict], filter: str = None,
4904
+ element_type_name: str | None = None,
4905
+ output_format: str = "DICT",
4906
+ output_format_set: str | dict = None) -> str | list:
5418
4907
  """
5419
4908
  Generate output for data classes in the specified format.
5420
4909
 
5421
4910
  Args:
5422
4911
  elements: Dictionary or list of dictionaries containing data class elements
5423
4912
  filter: The search string used to find the elements
4913
+ element_type_name: Optional specific subtype name to drive output format selection
5424
4914
  output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5425
4915
  output_format_set: Optional output format set
5426
4916
  - Option column/attribute selection and definition.
5427
4917
  Returns:
5428
4918
  Formatted output as either a string or list of dictionaries
5429
4919
  """
5430
- entity_type = "Data Class"
5431
- if output_format_set is None:
5432
- output_format_set = select_output_format_set(entity_type, output_format)
5433
-
4920
+ entity_type = element_type_name or "Data Class"
5434
4921
  if output_format_set:
5435
4922
  if isinstance(output_format_set, str):
5436
4923
  output_formats = select_output_format_set(output_format_set, output_format)
5437
- if isinstance(output_format_set, dict):
4924
+ elif isinstance(output_format_set, dict):
5438
4925
  output_formats = get_output_format_type_match(output_format_set, output_format)
4926
+ elif element_type_name:
4927
+ output_formats = select_output_format_set(element_type_name, output_format)
5439
4928
  else:
5440
- output_formats = None
4929
+ output_formats = select_output_format_set(entity_type, output_format)
4930
+ if output_formats is None:
4931
+ output_formats = select_output_format_set("Default", output_format)
4932
+
5441
4933
  logger.trace(f"Executing _generate_data_class_output for {entity_type}: {output_formats}")
5442
- return generate_output(elements,
5443
- filter,
5444
- entity_type,
5445
- output_format,
5446
- self._extract_data_class_properties,
5447
- None,
5448
- output_formats,
5449
- )
5450
-
5451
- def _generate_data_field_output(self, elements: dict|list[dict], filter: str = None, output_format: str = "DICT",
5452
- output_format_set: str|dict = None) -> str | list:
4934
+ return generate_output(
4935
+ elements,
4936
+ filter,
4937
+ entity_type,
4938
+ output_format,
4939
+ self._extract_data_class_properties,
4940
+ None,
4941
+ output_formats,
4942
+ )
4943
+
4944
+ def _generate_data_field_output(self, elements: dict | list[dict], filter: str = None,
4945
+ element_type_name: str | None = None,
4946
+ output_format: str = "DICT",
4947
+ output_format_set: str | dict = None) -> str | list:
5453
4948
  """
5454
4949
  Generate output for data fields in the specified format.
5455
4950
 
5456
4951
  Args:
5457
4952
  elements: Dictionary or list of dictionaries containing data field elements
5458
4953
  filter: The search string used to find the elements
4954
+ element_type_name: Optional specific subtype name to drive output format selection
5459
4955
  output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
5460
4956
  output_format_set: str|dict, Optional, default = None
5461
4957
  - Option column/attribute selection and definition.
@@ -5463,29 +4959,29 @@ r replace_all_properties: bool, default = False
5463
4959
  Returns:
5464
4960
  Formatted output as a string or list of dictionaries
5465
4961
  """
5466
- entity_type = "Data Field"
5467
- if output_format_set is None:
5468
- output_format_set = select_output_format_set(entity_type, output_format)
5469
-
4962
+ entity_type = element_type_name or "Data Field"
5470
4963
  if output_format_set:
5471
4964
  if isinstance(output_format_set, str):
5472
4965
  output_formats = select_output_format_set(output_format_set, output_format)
5473
- if isinstance(output_format_set, dict):
4966
+ elif isinstance(output_format_set, dict):
5474
4967
  output_formats = get_output_format_type_match(output_format_set, output_format)
4968
+ elif element_type_name:
4969
+ output_formats = select_output_format_set(element_type_name, output_format)
5475
4970
  else:
5476
- output_formats = None
5477
- logger.trace(f"Executing _generate_data_field_output for {entity_type}: {output_formats}")
5478
- return generate_output(elements,
5479
- filter,
5480
- entity_type,
5481
- output_format,
5482
- self._extract_data_field_properties,
5483
- None,
5484
- output_formats,
5485
- )
5486
-
5487
-
4971
+ output_formats = select_output_format_set(entity_type, output_format)
4972
+ if output_formats is None:
4973
+ output_formats = select_output_format_set("Default", output_format)
5488
4974
 
4975
+ logger.trace(f"Executing _generate_data_field_output for {entity_type}: {output_formats}")
4976
+ return generate_output(
4977
+ elements,
4978
+ filter,
4979
+ entity_type,
4980
+ output_format,
4981
+ self._extract_data_field_properties,
4982
+ None,
4983
+ output_formats,
4984
+ )
5489
4985
 
5490
4986
 
5491
4987
  if __name__ == "__main__":