pyegeria 5.3.9.9.7__py3-none-any.whl → 5.4.0__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 (163) hide show
  1. commands/cat/debug_log +2806 -0
  2. commands/cat/debug_log.2025-07-15_14-28-38_087378.zip +0 -0
  3. commands/cat/debug_log.2025-07-16_15-48-50_037087.zip +0 -0
  4. commands/cat/dr_egeria_command_help.py +273 -0
  5. commands/cat/dr_egeria_md.py +90 -20
  6. commands/cat/glossary_actions.py +2 -2
  7. commands/cat/list_collections.py +24 -10
  8. commands/cat/list_data_designer.py +183 -0
  9. md_processing/__init__.py +28 -5
  10. md_processing/data/commands.json +31474 -1096
  11. md_processing/dr_egeria_outbox-pycharm/.obsidian/app.json +1 -0
  12. md_processing/dr_egeria_outbox-pycharm/.obsidian/appearance.json +1 -0
  13. md_processing/dr_egeria_outbox-pycharm/.obsidian/core-plugins.json +31 -0
  14. md_processing/dr_egeria_outbox-pycharm/.obsidian/workspace.json +177 -0
  15. md_processing/dr_egeria_outbox-pycharm/monday/processed-2025-07-14 12:38-data_designer_out.md +663 -0
  16. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 15:00-Derive-Dr-Gov-Defs.md +719 -0
  17. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:13-Derive-Dr-Gov-Defs.md +41 -0
  18. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:14-Derive-Dr-Gov-Defs.md +33 -0
  19. md_processing/dr_egeria_outbox-pycharm/thursday/processed-2025-07-17 20:50-Derive-Dr-Gov-Defs.md +192 -0
  20. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-16 19:15-gov_def2.md +527 -0
  21. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 12:08-gov_def2.md +527 -0
  22. md_processing/dr_egeria_outbox-pycharm/tuesday/processed-2025-07-17 14:27-gov_def2.md +474 -0
  23. md_processing/family_docs/Data Designer/Create_Data_Class.md +164 -0
  24. md_processing/family_docs/Data Designer/Create_Data_Dictionary.md +30 -0
  25. md_processing/family_docs/Data Designer/Create_Data_Field.md +162 -0
  26. md_processing/family_docs/Data Designer/Create_Data_Specification.md +36 -0
  27. md_processing/family_docs/Data Designer/Create_Data_Structure.md +38 -0
  28. md_processing/family_docs/Data Designer/View_Data_Classes.md +78 -0
  29. md_processing/family_docs/Data Designer/View_Data_Dictionaries.md +78 -0
  30. md_processing/family_docs/Data Designer/View_Data_Fields.md +78 -0
  31. md_processing/family_docs/Data Designer/View_Data_Specifications.md +78 -0
  32. md_processing/family_docs/Data Designer/View_Data_Structures.md +78 -0
  33. md_processing/family_docs/Data Designer.md +842 -0
  34. md_processing/family_docs/Digital Product Manager/Add_Member->Collection.md +42 -0
  35. md_processing/family_docs/Digital Product Manager/Attach_Collection->Resource.md +36 -0
  36. md_processing/family_docs/Digital Product Manager/Create_Agreement.md +96 -0
  37. md_processing/family_docs/Digital Product Manager/Create_Data_Sharing_Agreement.md +72 -0
  38. md_processing/family_docs/Digital Product Manager/Create_DigitalSubscription.md +102 -0
  39. md_processing/family_docs/Digital Product Manager/Create_Digital_Product.md +134 -0
  40. md_processing/family_docs/Digital Product Manager/Link_Agreement_Items.md +60 -0
  41. md_processing/family_docs/Digital Product Manager/Link_Contracts.md +26 -0
  42. md_processing/family_docs/Digital Product Manager/Link_Digital_Product_-_Digital_Product.md +30 -0
  43. md_processing/family_docs/Digital Product Manager/Link_Subscribers.md +48 -0
  44. md_processing/family_docs/Digital Product Manager.md +668 -0
  45. md_processing/family_docs/Glossary/Attach_Category_Parent.md +18 -0
  46. md_processing/family_docs/Glossary/Attach_Term-Term_Relationship.md +26 -0
  47. md_processing/family_docs/Glossary/Create_Category.md +38 -0
  48. md_processing/family_docs/Glossary/Create_Glossary.md +42 -0
  49. md_processing/family_docs/Glossary/Create_Term.md +70 -0
  50. md_processing/family_docs/Glossary.md +206 -0
  51. md_processing/family_docs/Governance Officer/Create_Business_Imperative.md +106 -0
  52. md_processing/family_docs/Governance Officer/Create_Certification_Type.md +112 -0
  53. md_processing/family_docs/Governance Officer/Create_Governance_Approach.md +114 -0
  54. md_processing/family_docs/Governance Officer/Create_Governance_Obligation.md +114 -0
  55. md_processing/family_docs/Governance Officer/Create_Governance_Principle.md +114 -0
  56. md_processing/family_docs/Governance Officer/Create_Governance_Procedure.md +128 -0
  57. md_processing/family_docs/Governance Officer/Create_Governance_Process.md +122 -0
  58. md_processing/family_docs/Governance Officer/Create_Governance_Processing_Purpose.md +106 -0
  59. md_processing/family_docs/Governance Officer/Create_Governance_Responsibility.md +122 -0
  60. md_processing/family_docs/Governance Officer/Create_Governance_Rule.md +122 -0
  61. md_processing/family_docs/Governance Officer/Create_Governance_Strategy.md +106 -0
  62. md_processing/family_docs/Governance Officer/Create_License_Type.md +112 -0
  63. md_processing/family_docs/Governance Officer/Create_Naming_Standard_Rule.md +122 -0
  64. md_processing/family_docs/Governance Officer/Create_Regulation_Article.md +106 -0
  65. md_processing/family_docs/Governance Officer/Create_Regulation_Definition.md +118 -0
  66. md_processing/family_docs/Governance Officer/Create_Security_Access_Control.md +114 -0
  67. md_processing/family_docs/Governance Officer/Create_Security_Group.md +120 -0
  68. md_processing/family_docs/Governance Officer/Create_Service_Level_Objectives.md +122 -0
  69. md_processing/family_docs/Governance Officer/Create_Threat_Definition.md +106 -0
  70. md_processing/family_docs/Governance Officer/Link_Governance_Controls.md +32 -0
  71. md_processing/family_docs/Governance Officer/Link_Governance_Drivers.md +32 -0
  72. md_processing/family_docs/Governance Officer/Link_Governance_Policies.md +32 -0
  73. md_processing/family_docs/Governance Officer/View_Governance_Definitions.md +82 -0
  74. md_processing/family_docs/Governance Officer.md +2412 -0
  75. md_processing/family_docs/Solution Architect/Create_Information_Supply_Chain.md +70 -0
  76. md_processing/family_docs/Solution Architect/Create_Solution_Blueprint.md +44 -0
  77. md_processing/family_docs/Solution Architect/Create_Solution_Component.md +96 -0
  78. md_processing/family_docs/Solution Architect/Create_Solution_Role.md +66 -0
  79. md_processing/family_docs/Solution Architect/Link_Information_Supply_Chain_Peers.md +32 -0
  80. md_processing/family_docs/Solution Architect/Link_Solution_Component_Peers.md +32 -0
  81. md_processing/family_docs/Solution Architect/View_Information_Supply_Chains.md +32 -0
  82. md_processing/family_docs/Solution Architect/View_Solution_Blueprints.md +32 -0
  83. md_processing/family_docs/Solution Architect/View_Solution_Components.md +32 -0
  84. md_processing/family_docs/Solution Architect/View_Solution_Roles.md +32 -0
  85. md_processing/family_docs/Solution Architect.md +490 -0
  86. md_processing/md_commands/data_designer_commands.py +1192 -710
  87. md_processing/md_commands/glossary_commands.py +19 -32
  88. md_processing/md_commands/governance_officer_commands.py +420 -0
  89. md_processing/md_commands/product_manager_commands.py +1180 -0
  90. md_processing/md_commands/project_commands.py +5 -2
  91. md_processing/md_commands/solution_architect_commands.py +1140 -0
  92. md_processing/md_processing_utils/common_md_proc_utils.py +288 -96
  93. md_processing/md_processing_utils/common_md_utils.py +205 -6
  94. md_processing/md_processing_utils/debug_log +574 -0
  95. md_processing/md_processing_utils/dr-egeria-help-2025-07-17T17:22:09.md +2065 -0
  96. md_processing/md_processing_utils/extraction_utils.py +1 -1
  97. md_processing/md_processing_utils/generate_dr_help.py +165 -0
  98. md_processing/md_processing_utils/generate_md_cmd_templates.py +143 -0
  99. md_processing/md_processing_utils/generate_md_templates.py +92 -0
  100. md_processing/md_processing_utils/generated_help_terms.md +842 -0
  101. md_processing/md_processing_utils/md_processing_constants.py +94 -17
  102. pyegeria/__init__.py +1 -0
  103. pyegeria/_client.py +39 -1
  104. pyegeria/classification_manager_omvs.py +1 -1
  105. pyegeria/collection_manager_omvs.py +4667 -1178
  106. pyegeria/data_designer_omvs.py +348 -31
  107. pyegeria/egeria_tech_client.py +9 -25
  108. pyegeria/glossary_browser_omvs.py +5 -6
  109. pyegeria/glossary_manager_omvs.py +2 -2
  110. pyegeria/governance_officer_omvs.py +2367 -0
  111. pyegeria/output_formatter.py +157 -32
  112. pyegeria/solution_architect_omvs.py +5063 -1110
  113. pyegeria/utils.py +22 -2
  114. {pyegeria-5.3.9.9.7.dist-info → pyegeria-5.4.0.dist-info}/METADATA +3 -1
  115. pyegeria-5.4.0.dist-info/RECORD +243 -0
  116. {pyegeria-5.3.9.9.7.dist-info → pyegeria-5.4.0.dist-info}/entry_points.txt +5 -0
  117. commands/cat/.DS_Store +0 -0
  118. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  119. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  120. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  121. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  122. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  123. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  124. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  125. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  126. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  127. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  128. md_processing/dr_egeria_inbox/data_field.md +0 -54
  129. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  130. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2406
  131. md_processing/dr_egeria_inbox/data_test.md +0 -86
  132. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  133. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  134. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -313
  135. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  136. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  137. md_processing/dr_egeria_inbox/glossary_test1.md +0 -324
  138. md_processing/dr_egeria_inbox/rel.md +0 -8
  139. md_processing/dr_egeria_inbox/sb.md +0 -119
  140. md_processing/dr_egeria_inbox/search_test.md +0 -39
  141. md_processing/dr_egeria_inbox/solution-components.md +0 -154
  142. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  143. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  144. md_processing/dr_egeria_inbox/t1.md +0 -0
  145. md_processing/dr_egeria_inbox/t2.md +0 -268
  146. md_processing/dr_egeria_outbox/processed-2025-05-15 19:52-data_test.md +0 -94
  147. md_processing/dr_egeria_outbox/processed-2025-05-16 07:39-data_test.md +0 -88
  148. md_processing/dr_egeria_outbox/processed-2025-05-17 16:01-data_field.md +0 -56
  149. md_processing/dr_egeria_outbox/processed-2025-05-18 15:51-data_test.md +0 -103
  150. md_processing/dr_egeria_outbox/processed-2025-05-18 16:47-data_test.md +0 -94
  151. md_processing/dr_egeria_outbox/processed-2025-05-19 07:14-data_test.md +0 -96
  152. md_processing/dr_egeria_outbox/processed-2025-05-19 07:20-data_test.md +0 -100
  153. md_processing/dr_egeria_outbox/processed-2025-05-19 07:22-data_test.md +0 -88
  154. md_processing/dr_egeria_outbox/processed-2025-05-19 09:26-data_test.md +0 -91
  155. md_processing/dr_egeria_outbox/processed-2025-05-19 10:27-data_test.md +0 -91
  156. md_processing/dr_egeria_outbox/processed-2025-05-19 14:04-data_test.md +0 -91
  157. md_processing/md_commands/blueprint_commands.py +0 -303
  158. pyegeria/.DS_Store +0 -0
  159. pyegeria/m_test.py +0 -118
  160. pyegeria-5.3.9.9.7.dist-info/RECORD +0 -196
  161. /commands/cat/{list_data_structures.py → list_data_structures_full.py} +0 -0
  162. {pyegeria-5.3.9.9.7.dist-info → pyegeria-5.4.0.dist-info}/LICENSE +0 -0
  163. {pyegeria-5.3.9.9.7.dist-info → pyegeria-5.4.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1140 @@
1
+ """
2
+ This file contains blueprint/solution-related object_action functions for processing Egeria Markdown
3
+ """
4
+ import json
5
+ import sys
6
+ from typing import Optional
7
+
8
+ from loguru import logger
9
+ from pygments.lexers import blueprint
10
+ from rich import print
11
+ from rich.console import Console
12
+ from rich.markdown import Markdown
13
+
14
+ from md_processing.md_processing_utils.common_md_proc_utils import (parse_upsert_command, parse_view_command)
15
+ from md_processing.md_processing_utils.common_md_utils import update_element_dictionary, setup_log
16
+ from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
17
+ from md_processing.md_processing_utils.md_processing_constants import (load_commands)
18
+ from pyegeria import body_slimmer, EgeriaTech
19
+
20
+ load_commands('commands.json')
21
+
22
+ console = Console(width=int(200))
23
+ setup_log()
24
+
25
+
26
+ @logger.catch
27
+ def sync_chain_related_elements(egeria_client: EgeriaTech, guid:str, in_supply_chain_guids:list, display_name:str,
28
+ replace_all_props:bool):
29
+ if replace_all_props:
30
+ rel_el_list = egeria_client._get_supply_chain_rel_elements(guid)
31
+ if rel_el_list is None:
32
+ logger.warning("Unexpected -> the list was None - assigning empty list")
33
+ rel_el_list = {}
34
+
35
+ as_is_parent_guids = set(rel_el_list.get("parent_guids", []))
36
+
37
+ to_be_parent_guids = set(in_supply_chain_guids) if in_supply_chain_guids is not None else set()
38
+
39
+ logger.trace(
40
+ f"as_is_parent supply chains: {list(as_is_parent_guids)} to_be_parent supply chains: {list(to_be_parent_guids)}")
41
+
42
+
43
+ parent_guids_to_remove = as_is_parent_guids - to_be_parent_guids
44
+ logger.trace(f"parent_guids_to_remove: {list(parent_guids_to_remove)}")
45
+ if len(parent_guids_to_remove) > 0:
46
+ for parent_guid in parent_guids_to_remove:
47
+ egeria_client.decompose_info_supply_chains(parent_guid, guid, None)
48
+ msg = f"Removed `{display_name}` from supply chain parent `{parent_guid}`"
49
+ logger.trace(msg)
50
+
51
+ parent_guids_to_add = to_be_parent_guids - as_is_parent_guids
52
+ logger.trace(f"parent supply chains_to_add: {list(parent_guids_to_add)}")
53
+ if len(parent_guids_to_add) > 0:
54
+ for parent_guid in parent_guids_to_add:
55
+ egeria_client.compose_info_supply_chains(parent_guid, guid, None)
56
+ msg = f"Added `{display_name}` to supply chain parent `{parent_guid}`"
57
+ logger.trace(msg)
58
+
59
+ else: # merge - add supply chain to parents
60
+ if in_supply_chain_guids:
61
+ for parent_guid in in_supply_chain_guids:
62
+ egeria_client.compose_info_supply_chains(parent_guid, guid, None)
63
+ msg = f"Added `{display_name}` to supply chain `{parent_guid}`"
64
+ logger.trace(msg)
65
+
66
+
67
+
68
+ @logger.catch
69
+ def sync_component_related_elements(egeria_client: EgeriaTech, object_type: str,
70
+ supply_chain_guids: list, parent_component_guids: list,
71
+ actor_guids: list, in_blueprint_guids: list, guid: str, qualified_name: str,
72
+ display_name: str, merge_update: bool = True) -> None:
73
+ """Sync a components related elements.
74
+
75
+ """
76
+ if not merge_update:
77
+ rel_el_list = egeria_client.get_component_related_elements(guid)
78
+ # should I throw an exception if empty?
79
+
80
+ as_is_actors = set(rel_el_list.get("actor_guids", []))
81
+ as_is_blueprints = set(rel_el_list.get("blueprint_guids", []))
82
+ as_is_parent_components = set(rel_el_list.get("parent_component_guids", []))
83
+ as_is_supply_chains = set(rel_el_list.get("supply_chain_guids", []))
84
+
85
+
86
+ to_be_actors = set(actor_guids) if actor_guids is not None else set()
87
+ to_be_blueprints = set(in_blueprint_guids) if in_blueprint_guids is not None else set()
88
+ to_be_parent_components = set(parent_component_guids) if parent_component_guids is not None else set()
89
+ to_be_supply_chains = set(supply_chain_guids) if supply_chain_guids is not None else set()
90
+
91
+
92
+ logger.trace(
93
+ f"as_is_sub_components: {list(as_is_parent_components)} to_be_sub_components: {list(to_be_parent_components)}")
94
+ logger.trace(f"as_is_actors: {list(as_is_actors)} to_be_actors: {list(to_be_actors)}")
95
+ logger.trace(f"as_is_blueprints: {list(as_is_blueprints)} to_be_blueprints: {list(to_be_blueprints)}")
96
+
97
+ parent_components_to_remove = as_is_parent_components - to_be_parent_components
98
+ logger.trace(f"sub_components_to_remove: {list(parent_components_to_remove)}")
99
+ if len(parent_components_to_remove) > 0:
100
+ for ds in parent_components_to_remove:
101
+ egeria_client.detach_sub_component(ds, guid, None)
102
+ msg = f"Removed `{display_name}` from component `{ds}`"
103
+ logger.trace(msg)
104
+
105
+ parent_components_to_add = to_be_parent_components - as_is_parent_components
106
+ logger.trace(f"parent_components_to_add: {list(parent_components_to_add)}")
107
+ if len(parent_components_to_add) > 0:
108
+ for ds in parent_components_to_add:
109
+ egeria_client.link_subcomponent(ds, guid, None)
110
+ msg = f"Added `{display_name}` to component `{ds}`"
111
+ logger.trace(msg)
112
+
113
+ blueprints_to_remove = as_is_blueprints - to_be_blueprints
114
+ logger.trace(f"blueprints_to_remove: {list(blueprints_to_remove)}")
115
+ if len(blueprints_to_remove) > 0:
116
+ for bp in blueprints_to_remove:
117
+ egeria_client.detach_solution_component_from_blueprint(bp, guid, None)
118
+ msg = f"Removed `{display_name}` from blueprintt `{bp}`"
119
+ logger.trace(msg)
120
+
121
+ blueprints_to_add = to_be_blueprints - as_is_blueprints
122
+ logger.trace(f"blueprints_to_add: {list(blueprints_to_add)}")
123
+ if len(blueprints_to_add) > 0:
124
+ for bp in blueprints_to_add:
125
+ egeria_client.link_solution_component_to_blueprint(bp, guid, None)
126
+ msg = f"Added `{display_name}` to component `{bp}`"
127
+ logger.trace(msg)
128
+
129
+
130
+
131
+ actors_to_remove = to_be_actors - as_is_actors
132
+ logger.trace(f"actors_to_remove: {list(actors_to_remove)}")
133
+ if len(actors_to_remove) > 0:
134
+ for actor in actors_to_remove:
135
+ egeria_client.detach_component_actore(actor, guid, None)
136
+ msg = f"Removed actor `{actor}` from component `{display_name}`"
137
+ logger.trace(msg)
138
+
139
+ actors_to_add = to_be_actors - as_is_actors
140
+ logger.trace(f"actors_to_add: {list(actors_to_add)}")
141
+ if len(actors_to_add) > 0:
142
+ for actor in actors_to_add:
143
+ egeria_client.link_component_to_actor(actor, guid, None)
144
+ msg = f"Added `{display_name}` to role `{actor}`"
145
+ logger.trace(msg)
146
+
147
+ supply_chains_to_remove = as_is_supply_chains - to_be_supply_chains
148
+ logger.trace(f"supply_chains_to_remove: {list(supply_chains_to_remove)}")
149
+ if len(supply_chains_to_remove) > 0:
150
+ for isc in supply_chains_to_remove:
151
+ egeria_client.detach_design_from_implementation(isc, guid)
152
+ msg = f"Removed `{isc}` from `{display_name}`"
153
+ logger.trace(msg)
154
+ supply_chains_to_add = to_be_supply_chains - as_is_supply_chains
155
+ logger.trace(f"supply_chains_to_add: {list(supply_chains_to_add)}")
156
+ if len(supply_chains_to_add) > 0:
157
+ body = {
158
+ "class": "RelationshipRequestBody",
159
+ "properties": {
160
+ "class": "ImplementedByProperties",
161
+ "description": "a blank description to satisfy the Egeria gods"
162
+ }
163
+ }
164
+ for isc in supply_chains_to_add:
165
+ egeria_client.link_design_to_implementation(isc, guid, body)
166
+ msg = f"Added `{isc}` to`{display_name}`"
167
+ logger.trace(msg)
168
+ logger.info(f"Replaced the related elements in `{display_name}`")
169
+
170
+ else: # merge - add field to related elements
171
+ if parent_component_guids:
172
+ for comp in parent_component_guids:
173
+ egeria_client.link_subcomponent(guid, comp, None)
174
+ msg = f"Added `{parent_component_guids}` to `{display_name}`"
175
+ logger.trace(msg)
176
+
177
+ if actor_guids:
178
+ for actor in actor_guids:
179
+ egeria_client.link_component_to_actor(actor, guid, None)
180
+ msg = f"Added `{actor_guids}` to `{display_name}`"
181
+ logger.trace(msg)
182
+
183
+ if in_blueprint_guids:
184
+ for bp in in_blueprint_guids:
185
+ egeria_client.link_solution_component_to_blueprint(bp, guid, None)
186
+ msg = f"Added `{in_blueprint_guids}` to `{display_name}`"
187
+ logger.trace(msg)
188
+
189
+ if supply_chain_guids:
190
+ body = {
191
+ "class": "RelationshipRequestBody",
192
+ "properties": {
193
+ "class": "ImplementedByProperties",
194
+ "description": "a blank description to satisfy the Egeria gods"
195
+ }
196
+ }
197
+ for isc in supply_chain_guids:
198
+ egeria_client.link_design_to_implementation(isc, guid, body)
199
+ msg = f"Added `{display_name}` to `{isc}`"
200
+ logger.trace(msg)
201
+
202
+ logger.info(f"Merged related elements in `{display_name}`")
203
+
204
+
205
+ def sync_blueprint_related_elements(egeria_client: EgeriaTech, object_type: str, component_guids: list, guid: str,
206
+ qualified_name: str, display_name: str, replace_all_props: bool = True) -> None:
207
+ """Sync a blueprints related elements.
208
+
209
+ """
210
+ if replace_all_props:
211
+ bp_element = egeria_client.get_solution_blueprint_by_guid(guid)
212
+ solution_components = bp_element['solutionComponents']
213
+ as_is_components = {}
214
+ if len(solution_components) > 0:
215
+ for component in solution_components:
216
+ as_is_components.append(component['elementHeader']['guid'])
217
+
218
+ # should I throw an exception if empty?
219
+
220
+ to_be_components = set(component_guids) if component_guids is not None else set()
221
+
222
+ logger.trace(f"as_is_components: {list(as_is_components)} to_be_sub_components: {list(to_be_components)}")
223
+
224
+ components_to_remove = as_is_components - to_be_components
225
+ logger.trace(f"components_to_remove: {list(components_to_remove)}")
226
+ if len(components_to_remove) > 0:
227
+ for ds in components_to_remove:
228
+ egeria_client.detach_solution_component_from_blueprint(guid, ds, None)
229
+ msg = f"Removed `{ds}` from component `{display_name}`"
230
+ logger.trace(msg)
231
+ components_to_add = to_be_components - as_is_components
232
+ logger.trace(f"sub_components_to_add: {list(components_to_add)}")
233
+ if len(components_to_add) > 0:
234
+ for ds in components_to_add:
235
+ egeria_client.link_solution_component_to_blueprint(guid, ds, None)
236
+ msg = f"Added `{ds}` to component `{display_name}`"
237
+ logger.trace(msg)
238
+
239
+ logger.info(f"Replaced the related elements in `{display_name}`")
240
+
241
+ else: # merge - add field to related elements
242
+ if component_guids:
243
+ for comp in component_guids:
244
+ egeria_client.link_solution_component_to_blueprint(guid, comp, None)
245
+ msg = f"Added `{component_guids}` to `{display_name}`"
246
+ logger.trace(msg)
247
+
248
+ logger.info(f"Merged related elements in `{display_name}`")
249
+
250
+
251
+ @logger.catch
252
+ def process_blueprint_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
253
+ """
254
+ Processes a solution blueprint create or update object_action by extracting key attributes such as
255
+ blueprint name, description, and usage from the given text.
256
+
257
+ :param txt: A string representing the input cell to be processed for
258
+ extracting blueprint-related attributes.
259
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
260
+ :return: A string summarizing the outcome of the processing.
261
+ """
262
+ command, object_type, object_action = extract_command_plus(txt)
263
+ print(Markdown(f"# {command}\n"))
264
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
265
+
266
+ valid = parsed_output['valid']
267
+ exists = parsed_output['exists']
268
+
269
+ qualified_name = parsed_output.get('qualified_name', None)
270
+ guid = parsed_output.get('guid', None)
271
+
272
+ print(Markdown(parsed_output['display']))
273
+
274
+ logger.debug(json.dumps(parsed_output, indent=4))
275
+
276
+ attributes = parsed_output['attributes']
277
+ description = attributes.get('Description', {}).get('value', None)
278
+ display_name = attributes['Display Name'].get('value', None)
279
+ version_identifier = attributes.get('Version Identifier', {}).get('value', None)
280
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
281
+ effective_from = attributes.get('Effective From', {}).get('value', None)
282
+ effective_to = attributes.get('Effective To', {}).get('value', None)
283
+ external_source_guid = attributes.get('External Source GUID', {}).get('value', None)
284
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
285
+
286
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
287
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
288
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
289
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
290
+
291
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
292
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
293
+ if parent_guid is None:
294
+ is_own_anchor = True
295
+
296
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
297
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
298
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
299
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
300
+ component_guids = attributes.get('Solution Components', {}).get('guid_list', None)
301
+
302
+ initial_status = "ACTIVE"
303
+
304
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
305
+
306
+ if directive == "display":
307
+
308
+ return None
309
+ elif directive == "validate":
310
+ if valid:
311
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
312
+ else:
313
+ msg = f"Validation failed for object_action `{command}`\n"
314
+ return valid
315
+
316
+ elif directive == "process":
317
+ try:
318
+ if object_action == "Update":
319
+ if not exists:
320
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
321
+ f"object_action\n")
322
+ logger.error(msg)
323
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
324
+ elif not valid:
325
+ return None
326
+ else:
327
+ print(Markdown(
328
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
329
+
330
+ body = body_slimmer({
331
+ "class": "UpdateSolutionBlueprintRequestBody", "externalSourceGUID": external_source_guid,
332
+ "externalSourceName": external_source_name, "effectiveTime": effective_time,
333
+ "forLineage": False, "forDuplicateProcessing": False, "properties": {
334
+ "class": "SolutionBlueprintProperties", "qualifiedName": qualified_name,
335
+ "displayName": display_name, "description": description, "version": version_identifier,
336
+ "additionalProperties": additional_properties, "extendedProperties": extended_properties,
337
+ "effectiveFrom": effective_from, "effectiveTo": effective_to
338
+ }
339
+ })
340
+
341
+ egeria_client.update_solution_blueprint(guid, body, replace_all_props)
342
+ logger.success(f"==> Updated {object_type} `{display_name}` with GUID {guid}\n\n")
343
+ update_element_dictionary(qualified_name, {
344
+ 'guid': guid, 'display_name': display_name
345
+ })
346
+ sync_blueprint_related_elements(egeria_client, object_type, component_guids, guid, qualified_name,
347
+ display_name, replace_all_props)
348
+ logger.success(f"===> Updated {object_type} `{display_name}` related elements\n\n")
349
+ return egeria_client.find_solution_blueprints(qualified_name, output_format='MD')
350
+
351
+
352
+ elif object_action == "Create":
353
+ print(f"valid: {valid}, type: {type(valid)}")
354
+ try:
355
+ if valid is False and exists:
356
+ msg = (f" Data Specification `{display_name}` already exists and result document updated changing "
357
+ f"`Create` to `Update` in processed output\n\n___")
358
+ logger.error(msg)
359
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
360
+
361
+ elif not valid:
362
+ msg = (f"==>{object_type} `{display_name}` is not valid and can't be created")
363
+ logger.error(msg)
364
+ return
365
+
366
+ else:
367
+ body = {
368
+ "class": "NewSolutionBlueprintRequestBody",
369
+ "externalSourceGUID": external_source_guid,
370
+ "externalSourceName": external_source_name,
371
+ "forLineage": False,
372
+ "forDuplicateProcessing": False,
373
+ "effectiveTime": effective_time,
374
+ "anchorGUID": anchor_guid,
375
+ "isOwnAnchor": is_own_anchor,
376
+ "anchorScopeGUID": anchor_scope_guid,
377
+ "parentGUID": parent_guid,
378
+ "parentRelationshipTypeName": parent_relationship_type_name,
379
+ "parentAtEnd1": parent_at_end1,
380
+ "properties": {
381
+ "class": "SolutionBlueprintProperties",
382
+ "effectiveFrom": effective_from,
383
+ "effectiveTo": effective_to, # "typeName": type_name,
384
+ "extendedProperties": extended_properties,
385
+ "qualifiedName": qualified_name,
386
+ "additionalProperties": additional_properties,
387
+ "displayName": display_name,
388
+ "description": description,
389
+ "versionIdentifier": version_identifier
390
+ },
391
+ "initialStatus": initial_status,
392
+ }
393
+ guid = egeria_client.create_solution_blueprint(body)
394
+ except Exception as e:
395
+ print(f"Unexpected error: {e}, {type(valid)}, {valid}")
396
+
397
+
398
+ if guid:
399
+ update_element_dictionary(qualified_name, {
400
+ 'guid': guid, 'display_name': display_name
401
+ })
402
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
403
+ logger.success(msg)
404
+ return egeria_client.find_solution_blueprints(qualified_name, output_format='MD')
405
+ else:
406
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
407
+ logger.error(msg)
408
+ return None
409
+
410
+ except Exception as e:
411
+ print("why did I get here")
412
+ logger.error(f"Error performing {command}: {e}")
413
+ return None
414
+ else:
415
+ return None
416
+
417
+
418
+ @logger.catch
419
+ def process_solution_component_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> \
420
+ Optional[str]:
421
+ """
422
+ Processes a solution component create or update object_action by extracting key attributes such as
423
+ component name, description, and parent components from the given text.
424
+
425
+ :param txt: A string representing the input cell to be processed for
426
+ extracting component-related attributes.
427
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
428
+ :return: A string summarizing the outcome of the processing.
429
+ """
430
+ command, object_type, object_action = extract_command_plus(txt)
431
+ print(Markdown(f"# {command}\n"))
432
+
433
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
434
+
435
+ valid = parsed_output['valid']
436
+ exists = parsed_output['exists']
437
+
438
+ qualified_name = parsed_output.get('qualified_name', None)
439
+ guid = parsed_output.get('guid', None)
440
+
441
+ print(Markdown(parsed_output['display']))
442
+
443
+ logger.debug(json.dumps(parsed_output, indent=4))
444
+
445
+ attributes = parsed_output['attributes']
446
+
447
+ description = attributes.get('Description', {}).get('value', None)
448
+ display_name = attributes['Display Name'].get('value', None)
449
+ version_identifier = attributes.get('Version Identifier', {}).get('value', None)
450
+ solution_component_type = attributes.get('Solution Component Type', {}).get('value', None)
451
+ planned_deployed_impl_type = attributes.get('Planned Deployed Implementation Type', {}).get('value', None)
452
+ initial_status = attributes.get('Status', {}).get('value', None)
453
+ user_defined_status = attributes.get('User Defined Status', {}).get('value', None)
454
+ if initial_status != "OTHER":
455
+ user_defined_status = None
456
+
457
+ # sub_component_names = attributes.get('Solution SubComponents', {}).get('name_list', None)
458
+ # sub_component_guids = attributes.get('Solution SubComponents', {}).get('guid_list', None)
459
+ actor_names = attributes.get('Actors', {}).get('name_list', None)
460
+ actor_guids = attributes.get('Actors', {}).get('guid_list', None)
461
+ in_blueprint_names = attributes.get('In Solution Blueprints', {}).get('name_list', None)
462
+ in_blueprint_guids = attributes.get('In Solution Blueprints', {}).get('guid_list', None)
463
+ in_supply_chain_names = attributes.get('In Information Supply Chains', {}).get('name_list', None)
464
+ in_supply_chain_guids = attributes.get('In Information Supply Chains', {}).get('guid_list', None)
465
+ in_component_names = attributes.get('In Solution Components', {}).get('name_list', None)
466
+ in_component_guids = attributes.get('In Solution Components', {}).get('guid_list', None)
467
+ parent_component_guids = attributes.get('Parent Components', {}).get('guid_list', None)
468
+ parent_component_names = attributes.get('Parent Components', {}).get('name_list', None)
469
+
470
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
471
+ effective_from = attributes.get('Effective From', {}).get('value', None)
472
+ effective_to = attributes.get('Effective To', {}).get('value', None)
473
+ external_source_guid = attributes.get('External Source GUID', {}).get('value', None)
474
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
475
+
476
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
477
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
478
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
479
+ parent_relationship_properties = attributes.get('Parent Relationship Properties', {}).get('value', None)
480
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
481
+
482
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
483
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
484
+ if parent_guid is None:
485
+ is_own_anchor = True
486
+
487
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
488
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
489
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
490
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
491
+
492
+ merge_update = attributes.get('Merge Update', {}).get('value', True)
493
+
494
+
495
+
496
+ if directive == "display":
497
+
498
+ return None
499
+ elif directive == "validate":
500
+ if valid:
501
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
502
+ else:
503
+ msg = f"Validation failed for object_action `{command}`\n"
504
+ return valid
505
+
506
+ elif directive == "process":
507
+ try:
508
+ if object_action == "Update":
509
+ if not exists:
510
+ msg = (f"==> Element `{display_name}` does not exist! Updating result document with Create."
511
+ f"object_action\n")
512
+ logger.error(msg)
513
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
514
+ elif not valid:
515
+ logger.error(f"==> Element `{display_name}` entry is not valid. Please refer to the errors above.")
516
+ return None
517
+ else:
518
+ print(Markdown(
519
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
520
+
521
+ body = body_slimmer({
522
+ "class": "UpdateElementRequestBody",
523
+ "externalSourceGUID": external_source_guid,
524
+ "externalSourceName": external_source_name,
525
+ "effectiveTime": effective_time, "forLineage": False,
526
+ "forDuplicateProcessing": False,
527
+ "parentAtEnd1": parent_at_end1,
528
+ "properties": {
529
+ "class": "SolutionComponentProperties",
530
+ "qualifiedName": qualified_name,
531
+ "displayName": display_name,
532
+ "description": description,
533
+ "solutionComponentType": solution_component_type,
534
+ "plannedDeployedImplementationType": planned_deployed_impl_type,
535
+ "additionalProperties": additional_properties,
536
+ "extendedProperties": extended_properties,
537
+ "effectiveFrom": effective_from,
538
+ "effectiveTo": effective_to
539
+ }
540
+ })
541
+
542
+ egeria_client.update_solution_component(guid, body, not merge_update)
543
+ logger.success(f"==>Updated {object_type} `{display_name}` with GUID {guid}\n")
544
+ update_element_dictionary(qualified_name, {
545
+ 'guid': guid, 'display_name': display_name
546
+ })
547
+ # Sync Parent Components and Blueprints
548
+ sync_component_related_elements(egeria_client, object_type ,
549
+ in_supply_chain_guids,parent_component_guids,actor_guids,
550
+ in_blueprint_guids, guid, qualified_name,
551
+ display_name,
552
+ merge_update)
553
+ logger.success(f"==>Updated {object_type} `{display_name}` with related elements")
554
+ return egeria_client.get_solution_component_by_guid(guid, output_format='MD')
555
+
556
+
557
+ elif object_action == "Create":
558
+ if valid is False and exists:
559
+ msg = (f" {object_type} `{display_name}` already exists and result document updated changing "
560
+ f"`Create` to `Update` in processed output\n\n___")
561
+ logger.error(msg)
562
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
563
+
564
+ elif not valid:
565
+ msg = (f"==>{object_type} `{display_name}` is not valid and can't be created")
566
+ logger.error(msg)
567
+ return
568
+
569
+ else:
570
+ body = body_slimmer({
571
+ "class": "NewSolutionElementRequestBody",
572
+ "anchorGUID": anchor_guid,
573
+ "isOwnAnchor": is_own_anchor,
574
+ "parentGUID": parent_guid,
575
+ "parentRelationshipTypeName": parent_relationship_type_name,
576
+ "parentRelationshipProperties": parent_relationship_properties,
577
+ "parentAtEnd1": parent_at_end1,
578
+ "properties": {
579
+ "class": "SolutionComponentProperties",
580
+ "qualifiedName": qualified_name,
581
+ "displayName": display_name,
582
+ "description": description,
583
+ "solutionComponentType": solution_component_type,
584
+ "versionIdentifier" : version_identifier,
585
+ "plannedDeployedImplementationType": planned_deployed_impl_type,
586
+ "userDefinedStatus" : user_defined_status,
587
+ "additionalProperties": additional_properties,
588
+ "extendedProperties": extended_properties,
589
+ "effectiveFrom": effective_from,
590
+ "effectiveTo": effective_to
591
+ },
592
+ "initialStatus": initial_status,
593
+ "externalSourceGUID": external_source_guid,
594
+ "externalSourceName": external_source_name,
595
+ "effectiveTime": effective_time,
596
+ "forLineage": False,
597
+ "forDuplicateProcessing": False
598
+ })
599
+
600
+ guid = egeria_client.create_solution_component(body)
601
+ if guid:
602
+ update_element_dictionary(qualified_name, {
603
+ 'guid': guid, 'display_name': display_name
604
+ })
605
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
606
+ logger.success(msg)
607
+ if in_component_guids:
608
+ for comp in in_component_guids:
609
+ egeria_client.link_subcomponent(comp, guid, None)
610
+ msg = f"Added to parent components `{in_component_names}` "
611
+ logger.trace(msg)
612
+
613
+ if actor_guids:
614
+ for actor in actor_guids:
615
+ egeria_client.link_component_to_actor(actor, guid, None)
616
+ msg = f"Added `{actor_guids}` to `{display_name}`"
617
+ logger.trace(msg)
618
+
619
+ if in_blueprint_guids:
620
+ for bp in in_blueprint_guids:
621
+ egeria_client.link_solution_component_to_blueprint(bp, guid, None)
622
+ msg = f"Added `{display_name}`to blueprints `{in_blueprint_names}`"
623
+ logger.trace(msg)
624
+
625
+ if in_supply_chain_guids:
626
+ for isc in in_supply_chain_guids:
627
+ egeria_client.link_design_to_implementation(isc, guid, None)
628
+ msg = f"Added `{display_name}`to supply chain `{in_supply_chain_names}`"
629
+ logger.trace(msg)
630
+
631
+ return egeria_client.get_solution_component_by_guid(guid, output_format='MD')
632
+ else:
633
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
634
+ logger.error(msg)
635
+ return None
636
+
637
+ except Exception as e:
638
+ logger.error(f"Error performing {command}: {e}")
639
+ return None
640
+ else:
641
+ return None
642
+
643
+
644
+ @logger.catch
645
+ def process_component_link_unlink_command(egeria_client: EgeriaTech, txt: str,
646
+ directive: str = "display") -> Optional[str]:
647
+ """
648
+ Processes a link or unlink command to wire solution components.
649
+
650
+ :param txt: A string representing the input cell to be processed for
651
+ extracting blueprint-related attributes.
652
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
653
+ :return: A string summarizing the outcome of the processing.
654
+ """
655
+ command, object_type, object_action = extract_command_plus(txt)
656
+ print(Markdown(f"# {command}\n"))
657
+
658
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
659
+
660
+ print(Markdown(parsed_output['display']))
661
+
662
+ logger.debug(json.dumps(parsed_output, indent=4))
663
+
664
+ attributes = parsed_output['attributes']
665
+
666
+ component1 = attributes.get('Component1', {}).get('guid', None)
667
+ component2 = attributes.get('Component2', {}).get('guid', None)
668
+ label = attributes.get('Wire Label', {}).get('value', None)
669
+ description = attributes.get('Description', {}).get('value', None)
670
+
671
+ valid = parsed_output['valid']
672
+ exists = component1 is not None and component2 is not None
673
+
674
+
675
+ external_source_guid = attributes.get('External Source GUID', {}).get('value', None)
676
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
677
+
678
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
679
+ effective_from = attributes.get('Effective From', {}).get('value', None)
680
+ effective_to = attributes.get('Effective To', {}).get('value', None)
681
+
682
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
683
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
684
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
685
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
686
+
687
+ if directive == "display":
688
+
689
+ return None
690
+ elif directive == "validate":
691
+ if valid:
692
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
693
+ else:
694
+ msg = f"Validation failed for object_action `{command}`\n"
695
+ return valid
696
+
697
+ elif directive == "process":
698
+ try:
699
+ if object_action == "Unlink":
700
+ if not exists:
701
+ msg = (f" Link `{label}` does not exist! Updating result document with Link "
702
+ f"object_action\n")
703
+ logger.error(msg)
704
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
705
+ return out
706
+ elif not valid:
707
+ return None
708
+ else:
709
+ print(Markdown(
710
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
711
+
712
+ body = body_slimmer({
713
+ "class": "MetadataSourceRequestBody",
714
+ "externalSourceGUID": external_source_guid,
715
+ "externalSourceName": external_source_name,
716
+ "effectiveTime": effective_time,
717
+ "forLineage": False,
718
+ "forDuplicateProcessing": False
719
+ })
720
+
721
+ egeria_client.detach_solution_linking_wire(component1, component2, body)
722
+
723
+ logger.success(f"===> Detached segment with {label} from `{component1}`to {component2}\n")
724
+ out = parsed_output['display'].replace('Unlink', 'Link', 1)
725
+
726
+ return (out)
727
+
728
+
729
+ elif object_action == "Link":
730
+ if valid is False and exists:
731
+ msg = (f"--> Link called `{label}` already exists and result document updated changing "
732
+ f"`Link` to `Detach` in processed output\n")
733
+ logger.error(msg)
734
+
735
+ elif valid is False:
736
+ msg = f"==>{object_type} Link with label `{label}` is not valid and can't be created"
737
+ logger.error(msg)
738
+ return
739
+ else:
740
+ body = {
741
+ "class": "RelationshipRequestBody",
742
+ "effectiveTime": effective_time,
743
+ "forLineage": False,
744
+ "forDuplicateProcessing": False,
745
+ "properties": {
746
+ "class": "SolutionLinkingWireProperties",
747
+ "label": label,
748
+ "description": description,
749
+ "effectiveFrom": effective_from,
750
+ "effectiveTo": effective_to
751
+ }
752
+ }
753
+
754
+ egeria_client.link_solution_linking_wire(component1, component2, None)
755
+ msg = f"==>Created {object_type} link named `{label}`\n"
756
+ logger.success(msg)
757
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
758
+ return out
759
+
760
+
761
+ except Exception as e:
762
+ logger.error(f"Error performing {command}: {e}")
763
+ return None
764
+ else:
765
+ return None
766
+
767
+
768
+
769
+ @logger.catch
770
+ def process_information_supply_chain_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") \
771
+ -> \
772
+ Optional[str]:
773
+ """
774
+ Processes a solution blueprint create or update object_action by extracting key attributes such as
775
+ blueprint name, description, and usage from the given text.
776
+
777
+ :param txt: A string representing the input cell to be processed for
778
+ extracting blueprint-related attributes.
779
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
780
+ :return: A string summarizing the outcome of the processing.
781
+ """
782
+ command, object_type, object_action = extract_command_plus(txt)
783
+ print(Markdown(f"# {command}\n"))
784
+
785
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
786
+
787
+ valid = parsed_output['valid']
788
+ exists = parsed_output['exists']
789
+
790
+ qualified_name = parsed_output.get('qualified_name', None)
791
+ guid = parsed_output.get('guid', None)
792
+
793
+ print(Markdown(parsed_output['display']))
794
+
795
+ logger.debug(json.dumps(parsed_output, indent=4))
796
+
797
+ attributes = parsed_output['attributes']
798
+ description = attributes.get('Description', {}).get('value', None)
799
+ display_name = attributes['Display Name'].get('value', None)
800
+ version_identifier = attributes.get('Version Identifier', {}).get('value', None)
801
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
802
+ effective_from = attributes.get('Effective From', {}).get('value', None)
803
+ effective_to = attributes.get('Effective To', {}).get('value', None)
804
+ external_source_guid = attributes.get('External Source GUID', {}).get('value', None)
805
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
806
+
807
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
808
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
809
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
810
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
811
+
812
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
813
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
814
+ if parent_guid is None:
815
+ is_own_anchor = True
816
+ nested_supply_chain_guids = attributes.get('Nested Supply Chain', {}).get('guids', None)
817
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
818
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
819
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
820
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
821
+
822
+ scope = attributes.get('Scope', {}).get('value', None)
823
+ purposes = attributes.get('Purposes', {}).get('value', None)
824
+ in_supply_chain_guids = attributes.get('In Information Supply Chain', {}).get('guid_list', None)
825
+
826
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
827
+
828
+ if directive == "display":
829
+
830
+ return None
831
+ elif directive == "validate":
832
+ if valid:
833
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
834
+ else:
835
+ msg = f"Validation failed for object_action `{command}`\n"
836
+ return valid
837
+
838
+ elif directive == "process":
839
+ try:
840
+ if object_action == "Update":
841
+ if not exists:
842
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
843
+ f"object_action\n")
844
+ logger.error(msg)
845
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
846
+ elif not valid:
847
+ return None
848
+ else:
849
+ print(Markdown(
850
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
851
+
852
+ body = body_slimmer({
853
+ "class": "UpdateElementRequestBody",
854
+ "externalSourceGUID": external_source_guid,
855
+ "externalSourceName": external_source_name,
856
+ "effectiveTime": effective_time,
857
+ "forLineage": False,
858
+ "forDuplicateProcessing": False,
859
+ "properties": {
860
+ "class": "InformationSupplyChainProperties", "effectiveFrom": effective_from,
861
+ "effectiveTo": effective_to, "extendedProperties": extended_properties,
862
+ "qualifiedName": qualified_name, "additionalProperties": additional_properties,
863
+ "displayName": display_name, "description": description, "scope": scope,
864
+ "purposes": purposes, "version": version_identifier
865
+ }
866
+ })
867
+
868
+ egeria_client.update_info_supply_chain(guid, body, replace_all_props)
869
+
870
+ sync_chain_related_elements(egeria_client, guid, in_supply_chain_guids, display_name, replace_all_props)
871
+ logger.success(f"==> Updated {object_type} `{display_name}` with GUID {guid}\n\n")
872
+ update_element_dictionary(qualified_name, {
873
+ 'guid': guid, 'display_name': display_name
874
+ })
875
+
876
+ # logger.success(f"===> Updated {object_type} `{display_name}` related elements\n\n")
877
+ return egeria_client.get_info_supply_chain_by_guid(guid, output_format='MD')
878
+
879
+
880
+ elif object_action == "Create":
881
+ if valid is False and exists:
882
+ msg = (
883
+ f"--> Data Specification `{display_name}` already exists and result document updated changing "
884
+ f"`Create` to `Update` in processed output\n")
885
+ logger.error(msg)
886
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
887
+
888
+ elif valid is False:
889
+ msg = f"==>{object_type} `{display_name}` is not valid and can't be created"
890
+ logger.error(msg)
891
+ return
892
+ else:
893
+ body = {
894
+ "class": "NewElementRequestBody",
895
+ "externalSourceGUID": external_source_guid,
896
+ "externalSourceName": external_source_name,
897
+ "forLineage": False,
898
+ "forDuplicateProcessing": False,
899
+ "effectiveTime": effective_time,
900
+ "anchorGUID": anchor_guid,
901
+ "isOwnAnchor": is_own_anchor,
902
+ "anchorScopeGUID": anchor_scope_guid,
903
+ "parentGUID": parent_guid,
904
+ "parentRelationshipTypeName": parent_relationship_type_name,
905
+ "parentAtEnd1": parent_at_end1,
906
+ "properties": {
907
+ "class": "InformationSupplyChainProperties",
908
+ "effectiveFrom": effective_from,
909
+ "effectiveTo": effective_to,
910
+ "extendedProperties": extended_properties,
911
+ "qualifiedName": qualified_name,
912
+ "additionalProperties": additional_properties,
913
+ "displayName": display_name,
914
+ "description": description,
915
+ "scope": scope,
916
+ "purposes": purposes,
917
+ "version": version_identifier
918
+ }
919
+ }
920
+
921
+ guid = egeria_client.create_info_supply_chain(body)
922
+ if guid:
923
+ update_element_dictionary(qualified_name, {
924
+ 'guid': guid, 'display_name': display_name
925
+ })
926
+ if len(in_supply_chain_guids) > 0:
927
+ for nested_chain in in_supply_chain_guids:
928
+ egeria_client.compose_info_supply_chains(guid, nested_chain)
929
+
930
+ msg = f"==>Created Element `{display_name}` with GUID {guid}\n"
931
+ logger.success(msg)
932
+ return egeria_client.get_info_supply_chain_by_guid(guid, output_format='MD')
933
+ else:
934
+ msg = f"==>Failed to create element `{display_name}` with GUID {guid}\n"
935
+ logger.error(msg)
936
+ return None
937
+
938
+ except Exception as e:
939
+ logger.error(f"Error performing {command}: {e}")
940
+ return None
941
+ else:
942
+ return None
943
+
944
+
945
+
946
+ @logger.catch
947
+ def process_information_supply_chain_link_unlink_command(egeria_client: EgeriaTech, txt: str,
948
+ directive: str = "display") -> Optional[str]:
949
+ """
950
+ Processes a link or unlink command to associate or break up peer supply chains..
951
+
952
+ :param txt: A string representing the input cell to be processed for
953
+ extracting blueprint-related attributes.
954
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
955
+ :return: A string summarizing the outcome of the processing.
956
+ """
957
+ command, object_type, object_action = extract_command_plus(txt)
958
+ print(Markdown(f"# {command}\n"))
959
+
960
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
961
+
962
+ print(Markdown(parsed_output['display']))
963
+
964
+ logger.debug(json.dumps(parsed_output, indent=4))
965
+
966
+ attributes = parsed_output['attributes']
967
+
968
+ component1 = attributes.get('component1', {}).get('guid', None)
969
+ component2 = attributes.get('component2', {}).get('guid', None)
970
+ label = attributes.get('Link Label', {}).get('value', None)
971
+ description = attributes.get('Description', {}).get('value', None)
972
+
973
+ valid = parsed_output['valid']
974
+ exists = component1 is not None and component2 is not None
975
+
976
+
977
+ external_source_guid = attributes.get('External Source GUID', {}).get('value', None)
978
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
979
+
980
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
981
+ effective_from = attributes.get('Effective From', {}).get('value', None)
982
+ effective_to = attributes.get('Effective To', {}).get('value', None)
983
+
984
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
985
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
986
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
987
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
988
+
989
+ if directive == "display":
990
+
991
+ return None
992
+ elif directive == "validate":
993
+ if valid:
994
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
995
+ else:
996
+ msg = f"Validation failed for object_action `{command}`\n"
997
+ return valid
998
+
999
+ elif directive == "process":
1000
+ try:
1001
+ if object_action == "Unlink":
1002
+ if not exists:
1003
+ msg = (f" Link `{label}` does not exist! Updating result document with Link "
1004
+ f"object_action\n")
1005
+ logger.error(msg)
1006
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
1007
+ return out
1008
+ elif not valid:
1009
+ return None
1010
+ else:
1011
+ print(Markdown(
1012
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
1013
+
1014
+ body = body_slimmer({
1015
+ "class": "MetadataSourceRequestBody",
1016
+ "externalSourceGUID": external_source_guid,
1017
+ "externalSourceName": external_source_name,
1018
+ "effectiveTime": effective_time,
1019
+ "forLineage": False,
1020
+ "forDuplicateProcessing": False
1021
+ })
1022
+
1023
+ egeria_client.unlink_peer_info_supply_chains(component1, component2, body)
1024
+
1025
+ logger.success(f"===> Detached segment with {label} from `{component1}`to {component2}\n")
1026
+ out = parsed_output['display'].replace('Unlink', 'Link', 1)
1027
+
1028
+ return (out)
1029
+
1030
+
1031
+ elif object_action == "Link":
1032
+ if valid is False and exists:
1033
+ msg = (f"--> Link called `{label}` already exists and result document updated changing "
1034
+ f"`Link` to `Detach` in processed output\n")
1035
+ logger.error(msg)
1036
+
1037
+ elif valid is False:
1038
+ msg = f"==>{object_type} Link with label `{label}` is not valid and can't be created"
1039
+ logger.error(msg)
1040
+ return
1041
+ else:
1042
+ body = {
1043
+ "class": "RelationshipRequestBody",
1044
+ "effectiveTime": effective_time,
1045
+ "forLineage": False,
1046
+ "forDuplicateProcessing": False,
1047
+ "properties": {
1048
+ "class": "InformationSupplyChainLinkProperties",
1049
+ "label": label,
1050
+ "description": description,
1051
+ "effectiveFrom": effective_from,
1052
+ "effectiveTo": effective_to
1053
+ }
1054
+ }
1055
+
1056
+ egeria_client.link_peer_info_supply_chain(component1, component2, body)
1057
+ msg = f"==>Created {object_type} link named `{label}`\n"
1058
+ logger.success(msg)
1059
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
1060
+ return out
1061
+
1062
+
1063
+ except Exception as e:
1064
+ logger.error(f"Error performing {command}: {e}")
1065
+ return None
1066
+ else:
1067
+ return None
1068
+
1069
+ @logger.catch
1070
+ def process_sol_arch_list_command(egeria_client: EgeriaTech, txt: str, kind:str, directive: str = "display" ) -> Optional[str]:
1071
+ """
1072
+ Processes Solution Blueprint list object_action by extracting key attributes such as
1073
+ search string from the given text.
1074
+
1075
+ :param txt: A string representing the input cell to be processed for
1076
+ extracting term-related attributes.
1077
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1078
+ :return: A string summarizing the outcome of the processing.
1079
+ """
1080
+ command, object_type, object_action = extract_command_plus(txt)
1081
+ print(Markdown(f"# {command}\n"))
1082
+
1083
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1084
+
1085
+ attributes = parsed_output['attributes']
1086
+
1087
+ valid = parsed_output['valid']
1088
+
1089
+ print(Markdown(parsed_output['display']))
1090
+
1091
+ if directive == "display":
1092
+ return None
1093
+ elif directive == "validate":
1094
+ if valid:
1095
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1096
+ else:
1097
+ msg = f"Validation failed for object_action `{command}`\n"
1098
+ logger.error(msg)
1099
+ return valid
1100
+
1101
+ elif directive == "process":
1102
+ attributes = parsed_output['attributes']
1103
+ search_string = attributes.get('Search String', {}).get('value', '*')
1104
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1105
+ detailed = attributes.get('Detailed', {}).get('value', False)
1106
+
1107
+ match kind:
1108
+ case "Solution Blueprints":
1109
+ find_proc = egeria_client.find_solution_blueprints
1110
+ case "Information Supply Chains":
1111
+ find_proc = egeria_client.find_information_supply_chains
1112
+ case "Solution Components":
1113
+ find_proc = egeria_client.find_solution_components
1114
+ case "Solution Roles":
1115
+ find_proc = egeria_client.find_solution_roles
1116
+
1117
+ try:
1118
+ if not valid: # First validate the command before we process it
1119
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1120
+ logger.error(msg)
1121
+ return None
1122
+
1123
+ list_md = f"\n# {kind} with filter: `{search_string}`\n\n"
1124
+ if output_format == "DICT":
1125
+ struct = find_proc(search_string, output_format=output_format)
1126
+ list_md += f"```{json.dumps(struct, indent=4)}```\n"
1127
+ else:
1128
+ list_md += find_proc(search_string, output_format=output_format)
1129
+ logger.info(f"Wrote Output for search string: `{search_string}`")
1130
+
1131
+ return list_md
1132
+
1133
+ except Exception as e:
1134
+ logger.error(f"Error performing {command}: {e}")
1135
+ console.print_exception(show_locals=True)
1136
+ return None
1137
+ else:
1138
+ return None
1139
+
1140
+