pyegeria 5.4.8__py3-none-any.whl → 5.4.8.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. md_processing/__init__.py +2 -1
  2. md_processing/data/commands.json +59579 -52198
  3. md_processing/dr_egeria.py +7 -5
  4. md_processing/md_commands/solution_architect_commands.py +54 -10
  5. md_processing/md_processing_utils/common_md_proc_utils.py +8 -4
  6. md_processing/md_processing_utils/common_md_utils.py +41 -2
  7. pyegeria/_base_client.py +1 -17
  8. pyegeria/_client_new.py +1008 -323
  9. pyegeria/_client_new_backup.py +5359 -0
  10. pyegeria/_exceptions_new.py +6 -1
  11. pyegeria/base_report_formats.py +31 -2
  12. pyegeria/classification_manager.py +1430 -357
  13. pyegeria/collection_manager.py +52 -54
  14. pyegeria/config.py +1 -0
  15. pyegeria/data_designer.py +41 -41
  16. pyegeria/external_links.py +26 -26
  17. pyegeria/feedback_manager_omvs.py +13 -31
  18. pyegeria/glossary_manager.py +32 -35
  19. pyegeria/governance_officer.py +31 -31
  20. pyegeria/output_formatter.py +36 -11
  21. pyegeria/output_formatter_with_machine_keys.py +1127 -0
  22. pyegeria/project_manager.py +21 -21
  23. pyegeria/reference_data.py +2 -2
  24. pyegeria/solution_architect.py +112 -91
  25. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/METADATA +6 -5
  26. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/RECORD +30 -29
  27. pyegeria/md_processing_utils_orig.py +0 -1103
  28. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/WHEEL +0 -0
  29. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/entry_points.txt +0 -0
  30. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/licenses/LICENSE +0 -0
  31. {pyegeria-5.4.8.dist-info → pyegeria-5.4.8.3.dist-info}/top_level.txt +0 -0
@@ -23,10 +23,12 @@ from pyegeria._globals import NO_GUID_RETURNED
23
23
  from pyegeria._validators import validate_guid
24
24
  from pyegeria.collection_manager import CollectionManager
25
25
  from pyegeria.config import settings as app_settings
26
- from pyegeria.models import (NewElementRequestBody,
27
- ReferenceableProperties, UpdateElementRequestBody, DeleteRequestBody, TemplateRequestBody,
26
+ from pyegeria.models import (NewElementRequestBody, DeleteElementRequestBody, DeleteRelationshipRequestBody,
27
+ DeleteClassificationRequestBody,
28
+ ReferenceableProperties, UpdateElementRequestBody, TemplateRequestBody,
28
29
  NewRelationshipRequestBody, UpdateRelationshipRequestBody, NewClassificationRequestBody,
29
- FilterRequestBody, GetRequestBody, SearchStringRequestBody, UpdateStatusRequestBody)
30
+ FilterRequestBody, GetRequestBody, SearchStringRequestBody, UpdateStatusRequestBody,
31
+ DeleteClassificationRequestBody)
30
32
  from pyegeria.base_report_formats import select_report_spec, get_report_spec_match
31
33
  from pyegeria.output_formatter import (generate_output,
32
34
  _extract_referenceable_properties, populate_columns_from_properties,
@@ -36,11 +38,6 @@ from pyegeria.utils import body_slimmer, dynamic_catch
36
38
  EGERIA_LOCAL_QUALIFIER = app_settings.User_Profile.egeria_local_qualifier
37
39
 
38
40
 
39
- ("params are in the form of [(paramName, value), (param2Name, value)] if the value is not None, it will be added to "
40
- "the query string")
41
-
42
-
43
-
44
41
 
45
42
  class GlossaryProperties(ReferenceableProperties):
46
43
  class_: Annotated[Literal["GlossaryProperties"], Field(alias="class")]
@@ -145,7 +142,7 @@ class GlossaryManager(CollectionManager):
145
142
  )
146
143
  return response
147
144
 
148
- async def _async_delete_glossary(self, glossary_guid: str, body: dict | DeleteRequestBody = None,
145
+ async def _async_delete_glossary(self, glossary_guid: str, body: dict | DeleteElementRequestBody = None,
149
146
  cascade: bool = False) -> None:
150
147
  """Delete glossary. Async version.
151
148
 
@@ -166,7 +163,7 @@ class GlossaryManager(CollectionManager):
166
163
 
167
164
  logger.info(f"Deleted glossary {glossary_guid} with cascade {cascade}")
168
165
 
169
- def delete_glossary(self, glossary_guid: str, body: dict | DeleteRequestBody = None, cascade: bool = False) -> None:
166
+ def delete_glossary(self, glossary_guid: str, body: dict | DeleteElementRequestBody = None, cascade: bool = False) -> None:
170
167
  """Delete a new glossary.
171
168
 
172
169
  Parameters
@@ -998,7 +995,7 @@ class GlossaryManager(CollectionManager):
998
995
  self,
999
996
  term_guid: str,
1000
997
  cascade: bool = False,
1001
- body: dict | DeleteRequestBody = None
998
+ body: dict | DeleteElementRequestBody = None
1002
999
  ) -> None:
1003
1000
  """Delete the glossary terms associated with the specified glossary. Async version.
1004
1001
 
@@ -1033,7 +1030,7 @@ class GlossaryManager(CollectionManager):
1033
1030
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1034
1031
  f"terms/{term_guid}/delete"
1035
1032
  )
1036
- await self._async_delete_request(url, body, cascade)
1033
+ await self._async_delete_element_request(url, body, cascade)
1037
1034
  logger.info(f"Deleted collection {term_guid} with cascade {cascade}")
1038
1035
 
1039
1036
 
@@ -1041,7 +1038,7 @@ class GlossaryManager(CollectionManager):
1041
1038
  self,
1042
1039
  term_guid: str,
1043
1040
  cascade: bool = False,
1044
- body: dict | DeleteRequestBody = None
1041
+ body: dict | DeleteElementRequestBody = None
1045
1042
  ) -> None:
1046
1043
  """Delete the glossary terms associated with the specified glossary.
1047
1044
 
@@ -1078,7 +1075,7 @@ class GlossaryManager(CollectionManager):
1078
1075
  self,
1079
1076
  term_guid: str,
1080
1077
  glossary_guid: str,
1081
- body: dict | DeleteRequestBody = None
1078
+ body: dict | DeleteRelationshipRequestBody = None
1082
1079
  ) -> None:
1083
1080
  """Move the glossary terms to the specified glossary. Async version.
1084
1081
 
@@ -1110,7 +1107,7 @@ class GlossaryManager(CollectionManager):
1110
1107
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1111
1108
  f"terms/{term_guid}/move-to/{glossary_guid}"
1112
1109
  )
1113
- await self._async_delete_request(url, body)
1110
+ await self._async_delete_relationship_request(url, body)
1114
1111
  logger.info(f"Moved collection {term_guid} to glossary {glossary_guid}")
1115
1112
 
1116
1113
 
@@ -1118,7 +1115,7 @@ class GlossaryManager(CollectionManager):
1118
1115
  self,
1119
1116
  term_guid: str,
1120
1117
  glossary_guid: str,
1121
- body: dict | DeleteRequestBody = None
1118
+ body: dict | DeleteRelationshipRequestBody = None
1122
1119
  ) -> None:
1123
1120
  """Move the glossary terms to the specified glossary.
1124
1121
 
@@ -1224,7 +1221,7 @@ class GlossaryManager(CollectionManager):
1224
1221
  }
1225
1222
  }
1226
1223
 
1227
- await self._async_new_classification_request(url, "AbstractConceptProperties",body)
1224
+ await self._async_new_classification_request(url, "AbstractConceptProperties", body)
1228
1225
  logger.info(f"Added AbstractConcept classification to {term_guid}")
1229
1226
 
1230
1227
 
@@ -1285,7 +1282,7 @@ class GlossaryManager(CollectionManager):
1285
1282
  )
1286
1283
 
1287
1284
  async def _async_remove_is_abstract_concepts(
1288
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1285
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1289
1286
  ) -> None:
1290
1287
  """Add a relationship between terms. Async Version.
1291
1288
 
@@ -1336,11 +1333,11 @@ class GlossaryManager(CollectionManager):
1336
1333
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1337
1334
  f"terms/{term_guid}/is-abstract-concept/remove"
1338
1335
  )
1339
- await self._async_delete_request(url, body)
1336
+ await self._async_delete_classification_request(url, body)
1340
1337
  logger.info(f"Removed AbstractConcept classification to {term_guid}")
1341
1338
 
1342
1339
  def remove_is_abstract_concept(
1343
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1340
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1344
1341
  ) -> None:
1345
1342
  """Add a relationship between terms.
1346
1343
 
@@ -1457,7 +1454,7 @@ class GlossaryManager(CollectionManager):
1457
1454
  }
1458
1455
  }
1459
1456
 
1460
- await self._async_new_classification_request(url, "ContextDefinitionProperties",body)
1457
+ await self._async_new_classification_request(url, "ContextDefinitionProperties", body)
1461
1458
  logger.info(f"Added AbstractConcept classification to {term_guid}")
1462
1459
 
1463
1460
 
@@ -1519,7 +1516,7 @@ class GlossaryManager(CollectionManager):
1519
1516
  )
1520
1517
 
1521
1518
  async def _async_remove_is_context_definition(
1522
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1519
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1523
1520
  ) -> None:
1524
1521
  """Add a relationship between terms. Async Version.
1525
1522
 
@@ -1570,11 +1567,11 @@ class GlossaryManager(CollectionManager):
1570
1567
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1571
1568
  f"terms/{term_guid}/is-context-definition/remove"
1572
1569
  )
1573
- await self._async_delete_request(url, body)
1570
+ await self._async_delete_classification_request(url, body)
1574
1571
  logger.info(f"Removed ContextDefinition classification to {term_guid}")
1575
1572
 
1576
1573
  def remove_is_context_definition(
1577
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1574
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1578
1575
  ) -> None:
1579
1576
  """Add a relationship between terms.
1580
1577
 
@@ -1691,7 +1688,7 @@ class GlossaryManager(CollectionManager):
1691
1688
  }
1692
1689
  }
1693
1690
 
1694
- await self._async_new_classification_request(url, "DataValueProperties",body)
1691
+ await self._async_new_classification_request(url, "DataValueProperties", body)
1695
1692
  logger.info(f"Added DataValue classification to {term_guid}")
1696
1693
 
1697
1694
 
@@ -1753,7 +1750,7 @@ class GlossaryManager(CollectionManager):
1753
1750
  )
1754
1751
 
1755
1752
  async def _async_remove_is_data_value(
1756
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1753
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1757
1754
  ) -> None:
1758
1755
  """Add a relationship between terms. Async Version.
1759
1756
 
@@ -1804,11 +1801,11 @@ class GlossaryManager(CollectionManager):
1804
1801
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1805
1802
  f"terms/{term_guid}/is-data-value/remove"
1806
1803
  )
1807
- await self._async_delete_request(url, body)
1804
+ await self._async_delete_classification_request(url, body)
1808
1805
  logger.info(f"Removed DataValue classification to {term_guid}")
1809
1806
 
1810
1807
  def remove_is_data_value(
1811
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1808
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1812
1809
  ) -> None:
1813
1810
  """Add a relationship between terms.
1814
1811
 
@@ -1925,7 +1922,7 @@ class GlossaryManager(CollectionManager):
1925
1922
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
1926
1923
  f"terms/{term_guid}/is-activity"
1927
1924
  )
1928
- await self._async_new_classification_request(url, "ActivityDescriptionProperties",body)
1925
+ await self._async_new_classification_request(url, "ActivityDescriptionProperties", body)
1929
1926
  logger.info(f"Added DataValue classification to {term_guid}")
1930
1927
 
1931
1928
 
@@ -1987,7 +1984,7 @@ class GlossaryManager(CollectionManager):
1987
1984
  )
1988
1985
 
1989
1986
  async def _async_remove_activity_description(
1990
- self, term_guid: str, body: dict | DeleteRequestBody = None,
1987
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
1991
1988
  ) -> None:
1992
1989
  """Add a relationship between terms. Async Version.
1993
1990
 
@@ -2038,11 +2035,11 @@ class GlossaryManager(CollectionManager):
2038
2035
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/"
2039
2036
  f"terms/{term_guid}/is-activity/remove"
2040
2037
  )
2041
- await self._async_delete_request(url, body)
2038
+ await self._async_delete_classification_request(url, body)
2042
2039
  logger.info(f"Removed ActivityDescription classification to {term_guid}")
2043
2040
 
2044
2041
  def remove_activity_description(
2045
- self, term_guid: str, body: dict | DeleteRequestBody = None,
2042
+ self, term_guid: str, body: dict | DeleteClassificationRequestBody = None,
2046
2043
  ) -> None:
2047
2044
  """Add a relationship between terms.
2048
2045
 
@@ -2354,7 +2351,7 @@ class GlossaryManager(CollectionManager):
2354
2351
  )
2355
2352
 
2356
2353
  async def _async_remove_relationship_between_terms(
2357
- self, term1_guid: str, term2_guid: str, relationship_type: str, body: dict | DeleteRequestBody = None,
2354
+ self, term1_guid: str, term2_guid: str, relationship_type: str, body: dict | DeleteRelationshipRequestBody = None,
2358
2355
  ) -> None:
2359
2356
  """Remove a relationship between terms. Async Version.
2360
2357
 
@@ -2398,10 +2395,10 @@ class GlossaryManager(CollectionManager):
2398
2395
  f"terms/{term1_guid}/relationships/{relationship_type}/terms/{term2_guid}/remove"
2399
2396
  )
2400
2397
 
2401
- await self._async_delete_request(url, body)
2398
+ await self._async_delete_relationship_request(url, body)
2402
2399
 
2403
2400
  def remove_relationship_between_terms(
2404
- self, term1_guid: str, term2_guid: str, relationship_type: str, body: dict | DeleteRequestBody = None) -> None:
2401
+ self, term1_guid: str, term2_guid: str, relationship_type: str, body: dict | DeleteRelationshipRequestBody = None) -> None:
2405
2402
 
2406
2403
  """Remove a relationship between terms.
2407
2404
 
@@ -33,7 +33,7 @@ from pyegeria.config import settings as app_settings
33
33
  from pyegeria.models import (SearchStringRequestBody, FilterRequestBody, NewElementRequestBody,
34
34
  ReferenceableProperties, TemplateRequestBody,
35
35
  UpdateElementRequestBody, UpdateStatusRequestBody, NewRelationshipRequestBody,
36
- DeleteRequestBody)
36
+ DeleteElementRequestBody, DeleteRelationshipRequestBody,DeleteClassificationRequestBody)
37
37
  from pyegeria.utils import dynamic_catch
38
38
 
39
39
  GOV_DEF_PROPERTIES_LIST = ["GovernanceDefinitionProperties", "GovernanceStrategyProperties", "RegulationProperties",
@@ -851,7 +851,7 @@ class GovernanceOfficer(Client2):
851
851
 
852
852
  @dynamic_catch
853
853
  async def _async_delete_governance_definition(self, definition_guid: str,
854
- body: dict | DeleteRequestBody = None,
854
+ body: dict | DeleteElementRequestBody = None,
855
855
  cascade: bool = False) -> None:
856
856
  """ Delete a governance definition. Async Version.
857
857
 
@@ -863,7 +863,7 @@ class GovernanceOfficer(Client2):
863
863
  cascade: bool, optional, defaults to True
864
864
  If true, a cascade delete is performed.
865
865
 
866
- body: dict DeleteRequestBodyt, optional, default = None
866
+ body: dict DeleteElementRequestBodyt, optional, default = None
867
867
  A dict representing the details of the relationship.
868
868
 
869
869
  Returns
@@ -895,10 +895,10 @@ class GovernanceOfficer(Client2):
895
895
  f"{self.platform_url}/s"
896
896
  f"ervers/{self.view_server}/api/open-metadata/governance-officer/governance-definitions/"
897
897
  f"{definition_guid}/delete")
898
- await self._async_delete_request(url, body, cascade)
898
+ await self._async_delete_element_request(url, body, cascade)
899
899
  logger.info(f"Deleted collection {definition_guid} with cascade {cascade}")
900
900
 
901
- def delete_governance_definition(self, definition_guid: str, body: dict | DeleteRequestBody = None,
901
+ def delete_governance_definition(self, definition_guid: str, body: dict | DeleteElementRequestBody = None,
902
902
  cascade: bool = False) -> None:
903
903
  """Delete a governance definition.
904
904
 
@@ -910,7 +910,7 @@ class GovernanceOfficer(Client2):
910
910
  cascade: bool, optional, defaults to True
911
911
  If true, a cascade delete is performed.
912
912
 
913
- body: dict DeleteRequestBodyt, optional, default = None
913
+ body: dict DeleteElementRequestBodyt, optional, default = None
914
914
  A dict representing the details of the relationship.
915
915
 
916
916
  Returns
@@ -1065,7 +1065,7 @@ class GovernanceOfficer(Client2):
1065
1065
 
1066
1066
  @dynamic_catch
1067
1067
  async def _async_detach_peer_definitions(self, definition_guid1: str, relationship_type: str, definition_guid2: str,
1068
- body: dict | DeleteRequestBody = None) -> None:
1068
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
1069
1069
  """ Detach two peer governance definitions. Request body is optional. Async Version.
1070
1070
 
1071
1071
  Parameters
@@ -1110,12 +1110,12 @@ class GovernanceOfficer(Client2):
1110
1110
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/"
1111
1111
  f"{self.url_marker}/governance-definitions/"
1112
1112
  f"{definition_guid1}/peer-definitions/{relationship_type}/{definition_guid2}/detach")
1113
- await self._async_delete_request(url, body)
1113
+ await self._async_delete_relationship_request(url, body)
1114
1114
  logger.info(f"Detached peer definitions: {definition_guid1} -> {definition_guid2}")
1115
1115
 
1116
1116
  @dynamic_catch
1117
1117
  def detach_peer_definitions(self, definition_guid1: str, relationship_type: str, definition_guid2: str,
1118
- body: dict = None | DeleteRequestBody) -> None:
1118
+ body: dict = None | DeleteRelationshipRequestBody) -> None:
1119
1119
  """ Detach two peer governance definitions. Request body is optional.
1120
1120
 
1121
1121
  Parameters
@@ -1287,7 +1287,7 @@ class GovernanceOfficer(Client2):
1287
1287
  @dynamic_catch
1288
1288
  async def _async_detach_supporting_definitions(self, definition_guid1: str, relationship_type: str,
1289
1289
  definition_guid2: str,
1290
- body: dict | DeleteRequestBody = None) -> None:
1290
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
1291
1291
  """ Detach a governance definition from a supporting governance definition.
1292
1292
  Request body is optional. Async Version.
1293
1293
 
@@ -1333,12 +1333,12 @@ class GovernanceOfficer(Client2):
1333
1333
  f"{self.url_marker}/governance-definitions/"
1334
1334
  f"{definition_guid1}/supporting-definitions/{relationship_type}/{definition_guid2}/detach"
1335
1335
  )
1336
- await self._async_delete_request(url, body)
1336
+ await self._async_delete_relationship_request(url, body)
1337
1337
  logger.info(f"Detached digital supporting definitions: {definition_guid1} -> {definition_guid2}")
1338
1338
 
1339
1339
  @dynamic_catch
1340
- def detach_supporting_definitions(self, definition_guid: str, relationship_type: str, definition_guid2: str,
1341
- body: dict | DeleteRequestBody = None) -> None:
1340
+ def detach_supporting_definitions(self, definition_guid1: str, relationship_type: str, definition_guid2: str,
1341
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
1342
1342
  """ Detach a governance definition from a supporting governance definition.
1343
1343
  Request body is optional.
1344
1344
 
@@ -1481,7 +1481,7 @@ class GovernanceOfficer(Client2):
1481
1481
 
1482
1482
  @dynamic_catch
1483
1483
  async def _async_detach_governed_by_definition(self, element_guid: str, definition_guid: str,
1484
- body: dict | DeleteRequestBody = None) -> None:
1484
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
1485
1485
  """ Detach a governance definition from a supporting governance definition.
1486
1486
  Request body is optional. Async Version.
1487
1487
 
@@ -1512,7 +1512,7 @@ class GovernanceOfficer(Client2):
1512
1512
 
1513
1513
  Body structure:
1514
1514
  {
1515
- "class" : "DeleteRequestBody",
1515
+ "class" : "DeleteRelationshipRequestBody",
1516
1516
  "externalSourceGUID": "add guid here",
1517
1517
  "externalSourceName": "add qualified name here",
1518
1518
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1524,12 +1524,12 @@ class GovernanceOfficer(Client2):
1524
1524
  f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/"
1525
1525
  f"{self.url_marker}/elements/{element_guid}/governed-by/{definition_guid}/detach"
1526
1526
  )
1527
- await self._async_delete_request(url, body)
1527
+ await self._async_delete_relationship_request(url, body)
1528
1528
  logger.info(f"Detached governed-by relationshup between: {definition_guid} -> {element_guid}")
1529
1529
 
1530
1530
  @dynamic_catch
1531
1531
  def detach_governed_by_definitio(self, element_guid: str, definition_guid: str,
1532
- body: dict | DeleteRequestBody = None) -> None:
1532
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
1533
1533
  """ Detach a governance definition from a supporting governance definition.
1534
1534
  Request body is optional.
1535
1535
 
@@ -1560,7 +1560,7 @@ class GovernanceOfficer(Client2):
1560
1560
 
1561
1561
  Body structure:
1562
1562
  {
1563
- "class" : "DeleteRequestBody",
1563
+ "class" : "DeleteRelationshipRequestBody",
1564
1564
  "externalSourceGUID": "add guid here",
1565
1565
  "externalSourceName": "add qualified name here",
1566
1566
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1575,7 +1575,7 @@ class GovernanceOfficer(Client2):
1575
1575
 
1576
1576
 
1577
1577
  @dynamic_catch
1578
- async def _async_delete_governance_definition(self, guid: str, body: dict | DeleteRequestBody = None) -> None:
1578
+ async def _async_delete_governance_definition(self, guid: str, body: dict | DeleteElementRequestBody = None) -> None:
1579
1579
  """ Delete an information supply. Async version.
1580
1580
 
1581
1581
  Parameters
@@ -1617,12 +1617,12 @@ class GovernanceOfficer(Client2):
1617
1617
  """
1618
1618
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/"
1619
1619
  f"{self.url_marker}/governance-definitions/{guid}/delete")
1620
- await self._async_delete_request(url, body)
1620
+ await self._async_delete_element_request(url, body)
1621
1621
  logger.info(f"Deleted governance definition: {guid} ")
1622
1622
 
1623
1623
 
1624
1624
  @dynamic_catch
1625
- def delete_governance_definition(self, guid: str, body: dict | DeleteRequestBody = None) -> None:
1625
+ def delete_governance_definition(self, guid: str, body: dict | DeleteElementRequestBody = None) -> None:
1626
1626
  """ Delete an information supply. Request body is optional. Async version.
1627
1627
 
1628
1628
  Parameters
@@ -2180,7 +2180,7 @@ class GovernanceOfficer(Client2):
2180
2180
 
2181
2181
  @dynamic_catch
2182
2182
  async def _async_detach_design_from_implementation(self, design_desc_guid: str, implementation_guid: str,
2183
- body: dict | DeleteRequestBody = None) -> None:
2183
+ body: dict | DeleteElementRequestBody = None) -> None:
2184
2184
  """ Detach a governance definition from its implementation. Async Version.
2185
2185
 
2186
2186
  Parameters
@@ -2221,13 +2221,13 @@ class GovernanceOfficer(Client2):
2221
2221
 
2222
2222
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/{self.url_marker}/designs/"
2223
2223
  f"{design_desc_guid}/implementations/{implementation_guid}/detach")
2224
- await self._async_delete_request(url, body)
2224
+ await self._async_delete_relationship_request(url, body)
2225
2225
  logger.info(
2226
2226
  f"Detached design from implementation: {design_desc_guid} -> {implementation_guid}")
2227
2227
 
2228
2228
  @dynamic_catch
2229
2229
  def detach_design_from_implementation(self, design_desc_guid: str, implementation_guid: str,
2230
- body: dict | DeleteRequestBody = None) -> None:
2230
+ body: dict | DeleteElementRequestBody = None) -> None:
2231
2231
  """ Detach a governance definition from its implementation. Request body is optional.
2232
2232
 
2233
2233
  Parameters
@@ -2383,7 +2383,7 @@ class GovernanceOfficer(Client2):
2383
2383
 
2384
2384
  @dynamic_catch
2385
2385
  async def _async_detach_implementation_resource(self, design_desc_guid: str, implementation_guid: str,
2386
- body: dict | DeleteRequestBody = None) -> None:
2386
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
2387
2387
  """ Detach a design object such as a solution component or governance definition from one of its implementation
2388
2388
  resources. Request body is optional. Async version.
2389
2389
 
@@ -2425,12 +2425,12 @@ class GovernanceOfficer(Client2):
2425
2425
 
2426
2426
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/{self.url_marker}/designs/"
2427
2427
  f"{design_desc_guid}/implementation-resources/{implementation_guid}/detach")
2428
- await self._async_delete_request(url, body)
2428
+ await self._async_delete_relationship_request(url, body)
2429
2429
  logger.info(
2430
2430
  f"Detached design from implementation resource: {design_desc_guid} -> {implementation_guid}")
2431
2431
 
2432
2432
  def detach_implementation_resource(self, design_desc_guid: str, implementation_guid: str,
2433
- body: dict | DeleteRequestBody = None) -> None:
2433
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
2434
2434
  """ Detach a design object such as a solution component or governance definition from one of its implementation
2435
2435
  resources. Request body is optional.
2436
2436
 
@@ -2570,10 +2570,10 @@ class GovernanceOfficer(Client2):
2570
2570
  }
2571
2571
  """
2572
2572
  loop = asyncio.get_event_loop()
2573
- loop.run_until_complete(self._async_link_governance_results(gov_metric_guid, data_asset_guid, implementation_guid, body))
2573
+ loop.run_until_complete(self._async_link_governance_results(gov_metric_guid, data_asset_guid, body))
2574
2574
 
2575
2575
  @dynamic_catch
2576
- async def _async_detach_governance_results(self, gov_metric_guid: str, data_asset_guid: str, body: dict | DeleteRequestBody = None) -> None:
2576
+ async def _async_detach_governance_results(self, gov_metric_guid: str, data_asset_guid: str, body: dict | DeleteRelationshipRequestBody = None) -> None:
2577
2577
  """ Detach an governance metric from its measurements data set. Request body is optional.
2578
2578
  https://egeria-project.org/concepts/governance-definition/ Async version.
2579
2579
 
@@ -2611,12 +2611,12 @@ class GovernanceOfficer(Client2):
2611
2611
 
2612
2612
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/{self.url_marker}/governance-metrics/"
2613
2613
  f"{gov_metric_guid}/measurements/{data_asset_guid}/detach")
2614
- await self._async_delete_request(url, body)
2614
+ await self._async_delete_relationship_request(url, body)
2615
2615
  logger.info(
2616
2616
  f"Detached governance metric from the asset where measurements were stored: {gov_metric_guid} -> {data_asset_guid}")
2617
2617
 
2618
2618
  def detach_governance_results(self, gov_metric_guid: str, data_asset_guid: str,
2619
- body: dict | DeleteRequestBody = None) -> None:
2619
+ body: dict | DeleteRelationshipRequestBody = None) -> None:
2620
2620
  """ Detach an governance metric from its measurements data set. Request body is optional.
2621
2621
  https://egeria-project.org/concepts/governance-definition/
2622
2622
 
@@ -440,14 +440,16 @@ def generate_entity_md(elements: List[Dict],
440
440
  cols = returned_struct.get('formats', {}).get('attributes', [])
441
441
  # Find value from 'display_name' or 'title'
442
442
  for col in cols:
443
- if col.get('key') in ('display_name', 'title'):
443
+ if col.get('key') in ('display_name', 'title', 'keyword'):
444
444
  display_name = col.get('value')
445
445
  if display_name:
446
446
  break
447
447
  else:
448
- display_name = props.get('display_name') or props.get('title')
448
+ display_name = props.get('display_name') or props.get('title') or props.get('keyword')
449
449
 
450
- if display_name is None:
450
+ if display_name is None and (keyword:= element['properties'].get('keyword',None)) is not None:
451
+ display_name = keyword
452
+ elif display_name is None:
451
453
  display_name = "NO DISPLAY NAME"
452
454
 
453
455
  # Format header based on output format
@@ -632,16 +634,20 @@ def generate_entity_dict(elements: List[Dict],
632
634
 
633
635
  #####
634
636
  # Add attributes based on column spec if available, otherwise, add all
637
+ import copy
635
638
  for element in elements:
636
639
  if element is None:
637
640
  continue
638
641
 
639
642
  guid = element.get('elementHeader', {}).get('guid')
640
643
 
644
+ # Work on a per-element deep copy of the columns structure to avoid value leakage across rows
645
+ local_columns_struct = copy.deepcopy(columns_struct) if columns_struct is not None else None
646
+
641
647
  returned_struct = None
642
- if columns_struct is not None:
648
+ if local_columns_struct is not None:
643
649
  try:
644
- returned_struct = extract_properties_func(element, columns_struct)
650
+ returned_struct = extract_properties_func(element, local_columns_struct)
645
651
  except TypeError as e:
646
652
  logger.info(f"Error - didn't find extractor?: {e}")
647
653
  returned_struct = None
@@ -654,7 +660,7 @@ def generate_entity_dict(elements: List[Dict],
654
660
  # Create entity dictionary
655
661
  entity_dict = {}
656
662
 
657
- columns = columns_struct['formats'].get('attributes', None) if columns_struct else None
663
+ cols = local_columns_struct['formats'].get('attributes', None) if local_columns_struct else None
658
664
  if returned_struct is not None:
659
665
  for column in returned_struct.get('formats', {}).get('attributes', []):
660
666
  key = column.get('key')
@@ -664,9 +670,19 @@ def generate_entity_dict(elements: List[Dict],
664
670
  value = additional_props[key]
665
671
  if column.get('format'):
666
672
  value = format_for_markdown_table(value, guid)
667
- entity_dict[name] = value
668
- elif columns:
669
- for column in columns:
673
+ # Avoid overwriting when multiple columns share the same display name in a spec
674
+ dict_key = name
675
+ if dict_key in entity_dict:
676
+ logger.warning(f"DICT key collision for display name '{dict_key}'. Suffixing duplicate to preserve all values.")
677
+ suffix_idx = 1
678
+ tmp_key = f"{dict_key}_{suffix_idx}"
679
+ while tmp_key in entity_dict:
680
+ suffix_idx += 1
681
+ tmp_key = f"{dict_key}_{suffix_idx}"
682
+ dict_key = tmp_key
683
+ entity_dict[dict_key] = value
684
+ elif cols:
685
+ for column in cols:
670
686
  key = column['key']
671
687
  name = column['name']
672
688
  value = ""
@@ -677,9 +693,18 @@ def generate_entity_dict(elements: List[Dict],
677
693
  value = additional_props[key]
678
694
  if column.get('format', None):
679
695
  value = format_for_markdown_table(value, guid or props.get('GUID'))
680
- entity_dict[name] = value
696
+ dict_key = name
697
+ if dict_key in entity_dict:
698
+ logger.warning(f"DICT key collision for display name '{dict_key}'. Suffixing duplicate to preserve all values.")
699
+ suffix_idx = 1
700
+ tmp_key = f"{dict_key}_{suffix_idx}"
701
+ while tmp_key in entity_dict:
702
+ suffix_idx += 1
703
+ tmp_key = f"{dict_key}_{suffix_idx}"
704
+ dict_key = tmp_key
705
+ entity_dict[dict_key] = value
681
706
  else:
682
- props = extract_properties_func(element, columns_struct)
707
+ props = extract_properties_func(element, local_columns_struct)
683
708
  # Add properties based on include/exclude lists
684
709
  for key, value in props.items():
685
710
  if key not in ['properties', 'mermaid']: # Skip the raw properties object