pyegeria 5.4.3.3__py3-none-any.whl → 5.4.4__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 (230) hide show
  1. commands/cat/debug_log.2025-09-02_07-44-39_567276.log.zip +0 -0
  2. commands/cat/debug_log.2025-09-03_07-45-21_986388.log.zip +0 -0
  3. commands/cat/debug_log.2025-09-04_08-21-58_788009.log.zip +0 -0
  4. commands/cat/debug_log.2025-09-05_09-37-53_062579.log.zip +0 -0
  5. commands/cat/list_format_set.py +5 -3
  6. commands/tech/list_information_supply_chains.py +1 -1
  7. commands/tech/list_solution_blueprints.py +1 -1
  8. commands/tech/list_solution_components.py +1 -1
  9. commands/tech/list_solution_roles.py +1 -1
  10. md_processing/__init__.py +9 -5
  11. md_processing/data/commands.json +7182 -1401
  12. md_processing/data/generated_format_sets.json +4137 -0
  13. md_processing/data/generated_format_sets.py +51 -0
  14. md_processing/dr_egeria.py +20 -11
  15. md_processing/md_commands/data_designer_commands.py +90 -425
  16. md_processing/md_commands/ext_ref_commands.py +543 -0
  17. md_processing/md_commands/old_solution_architect_commands.py +1139 -0
  18. md_processing/md_commands/solution_architect_commands.py +26 -59
  19. md_processing/md_processing_utils/common_md_utils.py +50 -1
  20. md_processing/md_processing_utils/debug_log +1 -3
  21. md_processing/md_processing_utils/dr-egeria-help-2025-09-09T11:10:03.md +3305 -0
  22. md_processing/md_processing_utils/extraction_utils.py +14 -7
  23. md_processing/md_processing_utils/gen_format_sets.py +422 -0
  24. md_processing/md_processing_utils/md_processing_constants.py +20 -2
  25. pyegeria/__init__.py +1 -1
  26. pyegeria/_client_new.py +9 -7
  27. pyegeria/_output_formats.py +278 -3
  28. pyegeria/collection_manager.py +20 -59
  29. pyegeria/config.py +10 -1
  30. pyegeria/data_designer.py +166 -117
  31. pyegeria/egeria_client.py +1 -1
  32. pyegeria/egeria_tech_client.py +4 -1
  33. pyegeria/external_references.py +1794 -0
  34. pyegeria/glossary_manager.py +71 -85
  35. pyegeria/governance_officer.py +26 -29
  36. pyegeria/output_formatter.py +127 -1
  37. pyegeria/project_manager.py +33 -36
  38. pyegeria/{solution_architect_omvs.py → solution_architect.py} +733 -873
  39. {pyegeria-5.4.3.3.dist-info → pyegeria-5.4.4.dist-info}/METADATA +1 -1
  40. {pyegeria-5.4.3.3.dist-info → pyegeria-5.4.4.dist-info}/RECORD +43 -219
  41. commands/.DS_Store +0 -0
  42. commands/cat/.DS_Store +0 -0
  43. commands/cat/.env +0 -8
  44. commands/cat/debug_log.2025-08-29_07-07-27_848189.log.zip +0 -0
  45. commands/cat/debug_log.2025-08-30_21-15-48_528443.log.zip +0 -0
  46. commands/cat/debug_log.log +0 -6102
  47. commands/cat/logs/pyegeria.log +0 -90
  48. commands/cli/debug_log.log +0 -0
  49. commands/doc/.DS_Store +0 -0
  50. commands/ops/logs/pyegeria.log +0 -0
  51. md_processing/.DS_Store +0 -0
  52. md_processing/.idea/.gitignore +0 -8
  53. md_processing/.idea/inspectionProfiles/Project_Default.xml +0 -59
  54. md_processing/.idea/md_processing.iml +0 -15
  55. md_processing/.idea/modules.xml +0 -8
  56. md_processing/.idea/sonarlint/issuestore/index.pb +0 -0
  57. md_processing/.idea/sonarlint/securityhotspotstore/index.pb +0 -0
  58. md_processing/.idea/vcs.xml +0 -6
  59. md_processing/.idea/workspace.xml +0 -107
  60. md_processing/dr_egeria_inbox/Derive-Dr-Gov-Defs.md +0 -8
  61. md_processing/dr_egeria_inbox/Dr.Egeria Templates.md +0 -873
  62. md_processing/dr_egeria_inbox/arch_test.md +0 -57
  63. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  64. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  65. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  66. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  67. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  68. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  69. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  70. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  71. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  72. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  73. md_processing/dr_egeria_inbox/collections.md +0 -39
  74. md_processing/dr_egeria_inbox/data_designer_debug.log +0 -6
  75. md_processing/dr_egeria_inbox/data_designer_out.md +0 -60
  76. md_processing/dr_egeria_inbox/data_designer_search_test.md +0 -11
  77. md_processing/dr_egeria_inbox/data_field.md +0 -54
  78. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  79. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2340
  80. md_processing/dr_egeria_inbox/data_test.md +0 -179
  81. md_processing/dr_egeria_inbox/data_test2.md +0 -429
  82. md_processing/dr_egeria_inbox/data_test3.md +0 -462
  83. md_processing/dr_egeria_inbox/dr_egeria_data_designer_1.md +0 -124
  84. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  85. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  86. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -318
  87. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  88. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  89. md_processing/dr_egeria_inbox/generated_help_report.md +0 -9
  90. md_processing/dr_egeria_inbox/generated_help_terms.md +0 -842
  91. md_processing/dr_egeria_inbox/glossary_list.md +0 -5
  92. md_processing/dr_egeria_inbox/glossary_search_test.md +0 -40
  93. md_processing/dr_egeria_inbox/glossary_test1.md +0 -378
  94. md_processing/dr_egeria_inbox/gov_def.md +0 -718
  95. md_processing/dr_egeria_inbox/gov_def2.md +0 -447
  96. md_processing/dr_egeria_inbox/img.png +0 -0
  97. md_processing/dr_egeria_inbox/output_tests.md +0 -114
  98. md_processing/dr_egeria_inbox/product.md +0 -211
  99. md_processing/dr_egeria_inbox/rel.md +0 -8
  100. md_processing/dr_egeria_inbox/sb.md +0 -119
  101. md_processing/dr_egeria_inbox/solution-components.md +0 -136
  102. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  103. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  104. md_processing/dr_egeria_inbox/t2.md +0 -268
  105. md_processing/dr_egeria_outbox/.DS_Store +0 -0
  106. md_processing/dr_egeria_outbox/.obsidian/app.json +0 -1
  107. md_processing/dr_egeria_outbox/.obsidian/appearance.json +0 -1
  108. md_processing/dr_egeria_outbox/.obsidian/community-plugins.json +0 -7
  109. md_processing/dr_egeria_outbox/.obsidian/core-plugins.json +0 -33
  110. md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/main.js +0 -5164
  111. md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/manifest.json +0 -10
  112. md_processing/dr_egeria_outbox/.obsidian/plugins/buttons/styles.css +0 -624
  113. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/data.json +0 -10
  114. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/main.js +0 -4459
  115. md_processing/dr_egeria_outbox/.obsidian/plugins/calendar/manifest.json +0 -10
  116. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/data.json +0 -3
  117. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/main.js +0 -153
  118. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/manifest.json +0 -11
  119. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-kanban/styles.css +0 -1
  120. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/main.js +0 -500
  121. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +0 -12
  122. md_processing/dr_egeria_outbox/.obsidian/plugins/obsidian-tasks-plugin/styles.css +0 -1
  123. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/data.json +0 -38
  124. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/main.js +0 -37
  125. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/manifest.json +0 -11
  126. md_processing/dr_egeria_outbox/.obsidian/plugins/templater-obsidian/styles.css +0 -220
  127. md_processing/dr_egeria_outbox/.obsidian/types.json +0 -28
  128. md_processing/dr_egeria_outbox/.obsidian/workspace.json +0 -270
  129. md_processing/dr_egeria_outbox/Button Test.md +0 -11
  130. md_processing/dr_egeria_outbox/Scripts/.DS_Store +0 -0
  131. md_processing/dr_egeria_outbox/Scripts/sendRest.js +0 -24
  132. md_processing/dr_egeria_outbox/Templates/sendToApi.md.md +0 -17
  133. md_processing/dr_egeria_outbox/Untitled.canvas +0 -1
  134. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 09:26-product.md +0 -210
  135. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 14:03-product.md +0 -209
  136. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 14:24-product.md +0 -263
  137. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 16:03-data_spec_test.md +0 -2374
  138. md_processing/dr_egeria_outbox/monday/processed-2025-09-01 16:05-data_spec_test.md +0 -2374
  139. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:28-data_spec_test.md +0 -2321
  140. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:37-data_spec_test.md +0 -2304
  141. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 08:56-data_spec_test.md +0 -2324
  142. md_processing/dr_egeria_outbox/monday/processed-2025-09-02 09:00-data_spec_test.md +0 -2324
  143. md_processing/dr_egeria_outbox/processed-2025-08-30 16:56-generated_help_terms.md +0 -795
  144. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +0 -719
  145. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +0 -41
  146. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +0 -33
  147. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +0 -192
  148. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:08-gov_def2.md +0 -486
  149. md_processing/dr_egeria_outbox/thursday/processed-2025-07-17 22:10-gov_def2.md +0 -486
  150. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:53-gov_def2.md +0 -486
  151. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 08:54-gov_def2.md +0 -486
  152. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:03-gov_def2.md +0 -486
  153. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:06-gov_def2.md +0 -486
  154. md_processing/dr_egeria_outbox/thursday/processed-2025-07-18 09:10-gov_def2.md +0 -486
  155. md_processing/dr_egeria_outbox/tuesday/processed-2025-09-02 13:07-gov_def.md +0 -492
  156. md_processing/dr_egeria_outbox/tuesday/processed-2025-09-02 13:25-gov_def.md +0 -520
  157. md_processing/dr_egeria_outbox/tuesday/processed-2025-09-02 16:43-gov_def.md +0 -636
  158. md_processing/dr_egeria_outbox/tuesday/processed-2025-09-02 16:46-gov_def.md +0 -636
  159. md_processing/family_docs/Data Designer/Create_Data_Class.md +0 -164
  160. md_processing/family_docs/Data Designer/Create_Data_Dictionary.md +0 -30
  161. md_processing/family_docs/Data Designer/Create_Data_Field.md +0 -162
  162. md_processing/family_docs/Data Designer/Create_Data_Specification.md +0 -36
  163. md_processing/family_docs/Data Designer/Create_Data_Structure.md +0 -38
  164. md_processing/family_docs/Data Designer/View_Data_Classes.md +0 -78
  165. md_processing/family_docs/Data Designer/View_Data_Dictionaries.md +0 -78
  166. md_processing/family_docs/Data Designer/View_Data_Fields.md +0 -78
  167. md_processing/family_docs/Data Designer/View_Data_Specifications.md +0 -78
  168. md_processing/family_docs/Data Designer/View_Data_Structures.md +0 -78
  169. md_processing/family_docs/Data Designer.md +0 -842
  170. md_processing/family_docs/Digital Product Manager/Add_Member->Collection.md +0 -42
  171. md_processing/family_docs/Digital Product Manager/Attach_Collection->Resource.md +0 -36
  172. md_processing/family_docs/Digital Product Manager/Create_Agreement.md +0 -96
  173. md_processing/family_docs/Digital Product Manager/Create_Data_Sharing_Agreement.md +0 -72
  174. md_processing/family_docs/Digital Product Manager/Create_DigitalSubscription.md +0 -102
  175. md_processing/family_docs/Digital Product Manager/Create_Digital_Product.md +0 -134
  176. md_processing/family_docs/Digital Product Manager/Link_Agreement_Items.md +0 -60
  177. md_processing/family_docs/Digital Product Manager/Link_Contracts.md +0 -26
  178. md_processing/family_docs/Digital Product Manager/Link_Digital_Product_-_Digital_Product.md +0 -30
  179. md_processing/family_docs/Digital Product Manager/Link_Subscribers.md +0 -48
  180. md_processing/family_docs/Digital Product Manager.md +0 -668
  181. md_processing/family_docs/Glossary/Attach_Category_Parent.md +0 -18
  182. md_processing/family_docs/Glossary/Attach_Term-Term_Relationship.md +0 -26
  183. md_processing/family_docs/Glossary/Create_Category.md +0 -38
  184. md_processing/family_docs/Glossary/Create_Glossary.md +0 -42
  185. md_processing/family_docs/Glossary/Create_Term.md +0 -70
  186. md_processing/family_docs/Glossary.md +0 -206
  187. md_processing/family_docs/Governance Officer/Create_Business_Imperative.md +0 -106
  188. md_processing/family_docs/Governance Officer/Create_Certification_Type.md +0 -112
  189. md_processing/family_docs/Governance Officer/Create_Governance_Approach.md +0 -114
  190. md_processing/family_docs/Governance Officer/Create_Governance_Obligation.md +0 -114
  191. md_processing/family_docs/Governance Officer/Create_Governance_Principle.md +0 -114
  192. md_processing/family_docs/Governance Officer/Create_Governance_Procedure.md +0 -128
  193. md_processing/family_docs/Governance Officer/Create_Governance_Process.md +0 -122
  194. md_processing/family_docs/Governance Officer/Create_Governance_Processing_Purpose.md +0 -106
  195. md_processing/family_docs/Governance Officer/Create_Governance_Responsibility.md +0 -122
  196. md_processing/family_docs/Governance Officer/Create_Governance_Rule.md +0 -122
  197. md_processing/family_docs/Governance Officer/Create_Governance_Strategy.md +0 -106
  198. md_processing/family_docs/Governance Officer/Create_License_Type.md +0 -112
  199. md_processing/family_docs/Governance Officer/Create_Naming_Standard_Rule.md +0 -122
  200. md_processing/family_docs/Governance Officer/Create_Regulation_Article.md +0 -106
  201. md_processing/family_docs/Governance Officer/Create_Regulation_Definition.md +0 -118
  202. md_processing/family_docs/Governance Officer/Create_Security_Access_Control.md +0 -114
  203. md_processing/family_docs/Governance Officer/Create_Security_Group.md +0 -120
  204. md_processing/family_docs/Governance Officer/Create_Service_Level_Objectives.md +0 -122
  205. md_processing/family_docs/Governance Officer/Create_Threat_Definition.md +0 -106
  206. md_processing/family_docs/Governance Officer/Link_Governance_Controls.md +0 -32
  207. md_processing/family_docs/Governance Officer/Link_Governance_Drivers.md +0 -32
  208. md_processing/family_docs/Governance Officer/Link_Governance_Policies.md +0 -32
  209. md_processing/family_docs/Governance Officer/View_Governance_Definitions.md +0 -82
  210. md_processing/family_docs/Governance Officer.md +0 -2412
  211. md_processing/family_docs/Solution Architect/Create_Information_Supply_Chain.md +0 -70
  212. md_processing/family_docs/Solution Architect/Create_Solution_Blueprint.md +0 -44
  213. md_processing/family_docs/Solution Architect/Create_Solution_Component.md +0 -96
  214. md_processing/family_docs/Solution Architect/Create_Solution_Role.md +0 -66
  215. md_processing/family_docs/Solution Architect/Link_Information_Supply_Chain_Peers.md +0 -32
  216. md_processing/family_docs/Solution Architect/Link_Solution_Component_Peers.md +0 -32
  217. md_processing/family_docs/Solution Architect/View_Information_Supply_Chains.md +0 -32
  218. md_processing/family_docs/Solution Architect/View_Solution_Blueprints.md +0 -32
  219. md_processing/family_docs/Solution Architect/View_Solution_Components.md +0 -32
  220. md_processing/family_docs/Solution Architect/View_Solution_Roles.md +0 -32
  221. md_processing/family_docs/Solution Architect.md +0 -490
  222. md_processing/md_commands/old_project_commands.py +0 -164
  223. md_processing/md_processing_utils/debug_log.log +0 -5580
  224. md_processing/md_processing_utils/generated_help_terms.md +0 -842
  225. md_processing/md_processing_utils/logs/pyegeria.log +0 -56
  226. pyegeria/.DS_Store +0 -0
  227. pyegeria/___external_references.py +0 -3267
  228. {pyegeria-5.4.3.3.dist-info → pyegeria-5.4.4.dist-info}/LICENSE +0 -0
  229. {pyegeria-5.4.3.3.dist-info → pyegeria-5.4.4.dist-info}/WHEEL +0 -0
  230. {pyegeria-5.4.3.3.dist-info → pyegeria-5.4.4.dist-info}/entry_points.txt +0 -0
@@ -12,13 +12,18 @@ import sys
12
12
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
13
13
 
14
14
  from httpx import Response
15
+ from loguru import logger
16
+
17
+ from pyegeria.models import NewElementRequestBody, TemplateRequestBody, UpdateElementRequestBody, \
18
+ NewRelationshipRequestBody, DeleteRequestBody, UpdateStatusRequestBody, SearchStringRequestBody
15
19
  from pyegeria.output_formatter import make_preamble, make_md_attribute, generate_output, extract_mermaid_only, \
16
- extract_basic_dict, MD_SEPARATOR
20
+ extract_basic_dict, MD_SEPARATOR, populate_common_columns
21
+ from pyegeria._output_formats import select_output_format_set, get_output_format_type_match
17
22
  from pyegeria import validate_guid
18
23
  from pyegeria.governance_officer import GovernanceOfficer
19
- from pyegeria._client import Client, max_paging_size
20
- from pyegeria._globals import NO_ELEMENTS_FOUND
21
- from pyegeria.utils import body_slimmer
24
+ from pyegeria._client_new import Client2, max_paging_size
25
+ from pyegeria._globals import NO_ELEMENTS_FOUND, NO_GUID_RETURNED
26
+ from pyegeria.utils import body_slimmer, dynamic_catch
22
27
  from pyegeria._exceptions import (InvalidParameterException)
23
28
 
24
29
  sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
@@ -53,7 +58,7 @@ def base_path(client, view_server: str):
53
58
  return f"{client.platform_url}/servers/{view_server}/api/open-metadata/metadata-explorer"
54
59
 
55
60
 
56
- class SolutionArchitect(Client):
61
+ class SolutionArchitect(Client2):
57
62
  """SolutionArchitect is a class that extends the Client class. The Solution Architect OMVS provides APIs for
58
63
  searching for architectural elements such as information supply chains, solution blueprints, solution components,
59
64
  and component implementations.
@@ -82,7 +87,7 @@ class SolutionArchitect(Client):
82
87
  self.user_pwd = user_pwd
83
88
  self.solution_architect_command_root: str = (f"{self.platform_url}/servers/{self.view_server}"
84
89
  f"/api/open-metadata/solution-architect")
85
- Client.__init__(self, view_server, platform_url, user_id=user_id, user_pwd=user_pwd, token=token, )
90
+ Client2.__init__(self, view_server, platform_url, user_id=user_id, user_pwd=user_pwd, token=token, )
86
91
  self.url_marker = "solution-architect"
87
92
  #
88
93
  # Extract properties functions
@@ -220,7 +225,7 @@ class SolutionArchitect(Client):
220
225
  else:
221
226
  return []
222
227
 
223
- def _extract_info_supply_chain_properties(self, element: dict) -> dict:
228
+ def _extract_info_supply_chain_properties(self, element: dict, columns_struct: dict) -> dict:
224
229
  """
225
230
  Extract properties from an information supply chain element.
226
231
 
@@ -230,63 +235,18 @@ class SolutionArchitect(Client):
230
235
  Returns:
231
236
  Dictionary with extracted properties
232
237
  """
233
- guid = element['elementHeader'].get("guid", None)
234
- properties = element['properties']
235
- qualified_name = properties.get("qualifiedName", None)
236
- display_name = properties.get("displayName", None)
237
- description = properties.get("description", None)
238
- scope = properties.get("scope", None)
239
- purposes = properties.get("purposes", [])
240
- purpose_md = ""
241
- if purposes:
242
- for purpose in purposes:
243
- purpose_md += f"{purpose},\n"
244
- extended_properties = properties.get("extendedProperties", {})
245
- additional_properties = properties.get("additionalProperties", {})
246
- mer = element.get('mermaidGraph', None)
247
-
248
-
249
- parents = element.get("parents", [])
250
- parents_list = []
251
- if parents:
252
- for sub in parents:
253
- sub_rel_label = sub.get('relationshipProperties',{}).get("label", None)
254
- sub_qn = sub['relatedElement']['properties']['qualifiedName']
255
- sub_lab = f"--> <{sub_rel_label}> -->" if sub_rel_label else ""
256
- sub_info = f"{sub_lab} {sub_qn}"
257
- parents_list.append(sub_info)
258
-
259
- peer_supply_chains = element.get("links", {})
260
- peer_supply_chains_list = []
261
- if peer_supply_chains:
262
- for peer in peer_supply_chains:
263
- peer_supply_chain_qnames = peer['relatedElement']['properties'].get("qualifiedName", "")
264
- peer_supply_chain_label = peer['relationshipProperties'].get('label', None)
265
- peer_lab = f"==> <{peer_supply_chain_label}> ==>" if peer_supply_chain_label else ""
266
- peer_supply_chains_list.append(f"{peer_lab} {peer_supply_chain_qnames}")
267
-
268
- implemented_by = element.get("implementedByList", {})
269
- implemented_by_qnames = []
270
- if implemented_by:
271
- for peer in peer_supply_chains:
272
- implemented_by_qnames.append(peer['relatedElement']['properties'].get("qualifiedName", ""))
273
-
274
- return {
275
- 'GUID': guid,
276
- 'qualified_name': qualified_name,
277
- 'display_name': display_name,
278
- 'description': description,
279
- 'scope': scope,
280
- 'purposes': purpose_md,
281
- 'extended_properties': extended_properties,
282
- 'additional_properties': additional_properties,
283
- 'parents_list': parents_list,
284
- 'links': peer_supply_chains_list,
285
- 'implemented_by': implemented_by_qnames,
286
- 'mermaid': mer
287
- }
288
-
289
- def _extract_solution_blueprint_properties(self, element: dict) -> dict:
238
+ # Follow common extractor pattern using populate_common_columns
239
+ return populate_common_columns(
240
+ element,
241
+ columns_struct,
242
+ include_header=True,
243
+ include_relationships=True,
244
+ include_subject_area=True,
245
+ mermaid_source_key='mermaidGraph',
246
+ mermaid_dest_key='mermaid'
247
+ )
248
+
249
+ def _extract_solution_blueprint_properties(self, element: dict, columns_struct: dict) -> dict:
290
250
  """
291
251
  Extract properties from a solution blueprint element.
292
252
 
@@ -296,34 +256,17 @@ class SolutionArchitect(Client):
296
256
  Returns:
297
257
  Dictionary with extracted properties
298
258
  """
299
- guid = element['elementHeader'].get("guid", None)
300
- element_properties = element['properties']
301
- display_name = element_properties.get("displayName", None)
302
- description = element_properties.get("description", None)
303
- version = element_properties.get("version", None)
304
- qualified_name = element_properties.get("qualifiedName", None)
305
-
306
- solution_components = element.get('solutionComponents', None)
307
- solution_components_md = ""
308
- if solution_components:
309
- for solution_component in solution_components:
310
- sol_comp_prop = solution_component['solutionComponent']['properties']
311
- sol_comp_name = sol_comp_prop.get("displayName", None)
312
- sol_comp_desc = sol_comp_prop.get("description", None)
313
- solution_components_md += '{' + f" {sol_comp_name}:\t {sol_comp_desc}" + " },\n"
314
- mer = f"```mermaid\n\n{element.get('mermaidGraph', None)}\n\n```"
315
-
316
- return {
317
- 'GUID': guid,
318
- 'qualified_name': qualified_name,
319
- 'display_name': display_name,
320
- 'description': description,
321
- 'version': version,
322
- 'solution_components': solution_components_md,
323
- 'mermaid': mer
324
- }
325
-
326
- def _extract_solution_roles_properties(self, element: dict) -> dict:
259
+ return populate_common_columns(
260
+ element,
261
+ columns_struct,
262
+ include_header=True,
263
+ include_relationships=True,
264
+ include_subject_area=True,
265
+ mermaid_source_key='mermaidGraph',
266
+ mermaid_dest_key='mermaid'
267
+ )
268
+
269
+ def _extract_solution_roles_properties(self, element: dict, columns_struct: dict) -> dict:
327
270
  """
328
271
  Extract properties from a solution role element.
329
272
 
@@ -333,35 +276,15 @@ class SolutionArchitect(Client):
333
276
  Returns:
334
277
  Dictionary with extracted properties
335
278
  """
336
- guid = element['elementHeader'].get("guid", None)
337
- element_properties = element['properties']
338
- display_name = element_properties.get("title", None)
339
- role_id = element_properties.get("roleId", None)
340
- scope = element_properties.get("scope", None)
341
- description = element_properties.get("description", None)
342
- domain_identifier = element_properties.get("domainIdentifier", None)
343
- qualified_name = element_properties.get("qualifiedName", None)
344
-
345
- solution_components = element.get('solutionComponents', None)
346
- solution_components_md = ""
347
- if solution_components:
348
- for solution_component in solution_components:
349
- sol_comp_prop = solution_component.get('relationshipProperties', None)
350
- if sol_comp_prop:
351
- sol_comp_name = sol_comp_prop.get("role", None)
352
- sol_comp_desc = sol_comp_prop.get("description", None)
353
- solution_components_md += "{" + f" {sol_comp_name}:\t {sol_comp_desc}" + " },\n"
354
-
355
- return {
356
- 'GUID': guid,
357
- 'qualified_name': qualified_name,
358
- 'display_name': display_name,
359
- 'description': description,
360
- 'role_id': role_id,
361
- 'scope': scope,
362
- 'domain_identifier': domain_identifier,
363
- 'solution_components': solution_components_md
364
- }
279
+ return populate_common_columns(
280
+ element,
281
+ columns_struct,
282
+ include_header=True,
283
+ include_relationships=True,
284
+ include_subject_area=True,
285
+ mermaid_source_key='mermaidGraph',
286
+ mermaid_dest_key='mermaid'
287
+ )
365
288
 
366
289
 
367
290
 
@@ -548,7 +471,7 @@ class SolutionArchitect(Client):
548
471
  else:
549
472
  return []
550
473
 
551
- def _extract_solution_components_properties(self, element: Union[Dict,List[Dict]]) -> dict:
474
+ def _extract_solution_components_properties(self, element: Union[Dict,List[Dict]], columns_struct: dict) -> dict:
552
475
  """
553
476
  Extract properties from a solution component element.
554
477
 
@@ -559,125 +482,51 @@ class SolutionArchitect(Client):
559
482
  Dictionary with extracted properties
560
483
  """
561
484
 
562
- guid = element['elementHeader'].get("guid", None)
563
- properties = element.get('glossaryCategoryProperties', element.get('properties', {}))
564
- display_name = properties.get("displayName", None)
565
- description = properties.get("description", None)
566
- component_type = properties.get("solutionComponentType", properties.get("componentType", None))
567
- version = properties.get("version", None)
568
- qualified_name = properties.get("qualifiedName", None)
569
-
570
- # Extract extended properties
571
- extended_props = properties.get("extendedProperties", None)
572
- extended_props_md = ""
573
- if extended_props:
574
- for key in extended_props.keys():
575
- extended_props_md += "{" + f" {key}: {extended_props[key]}" + " }, "
576
-
577
- # Extract additional properties
578
- additional_props = properties.get("additionalProperties", None)
579
- additional_props_md = ""
580
- if additional_props:
581
- for key in additional_props.keys():
582
- additional_props_md += "{" + f" {key}: {additional_props[key]}" + " }, "
583
-
584
- rel_elements = self._get_component_rel_elements_dict(element)
585
-
586
- # actors
587
- actors_md = ", ".join(rel_elements.get("actor.qnames", []) )
588
-
589
- # Extract blueprints & supply chains
590
- blueprints_md = ", ".join(rel_elements.get("blueprint_qnames",[]))
591
- owning_supply_chains_md = ", ".join(rel_elements.get("owning_info_supply_chain_qnames",[]))
592
-
593
- # Extract parent components
594
- parent_comp_md = ", ".join(rel_elements.get("parent_qnames",[]))
595
-
596
- # Extract sub-components
597
- sub_comp_md = ", ".join(rel_elements.get("sub_component_qnames",[]))
598
-
599
- # wired from and to
600
- wired_from_md = ", ".join(rel_elements.get("wired_from_qnames",[]))
601
- wired_to_md = ", ".join(rel_elements.get("wired_to_qnames",[]))
602
-
603
-
604
- comp_graph = element.get('mermaidGraph', None)
605
-
606
- return {
607
- 'GUID': guid,
608
- 'qualified_name': qualified_name,
609
- 'display_name': display_name,
610
- 'description': description,
611
- 'component_type': component_type,
612
- 'version': version,
613
- 'blueprints': blueprints_md,
614
- 'owning_supply_chains': owning_supply_chains_md,
615
- 'actors': actors_md,
616
- 'parent_components': parent_comp_md,
617
- 'sub_components': sub_comp_md,
618
- 'wired_from_components': wired_from_md,
619
- 'wired_to_components': wired_to_md,
620
- 'additional_properties': additional_props_md,
621
- 'extended_properties': extended_props_md,
622
- 'mermaid_graph': comp_graph
623
- }
485
+ return populate_common_columns(
486
+ element,
487
+ columns_struct,
488
+ include_header=True,
489
+ include_relationships=True,
490
+ include_subject_area=True,
491
+ mermaid_source_key='mermaidGraph',
492
+ mermaid_dest_key='mermaid'
493
+ )
624
494
 
625
495
  #
626
496
  # Markdown output support
627
497
  #
628
- def generate_info_supply_chain_output(self, elements: list | dict, search_string: str,
629
- output_format: str = 'MD') -> str | list:
630
- """
631
- Generate output for information supply chains in the specified format.
632
-
633
- Args:
634
- elements: Dictionary or list of dictionaries containing information supply chain elements
635
- search_string: The search string used to find the elements
636
- output_format: The desired output format (MD, FORM, REPORT, LIST, DICT, MERMAID, HTML)
637
-
638
- Returns:
639
- Formatted output as string or list of dictionaries
498
+ def generate_info_supply_chain_output(self, elements: list | dict, search_string: str, element_type_name: str | None,
499
+ output_format: str = 'MD', output_format_set: dict | str = None) -> str | list:
500
+ """Render Information Supply Chains using the shared output pipeline.
640
501
  """
641
- # Handle MERMAID and DICT formats
642
502
  if output_format == "MERMAID":
643
503
  return extract_mermaid_only(elements)
644
- elif output_format == "DICT":
645
- # return extract_basic_dict(elements)
646
- return self._extract_supply_chain_list(elements)
647
- elif output_format == "HTML":
648
- return generate_output(
649
- elements=elements,
650
- search_string=search_string,
651
- entity_type="Information Supply Chain",
652
- output_format="HTML",
653
- extract_properties_func=self._extract_info_supply_chain_properties
654
- )
655
- # For other formats (MD, FORM, REPORT, LIST), use generate_output
656
- elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
657
- # Define columns for LIST format
658
- columns = [
659
- {'name': 'Name', 'key': 'display_name'},
660
- {'name': 'Qualified Name', 'key': 'qualified_name'},
661
- {'name': 'Scope', 'key': 'scope'},
662
- {'name': 'Description', 'key': 'description', 'format': True},
663
- {'name': 'Purposes', 'key': 'purposes', 'format': True},
664
- {'name': 'Peer Links', 'key': 'links', 'format': True},
665
- ]
666
-
667
- return generate_output(
668
- elements=elements,
669
- search_string=search_string,
670
- entity_type="Information Supply Chain",
671
- output_format=output_format,
672
- extract_properties_func=self._extract_info_supply_chain_properties,
673
- columns=columns if output_format == 'LIST' else None
674
- )
675
-
676
- # Default case
677
- return None
678
-
679
- def generate_solution_blueprint_output(self, elements: list | dict, search_string: str,
680
- output_format: str = 'MD') -> str | list:
504
+
505
+ entity_type = "Information Supply Chain"
506
+ if output_format_set:
507
+ if isinstance(output_format_set, str):
508
+ output_formats = select_output_format_set(output_format_set, output_format)
509
+ elif isinstance(output_format_set, dict):
510
+ output_formats = get_output_format_type_match(output_format_set, output_format)
511
+ else:
512
+ output_formats = None
513
+ else:
514
+ output_formats = select_output_format_set("Information Supply Chains", output_format)
515
+ if output_formats is None:
516
+ output_formats = select_output_format_set("Default", output_format)
517
+
518
+ return generate_output(
519
+ elements=elements,
520
+ search_string=search_string,
521
+ entity_type=entity_type,
522
+ output_format=output_format,
523
+ extract_properties_func=self._extract_info_supply_chain_properties,
524
+ get_additional_props_func=None,
525
+ columns_struct=output_formats,
526
+ )
527
+
528
+ def generate_solution_blueprint_output(self, elements: list | dict, search_string: str, element_type_name: str | None,
529
+ output_format: str = 'MD', output_format_set: dict | str = None) -> str | list:
681
530
  """
682
531
  Generate output for solution blueprints in the specified format.
683
532
 
@@ -689,43 +538,34 @@ class SolutionArchitect(Client):
689
538
  Returns:
690
539
  Formatted output as string or list of dictionaries
691
540
  """
692
- # Handle MERMAID and DICT formats
693
541
  if output_format == "MERMAID":
694
542
  return extract_mermaid_only(elements)
695
- elif output_format == "DICT":
696
- return extract_basic_dict(elements)
697
- elif output_format == "HTML":
698
- return generate_output(
699
- elements=elements,
700
- search_string=search_string,
701
- entity_type="Solution Blueprint",
702
- output_format="HTML",
703
- extract_properties_func=self._extract_solution_blueprint_properties
704
- )
705
-
706
- # For other formats (MD, FORM, REPORT, LIST), use generate_output
707
- elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
708
- # Define columns for LIST format
709
- columns = [
710
- {'name': 'Blueprint Name', 'key': 'display_name'},
711
- {'name': 'Qualified Name', 'key': 'qualified_name'},
712
- {'name': 'Version', 'key': 'version'},
713
- {'name': 'Description', 'key': 'description', 'format': True}
714
- ]
715
-
716
- return generate_output(
717
- elements=elements,
718
- search_string=search_string,
719
- entity_type="Solution Blueprint",
720
- output_format=output_format,
721
- extract_properties_func=self._extract_solution_blueprint_properties,
722
- columns=columns if output_format == 'LIST' else None
723
- )
724
-
725
- # Default case
726
- return None
727
-
728
- def generate_solution_roles_output(self, elements: list | dict, search_string: str, output_format: str = 'MD') -> str | list:
543
+
544
+ entity_type = "Solution Blueprint"
545
+ if output_format_set:
546
+ if isinstance(output_format_set, str):
547
+ output_formats = select_output_format_set(output_format_set, output_format)
548
+ elif isinstance(output_format_set, dict):
549
+ output_formats = get_output_format_type_match(output_format_set, output_format)
550
+ else:
551
+ output_formats = None
552
+ else:
553
+ output_formats = select_output_format_set("Solution Blueprints", output_format)
554
+ if output_formats is None:
555
+ output_formats = select_output_format_set("Default", output_format)
556
+
557
+ return generate_output(
558
+ elements=elements,
559
+ search_string=search_string,
560
+ entity_type=entity_type,
561
+ output_format=output_format,
562
+ extract_properties_func=self._extract_solution_blueprint_properties,
563
+ get_additional_props_func=None,
564
+ columns_struct=output_formats,
565
+ )
566
+
567
+ def generate_solution_roles_output(self, elements: list | dict, search_string: str, element_type_name: str | None,
568
+ output_format: str = 'MD', output_format_set: dict | str = None) -> str | list:
729
569
  """
730
570
  Generate output for solution roles in the specified format.
731
571
 
@@ -737,45 +577,34 @@ class SolutionArchitect(Client):
737
577
  Returns:
738
578
  Formatted output as string or list of dictionaries
739
579
  """
740
- # Handle MERMAID and DICT formats
741
580
  if output_format == "MERMAID":
742
581
  return extract_mermaid_only(elements)
743
- elif output_format == "DICT":
744
- return extract_basic_dict(elements)
745
- elif output_format == "HTML":
746
- return generate_output(
747
- elements=elements,
748
- search_string=search_string,
749
- entity_type="Solution Role",
750
- output_format="HTML",
751
- extract_properties_func=self._extract_solution_roles_properties
752
- )
753
-
754
- # For other formats (MD, FORM, REPORT, LIST), use generate_output
755
- elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
756
- # Define columns for LIST format
757
- columns = [
758
- {'name': 'Role Name', 'key': 'display_name'},
759
- {'name': 'Role ID', 'key': 'role_id'},
760
- {'name': 'Scope', 'key': 'scope'},
761
- {'name': 'Domain', 'key': 'domain_identifier'},
762
- {'name': 'Description', 'key': 'description', 'format': True}
763
- ]
764
-
765
- return generate_output(
766
- elements=elements,
767
- search_string=search_string,
768
- entity_type="Solution Role",
769
- output_format=output_format,
770
- extract_properties_func=self._extract_solution_roles_properties,
771
- columns=columns if output_format == 'LIST' else None
772
- )
773
-
774
- # Default case
775
- return None
776
-
777
- def generate_solution_components_output(self, elements: list | dict, search_string: str,
778
- output_format: str = 'MD') -> str | list:
582
+
583
+ entity_type = "Solution Role"
584
+ if output_format_set:
585
+ if isinstance(output_format_set, str):
586
+ output_formats = select_output_format_set(output_format_set, output_format)
587
+ elif isinstance(output_format_set, dict):
588
+ output_formats = get_output_format_type_match(output_format_set, output_format)
589
+ else:
590
+ output_formats = None
591
+ else:
592
+ output_formats = select_output_format_set("Solution Roles", output_format)
593
+ if output_formats is None:
594
+ output_formats = select_output_format_set("Default", output_format)
595
+
596
+ return generate_output(
597
+ elements=elements,
598
+ search_string=search_string,
599
+ entity_type=entity_type,
600
+ output_format=output_format,
601
+ extract_properties_func=self._extract_solution_roles_properties,
602
+ get_additional_props_func=None,
603
+ columns_struct=output_formats,
604
+ )
605
+
606
+ def generate_solution_components_output(self, elements: list | dict, search_string: str, element_type_name: str | None,
607
+ output_format: str = 'MD', output_format_set: dict | str = None) -> str | list:
779
608
  """
780
609
  Generate output for solution components in the specified format.
781
610
 
@@ -792,50 +621,39 @@ class SolutionArchitect(Client):
792
621
  Returns:
793
622
  Formatted output as string or list of dictionaries
794
623
  """
795
- # Handle MERMAID and DICT formats
796
624
  if output_format == "MERMAID":
797
625
  return extract_mermaid_only(elements)
798
- elif output_format == "DICT":
799
- return self._extract_component_list(elements)
800
- # return extract_basic_dict(elements)
801
- # add more to the body
802
- elif output_format == "HTML":
803
- return generate_output(
804
- elements=elements,
805
- search_string=search_string,
806
- entity_type="Solution Component",
807
- output_format="HTML",
808
- extract_properties_func=self._extract_solution_components_properties
809
- )
810
- # For other formats (MD, FORM, REPORT, LIST), use generate_output
811
- elif output_format in ["MD", "FORM", "REPORT", "LIST"]:
812
- # Define columns for LIST format
813
- columns = [
814
- {'name': 'Component Name', 'key': 'display_name'},
815
- {'name': 'Component Type', 'key': 'component_type'},
816
- {'name': 'Version', 'key': 'version'},
817
- {'name': 'Qualified Name', 'key': 'qualified_name'},
818
- {'name': 'Description', 'key': 'description', 'format': True}
819
- ]
820
-
821
- return generate_output(
822
- elements=elements,
823
- search_string=search_string,
824
- entity_type="Solution Component",
825
- output_format=output_format,
826
- extract_properties_func=self._extract_solution_components_properties,
827
- columns=columns if output_format == 'LIST' else None
828
- )
829
-
830
- # Default case
831
- return None
832
-
833
- async def _async_create_info_supply_chain(self, body: dict) -> str:
626
+
627
+ entity_type = "Solution Component"
628
+ if output_format_set:
629
+ if isinstance(output_format_set, str):
630
+ output_formats = select_output_format_set(output_format_set, output_format)
631
+ elif isinstance(output_format_set, dict):
632
+ output_formats = get_output_format_type_match(output_format_set, output_format)
633
+ else:
634
+ output_formats = None
635
+ else:
636
+ output_formats = select_output_format_set("Solution Components", output_format)
637
+ if output_formats is None:
638
+ output_formats = select_output_format_set("Default", output_format)
639
+
640
+ return generate_output(
641
+ elements=elements,
642
+ search_string=search_string,
643
+ entity_type=entity_type,
644
+ output_format=output_format,
645
+ extract_properties_func=self._extract_solution_components_properties,
646
+ get_additional_props_func=None,
647
+ columns_struct=output_formats,
648
+ )
649
+
650
+ @dynamic_catch
651
+ async def _async_create_info_supply_chain(self, body: dict | NewElementRequestBody) -> str:
834
652
  """Create an information supply. Async version.
835
653
 
836
654
  Parameters
837
655
  ----------
838
- body: dict
656
+ body: dict | NewElementRequestBody
839
657
  A dictionary containing the definition of the supply chain to create.
840
658
 
841
659
  Returns
@@ -887,6 +705,7 @@ class SolutionArchitect(Client):
887
705
  "description": "add description here",
888
706
  "scope": "add scope of this information supply chain's applicability.",
889
707
  "purposes": ["purpose1", "purpose2"],
708
+ "estimatedVolumetrics": {},
890
709
  "additionalProperties": {
891
710
  "property1": "propertyValue1",
892
711
  "property2": "propertyValue2"
@@ -900,16 +719,15 @@ class SolutionArchitect(Client):
900
719
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
901
720
  f"information-supply-chains")
902
721
 
903
- response = await self._async_make_request("POST", url, body_slimmer(body))
904
-
905
- return response.json().get("guid", "Supply Chain not created")
722
+ return await self._async_create_element_body_request(url, ["InformationSupplyChainProperties"], body)
906
723
 
907
- def create_info_supply_chain(self, body: dict) -> str:
724
+ @dynamic_catch
725
+ def create_info_supply_chain(self, body: dict | NewElementRequestBody) -> str:
908
726
  """Create an information supply.
909
727
 
910
728
  Parameters
911
729
  ----------
912
- body: dict
730
+ body: dict | NewElementRequestBody
913
731
  A dictionary containing the definition of the supply chain to create.
914
732
 
915
733
  Returns
@@ -961,6 +779,7 @@ class SolutionArchitect(Client):
961
779
  "description": "add description here",
962
780
  "scope": "add scope of this information supply chain's applicability.",
963
781
  "purposes": ["purpose1", "purpose2"],
782
+ "estimatedVolumetrics": {},
964
783
  "additionalProperties": {
965
784
  "property1": "propertyValue1",
966
785
  "property2": "propertyValue2"
@@ -975,7 +794,8 @@ class SolutionArchitect(Client):
975
794
  response = loop.run_until_complete(self._async_create_info_supply_chain(body))
976
795
  return response
977
796
 
978
- async def _async_create_info_supply_chain_from_template(self, body: dict) -> str:
797
+ @dynamic_catch
798
+ async def _async_create_info_supply_chain_from_template(self, body: dict | TemplateRequestBody) -> str:
979
799
  """ Create a new metadata element to represent an information supply chain using an existing metadata element
980
800
  as a template. The template defines additional classifications and relationships that should be added to
981
801
  the new element. Async Version.
@@ -983,7 +803,7 @@ class SolutionArchitect(Client):
983
803
 
984
804
  Parameters
985
805
  ----------
986
- body: dict
806
+ body: dict | NewElementRequestBody
987
807
  A dictionary containing the definition of the supply chain to create.
988
808
 
989
809
  Returns
@@ -1049,18 +869,27 @@ class SolutionArchitect(Client):
1049
869
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1050
870
  f"information-supply-chains/from-template")
1051
871
 
1052
- response = await self._async_make_request("POST", url, body_slimmer(body))
872
+ if isinstance(body, TemplateRequestBody):
873
+ validated_body = body
874
+
875
+ elif isinstance(body, dict):
876
+ validated_body = self._template_request_adapter.validate_python(body)
1053
877
 
1054
- return response.json().get("guid", "Supply Chain not created")
878
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
879
+ logger.info(json_body)
880
+ resp = await self._async_make_request("POST", url, json_body, is_json=True)
881
+ logger.info(f"Create Supply Chain from template with GUID: {resp.json().get('guid')}")
882
+ return resp.json().get("guid", NO_GUID_RETURNED)
1055
883
 
1056
- def create_info_supply_chain_from_template(self, body: dict) -> str:
884
+ @dynamic_catch
885
+ def create_info_supply_chain_from_template(self, body: dict| TemplateRequestBody) -> str:
1057
886
  """ Create a new metadata element to represent an information supply chain using an existing metadata element
1058
887
  as a template. The template defines additional classifications and relationships that should be added to
1059
888
  the new element.
1060
889
 
1061
890
  Parameters
1062
891
  ----------
1063
- body: dict
892
+ body: dict | TemplateRequestBody
1064
893
  A dictionary containing the definition of the supply chain to create.
1065
894
 
1066
895
  Returns
@@ -1128,18 +957,17 @@ class SolutionArchitect(Client):
1128
957
  response = loop.run_until_complete(self._async_create_info_supply_chain_from_template(body))
1129
958
  return response
1130
959
 
1131
- async def _async_update_info_supply_chain(self, guid: str, body: dict,
1132
- replace_all_properties: bool = False) -> None:
960
+ @dynamic_catch
961
+ async def _async_update_info_supply_chain(self, guid: str, body: dict | UpdateElementRequestBody,) -> None:
1133
962
  """ Update the properties of an information supply chain. Async Version.
1134
963
 
1135
964
  Parameters
1136
965
  ----------
1137
966
  guid: str
1138
967
  guid of the information supply chain to update.
1139
- body: dict
968
+ body: dict | UpdateElementRequestBody
1140
969
  A dictionary containing the updates to the supply chain.
1141
- replace_all_properties: bool, optional
1142
- Whether to replace all properties with those provided in the body or to merge with existing properties.
970
+
1143
971
 
1144
972
  Returns
1145
973
  -------
@@ -1184,24 +1012,22 @@ class SolutionArchitect(Client):
1184
1012
  }
1185
1013
  }
1186
1014
  """
1187
- validate_guid(guid)
1188
- replace_all_properties_s = str(replace_all_properties).lower()
1015
+
1189
1016
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1190
- f"information-supply-chains/{guid}/update?replaceAllProperties={replace_all_properties_s}")
1017
+ f"information-supply-chains/{guid}/update")
1191
1018
 
1192
- await self._async_make_request("POST", url, body_slimmer(body))
1019
+ await self._async_update_element_body_request(url, ["InformationSupplyChainProperties"],body)
1193
1020
 
1194
- def update_info_supply_chain(self, guid: str, body: dict, replace_all_properties: bool = False) -> None:
1021
+ @dynamic_catch
1022
+ def update_info_supply_chain(self, guid: str, body: dict | UpdateElementRequestBody) -> None:
1195
1023
  """ Update the properties of an information supply chain. Async Version.
1196
1024
 
1197
1025
  Parameters
1198
1026
  ----------
1199
1027
  guid: str
1200
1028
  guid of the information supply chain to update.
1201
- body: dict
1029
+ body: dict | UpdateElementRequestBody
1202
1030
  A dictionary containing the updates to the supply chain.
1203
- replace_all_properties: bool, optional
1204
- Whether to replace all properties with those provided in the body or to merge with existing properties.
1205
1031
 
1206
1032
  Returns
1207
1033
  -------
@@ -1247,10 +1073,10 @@ class SolutionArchitect(Client):
1247
1073
  }
1248
1074
  """
1249
1075
  loop = asyncio.get_event_loop()
1250
- loop.run_until_complete(self._async_update_info_supply_chain(guid, body, replace_all_properties))
1076
+ loop.run_until_complete(self._async_update_info_supply_chain(guid, body))
1251
1077
 
1252
-
1253
- async def _async_link_peer_info_supply_chain(self, peer1_guid: str, peer2_guid: str, body: dict = None) -> None:
1078
+ @dynamic_catch
1079
+ async def _async_link_peer_info_supply_chains(self, peer1_guid: str, peer2_guid: str, body: dict | NewRelationshipRequestBody = None) -> None:
1254
1080
  """ Connect two peer information supply chains. The linked elements are of type 'Referenceable' to
1255
1081
  allow significant data stores to be included in the definition of the information supply chain.
1256
1082
  Request body is optional. Async Version.
@@ -1261,7 +1087,7 @@ class SolutionArchitect(Client):
1261
1087
  guid of the first information supply chain to link.
1262
1088
  peer2_guid: str
1263
1089
  guid of the second information supply chain to link.
1264
- body: dict, optional
1090
+ body: dict | NewRelationshipRequestBody, optional
1265
1091
  The body describing the link between the two chains.
1266
1092
 
1267
1093
  Returns
@@ -1282,7 +1108,7 @@ class SolutionArchitect(Client):
1282
1108
 
1283
1109
  Body structure:
1284
1110
  {
1285
- "class" : "RelationshipRequestBody",
1111
+ "class" : "NewRelationshipRequestBody",
1286
1112
  "externalSourceGUID": "add guid here",
1287
1113
  "externalSourceName": "add qualified name here",
1288
1114
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1297,17 +1123,15 @@ class SolutionArchitect(Client):
1297
1123
  }
1298
1124
  }
1299
1125
  """
1300
- validate_guid(peer1_guid)
1301
- validate_guid(peer2_guid)
1126
+
1302
1127
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1303
1128
  f"information-supply-chains/{peer1_guid}/peer-links/{peer2_guid}/attach")
1304
1129
 
1305
- if body:
1306
- await self._async_make_request("POST", url, body_slimmer(body))
1307
- else:
1308
- await self._async_make_request("POST", url)
1130
+ await self._async_new_relationship_request(url, ["InformationSupplyChainLinkProperties"], body)
1131
+ logger.info(f"Linked Supply Chains {peer1_guid} -> {peer2_guid}")
1309
1132
 
1310
- def link_peer_info_supply_chain(self, peer1_guid: str, peer2_guid: str, body: dict) -> None:
1133
+ @dynamic_catch
1134
+ def link_peer_info_supply_chains(self, peer1_guid: str, peer2_guid: str, body: dict | NewRelationshipRequestBody) -> None:
1311
1135
  """ Connect two peer information supply chains. The linked elements are of type 'Referenceable' to
1312
1136
  allow significant data stores to be included in the definition of the information supply chain.
1313
1137
  Request body is optional.
@@ -1318,7 +1142,7 @@ class SolutionArchitect(Client):
1318
1142
  guid of the first information supply chain to link.
1319
1143
  peer2_guid: str
1320
1144
  guid of the second information supply chain to link.
1321
- body: dict
1145
+ body: dict | NewRelationshipRequestBody, optional
1322
1146
  The body describing the link between the two chains.
1323
1147
 
1324
1148
  Returns
@@ -1355,10 +1179,11 @@ class SolutionArchitect(Client):
1355
1179
  }
1356
1180
  """
1357
1181
  loop = asyncio.get_event_loop()
1358
- loop.run_until_complete(self._async_link_peer_info_supply_chain(peer1_guid, peer2_guid, body))
1182
+ loop.run_until_complete(self._async_link_peer_info_supply_chains(peer1_guid, peer2_guid, body))
1359
1183
 
1184
+ @dynamic_catch
1360
1185
  async def _async_unlink_peer_info_supply_chains(self, peer1_guid: str, peer2_guid: str,
1361
- body: dict = None) -> None:
1186
+ body: dict | DeleteRequestBody = None) -> None:
1362
1187
  """ Detach two peers in an information supply chain from one another. The linked elements are of type
1363
1188
  'Referenceable' to allow significant data stores to be included in the definition of the information
1364
1189
  supply chain. Request body is optional. Async Version.
@@ -1369,7 +1194,7 @@ class SolutionArchitect(Client):
1369
1194
  guid of the first information supply chain to link.
1370
1195
  peer2_guid: str
1371
1196
  guid of the second information supply chain to link.
1372
- body: dict, optional
1197
+ body: dict | DeleteRequestBody, optional
1373
1198
  The body describing the link between the two segments.
1374
1199
 
1375
1200
  Returns
@@ -1390,7 +1215,7 @@ class SolutionArchitect(Client):
1390
1215
 
1391
1216
  Body structure:
1392
1217
  {
1393
- "class": "MetadataSourceRequestBody",
1218
+ "class": "DeleteRequestBody",
1394
1219
  "externalSourceGUID": "add guid here",
1395
1220
  "externalSourceName": "add qualified name here",
1396
1221
  "effectiveTime": {{isotime}},
@@ -1403,11 +1228,11 @@ class SolutionArchitect(Client):
1403
1228
  validate_guid(peer2_guid)
1404
1229
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1405
1230
  f"information-supply-chains/{peer1_guid}/peer-links/{peer2_guid}/detach")
1406
- if body:
1407
- await self._async_make_request("POST", url, body_slimmer(body))
1408
- else:
1409
- await self._async_make_request("POST", url)
1231
+ await self._async_delete_request(url, body)
1232
+ logger.info(
1233
+ f"Detached supply chains {peer1_guid} -> {peer2_guid}")
1410
1234
 
1235
+ @dynamic_catch
1411
1236
  def unlink_peer_info_supply_chains(self, peer1_guid: str, peer2_guid: str,
1412
1237
  body: dict = None) -> None:
1413
1238
  """ Detach two peers in an information supply chain from one another. The linked elements are of type
@@ -1452,7 +1277,9 @@ class SolutionArchitect(Client):
1452
1277
  loop = asyncio.get_event_loop()
1453
1278
  loop.run_until_complete(self._async_unlink_peer_info_supply_chains(peer1_guid,peer2_guid, body))
1454
1279
 
1455
- async def _async_compose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str, body: dict = None) -> None:
1280
+ @dynamic_catch
1281
+ async def _async_compose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str,
1282
+ body: dict | NewRelationshipRequestBody = None) -> None:
1456
1283
  """ Connect a nested information supply chain to its parent. Request body is optional.
1457
1284
  Async Version.
1458
1285
 
@@ -1462,7 +1289,7 @@ class SolutionArchitect(Client):
1462
1289
  guid of the first information supply chain to link.
1463
1290
  nested_chain_guid: str
1464
1291
  guid of the second information supply chain to link.
1465
- body: dict, optional
1292
+ body: dict | NewRelationshipRequestBody, optional
1466
1293
  The body describing the link between the two chains.
1467
1294
 
1468
1295
  Returns
@@ -1483,7 +1310,7 @@ class SolutionArchitect(Client):
1483
1310
 
1484
1311
  Body structure:
1485
1312
  {
1486
- "class" : "RelationshipRequestBody",
1313
+ "class" : "NewRelationshipRequestBody",
1487
1314
  "externalSourceGUID": "add guid here",
1488
1315
  "externalSourceName": "add qualified name here",
1489
1316
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1502,21 +1329,21 @@ class SolutionArchitect(Client):
1502
1329
  validate_guid(nested_chain_guid)
1503
1330
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1504
1331
  f"information-supply-chains/{chain_guid}/compositions/{nested_chain_guid}/attach")
1505
- if body:
1506
- await self._async_make_request("POST", url, body_slimmer(body))
1507
- else:
1508
- await self._async_make_request("POST", url)
1509
1332
 
1510
- def compose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str, body: dict = None) -> None:
1333
+ await self._async_new_relationship_request(url, ["InformationSupplyChainCompositionProperties"], body)
1334
+ logger.info(f"Linked {chain_guid} -> {nested_chain_guid}")
1335
+
1336
+ @dynamic_catch
1337
+ def compose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str, body: dict | NewRelationshipRequestBody = None) -> None:
1511
1338
  """ Connect a nested information supply chain to its parent. Request body is optional.
1512
1339
 
1513
1340
  Parameters
1514
1341
  ----------
1515
1342
  chain_guid: str
1516
- guid of the first information supply chain to link.
1343
+ guid of the first information supply chain to link.
1517
1344
  nested_chain_guid: str
1518
1345
  guid of the second information supply chain to link.
1519
- body: dict, optional
1346
+ body: dict | NewRelationshipRequestBody, optional
1520
1347
  The body describing the link between the two chains.
1521
1348
 
1522
1349
  Returns
@@ -1537,7 +1364,7 @@ class SolutionArchitect(Client):
1537
1364
 
1538
1365
  Body structure:
1539
1366
  {
1540
- "class" : "RelationshipRequestBody",
1367
+ "class" : "NewRelationshipRequestBody",
1541
1368
  "externalSourceGUID": "add guid here",
1542
1369
  "externalSourceName": "add qualified name here",
1543
1370
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -1555,6 +1382,8 @@ class SolutionArchitect(Client):
1555
1382
  loop = asyncio.get_event_loop()
1556
1383
  loop.run_until_complete(self._async_compose_info_supply_chains(chain_guid, nested_chain_guid, body))
1557
1384
 
1385
+
1386
+ @dynamic_catch
1558
1387
  async def _async_decompose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str,
1559
1388
  body: dict = None) -> None:
1560
1389
  """ Detach two peers in an information supply chain from one another. Request body is optional. Async Version.
@@ -1600,10 +1429,12 @@ class SolutionArchitect(Client):
1600
1429
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1601
1430
  f"information-supply-chains/{chain_guid}/compositions/{nested_chain_guid}/detach")
1602
1431
 
1603
- await self._async_make_request("POST", url, body_slimmer(body))
1432
+ await self._async_delete_request(url, body)
1433
+ logger.info(f"Removed composition of {nested_chain_guid} -> {chain_guid}")
1604
1434
 
1435
+ @dynamic_catch
1605
1436
  def decompose_info_supply_chains(self, chain_guid: str, nested_chain_guid: str,
1606
- body: dict = None) -> None:
1437
+ body: dict | DeleteRequestBody = None) -> None:
1607
1438
  """ Detach two peers in an information supply chain from one another. Request body is optional.
1608
1439
 
1609
1440
  Parameters
@@ -1612,7 +1443,7 @@ class SolutionArchitect(Client):
1612
1443
  guid of the first information supply chain to link.
1613
1444
  nested_chain_guid: str
1614
1445
  guid of the second information supply chain to link.
1615
- body: dict, optional
1446
+ body: dict | DeleteRequestBody, optional
1616
1447
  The body describing the link between the two segments.
1617
1448
 
1618
1449
  Returns
@@ -1633,7 +1464,7 @@ class SolutionArchitect(Client):
1633
1464
 
1634
1465
  Body structure:
1635
1466
  {
1636
- "class": "MetadataSourceRequestBody",
1467
+ "class": "DeleteRequestBody",
1637
1468
  "externalSourceGUID": "add guid here",
1638
1469
  "externalSourceName": "add qualified name here",
1639
1470
  "effectiveTime": {{isotime}},
@@ -1645,8 +1476,8 @@ class SolutionArchitect(Client):
1645
1476
  loop.run_until_complete(self._async_decompose_info_supply_chains(chain_guid,
1646
1477
  nested_chain_guid, body))
1647
1478
 
1648
-
1649
- async def _async_delete_info_supply_chain(self, guid: str, body: dict = None, cascade_delete: bool = False) -> None:
1479
+ @dynamic_catch
1480
+ async def _async_delete_info_supply_chain(self, guid: str, body: dict | DeleteRequestBody = None, cascade_delete: bool = False) -> None:
1650
1481
  """Delete an information supply chain. Async Version.
1651
1482
 
1652
1483
  Parameters
@@ -1662,8 +1493,6 @@ class SolutionArchitect(Client):
1662
1493
  -------
1663
1494
  None
1664
1495
 
1665
- Raises
1666
- ------
1667
1496
  Raises
1668
1497
  ------
1669
1498
  InvalidParameterException
@@ -1678,7 +1507,7 @@ class SolutionArchitect(Client):
1678
1507
 
1679
1508
  Body structure:
1680
1509
  {
1681
- "class": "MetadataSourceRequestBody",
1510
+ "class": "DeleteRequestBody",
1682
1511
  "externalSourceGUID": "add guid here",
1683
1512
  "externalSourceName": "add qualified name here",
1684
1513
  "effectiveTime": {{isotime}},
@@ -1686,25 +1515,23 @@ class SolutionArchitect(Client):
1686
1515
  "forDuplicateProcessing": false
1687
1516
  }
1688
1517
  """
1689
- validate_guid(guid)
1690
- cascaded_s = str(cascade_delete).lower()
1518
+
1691
1519
 
1692
1520
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
1693
- f"information-supply-chains/{guid}/delete?cascadedDelete={cascaded_s}")
1694
- try:
1695
- await self._async_make_request("POST", url, body_slimmer(body))
1696
- except (InvalidParameterException) as e:
1697
- if e.exception_error_message_id == 'OMAG-REPOSITORY-HANDLER-404-007':
1698
- print("The GUID does not exist")
1699
-
1700
- def delete_info_supply_chain(self, guid: str, body: dict = None, cascade_delete: bool = False) -> None:
1521
+ f"information-supply-chains/{guid}/delete")
1522
+
1523
+ await self._async_delete_request(url, body, cascade_delete=cascade_delete)
1524
+ logger.info(f"Deleted Info Supply Chain {guid} with cascade {cascade_delete}")
1525
+
1526
+ @dynamic_catch
1527
+ def delete_info_supply_chain(self, guid: str, body: dict | DeleteRequestBody= None, cascade_delete: bool = False) -> None:
1701
1528
  """ Delete an information supply chain.
1702
1529
 
1703
1530
  Parameters
1704
1531
  ----------
1705
1532
  guid: str
1706
1533
  guid of the information supply chain to delete.
1707
- body: dict, optional
1534
+ body: dict | DeleteRequestBody, optional
1708
1535
  A dictionary containing parameters of the deletion.
1709
1536
  cascade_delete: bool, optional
1710
1537
  If true, the child objects will also be deleted.
@@ -1726,7 +1553,7 @@ class SolutionArchitect(Client):
1726
1553
 
1727
1554
  Body structure:
1728
1555
  {
1729
- "class": "MetadataSourceRequestBody",
1556
+ "class": "DeleteRequestBody",
1730
1557
  "externalSourceGUID": "add guid here",
1731
1558
  "externalSourceName": "add qualified name here",
1732
1559
  "effectiveTime": {{isotime}},
@@ -1737,8 +1564,13 @@ class SolutionArchitect(Client):
1737
1564
  loop = asyncio.get_event_loop()
1738
1565
  loop.run_until_complete(self._async_delete_info_supply_chain(guid, body, cascade_delete))
1739
1566
 
1740
- def find_all_information_supply_chains(self, body: dict = None, start_from: int = 0, page_size: int = max_paging_size,
1741
- output_format: str = "JSON") -> (list[dict] | str):
1567
+ def find_all_information_supply_chains(self, search_string: str = "*", classification_names: list[str] = None,
1568
+ metadata_element_types: list[str] = None,
1569
+ starts_with: bool = True, ends_with: bool = False,
1570
+ ignore_case: bool = False, start_from: int = 0,
1571
+ page_size: int = 0, output_format: str = 'JSON',
1572
+ output_format_set: str = None,
1573
+ body: dict| SearchStringRequestBody = None) -> (list[dict] | str):
1742
1574
  """ Retrieve a list of all information supply chains
1743
1575
  Parameters
1744
1576
  ----------
@@ -1785,14 +1617,15 @@ class SolutionArchitect(Client):
1785
1617
  }
1786
1618
  """
1787
1619
 
1788
- return self.find_information_supply_chains("*", body = body, start_from=start_from, page_size=page_size,
1789
- output_format=output_format)
1620
+ return self.find_information_supply_chains("*", classification_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body)
1790
1621
 
1791
- async def _async_find_information_supply_chains(self, search_filter: str = "*", add_implementation: bool = True,
1622
+ async def _async_find_information_supply_chains(self, search_string: str = "*", classification_names: list[str] = None,
1623
+ metadata_element_types: list[str] = None,
1792
1624
  starts_with: bool = True, ends_with: bool = False,
1793
1625
  ignore_case: bool = False, start_from: int = 0,
1794
- page_size: int = max_paging_size, body: dict = None,
1795
- output_format: str = 'JSON') -> list[dict] | str:
1626
+ page_size: int = 0, output_format: str = 'JSON',
1627
+ output_format_set: str = None,
1628
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
1796
1629
  """Retrieve the list of information supply chain metadata elements that contain the search string.
1797
1630
  https://egeria-project.org/concepts/information-supply-chain
1798
1631
  Async version.
@@ -1848,39 +1681,26 @@ class SolutionArchitect(Client):
1848
1681
  }
1849
1682
 
1850
1683
  """
1851
- starts_with_s = str(starts_with).lower()
1852
- ends_with_s = str(ends_with).lower()
1853
- ignore_case_s = str(ignore_case).lower()
1854
-
1855
- possible_query_params = query_string(
1856
- [("addImplementation", add_implementation), ("startFrom", start_from), ("pageSize", page_size),
1857
- ("startsWith", starts_with_s), ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
1858
-
1859
- if search_filter is None or search_filter == "*":
1860
- search_filter = None
1861
-
1862
- if body is None:
1863
- body = {
1864
- "filter": search_filter,
1865
- }
1866
- else:
1867
- body["filter"] = search_filter
1868
-
1869
- url = (f"{self.solution_architect_command_root}/information-supply-chains/by-search-string"
1870
- f"{possible_query_params}")
1871
-
1872
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
1873
- element = response.json().get("elements", NO_ELEMENTS_FOUND)
1874
- if element == NO_ELEMENTS_FOUND:
1875
- return NO_ELEMENTS_FOUND
1876
- if output_format != 'JSON': # return a simplified markdown representation
1877
- return self.generate_info_supply_chain_output(element, search_filter, output_format)
1878
- return response.json().get("elements", NO_ELEMENTS_FOUND)
1879
1684
 
1880
- def find_information_supply_chains(self, filter: str = "*", add_implementation: bool = True,
1881
- starts_with: bool = True, ends_with: bool = False, ignore_case: bool = False,
1882
- start_from: int = 0, page_size: int = max_paging_size, body: dict = None,
1883
- output_format: str = 'JSON', ) -> list[dict] | str:
1685
+ url = f"{self.solution_architect_command_root}/information-supply-chains/by-search-string"
1686
+ return await self._async_find_request(url, _type="GovernanceDefinition",
1687
+ _gen_output=self.generate_info_supply_chain_output,
1688
+ search_string=search_string, classification_names=classification_names,
1689
+ metadata_element_types=metadata_element_types,
1690
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
1691
+ start_from=start_from, page_size=page_size,
1692
+ output_format=output_format, output_format_set=output_format_set,
1693
+ body=body)
1694
+
1695
+
1696
+
1697
+ def find_information_supply_chains(self, search_string: str = "*", classification_names: list[str] = None,
1698
+ metadata_element_types: list[str] = None,
1699
+ starts_with: bool = True, ends_with: bool = False,
1700
+ ignore_case: bool = False, start_from: int = 0,
1701
+ page_size: int = 0, output_format: str = 'JSON',
1702
+ output_format_set: str = None,
1703
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
1884
1704
  """Retrieve the list of information supply chain metadata elements that contain the search string.
1885
1705
  https://egeria-project.org/concepts/information-supply-chain
1886
1706
 
@@ -1929,7 +1749,7 @@ class SolutionArchitect(Client):
1929
1749
  -----
1930
1750
 
1931
1751
  {
1932
- "class" : "FilterRequestBody",
1752
+ "class" : "SearchStringRequestBody",
1933
1753
  "asOfTime" : "{{$isoTimestamp}}",
1934
1754
  "effectiveTime" : "{{$isoTimestamp}}",
1935
1755
  "forLineage" : false,
@@ -1943,8 +1763,10 @@ class SolutionArchitect(Client):
1943
1763
 
1944
1764
  loop = asyncio.get_event_loop()
1945
1765
  response = loop.run_until_complete(
1946
- self._async_find_information_supply_chains(filter, add_implementation, starts_with, ends_with, ignore_case,
1947
- start_from, page_size, body, output_format))
1766
+ self._async_find_information_supply_chains(search_string, classification_names, metadata_element_types,
1767
+ starts_with, ends_with, ignore_case,
1768
+ start_from, page_size, output_format,
1769
+ output_format_set, body))
1948
1770
  return response
1949
1771
 
1950
1772
  async def _async_get_info_supply_chain_by_name(self, search_filter: str, body: dict = None,
@@ -2195,7 +2017,8 @@ class SolutionArchitect(Client):
2195
2017
  # Blueprints
2196
2018
  #
2197
2019
 
2198
- async def _async_create_solution_blueprint(self, body: dict) -> str:
2020
+ @dynamic_catch
2021
+ async def _async_create_solution_blueprint(self, body: dict | NewElementRequestBody) -> str:
2199
2022
  """ Create a solution blueprint. To set a lifecycle status
2200
2023
  use a NewSolutionElementRequestBody which has a default status of DRAFT. Using a
2201
2024
  NewElementRequestBody sets the status to ACTIVE.
@@ -2203,7 +2026,7 @@ class SolutionArchitect(Client):
2203
2026
 
2204
2027
  Parameters
2205
2028
  ----------
2206
- body: dict
2029
+ body: dict | NewElementRequestBody
2207
2030
  A dictionary containing the definition of the blueprint to create.
2208
2031
 
2209
2032
  Returns
@@ -2251,6 +2074,8 @@ class SolutionArchitect(Client):
2251
2074
  "displayName": "add short name here",
2252
2075
  "description": "add description here",
2253
2076
  "versionIdentifier": "add version here",
2077
+ "userDefinedStatus" : "add status here",
2078
+ "lifecycleStatus": "DRAFT"
2254
2079
  "additionalProperties": {
2255
2080
  "property1": "propertyValue1",
2256
2081
  "property2": "propertyValue2"
@@ -2308,18 +2133,17 @@ class SolutionArchitect(Client):
2308
2133
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2309
2134
  f"solution-blueprints")
2310
2135
 
2311
- response = await self._async_make_request("POST", url, body_slimmer(body))
2312
-
2313
- return response.json().get("guid", "Blueprint not created")
2136
+ return await self._async_create_element_body_request(url, ["SolutionBlueprintProperties"], body)
2314
2137
 
2315
- def create_solution_blueprint(self, body: dict) -> str:
2138
+ @dynamic_catch
2139
+ def create_solution_blueprint(self, body: dict | NewElementRequestBody) -> str:
2316
2140
  """ Create a solution blueprint. To set a lifecycle status
2317
2141
  use a NewSolutionElementRequestBody which has a default status of DRAFT. Using a
2318
2142
  NewElementRequestBody sets the status to ACTIVE.
2319
2143
 
2320
2144
  Parameters
2321
2145
  ----------
2322
- body: dict
2146
+ body: dict | NewElementRequestBody
2323
2147
  A dictionary containing the definition of the blueprint to create.
2324
2148
 
2325
2149
  Returns
@@ -2420,13 +2244,14 @@ class SolutionArchitect(Client):
2420
2244
  "forDuplicateProcessing" : false
2421
2245
  }
2422
2246
 
2423
- """
2247
+ """
2424
2248
 
2425
2249
  loop = asyncio.get_event_loop()
2426
2250
  response = loop.run_until_complete(self._async_create_solution_blueprint(body))
2427
2251
  return response
2428
2252
 
2429
- async def _async_create_solution_blueprint_from_template(self, body: dict) -> str:
2253
+ @dynamic_catch
2254
+ async def _async_create_solution_blueprint_from_template(self, body: dict | TemplateRequestBody) -> str:
2430
2255
  """ Create a new solution blueprint using an existing metadata element
2431
2256
  as a template. The template defines additional classifications and relationships that should be added to
2432
2257
  the new element. Async Version.
@@ -2434,7 +2259,7 @@ class SolutionArchitect(Client):
2434
2259
 
2435
2260
  Parameters
2436
2261
  ----------
2437
- body: dict
2262
+ body: dict | TemplateRequestBody
2438
2263
  A dictionary containing the definition of the solution blueprint to create.
2439
2264
 
2440
2265
  Returns
@@ -2499,19 +2324,28 @@ class SolutionArchitect(Client):
2499
2324
  """
2500
2325
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2501
2326
  f"solution-blueprints/from-template")
2327
+ if isinstance(body, TemplateRequestBody):
2328
+ validated_body = body
2329
+
2330
+ elif isinstance(body, dict):
2331
+ validated_body = self._template_request_adapter.validate_python(body)
2502
2332
 
2503
- response = await self._async_make_request("POST", url, body_slimmer(body))
2333
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
2334
+ logger.info(json_body)
2335
+ resp = await self._async_make_request("POST", url, json_body, is_json=True)
2336
+ logger.info(f"Create Blueprint from template with GUID: {resp.json().get('guid')}")
2337
+ return resp.json().get("guid", NO_GUID_RETURNED)
2504
2338
 
2505
- return response.json().get("guid", "Blueprint not created")
2506
2339
 
2507
- def create_solution_blueprint_from_template(self, body: dict) -> str:
2340
+ @dynamic_catch
2341
+ def create_solution_blueprint_from_template(self, body: dict | TemplateRequestBody) -> str:
2508
2342
  """ Create a new solution blueprint using an existing metadata element
2509
2343
  as a template. The template defines additional classifications and relationships that should be added to
2510
2344
  the new element.
2511
2345
 
2512
2346
  Parameters
2513
2347
  ----------
2514
- body: dict
2348
+ body: dict | TemplateRequestBody
2515
2349
  A dictionary containing the definition of the solution blueprint to create.
2516
2350
 
2517
2351
  Returns
@@ -2519,8 +2353,6 @@ class SolutionArchitect(Client):
2519
2353
 
2520
2354
  str - guid of the supply chain created.
2521
2355
 
2522
- Raises
2523
- ------
2524
2356
  Raises
2525
2357
  ------
2526
2358
  InvalidParameterException
@@ -2578,26 +2410,21 @@ class SolutionArchitect(Client):
2578
2410
  response = loop.run_until_complete(self._async_create_solution_blueprint_from_template(body))
2579
2411
  return response
2580
2412
 
2581
- async def _async_update_solution_blueprint(self, guid: str, body: dict,
2582
- replace_all_properties: bool = False) -> None:
2583
- """ Update the properties of a solution blueprint. Async Version.
2413
+ @dynamic_catch
2414
+ async def _async_update_solution_blueprint(self, guid: str, body: dict | UpdateElementRequestBody) -> None:
2415
+ """ Update a solution blueprint. Async Version.
2584
2416
 
2585
2417
  Parameters
2586
2418
  ----------
2587
2419
  guid: str
2588
2420
  guid of the information supply chain to update.
2589
- body: dict
2421
+ body: dict | UpdateElementRequestBody
2590
2422
  A dictionary containing the updates to the supply chain.
2591
- replace_all_properties: bool, optional
2592
- Whether to replace all properties with those provided in the body or to merge with existing properties.
2593
-
2594
2423
  Returns
2595
2424
  -------
2596
2425
 
2597
2426
  None
2598
2427
 
2599
- Raises
2600
- ------
2601
2428
  Raises
2602
2429
  ------
2603
2430
  InvalidParameterException
@@ -2633,24 +2460,22 @@ class SolutionArchitect(Client):
2633
2460
  }
2634
2461
  }
2635
2462
  """
2636
- validate_guid(guid)
2637
- replace_all_properties_s = str(replace_all_properties).lower()
2463
+
2638
2464
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2639
- f"solution-blueprints/{guid}/update?replaceAllProperties={replace_all_properties_s}")
2465
+ f"solution-blueprints/{guid}/update")
2640
2466
 
2641
- await self._async_make_request("POST", url, body_slimmer(body))
2467
+ await self._async_update_element_body_request(url, ["SolutionBlueprintProperties"],body)
2642
2468
 
2643
- def update_solution_blueprint(self, guid: str, body: dict, replace_all_properties: bool = False) -> None:
2469
+ @dynamic_catch
2470
+ def update_solution_blueprint(self, guid: str, body: dict | UpdateElementRequestBody) -> None:
2644
2471
  """ Update the properties of a solution blueprint. Async Version.
2645
2472
 
2646
2473
  Parameters
2647
2474
  ----------
2648
2475
  guid: str
2649
2476
  guid of the information supply chain to update.
2650
- body: dict
2651
- A dictionary containing the updates to the supply chain.
2652
- replace_all_properties: bool, optional
2653
- Whether to replace all properties with those provided in the body or to merge with existing properties.
2477
+ body: dict | UpdateElementRequestBody
2478
+ A dictionary containing the updates to the blueprint.
2654
2479
 
2655
2480
  Returns
2656
2481
  -------
@@ -2696,18 +2521,110 @@ class SolutionArchitect(Client):
2696
2521
  }
2697
2522
  """
2698
2523
  loop = asyncio.get_event_loop()
2699
- loop.run_until_complete(self._async_update_solution_blueprint(guid, body, replace_all_properties))
2524
+ loop.run_until_complete(self._async_update_solution_blueprint(guid, body))
2525
+
2526
+
2527
+ @dynamic_catch
2528
+ async def _async_delete_solution_blueprint(self, guid: str, body: dict | DeleteRequestBody, cascade: bool = False) -> None:
2529
+ """ Delete a solution blueprint. Async Version.
2530
+ Parameters
2531
+ ----------
2532
+ guid: str
2533
+ guid of the information supply chain to delete.
2534
+ body: dict, optional
2535
+ A dictionary containing parameters of the deletion.
2536
+ cascade: bool, optional
2537
+ If true, the child objects will also be deleted.
2538
+
2539
+ Returns
2540
+ -------
2541
+ None
2542
+
2543
+ Raises
2544
+ ------
2545
+ InvalidParameterException
2546
+ one of the parameters is null or invalid or
2547
+ PropertyServerException
2548
+ There is a problem adding the element properties to the metadata repository or
2549
+ UserNotAuthorizedException
2550
+ the requesting user is not authorized to issue this request.
2551
+
2552
+ Notes
2553
+ ----
2554
+
2555
+ Body structure:
2556
+ {
2557
+ "class": "DeleteRequestBody",
2558
+ "externalSourceGUID": "add guid here",
2559
+ "externalSourceName": "add qualified name here",
2560
+ "effectiveTime": {{isotime}},
2561
+ "forLineage": false,
2562
+ "forDuplicateProcessing": false
2563
+ }
2564
+ """
2565
+
2566
+ url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2567
+ f"information-supply-chains/{guid}/delete")
2568
+
2569
+ await self._async_delete_request(url, body, cascade_delete=cascade)
2570
+ logger.info(f"Deleted Info Supply Chain {guid} with cascade {cascade}")
2571
+
2572
+ @dynamic_catch
2573
+ def delete_solution_blueprint(self, guid: str, body: dict | DeleteRequestBody = None,
2574
+ cascade: bool = False) -> None:
2575
+ """ Delete an Solution Blueprint.
2576
+
2577
+ Parameters
2578
+ ----------
2579
+ guid: str
2580
+ guid of the information supply chain to delete.
2581
+ body: dict | DeleteRequestBody, optional
2582
+ A dictionary containing parameters of the deletion.
2583
+ cascade: bool, optional
2584
+ If true, the child objects will also be deleted.
2585
+ Returns
2586
+ -------
2587
+ None
2588
+
2589
+ Raises
2590
+ ------
2591
+ InvalidParameterException
2592
+ one of the parameters is null or invalid or
2593
+ PropertyServerException
2594
+ There is a problem adding the element properties to the metadata repository or
2595
+ UserNotAuthorizedException
2596
+ the requesting user is not authorized to issue this request.
2597
+
2598
+ Notes
2599
+ ----
2600
+
2601
+ Body structure:
2602
+ {
2603
+ "class": "DeleteRequestBody",
2604
+ "externalSourceGUID": "add guid here",
2605
+ "externalSourceName": "add qualified name here",
2606
+ "effectiveTime": {{isotime}},
2607
+ "forLineage": false,
2608
+ "forDuplicateProcessing": false
2609
+ }
2610
+ """
2611
+ loop = asyncio.get_event_loop()
2612
+ loop.run_until_complete(self._async_delete_info_supply_chain(guid, body, cascade))
2613
+
2700
2614
 
2701
- async def _async_update_solution_element_status(self, guid: str, body: dict,
2702
- replace_all_properties: bool = False) -> None:
2615
+ @dynamic_catch
2616
+ async def _async_update_solution_element_status(self, guid: str, status: str= None, body: dict| UpdateStatusRequestBody = None,
2617
+ ) -> None:
2703
2618
  """ Update the properties of a blueprint, solution component, or solution port. Async Version.
2704
2619
 
2705
2620
  Parameters
2706
2621
  ----------
2707
2622
  guid: str
2708
2623
  guid of the information supply chain to update.
2709
- body: dict
2624
+ body: dict | UpdateStatusRequestBody, optional
2710
2625
  A dictionary containing the updates to the supply chain.
2626
+ status: str, optional
2627
+ The status to update the supply chain to.
2711
2628
 
2712
2629
  Returns
2713
2630
  -------
@@ -2728,7 +2645,7 @@ class SolutionArchitect(Client):
2728
2645
 
2729
2646
  Body structure:
2730
2647
  {
2731
- "class" : "SolutionElementStatusRequestBody",
2648
+ "class" : "UpdateStatusRequestBody",
2732
2649
  "status" : "APPROVED",
2733
2650
  "externalSourceGUID": "add guid here",
2734
2651
  "externalSourceName": "add qualified name here",
@@ -2737,14 +2654,14 @@ class SolutionArchitect(Client):
2737
2654
  "forDuplicateProcessing" : false
2738
2655
  }
2739
2656
  """
2740
- validate_guid(guid)
2741
- replace_all_properties_s = str(replace_all_properties).lower()
2657
+
2742
2658
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2743
- f"solution-blueprints/{guid}/update?replaceAllProperties={replace_all_properties_s}")
2659
+ f"solution-blueprints/{guid}/update")
2744
2660
 
2745
- await self._async_make_request("POST", url, body_slimmer(body))
2661
+ await self._async_update_status_request(url, status, body)
2746
2662
 
2747
- def update_solution_element_status(self, guid: str, body: dict) -> None:
2663
+ @dynamic_catch
2664
+ def update_solution_element_status(self, guid: str, status: str = None, body: dict| UpdateStatusRequestBody = None) -> None:
2748
2665
  """ Update the status of a blueprint, solution component, or solution port.
2749
2666
 
2750
2667
  Parameters
@@ -2782,12 +2699,12 @@ class SolutionArchitect(Client):
2782
2699
  }
2783
2700
  """
2784
2701
  loop = asyncio.get_event_loop()
2785
- loop.run_until_complete(self._async_update_solution_element_status(guid, body))
2786
-
2702
+ loop.run_until_complete(self._async_update_solution_element_status(guid = guid, status= status, body=body))
2787
2703
 
2788
2704
 
2705
+ @dynamic_catch
2789
2706
  async def _async_link_solution_component_to_blueprint(self, blueprint_guid: str, component_guid: str,
2790
- body: dict) -> None:
2707
+ body: dict | NewRelationshipRequestBody) -> None:
2791
2708
  """ Connect a solution component to a blueprint. Async Version.
2792
2709
 
2793
2710
  Parameters
@@ -2796,7 +2713,7 @@ class SolutionArchitect(Client):
2796
2713
  guid of the blueprint to connect to.
2797
2714
  component_guid: str
2798
2715
  guid of the component to link.
2799
- body: dict
2716
+ body: dict | NewRelationshipRequestBody
2800
2717
  The body describing the link.
2801
2718
 
2802
2719
  Returns
@@ -2817,7 +2734,7 @@ class SolutionArchitect(Client):
2817
2734
 
2818
2735
  Body structure:
2819
2736
  {
2820
- "class" : "RelationshipRequestBody",
2737
+ "class" : "NewRelationshipRequestBody",
2821
2738
  "properties": {
2822
2739
  "class": "SolutionBlueprintCompositionProperties",
2823
2740
  "role": "Add role that the component plays in the solution blueprint here",
@@ -2833,14 +2750,15 @@ class SolutionArchitect(Client):
2833
2750
  }
2834
2751
 
2835
2752
  """
2836
- validate_guid(blueprint_guid)
2837
- validate_guid(component_guid)
2753
+
2838
2754
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2839
2755
  f"solution-blueprints/{blueprint_guid}/solution-components/{component_guid}/attach")
2840
2756
 
2841
- await self._async_make_request("POST", url, body_slimmer(body))
2757
+ await self._async_new_relationship_request(url, ["SolutionComponentCompositionProperties"], body)
2758
+ logger.info(f"Linked component to blueprint {component_guid} -> {blueprint_guid}")
2842
2759
 
2843
- def link_solution_component_to_blueprint(self, blueprint_guid: str, component_guid: str, body: dict) -> None:
2760
+ @dynamic_catch
2761
+ def link_solution_component_to_blueprint(self, blueprint_guid: str, component_guid: str, body: dict | NewRelationshipRequestBody) -> None:
2844
2762
  """ Connect a solution component to a blueprint.
2845
2763
 
2846
2764
  Parameters
@@ -2849,7 +2767,7 @@ class SolutionArchitect(Client):
2849
2767
  guid of the blueprint to connect to.
2850
2768
  component_guid: str
2851
2769
  guid of the component to link.
2852
- body: dict
2770
+ body: dict | NewRelationshipRequestBody
2853
2771
  The body describing the link.
2854
2772
 
2855
2773
  Returns
@@ -2888,8 +2806,9 @@ class SolutionArchitect(Client):
2888
2806
  loop = asyncio.get_event_loop()
2889
2807
  loop.run_until_complete(self._async_link_solution_component_to_blueprint(blueprint_guid, component_guid, body))
2890
2808
 
2809
+ @dynamic_catch
2891
2810
  async def _async_detach_solution_component_from_blueprint(self, blueprint_guid: str, component_guid: str,
2892
- body: dict = None) -> None:
2811
+ body: dict | DeleteRequestBody = None) -> None:
2893
2812
  """ Detach a solution component from a solution blueprint.
2894
2813
  Async Version.
2895
2814
 
@@ -2929,15 +2848,17 @@ class SolutionArchitect(Client):
2929
2848
  }
2930
2849
 
2931
2850
  """
2932
- validate_guid(blueprint_guid)
2933
- validate_guid(component_guid)
2851
+
2934
2852
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
2935
2853
  f"solution-blueprints/{blueprint_guid}/solution-components/{component_guid}/detach")
2936
2854
 
2937
- await self._async_make_request("POST", url, body_slimmer(body))
2855
+ await self._async_delete_request(url, body)
2856
+ logger.info(
2857
+ f"Detached component from blueprint {component_guid} -> {blueprint_guid}")
2938
2858
 
2859
+ @dynamic_catch
2939
2860
  def detach_solution_component_from_blueprint(self, blueprint_guid: str, component_guid: str,
2940
- body: dict = None) -> None:
2861
+ body: dict | DeleteRequestBody = None) -> None:
2941
2862
  """ Detach a solution component from a solution blueprint.
2942
2863
 
2943
2864
  Parameters
@@ -2980,8 +2901,10 @@ class SolutionArchitect(Client):
2980
2901
  loop.run_until_complete(
2981
2902
  self._async_detach_solution_component_from_blueprint(blueprint_guid, component_guid, body))
2982
2903
 
2904
+
2905
+ @dynamic_catch
2983
2906
  async def _async_delete_solution_blueprint(self, blueprint_guid: str, cascade_delete: bool = False,
2984
- body: dict = None) -> None:
2907
+ body: dict | DeleteRequestBody = None) -> None:
2985
2908
  """Delete a solution blueprint. Async Version.
2986
2909
 
2987
2910
  Parameters
@@ -3022,15 +2945,14 @@ class SolutionArchitect(Client):
3022
2945
  }
3023
2946
  """
3024
2947
  validate_guid(blueprint_guid)
3025
- cascaded_s = str(cascade_delete).lower()
2948
+
3026
2949
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
3027
- f"solution-blueprints/{blueprint_guid}/delete?cascadeDelete={cascaded_s}")
3028
- if body:
3029
- await self._async_make_request("POST", url, body_slimmer(body))
3030
- else:
3031
- await self._async_make_request("POST", url)
2950
+ f"solution-blueprints/{blueprint_guid}/delete")
2951
+ await self._async_delete_request(url, body, cascade_delete=cascade_delete)
2952
+ logger.info(f"Deleted Blueprint {blueprint_guid} with cascade {cascade_delete}")
3032
2953
 
3033
- def delete_solution_blueprint(self, blueprint_guid: str, cascade_delete: bool = False, body: dict = None) -> None:
2954
+ @dynamic_catch
2955
+ def delete_solution_blueprint(self, blueprint_guid: str, cascade_delete: bool = False, body: dict | DeleteRequestBody = None) -> None:
3034
2956
  """ Delete a solution blueprint.
3035
2957
  Parameters
3036
2958
  ----------
@@ -3071,10 +2993,15 @@ class SolutionArchitect(Client):
3071
2993
  loop.run_until_complete(self._async_delete_solution_blueprint(blueprint_guid, cascade_delete, body))
3072
2994
 
3073
2995
 
3074
- async def _async_find_solution_blueprints(self, search_filter: str = "*", starts_with: bool = True,
3075
- ends_with: bool = False, ignore_case: bool = False, start_from: int = 0,
3076
- page_size: int = max_paging_size, body: dict = None,
3077
- output_format: str = "JSON") -> list[dict] | str:
2996
+
2997
+
2998
+ async def _async_find_solution_blueprints(self, search_string: str = "*", classification_names: list[str] = None,
2999
+ metadata_element_types: list[str] = None,
3000
+ starts_with: bool = True, ends_with: bool = False,
3001
+ ignore_case: bool = False, start_from: int = 0,
3002
+ page_size: int = 0, output_format: str = 'JSON',
3003
+ output_format_set: str = None,
3004
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
3078
3005
  """Retrieve the solution blueprint elements that contain the search string.
3079
3006
  https://egeria-project.org/concepts/solution-blueprint
3080
3007
  Async version.
@@ -3127,37 +3054,28 @@ class SolutionArchitect(Client):
3127
3054
  }
3128
3055
 
3129
3056
  """
3130
- starts_with_s = str(starts_with).lower()
3131
- ends_with_s = str(ends_with).lower()
3132
- ignore_case_s = str(ignore_case).lower()
3133
3057
 
3134
- possible_query_params = query_string(
3135
- [("startFrom", start_from), ("pageSize", page_size),
3136
- ("startsWith", starts_with_s), ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
3137
3058
 
3138
- if search_filter is None or search_filter == "*":
3139
- search_filter = None
3140
3059
 
3141
- if body is None:
3142
- body = {
3143
- "filter": search_filter,
3144
- }
3145
- else:
3146
- body["filter"] = search_filter
3147
3060
 
3148
- url = (f"{self.solution_architect_command_root}/solution-blueprints/by-search-string"
3149
- f"{possible_query_params}")
3150
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
3151
- element = response.json().get("elements", NO_ELEMENTS_FOUND)
3152
- if element == NO_ELEMENTS_FOUND:
3153
- return NO_ELEMENTS_FOUND
3154
- if output_format != 'JSON': # return a simplified markdown representation
3155
- return self.generate_solution_blueprint_output(element, search_filter, output_format)
3156
- return response.json().get("elements", NO_ELEMENTS_FOUND)
3061
+ url = f"{self.solution_architect_command_root}/solution-blueprints/by-search-string"
3062
+ return await self._async_find_request(url, _type="GovernanceDefinition",
3063
+ _gen_output=self.generate_info_supply_chain_output,
3064
+ search_string=search_string, classification_names=classification_names,
3065
+ metadata_element_types=metadata_element_types,
3066
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
3067
+ start_from=start_from, page_size=page_size,
3068
+ output_format=output_format, output_format_set=output_format_set,
3069
+ body=body)
3070
+
3157
3071
 
3158
- def find_solution_blueprints(self, filter: str = "*", starts_with: bool = True, ends_with: bool = False,
3159
- ignore_case: bool = False, start_from: int = 0, page_size: int = max_paging_size,
3160
- body: dict = None, output_format: str = 'JSON') -> list[dict] | str:
3072
+ def find_solution_blueprints(self, search_string: str = "*", classification_names: list[str] = None,
3073
+ metadata_element_types: list[str] = None,
3074
+ starts_with: bool = True, ends_with: bool = False,
3075
+ ignore_case: bool = False, start_from: int = 0,
3076
+ page_size: int = 0, output_format: str = 'JSON',
3077
+ output_format_set: str = None,
3078
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
3161
3079
  """Retrieve the list of solution blueprint elements that contain the search string.
3162
3080
  https://egeria-project.org/concepts/solution-blueprint
3163
3081
 
@@ -3217,17 +3135,24 @@ class SolutionArchitect(Client):
3217
3135
 
3218
3136
  loop = asyncio.get_event_loop()
3219
3137
  response = loop.run_until_complete(
3220
- self._async_find_solution_blueprints(filter, starts_with, ends_with, ignore_case, start_from, page_size,
3221
- body, output_format))
3138
+ self._async_find_solution_blueprints(search_string, classification_names, metadata_element_types,
3139
+ starts_with, ends_with, ignore_case, start_from,
3140
+ page_size, output_format, output_format_set, body))
3222
3141
  return response
3223
3142
 
3224
- def find_all_solution_blueprints(self, start_from: int = 0, page_size: int = max_paging_size,
3225
- output_format: str = "JSON") -> list[dict] | str:
3143
+ def find_all_solution_blueprints(self, classification_names: list[str] = None,
3144
+ metadata_element_types: list[str] = None,
3145
+ starts_with: bool = True, ends_with: bool = False,
3146
+ ignore_case: bool = False, start_from: int = 0,
3147
+ page_size: int = 0, output_format: str = 'JSON',
3148
+ output_format_set: str = None,
3149
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
3226
3150
  """Retrieve a list of all solution blueprint elements
3227
3151
  https://egeria-project.org/concepts/solution-blueprint
3228
3152
  """
3229
- return self.find_solution_blueprints("*", start_from=start_from, page_size=page_size,
3230
- output_format=output_format)
3153
+ return self.find_solution_blueprints("*", classification_names, metadata_element_types,
3154
+ starts_with, ends_with, ignore_case, start_from,
3155
+ page_size, output_format, output_format_set, body)
3231
3156
 
3232
3157
 
3233
3158
  async def _async_get_solution_blueprint_by_guid(self, guid: str, body: dict = None,
@@ -3467,7 +3392,8 @@ class SolutionArchitect(Client):
3467
3392
  # Components
3468
3393
  #
3469
3394
 
3470
- async def _async_create_solution_component(self, body: dict) -> str:
3395
+ @dynamic_catch
3396
+ async def _async_create_solution_component(self, body: dict | NewElementRequestBody) -> str:
3471
3397
  """Create a solution component. To set a lifecycle status
3472
3398
  use a NewSolutionElementRequestBody which has a default status of DRAFT. Using a
3473
3399
  NewElementRequestBody sets the status to ACTIVE.
@@ -3475,7 +3401,8 @@ class SolutionArchitect(Client):
3475
3401
 
3476
3402
  Parameters
3477
3403
  ----------
3478
- body: dict
3404
+ body: dict | NewElementRequestBody
3405
+ A dictionary containing parameters of the creation.
3479
3406
  A dictionary containing the definition of the component to create.
3480
3407
 
3481
3408
  Returns
@@ -3500,7 +3427,7 @@ class SolutionArchitect(Client):
3500
3427
 
3501
3428
  Body structure:
3502
3429
  {
3503
- "class": "NewSolutionComponentRequestBody",
3430
+ "class": "NewElementRequestBody",
3504
3431
  "externalSourceGUID": "add guid here",
3505
3432
  "externalSourceName": "add qualified name here",
3506
3433
  "effectiveTime": {{isotime}},
@@ -3545,61 +3472,22 @@ class SolutionArchitect(Client):
3545
3472
  "forDuplicateProcessing" : false
3546
3473
  }
3547
3474
 
3548
- Without lifecycle:
3549
- {
3550
- "class" : "NewElementRequestBody",
3551
- "anchorGUID" : "add guid here",
3552
- "isOwnAnchor": false,
3553
- "parentGUID": "add guid here",
3554
- "parentRelationshipTypeName": "add type name here",
3555
- "parentRelationshipProperties": {
3556
- "class": "ElementProperties",
3557
- "propertyValueMap" : {
3558
- "description" : {
3559
- "class": "PrimitiveTypePropertyValue",
3560
- "typeName": "string",
3561
- "primitiveValue" : "New description"
3562
- }
3563
- }
3564
- },
3565
- "parentAtEnd1": false,
3566
- "properties": {
3567
- "class" : "SolutionComponentProperties",
3568
- "qualifiedName": "add unique name here",
3569
- "displayName": "add short name here",
3570
- "description": "add description here",
3571
- "solutionComponentType": "add optional type for this component",
3572
- "versionIdentifier": "add version for this component",
3573
- "plannedDeployedImplementationType": "add details of the type of implementation for this component",
3574
- "additionalProperties": {
3575
- "property1" : "propertyValue1",
3576
- "property2" : "propertyValue2"
3577
- },
3578
- "effectiveFrom": "{{$isoTimestamp}}",
3579
- "effectiveTo": "{{$isoTimestamp}}"
3580
- },
3581
- "externalSourceGUID": "add guid here",
3582
- "externalSourceName": "add qualified name here",
3583
- "effectiveTime" : "{{$isoTimestamp}}",
3584
- "forLineage" : false,
3585
- "forDuplicateProcessing" : false
3586
- }
3475
+
3587
3476
  """
3588
3477
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
3589
3478
  f"solution-components")
3590
3479
 
3591
- response = await self._async_make_request("POST", url, body_slimmer(body))
3592
-
3593
- return response.json().get("guid", "Solution component not created")
3480
+ return await self._async_create_element_body_request(url, ["SolutionComponentProperties"], body)
3594
3481
 
3595
- def create_solution_component(self, body: dict) -> str:
3482
+ @dynamic_catch
3483
+ def create_solution_component(self, body: dict | NewElementRequestBody) -> str:
3596
3484
  """Create a solution component. To set a lifecycle status
3597
3485
  use a NewSolutionElementRequestBody which has a default status of DRAFT. Using a
3598
3486
  NewElementRequestBody sets the status to ACTIVE.
3599
3487
 
3600
3488
  Parameters
3601
3489
  ----------
3602
- body: dict
3490
+ body: dict | NewElementRequestBody
3603
3491
  A dictionary containing the definition of the component to create.
3604
3492
 
3605
3493
  Returns
@@ -3624,7 +3512,7 @@ class SolutionArchitect(Client):
3624
3512
 
3625
3513
  Body structure:
3626
3514
  {
3627
- "class": "NewSolutionComponentRequestBody",
3515
+ "class": "NewElementRequestBody",
3628
3516
  "externalSourceGUID": "add guid here",
3629
3517
  "externalSourceName": "add qualified name here",
3630
3518
  "effectiveTime": {{isotime}},
@@ -3669,52 +3557,15 @@ class SolutionArchitect(Client):
3669
3557
  "forDuplicateProcessing" : false
3670
3558
  }
3671
3559
 
3672
- Without lifecycle:
3673
- {
3674
- "class" : "NewElementRequestBody",
3675
- "anchorGUID" : "add guid here",
3676
- "isOwnAnchor": false,
3677
- "parentGUID": "add guid here",
3678
- "parentRelationshipTypeName": "add type name here",
3679
- "parentRelationshipProperties": {
3680
- "class": "ElementProperties",
3681
- "propertyValueMap" : {
3682
- "description" : {
3683
- "class": "PrimitiveTypePropertyValue",
3684
- "typeName": "string",
3685
- "primitiveValue" : "New description"
3686
- }
3687
- }
3688
- },
3689
- "parentAtEnd1": false,
3690
- "properties": {
3691
- "class" : "SolutionComponentProperties",
3692
- "qualifiedName": "add unique name here",
3693
- "displayName": "add short name here",
3694
- "description": "add description here",
3695
- "solutionComponentType": "add optional type for this component",
3696
- "versionIdentifier": "add version for this component",
3697
- "plannedDeployedImplementationType": "add details of the type of implementation for this component",
3698
- "additionalProperties": {
3699
- "property1" : "propertyValue1",
3700
- "property2" : "propertyValue2"
3701
- },
3702
- "effectiveFrom": "{{$isoTimestamp}}",
3703
- "effectiveTo": "{{$isoTimestamp}}"
3704
- },
3705
- "externalSourceGUID": "add guid here",
3706
- "externalSourceName": "add qualified name here",
3707
- "effectiveTime" : "{{$isoTimestamp}}",
3708
- "forLineage" : false,
3709
- "forDuplicateProcessing" : false
3710
- }
3560
+
3711
3561
  """
3712
3562
 
3713
3563
  loop = asyncio.get_event_loop()
3714
3564
  response = loop.run_until_complete(self._async_create_solution_component(body))
3715
3565
  return response
3716
3566
 
3717
- async def _async_create_solution_component_from_template(self, body: dict) -> str:
3567
+ @dynamic_catch
3568
+ async def _async_create_solution_component_from_template(self, body: dict| TemplateRequestBody) -> str:
3718
3569
  """ Create a new solution component using an existing metadata element
3719
3570
  as a template. The template defines additional classifications and relationships that should be added to
3720
3571
  the new element. Async Version.
@@ -3722,7 +3573,7 @@ class SolutionArchitect(Client):
3722
3573
 
3723
3574
  Parameters
3724
3575
  ----------
3725
- body: dict
3576
+ body: dict | TemplateRequestBody
3726
3577
  A dictionary containing the definition of the solution component to create.
3727
3578
 
3728
3579
  Returns
@@ -3786,11 +3637,20 @@ class SolutionArchitect(Client):
3786
3637
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
3787
3638
  f"solution-components/from-template")
3788
3639
 
3789
- response = await self._async_make_request("POST", url, body_slimmer(body))
3640
+ if isinstance(body, TemplateRequestBody):
3641
+ validated_body = body
3790
3642
 
3791
- return response.json().get("guid", "Component not created")
3643
+ elif isinstance(body, dict):
3644
+ validated_body = self._template_request_adapter.validate_python(body)
3792
3645
 
3793
- def create_solution_component_from_template(self, body: dict) -> str:
3646
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
3647
+ logger.info(json_body)
3648
+ resp = await self._async_make_request("POST", url, json_body, is_json=True)
3649
+ logger.info(f"Create Solution Component from template with GUID: {resp.json().get('guid')}")
3650
+ return resp.json().get("guid", NO_GUID_RETURNED)
3651
+
3652
+ @dynamic_catch
3653
+ def create_solution_component_from_template(self, body: dict| TemplateRequestBody) -> str:
3794
3654
  """ Create a new solution component using an existing metadata element
3795
3655
  as a template. The template defines additional classifications and relationships that should be
3796
3656
  added to
@@ -3799,7 +3659,7 @@ class SolutionArchitect(Client):
3799
3659
 
3800
3660
  Parameters
3801
3661
  ----------
3802
- body: dict
3662
+ body: dict| TemplateRequestBody
3803
3663
  A dictionary containing the definition of the solution component to create.
3804
3664
 
3805
3665
  Returns
@@ -3865,26 +3725,22 @@ class SolutionArchitect(Client):
3865
3725
  response = loop.run_until_complete(self._async_create_solution_component_from_template(body))
3866
3726
  return response
3867
3727
 
3868
- async def _async_update_solution_component(self, guid: str, body: dict,
3869
- replace_all_properties: bool = False) -> None:
3728
+ @dynamic_catch
3729
+ async def _async_update_solution_component(self, guid: str, body: dict | UpdateElementRequestBody,
3730
+ ) -> None:
3870
3731
  """ Update the properties of a solution component. Async Version.
3871
3732
 
3872
3733
  Parameters
3873
3734
  ----------
3874
3735
  guid: str
3875
3736
  guid of the solution component to update.
3876
- body: dict
3737
+ body: dict | UpdateElementRequestBody
3877
3738
  A dictionary containing the updates to the component.
3878
- replace_all_properties: bool, optional
3879
- Whether to replace all properties with those provided in the body or to merge with existing properties.
3880
3739
 
3881
3740
  Returns
3882
3741
  -------
3883
-
3884
3742
  None
3885
3743
 
3886
- Raises
3887
- ------
3888
3744
  Raises
3889
3745
  ------
3890
3746
  InvalidParameterException
@@ -3923,32 +3779,26 @@ class SolutionArchitect(Client):
3923
3779
  }
3924
3780
 
3925
3781
  """
3926
- validate_guid(guid)
3927
- replace_all_properties_s = str(replace_all_properties).lower()
3782
+
3928
3783
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
3929
- f"solution-components/{guid}/update?replaceAllProperties={replace_all_properties_s}")
3784
+ f"solution-components/{guid}/update")
3930
3785
 
3931
- await self._async_make_request("POST", url, body_slimmer(body))
3786
+ await self._async_update_element_body_request(url, ["SolutionComponentProperties"], body)
3932
3787
 
3933
- def update_solution_component(self, guid: str, body: dict, replace_all_properties: bool = False) -> None:
3788
+ @dynamic_catch
3789
+ def update_solution_component(self, guid: str, body: dict | UpdateElementRequestBody) -> None:
3934
3790
  """ Update the properties of a solution component. Async Version.
3935
3791
 
3936
3792
  Parameters
3937
3793
  ----------
3938
3794
  guid: str
3939
3795
  guid of the solution component to update.
3940
- body: dict
3796
+ body: dict | UpdateElementRequestBody
3941
3797
  A dictionary containing the updates to the component.
3942
- replace_all_properties: bool, optional
3943
- Whether to replace all properties with those provided in the body or to merge with existing properties.
3944
-
3945
3798
  Returns
3946
3799
  -------
3947
-
3948
3800
  None
3949
3801
 
3950
- Raises
3951
- ------
3952
3802
  Raises
3953
3803
  ------
3954
3804
  InvalidParameterException
@@ -3988,9 +3838,10 @@ class SolutionArchitect(Client):
3988
3838
 
3989
3839
  """
3990
3840
  loop = asyncio.get_event_loop()
3991
- loop.run_until_complete(self._async_update_solution_component(guid, body, replace_all_properties))
3841
+ loop.run_until_complete(self._async_update_solution_component(guid, body))
3992
3842
 
3993
- async def _async_link_subcomponent(self, component_guid: str, sub_component_guid: str, body: dict) -> None:
3843
+ @dynamic_catch
3844
+ async def _async_link_subcomponent(self, component_guid: str, sub_component_guid: str, body: dict | NewRelationshipRequestBody) -> None:
3994
3845
  """ Attach a solution component to a solution component. Async Version.
3995
3846
 
3996
3847
  Parameters
@@ -3999,7 +3850,7 @@ class SolutionArchitect(Client):
3999
3850
  guid of the blueprint to connect to.
4000
3851
  sub_component_guid: str
4001
3852
  guid of the component to link.
4002
- body: dict
3853
+ body: dict | NewRelationshipRequestBody
4003
3854
  The body describing the link.
4004
3855
 
4005
3856
  Returns
@@ -4020,25 +3871,23 @@ class SolutionArchitect(Client):
4020
3871
 
4021
3872
  Body structure:
4022
3873
  {
4023
- "class" : "RelationshipRequestBody",
3874
+ "class": "NewRelationshipRequestBody",
4024
3875
  "externalSourceGUID": "add guid here",
4025
3876
  "externalSourceName": "add qualified name here",
4026
- "effectiveTime" : "{{$isoTimestamp}}",
4027
- "forLineage" : false,
4028
- "forDuplicateProcessing" : false
3877
+ "effectiveTime": "{{$isoTimestamp}}",
3878
+ "forLineage": false,
3879
+ "forDuplicateProcessing": false
4029
3880
  }
4030
3881
  """
4031
- validate_guid(component_guid)
4032
- validate_guid(sub_component_guid)
3882
+
4033
3883
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
4034
3884
  f"solution-components/{component_guid}/subcomponents/{sub_component_guid}/attach")
4035
- if body:
4036
- await self._async_make_request("POST", url, body_slimmer(body))
4037
- else:
4038
- await self._async_make_request("POST", url)
4039
3885
 
3886
+ await self._async_new_relationship_request(url, ["SolutionCompositionProperties"], body)
3887
+ logger.info(f"Linked Subcomponent {component_guid} -> {sub_component_guid}")
4040
3888
 
4041
- def link_subcomponent(self, component_guid: str, sub_component_guid: str, body: dict) -> None:
3889
+ @dynamic_catch
3890
+ def link_subcomponent(self, component_guid: str, sub_component_guid: str, body: dict | NewRelationshipRequestBody) -> None:
4042
3891
  """ Attach a solution component to a solution component.
4043
3892
 
4044
3893
  Parameters
@@ -4047,7 +3896,7 @@ class SolutionArchitect(Client):
4047
3896
  guid of the blueprint to connect to.
4048
3897
  sub_component_guid: str
4049
3898
  guid of the component to link.
4050
- body: dict
3899
+ body: dict | NewRelationshipRequestBody
4051
3900
  The body describing the link.
4052
3901
 
4053
3902
  Returns
@@ -4068,7 +3917,7 @@ class SolutionArchitect(Client):
4068
3917
 
4069
3918
  Body structure:
4070
3919
  {
4071
- "class" : "RelationshipRequestBody",
3920
+ "class" : "NewRelationshipRequestBody",
4072
3921
  "externalSourceGUID": "add guid here",
4073
3922
  "externalSourceName": "add qualified name here",
4074
3923
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -4078,9 +3927,9 @@ class SolutionArchitect(Client):
4078
3927
  """
4079
3928
  loop = asyncio.get_event_loop()
4080
3929
  loop.run_until_complete(self._async_link_subcomponent(component_guid, sub_component_guid, body))
4081
-
3930
+ @dynamic_catch
4082
3931
  async def _async_detach_sub_component(self, parent_component_guid: str, member_component_guid: str,
4083
- body: dict = None) -> None:
3932
+ body: dict |DeleteRequestBody = None) -> None:
4084
3933
  """ Detach a solution component from a solution component.
4085
3934
  Async Version.
4086
3935
 
@@ -4111,7 +3960,7 @@ class SolutionArchitect(Client):
4111
3960
 
4112
3961
  Body structure:
4113
3962
  {
4114
- "class": "MetadataSourceRequestBody",
3963
+ "class": "DeleteRequestBody",
4115
3964
  "externalSourceGUID": "add guid here",
4116
3965
  "externalSourceName": "add qualified name here",
4117
3966
  "effectiveTime": {{isotime}},
@@ -4120,14 +3969,16 @@ class SolutionArchitect(Client):
4120
3969
  }
4121
3970
 
4122
3971
  """
4123
- validate_guid(parent_component_guid)
4124
- validate_guid(member_component_guid)
3972
+
4125
3973
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
4126
3974
  f"solution-components/{parent_component_guid}/subcomponents/{member_component_guid}/detach")
4127
3975
 
4128
- await self._async_make_request("POST", url, body_slimmer(body))
3976
+ await self._async_delete_request(url, body)
3977
+ logger.info(
3978
+ f"Detached components {parent_component_guid} -> {member_component_guid}")
4129
3979
 
4130
- def detach_sub_component(self, parent_component_guid: str, member_component_guid: str, body: dict = None) -> None:
3980
+ @dynamic_catch
3981
+ def detach_sub_component(self, parent_component_guid: str, member_component_guid: str, body: dict| DeleteRequestBody = None) -> None:
4131
3982
  """ Detach a solution component from a solution component.
4132
3983
  Async Version.
4133
3984
 
@@ -4137,7 +3988,7 @@ class SolutionArchitect(Client):
4137
3988
  guid of the parent component to disconnect from.
4138
3989
  member_component_guid: str
4139
3990
  guid of the member (child) component to disconnect.
4140
- body: dict
3991
+ body: dict | DeleteRequestBody
4141
3992
  The body describing the request.
4142
3993
 
4143
3994
  Returns
@@ -4158,7 +4009,7 @@ class SolutionArchitect(Client):
4158
4009
 
4159
4010
  Body structure:
4160
4011
  {
4161
- "class": "MetadataSourceRequestBody",
4012
+ "class": "DeleteRequestBody",
4162
4013
  "externalSourceGUID": "add guid here",
4163
4014
  "externalSourceName": "add qualified name here",
4164
4015
  "effectiveTime": {{isotime}},
@@ -4170,7 +4021,8 @@ class SolutionArchitect(Client):
4170
4021
  loop = asyncio.get_event_loop()
4171
4022
  loop.run_until_complete(self._async_detach_sub_component(parent_component_guid, member_component_guid, body))
4172
4023
 
4173
- async def _async_link_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict) -> None:
4024
+ @dynamic_catch
4025
+ async def _async_link_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict | NewRelationshipRequestBody) -> None:
4174
4026
  """ Attach a solution component to a solution component as a peer in a solution. Async Version.
4175
4027
 
4176
4028
  Parameters
@@ -4179,9 +4031,10 @@ class SolutionArchitect(Client):
4179
4031
  GUID of the first component to link.
4180
4032
  component2_guid: str
4181
4033
  GUID of the second component to link.
4182
- body: dict
4034
+ body: dict | NewRelationshipRequestBody
4183
4035
  The body describing the link.
4184
4036
 
4037
+
4185
4038
  Returns
4186
4039
  -------
4187
4040
  None
@@ -4200,7 +4053,7 @@ class SolutionArchitect(Client):
4200
4053
 
4201
4054
  Body structure:
4202
4055
  {
4203
- "class": "RelationshipRequestBody",
4056
+ "class": "NewRelationshipRequestBody",
4204
4057
  "externalSourceGUID": "add guid here",
4205
4058
  "externalSourceName": "add qualified name here",
4206
4059
  "properties": {
@@ -4214,16 +4067,14 @@ class SolutionArchitect(Client):
4214
4067
  "forDuplicateProcessing": false
4215
4068
  }
4216
4069
  """
4217
- validate_guid(component1_guid)
4218
- validate_guid(component2_guid)
4070
+
4219
4071
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
4220
4072
  f"solution-components/{component1_guid}/wired-to/{component2_guid}/attach")
4221
- if body:
4222
- await self._async_make_request("POST", url, body_slimmer(body))
4223
- else:
4224
- await self._async_make_request("POST", url)
4073
+ await self._async_new_relationship_request(url, ["SolutionLinkingWireProperties"], body)
4074
+ logger.info(f"Linked Solution Linking wires between {component1_guid} -> {component2_guid}")
4225
4075
 
4226
- def link_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict) -> None:
4076
+ @dynamic_catch
4077
+ def link_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict | NewRelationshipRequestBody) -> None:
4227
4078
  """ Attach a solution component to a solution component as a peer in a solution.
4228
4079
 
4229
4080
  Parameters
@@ -4232,7 +4083,7 @@ class SolutionArchitect(Client):
4232
4083
  GUID of the first component to link.
4233
4084
  component2_guid: str
4234
4085
  GUID of the second component to link.
4235
- body: dict
4086
+ body: dict | NewRelationshipRequestBody
4236
4087
  The body describing the link.
4237
4088
 
4238
4089
  Returns
@@ -4253,7 +4104,7 @@ class SolutionArchitect(Client):
4253
4104
 
4254
4105
  Body structure:
4255
4106
  {
4256
- "class": "RelationshipRequestBody",
4107
+ "class": "NewRelationshipRequestBody",
4257
4108
  "externalSourceGUID": "add guid here",
4258
4109
  "externalSourceName": "add qualified name here",
4259
4110
  "properties": {
@@ -4270,8 +4121,9 @@ class SolutionArchitect(Client):
4270
4121
  loop = asyncio.get_event_loop()
4271
4122
  loop.run_until_complete(self._async_link_solution_linking_wire(component1_guid, component2_guid, body))
4272
4123
 
4124
+ @dynamic_catch
4273
4125
  async def _async_detach_solution_linking_wire(self, component1_guid: str, component2_guid: str,
4274
- body: dict = None) -> None:
4126
+ body: dict | DeleteRequestBody = None) -> None:
4275
4127
  """ Detach a solution component from a peer solution component.
4276
4128
  Async Version.
4277
4129
 
@@ -4281,7 +4133,7 @@ class SolutionArchitect(Client):
4281
4133
  GUID of the first component to unlink.
4282
4134
  component2_guid: str
4283
4135
  GUID of the second component to unlink.
4284
- body: dict
4136
+ body: dict | DeleteRequestBody
4285
4137
  The body describing the request.
4286
4138
 
4287
4139
  Returns
@@ -4302,7 +4154,7 @@ class SolutionArchitect(Client):
4302
4154
 
4303
4155
  Body structure:
4304
4156
  {
4305
- "class" : "MetadataSourceRequestBody",
4157
+ "class" : "DeleteRequestBody",
4306
4158
  "externalSourceGUID": "add guid here",
4307
4159
  "externalSourceName": "add qualified name here",
4308
4160
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -4311,14 +4163,16 @@ class SolutionArchitect(Client):
4311
4163
  }
4312
4164
 
4313
4165
  """
4314
- validate_guid(component1_guid)
4315
- validate_guid(component2_guid)
4166
+
4316
4167
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
4317
4168
  f"solution-components/{component1_guid}/wired-to/{component2_guid}/detach")
4318
4169
 
4319
- await self._async_make_request("POST", url, body_slimmer(body))
4170
+ await self._async_delete_request(url, body)
4171
+ logger.info(
4172
+ f"Detached solution linking wire between {component1_guid} -> {component2_guid}")
4320
4173
 
4321
- def detach_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict = None) -> None:
4174
+ @dynamic_catch
4175
+ def detach_solution_linking_wire(self, component1_guid: str, component2_guid: str, body: dict | DeleteRequestBody = None) -> None:
4322
4176
  """ Detach a solution component from a peer solution component.
4323
4177
  Async Version.
4324
4178
 
@@ -4328,7 +4182,8 @@ class SolutionArchitect(Client):
4328
4182
  GUID of the first component to unlink.
4329
4183
  component2_guid: str
4330
4184
  GUID of the second component to unlink.
4331
- body: dict
4185
+ body: dict | DeleteRequestBody
4186
+ The body describing the request.
4332
4187
  The body describing the request.
4333
4188
 
4334
4189
  Returns
@@ -4349,7 +4204,7 @@ class SolutionArchitect(Client):
4349
4204
 
4350
4205
  Body structure:
4351
4206
  {
4352
- "class" : "MetadataSourceRequestBody",
4207
+ "class" : "DeleteRequestBody",
4353
4208
  "externalSourceGUID": "add guid here",
4354
4209
  "externalSourceName": "add qualified name here",
4355
4210
  "effectiveTime" : "{{$isoTimestamp}}",
@@ -4361,9 +4216,9 @@ class SolutionArchitect(Client):
4361
4216
  loop = asyncio.get_event_loop()
4362
4217
  loop.run_until_complete(self._async_detach_solution_linking_wire(component1_guid, component2_guid, body))
4363
4218
 
4364
-
4219
+ @dynamic_catch
4365
4220
  async def _async_delete_solution_component(self, solution_component_guid: str, cascade_delete: bool = False,
4366
- body: dict = None) -> None:
4221
+ body: dict | DeleteRequestBody= None) -> None:
4367
4222
  """Delete a solution component. Async Version.
4368
4223
 
4369
4224
  Parameters
@@ -4372,7 +4227,7 @@ class SolutionArchitect(Client):
4372
4227
  guid of the component to delete.
4373
4228
  cascade_delete: bool, optional, default: False
4374
4229
  Cascade the delete to dependent objects?
4375
- body: dict, optional
4230
+ body: dict | DeleteRequestBody, optional
4376
4231
  A dictionary containing parameters for the deletion.
4377
4232
 
4378
4233
  Returns
@@ -4393,7 +4248,7 @@ class SolutionArchitect(Client):
4393
4248
 
4394
4249
  Body structure:
4395
4250
  {
4396
- "class": "MetadataSourceRequestBody",
4251
+ "class": "DeleteRequestBody",
4397
4252
  "externalSourceGUID": "add guid here",
4398
4253
  "externalSourceName": "add qualified name here",
4399
4254
  "effectiveTime": {{isotime}},
@@ -4401,18 +4256,16 @@ class SolutionArchitect(Client):
4401
4256
  "forDuplicateProcessing": false
4402
4257
  }
4403
4258
  """
4404
- validate_guid(solution_component_guid)
4405
- cascaded_s = str(cascade_delete).lower()
4259
+
4406
4260
 
4407
4261
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
4408
- f"solution-components/{solution_component_guid}/delete?cascadeDelete={cascade_delete}")
4409
- if body:
4410
- await self._async_make_request("POST", url, body_slimmer(body))
4411
- else:
4412
- await self._async_make_request("POST", url)
4262
+ f"solution-components/{solution_component_guid}/delete")
4263
+ await self._async_delete_request(url, body, cascade_delete=cascade_delete)
4264
+ logger.info(f"Deleted Solution Component {solution_component_guid} with cascade {cascade_delete}")
4413
4265
 
4266
+ @dynamic_catch
4414
4267
  def delete_solution_component(self, solution_component_guid: str, cascade_delete: bool = False,
4415
- body: dict = None) -> None:
4268
+ body: dict | DeleteRequestBody = None) -> None:
4416
4269
  """Delete a solution component.
4417
4270
  Parameters
4418
4271
  ----------
@@ -4420,7 +4273,7 @@ class SolutionArchitect(Client):
4420
4273
  guid of the component to delete.
4421
4274
  cascade_delete: bool, optional, default: False
4422
4275
  Cascade the delete to dependent objects?
4423
- body: dict, optional
4276
+ body: dict | DeleteRequestBody, optional
4424
4277
  A dictionary containing parameters for the deletion.
4425
4278
 
4426
4279
  Returns
@@ -4441,7 +4294,7 @@ class SolutionArchitect(Client):
4441
4294
 
4442
4295
  Body structure:
4443
4296
  {
4444
- "class": "MetadataSourceRequestBody",
4297
+ "class": "DeleteRequestBody",
4445
4298
  "externalSourceGUID": "add guid here",
4446
4299
  "externalSourceName": "add qualified name here",
4447
4300
  "effectiveTime": {{isotime}},
@@ -4452,10 +4305,13 @@ class SolutionArchitect(Client):
4452
4305
  loop = asyncio.get_event_loop()
4453
4306
  loop.run_until_complete(self._async_delete_solution_component(solution_component_guid, cascade_delete, body))
4454
4307
 
4455
- async def _async_find_solution_components(self, search_filter: str = "*", starts_with: bool = True,
4456
- ends_with: bool = False, ignore_case: bool = False, start_from: int = 0,
4457
- page_size: int = 0, body: dict = None,
4458
- output_format: str = "JSON") -> list[dict] | str:
4308
+ async def _async_find_solution_components(self, search_string: str = "*", classification_names: list[str] = None,
4309
+ metadata_element_types: list[str] = None,
4310
+ starts_with: bool = True, ends_with: bool = False,
4311
+ ignore_case: bool = False, start_from: int = 0,
4312
+ page_size: int = 0, output_format: str = 'JSON',
4313
+ output_format_set: str = None,
4314
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
4459
4315
  """ Retrieve the solution component elements that contain the search string. The solutions components returned
4460
4316
  include information about consumers, actors, and other solution components that are associated with them.
4461
4317
  https://egeria-project.org/concepts/solution-components
@@ -4511,35 +4367,26 @@ class SolutionArchitect(Client):
4511
4367
  }
4512
4368
  """
4513
4369
 
4514
- starts_with_s = str(starts_with).lower()
4515
- ends_with_s = str(ends_with).lower()
4516
- ignore_case_s = str(ignore_case).lower()
4517
4370
 
4518
- possible_query_params = query_string(
4519
- [ ("startFrom", start_from), ("pageSize", page_size),
4520
- ("startsWith", starts_with_s), ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
4521
4371
 
4522
- if search_filter is None or search_filter == "*":
4523
- search_filter = None
4372
+ url = f"{self.solution_architect_command_root}/solution-components/by-search-string"
4524
4373
 
4525
- if body is None:
4526
- body = {
4527
- "filter": search_filter,
4528
- }
4374
+ return await self._async_find_request(url, _type="GovernanceDefinition",
4375
+ _gen_output=self.generate_info_supply_chain_output,
4376
+ search_string=search_string, classification_names=classification_names,
4377
+ metadata_element_types=metadata_element_types,
4378
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
4379
+ start_from=start_from, page_size=page_size,
4380
+ output_format=output_format, output_format_set=output_format_set,
4381
+ body=body)
4529
4382
 
4530
- url = (f"{self.solution_architect_command_root}/solution-components/by-search-string"
4531
- f"{possible_query_params}")
4532
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
4533
- element = response.json().get("elements", NO_ELEMENTS_FOUND)
4534
- if element == NO_ELEMENTS_FOUND:
4535
- return NO_ELEMENTS_FOUND
4536
- if output_format != 'JSON': # return a simplified markdown representation
4537
- return self.generate_solution_components_output(element, filter, output_format)
4538
- return response.json().get("elements", NO_ELEMENTS_FOUND)
4539
-
4540
- def find_solution_components(self, search_filter: str = "*", starts_with: bool = True, ends_with: bool = False,
4541
- ignore_case: bool = False, start_from: int = 0, page_size: int = 0,
4542
- body: dict = None, output_format: str = "JSON") -> list[dict] | str:
4383
+ def find_solution_components(self, search_string: str = "*", classification_names: list[str] = None,
4384
+ metadata_element_types: list[str] = None,
4385
+ starts_with: bool = True, ends_with: bool = False,
4386
+ ignore_case: bool = False, start_from: int = 0,
4387
+ page_size: int = 0, output_format: str = 'JSON',
4388
+ output_format_set: str = None,
4389
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
4543
4390
  """ Retrieve the solution component elements that contain the search string. The solutions components returned
4544
4391
  include information about consumers, actors, and other solution components that are associated with them.
4545
4392
  https://egeria-project.org/concepts/solution-components
@@ -4597,17 +4444,20 @@ class SolutionArchitect(Client):
4597
4444
 
4598
4445
  loop = asyncio.get_event_loop()
4599
4446
  response = loop.run_until_complete(
4600
- self._async_find_solution_components(search_filter, starts_with, ends_with, ignore_case, start_from,
4601
- page_size, body, output_format))
4447
+ self._async_find_solution_components(search_string, classification_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body))
4602
4448
  return response
4603
4449
 
4604
- def find_all_solution_components(self, body: dict = None, start_from: int = 0, page_size: int = max_paging_size,
4605
- output_format: str = "JSON") -> list[dict] | str:
4450
+ def find_all_solution_components(self, classification_names: list[str] = None,
4451
+ metadata_element_types: list[str] = None,
4452
+ starts_with: bool = True, ends_with: bool = False,
4453
+ ignore_case: bool = False, start_from: int = 0,
4454
+ page_size: int = 0, output_format: str = 'JSON',
4455
+ output_format_set: str = None,
4456
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
4606
4457
  """Retrieve a list of all solution component elements
4607
4458
  https://egeria-project.org/concepts/solution-components
4608
4459
  """
4609
- return self.find_solution_components("*", body = body, start_from=start_from, page_size=page_size,
4610
- output_format=output_format)
4460
+ return self.find_solution_components("*", classification_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body)
4611
4461
 
4612
4462
  async def _async_get_solution_components_by_name(self, search_filter: str, body: dict = None, start_from: int = 0,
4613
4463
  page_size: int = 0, output_format: str = "JSON") -> dict | str:
@@ -5018,22 +4868,20 @@ class SolutionArchitect(Client):
5018
4868
  #
5019
4869
  # Roles
5020
4870
  #
5021
-
5022
- async def _async_create_solution_role(self, body: dict) -> str:
4871
+ @dynamic_catch
4872
+ async def _async_create_solution_role(self, body: dict | NewElementRequestBody) -> str:
5023
4873
  """ Create a solution role. Async version.
5024
4874
 
5025
4875
  Parameters
5026
4876
  ----------
5027
- body: dict
5028
- A dictionary containing the definition of the role to create.
4877
+ body: dict | NewElementRequestBody
4878
+ A dictionary containing the properties of the solution role to create.
5029
4879
 
5030
4880
  Returns
5031
4881
  -------
5032
4882
 
5033
4883
  str - guid of the role created.
5034
4884
 
5035
- Raises
5036
- ------
5037
4885
  Raises
5038
4886
  ------
5039
4887
  InvalidParameterException
@@ -5087,17 +4935,16 @@ class SolutionArchitect(Client):
5087
4935
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5088
4936
  f"solution-roles")
5089
4937
 
5090
- response = await self._async_make_request("POST", url, body_slimmer(body))
4938
+ return await self._async_create_element_body_request(url, ["SolutionRoleProperties"], body)
5091
4939
 
5092
- return response.json().get("guid", "Solution role not created")
5093
-
5094
- def create_solution_role(self, body: dict) -> str:
4940
+ @dynamic_catch
4941
+ def create_solution_role(self, body: dict| NewElementRequestBody) -> str:
5095
4942
  """Create a solution role. Async version.
5096
4943
 
5097
4944
  Parameters
5098
4945
  ----------
5099
- body: dict
5100
- A dictionary containing the definition of the role to create.
4946
+ body: dict | NewElementRequestBody
4947
+ A dictionary containing the properties of the solution role to create.
5101
4948
 
5102
4949
  Returns
5103
4950
  -------
@@ -5162,7 +5009,8 @@ class SolutionArchitect(Client):
5162
5009
  response = loop.run_until_complete(self._async_create_solution_role(body))
5163
5010
  return response
5164
5011
 
5165
- async def _async_create_solution_role_from_template(self, body: dict) -> str:
5012
+ @dynamic_catch
5013
+ async def _async_create_solution_role_from_template(self, body: dict | TemplateRequestBody) -> str:
5166
5014
  """ Create a new metadata element to represent a solution role using an existing metadata element as a template.
5167
5015
  The template defines additional classifications and relationships that should be added to the new element.
5168
5016
  Async Version.
@@ -5170,8 +5018,9 @@ class SolutionArchitect(Client):
5170
5018
 
5171
5019
  Parameters
5172
5020
  ----------
5173
- body: dict
5174
- A dictionary containing the definition of the solution component to create.
5021
+ body: dict | TemplateRequestBody
5022
+ A dictionary containing the properties of the solution role to create.
5023
+
5175
5024
 
5176
5025
  Returns
5177
5026
  -------
@@ -5233,12 +5082,20 @@ class SolutionArchitect(Client):
5233
5082
  """
5234
5083
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5235
5084
  f"solution-roles/from-template")
5085
+ if isinstance(body, TemplateRequestBody):
5086
+ validated_body = body
5236
5087
 
5237
- response = await self._async_make_request("POST", url, body_slimmer(body))
5088
+ elif isinstance(body, dict):
5089
+ validated_body = self._template_request_adapter.validate_python(body)
5238
5090
 
5239
- return response.json().get("guid", "Role not created")
5091
+ json_body = validated_body.model_dump_json(indent=2, exclude_none=True)
5092
+ logger.info(json_body)
5093
+ resp = await self._async_make_request("POST", url, json_body, is_json=True)
5094
+ logger.info(f"Create Solution Role from template with GUID: {resp.json().get('guid')}")
5095
+ return resp.json().get("guid", NO_GUID_RETURNED)
5240
5096
 
5241
- def create_solution_role_from_template(self, body: dict) -> str:
5097
+ @dynamic_catch
5098
+ def create_solution_role_from_template(self, body: dict |TemplateRequestBody) -> str:
5242
5099
  """ Create a new solution component using an existing metadata element
5243
5100
  as a template. The template defines additional classifications and relationships that should be
5244
5101
  added to
@@ -5247,8 +5104,8 @@ class SolutionArchitect(Client):
5247
5104
 
5248
5105
  Parameters
5249
5106
  ----------
5250
- body: dict
5251
- A dictionary containing the definition of the solution component to create.
5107
+ body: dict | TemplateRequestBody
5108
+ A dictionary containing the properties of the solution role to create.
5252
5109
 
5253
5110
  Returns
5254
5111
  -------
@@ -5313,7 +5170,8 @@ class SolutionArchitect(Client):
5313
5170
  response = loop.run_until_complete(self._async_create_solution_role_from_template(body))
5314
5171
  return response
5315
5172
 
5316
- async def _async_update_solution_role(self, guid: str, body: dict, replace_all_properties: bool = False) -> None:
5173
+ @dynamic_catch
5174
+ async def _async_update_solution_role(self, guid: str, body: dict |UpdateElementRequestBody) -> None:
5317
5175
  """ Update the properties of a solution role. Async Version.
5318
5176
 
5319
5177
  Parameters
@@ -5368,24 +5226,22 @@ class SolutionArchitect(Client):
5368
5226
  }
5369
5227
 
5370
5228
  """
5371
- validate_guid(guid)
5372
- replace_all_properties_s = str(replace_all_properties).lower()
5229
+
5373
5230
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5374
- f"solution-roles/{guid}/update?replaceAllProperties={replace_all_properties_s}")
5231
+ f"solution-roles/{guid}/update")
5375
5232
 
5376
- await self._async_make_request("POST", url, body_slimmer(body))
5233
+ await self._async_update_element_body_request(url, ["SolutionRoleProperties"], body)
5377
5234
 
5378
- def update_solution_role(self, guid: str, body: dict, replace_all_properties: bool = False) -> None:
5235
+ @dynamic_catch
5236
+ def update_solution_role(self, guid: str, body: dict | UpdateElementRequestBody) -> None:
5379
5237
  """ Update the properties of a solution role.
5380
5238
 
5381
5239
  Parameters
5382
5240
  ----------
5383
5241
  guid: str
5384
5242
  guid of the solution role to update.
5385
- body: dict
5386
- A dictionary containing the updates to the component.
5387
- replace_all_properties: bool, optional, default is False
5388
- Whether to replace all properties with those provided in the body or to merge with existing properties.
5243
+ body: dict | UpdateElementRequestBody
5244
+ A dictionary containing the updates to the role.
5389
5245
 
5390
5246
  Returns
5391
5247
  -------
@@ -5430,9 +5286,10 @@ class SolutionArchitect(Client):
5430
5286
  }
5431
5287
  """
5432
5288
  loop = asyncio.get_event_loop()
5433
- loop.run_until_complete(self._async_update_solution_role(guid, body, replace_all_properties))
5289
+ loop.run_until_complete(self._async_update_solution_role(guid, body))
5434
5290
 
5435
- async def _async_link_component_to_actor(self, role_guid: str, component_guid: str, body: dict) -> None:
5291
+ @dynamic_catch
5292
+ async def _async_link_component_to_actor(self, role_guid: str, component_guid: str, body: dict | NewRelationshipRequestBody) -> None:
5436
5293
  """ Attach a solution component to a solution role. Async Version.
5437
5294
 
5438
5295
  Parameters
@@ -5441,8 +5298,8 @@ class SolutionArchitect(Client):
5441
5298
  guid of the role to link.
5442
5299
  component_guid: str
5443
5300
  guid of the component to link.
5444
- body: dict
5445
- The body describing the link.
5301
+ body: dict | NewRelationshipRequestBody
5302
+ A dictionary containing the properties of the relationship to create.
5446
5303
 
5447
5304
  Returns
5448
5305
  -------
@@ -5462,7 +5319,7 @@ class SolutionArchitect(Client):
5462
5319
 
5463
5320
  Body structure:
5464
5321
  {
5465
- "class" : "RelationshipRequestBody",
5322
+ "class" : "NewRelationshipRequestBody",
5466
5323
  "properties": {
5467
5324
  "class": "SolutionComponentActorProperties",
5468
5325
  "role": "Add role here",
@@ -5477,14 +5334,15 @@ class SolutionArchitect(Client):
5477
5334
  "forDuplicateProcessing" : false
5478
5335
  }
5479
5336
  """
5480
- validate_guid(component_guid)
5481
- validate_guid(role_guid)
5337
+
5482
5338
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5483
5339
  f"solution-roles/{role_guid}/solution-roles/{component_guid}/attach")
5484
5340
 
5485
- await self._async_make_request("POST", url, body_slimmer(body))
5341
+ await self._async_new_relationship_request(url, ["InformationSupplyChainLinkProperties"], body)
5342
+ logger.info(f"Linked Role to Component {role_guid} -> {component_guid}")
5486
5343
 
5487
- def link_component_to_actor(self, role_guid: str, component_guid: str, body: dict) -> None:
5344
+ @dynamic_catch
5345
+ def link_component_to_actor(self, role_guid: str, component_guid: str, body: dict | NewRelationshipRequestBody) -> None:
5488
5346
  """ Attach a solution component to a solution role.
5489
5347
 
5490
5348
  Parameters
@@ -5493,8 +5351,8 @@ class SolutionArchitect(Client):
5493
5351
  guid of the role to link.
5494
5352
  component_guid: str
5495
5353
  guid of the component to link.
5496
- body: dict
5497
- The body describing the link.
5354
+ body: dict | NewRelationshipRequestBody
5355
+ A dictionary containing the properties of the relationship to create.
5498
5356
 
5499
5357
  Returns
5500
5358
  -------
@@ -5514,7 +5372,7 @@ class SolutionArchitect(Client):
5514
5372
 
5515
5373
  Body structure:
5516
5374
  {
5517
- "class" : "RelationshipRequestBody",
5375
+ "class" : "NewRelationshipRequestBody",
5518
5376
  "properties": {
5519
5377
  "class": "SolutionComponentActorProperties",
5520
5378
  "role": "Add role here",
@@ -5533,7 +5391,8 @@ class SolutionArchitect(Client):
5533
5391
  loop = asyncio.get_event_loop()
5534
5392
  loop.run_until_complete(self._async_link_component_to_actor(role_guid, component_guid, body))
5535
5393
 
5536
- async def _async_detach_component_actor(self, role_guid: str, component_guid: str, body: dict = None) -> None:
5394
+ @dynamic_catch
5395
+ async def _async_detach_component_actor(self, role_guid: str, component_guid: str, body: dict | DeleteRequestBody = None) -> None:
5537
5396
  """ Detach a solution role from a solution component.
5538
5397
  Async Version.
5539
5398
 
@@ -5543,8 +5402,8 @@ class SolutionArchitect(Client):
5543
5402
  guid of the role to disconnect from.
5544
5403
  component_guid: str
5545
5404
  guid of the component to disconnect.
5546
- body: dict
5547
- The body describing the request.
5405
+ body: dict | DeleteRequestBody, optional
5406
+ A dictionary containing the properties of the relationship to create.
5548
5407
 
5549
5408
  Returns
5550
5409
  -------
@@ -5564,7 +5423,7 @@ class SolutionArchitect(Client):
5564
5423
 
5565
5424
  Body structure:
5566
5425
  {
5567
- "class": "MetadataSourceRequestBody",
5426
+ "class": "DeleteRequestBody",
5568
5427
  "externalSourceGUID": "add guid here",
5569
5428
  "externalSourceName": "add qualified name here",
5570
5429
  "effectiveTime": {{isotime}},
@@ -5573,14 +5432,16 @@ class SolutionArchitect(Client):
5573
5432
  }
5574
5433
 
5575
5434
  """
5576
- validate_guid(role_guid)
5577
- validate_guid(component_guid)
5435
+
5578
5436
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5579
5437
  f"solution-components/{role_guid}/solution-component-actors/{component_guid}/detach")
5580
5438
 
5581
- await self._async_make_request("POST", url, body_slimmer(body))
5439
+ await self._async_delete_request(url, body)
5440
+ logger.info(
5441
+ f"Detached role from component {role_guid} -> {component_guid}")
5582
5442
 
5583
- def detach_component_actore(self, role_guid: str, component_guid: str, body: dict = None) -> None:
5443
+ @dynamic_catch
5444
+ def detach_component_actore(self, role_guid: str, component_guid: str, body: dict |DeleteRequestBody = None) -> None:
5584
5445
  """ Detach a solution role from a solution component.
5585
5446
 
5586
5447
  Parameters
@@ -5589,8 +5450,8 @@ class SolutionArchitect(Client):
5589
5450
  guid of the role to disconnect from.
5590
5451
  component_guid: str
5591
5452
  guid of the component to disconnect.
5592
- body: dict
5593
- The body describing the request.
5453
+ body: dict | DeleteRequestBody, optional
5454
+ A dictionary containing the properties of the relationship to create.
5594
5455
 
5595
5456
  Returns
5596
5457
  -------
@@ -5610,7 +5471,7 @@ class SolutionArchitect(Client):
5610
5471
 
5611
5472
  Body structure:
5612
5473
  {
5613
- "class": "MetadataSourceRequestBody",
5474
+ "class": "DeleteRequestBody",
5614
5475
  "externalSourceGUID": "add guid here",
5615
5476
  "externalSourceName": "add qualified name here",
5616
5477
  "effectiveTime": {{isotime}},
@@ -5621,15 +5482,15 @@ class SolutionArchitect(Client):
5621
5482
  loop = asyncio.get_event_loop()
5622
5483
  loop.run_until_complete(self._async_detach_component_actor(role_guid, component_guid, body))
5623
5484
 
5624
-
5625
- async def _async_delete_solution_role(self, guid: str, body: dict = None, cascade_delete: bool = False,) -> None:
5485
+ @dynamic_catch
5486
+ async def _async_delete_solution_role(self, guid: str, body: dict | DeleteRequestBody= None, cascade_delete: bool = False,) -> None:
5626
5487
  """Delete a solution role. Async Version.
5627
5488
 
5628
5489
  Parameters
5629
5490
  ----------
5630
5491
  guid: str
5631
5492
  guid of the role to delete.
5632
- body: dict, optional
5493
+ body: dict | DeleteRequestBody, optional
5633
5494
  A dictionary containing parameters for the deletion.
5634
5495
  cascade_delete: bool, optional, default: False
5635
5496
  Cascade the delete to dependent objects?
@@ -5653,7 +5514,7 @@ class SolutionArchitect(Client):
5653
5514
 
5654
5515
  Body structure:
5655
5516
  {
5656
- "class": "MetadataSourceRequestBody",
5517
+ "class": "DeleteRequestBody",
5657
5518
  "externalSourceGUID": "add guid here",
5658
5519
  "externalSourceName": "add qualified name here",
5659
5520
  "effectiveTime": {{isotime}},
@@ -5661,22 +5522,22 @@ class SolutionArchitect(Client):
5661
5522
  "forDuplicateProcessing": false
5662
5523
  }
5663
5524
  """
5664
- validate_guid(guid)
5665
- cascaded_s = str(cascade_delete).lower()
5666
5525
 
5667
5526
  url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/solution-architect/"
5668
- f"solution-roles/{guid}/delete?cascadedDelete={cascaded_s}")
5527
+ f"solution-roles/{guid}/delete")
5669
5528
 
5670
- await self._async_make_request("POST", url, body_slimmer(body))
5529
+ await self._async_delete_request(url, body, cascade_delete=cascade_delete)
5530
+ logger.info(f"Delete solution rule {guid} with cascade {cascade_delete}")
5671
5531
 
5672
- def delete_solution_role(self, guid: str, body: dict = None,cascade_delete: bool = False) -> None:
5532
+ @dynamic_catch
5533
+ def delete_solution_role(self, guid: str, body: dict | DeleteRequestBody = None,cascade_delete: bool = False) -> None:
5673
5534
  """Delete a solution role. Async Version.
5674
5535
 
5675
5536
  Parameters
5676
5537
  ----------
5677
5538
  guid: str
5678
5539
  guid of the role to delete.
5679
- body: dict, optional
5540
+ body: dict | DeleteRequestBody, optional
5680
5541
  A dictionary containing parameters for the deletion.
5681
5542
  cascade_delete: bool, optional, default: False
5682
5543
  Cascade the delete to dependent objects?
@@ -5699,7 +5560,7 @@ class SolutionArchitect(Client):
5699
5560
 
5700
5561
  Body structure:
5701
5562
  {
5702
- "class": "MetadataSourceRequestBody",
5563
+ "class": "DeleteRequestBody",
5703
5564
  "externalSourceGUID": "add guid here",
5704
5565
  "externalSourceName": "add qualified name here",
5705
5566
  "effectiveTime": {{isotime}},
@@ -5710,10 +5571,13 @@ class SolutionArchitect(Client):
5710
5571
  loop = asyncio.get_event_loop()
5711
5572
  loop.run_until_complete(self._async_delete_solution_role(guid, cascade_delete, body))
5712
5573
 
5713
- async def _async_find_solution_roles(self, search_filter: str = "*", body: dict = None, starts_with: bool = True,
5714
- ends_with: bool = False, ignore_case: bool = False, start_from: int = 0,
5715
- page_size: int = 0,
5716
- output_format: str = "JSON", ) -> list[dict] | str:
5574
+ async def _async_find_solution_roles(self, search_string: str = "*", classification_names: list[str] = None,
5575
+ metadata_element_types: list[str] = None,
5576
+ starts_with: bool = True, ends_with: bool = False,
5577
+ ignore_case: bool = False, start_from: int = 0,
5578
+ page_size: int = 0, output_format: str = 'JSON',
5579
+ output_format_set: str = None,
5580
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
5717
5581
  """Retrieve the solution role elements that contain the search string.
5718
5582
  https://egeria-project.org/concepts/actor
5719
5583
  Async version.
@@ -5769,34 +5633,26 @@ class SolutionArchitect(Client):
5769
5633
  "filter": "Add name here"
5770
5634
  }
5771
5635
  """
5772
- starts_with_s = str(starts_with).lower()
5773
- ends_with_s = str(ends_with).lower()
5774
- ignore_case_s = str(ignore_case).lower()
5775
-
5776
- possible_query_params = query_string(
5777
- [ ("startFrom", start_from), ("pageSize", page_size),
5778
- ("startsWith", starts_with_s), ("endsWith", ends_with_s), ("ignoreCase", ignore_case_s), ])
5779
- if search_filter is None or search_filter == "*":
5780
- search_filter = None
5781
5636
 
5782
- if body is None:
5783
- body = {
5784
- "filter": search_filter,
5785
- }
5786
-
5787
- url = (f"{self.solution_architect_command_root}/solution-roles/by-search-string"
5788
- f"{possible_query_params}")
5789
- response: Response = await self._async_make_request("POST", url, body_slimmer(body))
5790
- element = response.json().get("elements", NO_ELEMENTS_FOUND)
5791
- if element == NO_ELEMENTS_FOUND:
5792
- return NO_ELEMENTS_FOUND
5793
- if output_format != 'JSON': # return a simplified markdown representation
5794
- return self.generate_solution_roles_output(element, filter, output_format)
5795
- return response.json().get("elements", NO_ELEMENTS_FOUND)
5796
5637
 
5797
- def find_solution_roles(self, search_filter: str = "*", body: dict = None, starts_with: bool = True, ends_with: bool = False,
5798
- ignore_case: bool = False, start_from: int = 0, page_size: int = max_paging_size,
5799
- output_format: str = "JSON", ) -> list[dict] | str:
5638
+ url = f"{self.solution_architect_command_root}/solution-roles/by-search-string"
5639
+
5640
+ return await self._async_find_request(url, _type="GovernanceDefinition",
5641
+ _gen_output=self.generate_info_supply_chain_output,
5642
+ search_string=search_string, classification_names=classification_names,
5643
+ metadata_element_types=metadata_element_types,
5644
+ starts_with=starts_with, ends_with=ends_with, ignore_case=ignore_case,
5645
+ start_from=start_from, page_size=page_size,
5646
+ output_format=output_format, output_format_set=output_format_set,
5647
+ body=body)
5648
+
5649
+ def find_solution_roles(self, search_string: str = "*", classification_names: list[str] = None,
5650
+ metadata_element_types: list[str] = None,
5651
+ starts_with: bool = True, ends_with: bool = False,
5652
+ ignore_case: bool = False, start_from: int = 0,
5653
+ page_size: int = 0, output_format: str = 'JSON',
5654
+ output_format_set: str = None,
5655
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
5800
5656
  """Retrieve the list of solution role elements that contain the search string.
5801
5657
  https://egeria-project.org/concepts/actor
5802
5658
 
@@ -5860,16 +5716,20 @@ class SolutionArchitect(Client):
5860
5716
 
5861
5717
  loop = asyncio.get_event_loop()
5862
5718
  response = loop.run_until_complete(
5863
- self._async_find_solution_roles(search_filter, body, starts_with, ends_with, ignore_case, start_from, page_size,
5864
- output_format=output_format, ))
5719
+ self._async_find_solution_roles(search_string, classification_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body))
5865
5720
  return response
5866
5721
 
5867
- def find_all_solution_roles(self, body: dict = None, start_from: int = 0, page_size: int = max_paging_size,
5868
- output_format: str = "JSON") -> list[dict] | str:
5722
+ def find_all_solution_roles(self, classification_names: list[str] = None,
5723
+ metadata_element_types: list[str] = None,
5724
+ starts_with: bool = True, ends_with: bool = False,
5725
+ ignore_case: bool = False, start_from: int = 0,
5726
+ page_size: int = 0, output_format: str = 'JSON',
5727
+ output_format_set: str = None,
5728
+ body: dict| SearchStringRequestBody = None) -> list[dict] | str:
5869
5729
  """Retrieve a list of all solution blueprint elements
5870
5730
  https://egeria-project.org/concepts/actor
5871
5731
  """
5872
- return self.find_solution_roles("*", body, start_from=start_from, page_size=page_size, output_format=output_format)
5732
+ return self.find_solution_roles("*", classification_names, metadata_element_types, starts_with, ends_with, ignore_case, start_from, page_size, output_format, output_format_set, body)
5873
5733
 
5874
5734
 
5875
5735
  async def _async_get_solution_roles_by_name(self, search_filter: str, body: dict = None, start_from: int = 0,