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,1180 @@
1
+ """
2
+ This file contains product manager commands for processing Egeria Markdown
3
+ """
4
+ import json
5
+ import os
6
+ import sys
7
+ from typing import Optional
8
+
9
+ from loguru import logger
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, set_update_body, \
16
+ set_element_status_request_body, set_prop_body, set_metadata_source_request_body, set_peer_gov_def_request_body, \
17
+ set_rel_request_body
18
+ from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
19
+ from md_processing.md_processing_utils.md_processing_constants import (load_commands, ERROR)
20
+ from pyegeria import DEBUG_LEVEL, body_slimmer
21
+ from pyegeria.egeria_tech_client import EgeriaTech
22
+
23
+ GERIA_METADATA_STORE = os.environ.get("EGERIA_METADATA_STORE", "active-metadata-store")
24
+ EGERIA_KAFKA_ENDPOINT = os.environ.get("KAFKA_ENDPOINT", "localhost:9092")
25
+ EGERIA_PLATFORM_URL = os.environ.get("EGERIA_PLATFORM_URL", "https://localhost:9443")
26
+ EGERIA_VIEW_SERVER = os.environ.get("EGERIA_VIEW_SERVER", "view-server")
27
+ EGERIA_VIEW_SERVER_URL = os.environ.get("EGERIA_VIEW_SERVER_URL", "https://localhost:9443")
28
+ EGERIA_INTEGRATION_DAEMON = os.environ.get("EGERIA_INTEGRATION_DAEMON", "integration-daemon")
29
+ EGERIA_INTEGRATION_DAEMON_URL = os.environ.get("EGERIA_INTEGRATION_DAEMON_URL", "https://localhost:9443")
30
+ EGERIA_ADMIN_USER = os.environ.get("ADMIN_USER", "garygeeke")
31
+ EGERIA_ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "secret")
32
+ EGERIA_USER = os.environ.get("EGERIA_USER", "erinoverview")
33
+ EGERIA_USER_PASSWORD = os.environ.get("EGERIA_USER_PASSWORD", "secret")
34
+ EGERIA_WIDTH = os.environ.get("EGERIA_WIDTH", 220)
35
+ EGERIA_JUPYTER = os.environ.get("EGERIA_JUPYTER", False)
36
+ EGERIA_HOME_GLOSSARY_GUID = os.environ.get("EGERIA_HOME_GLOSSARY_GUID", None)
37
+ EGERIA_GLOSSARY_PATH = os.environ.get("EGERIA_GLOSSARY_PATH", None)
38
+ EGERIA_ROOT_PATH = os.environ.get("EGERIA_ROOT_PATH", "../../")
39
+ EGERIA_INBOX_PATH = os.environ.get("EGERIA_INBOX_PATH", "md_processing/dr_egeria_inbox")
40
+ EGERIA_OUTBOX_PATH = os.environ.get("EGERIA_OUTBOX_PATH", "md_processing/dr_egeria_outbox")
41
+
42
+ load_commands('commands.json')
43
+ debug_level = DEBUG_LEVEL
44
+
45
+ console = Console(width=int(200))
46
+ setup_log()
47
+
48
+
49
+ #
50
+ # Helper functions for the data designer commands
51
+ #
52
+ @logger.catch
53
+ def add_member_to_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
54
+ guid: str) -> None:
55
+ """
56
+ Add member to data dictionaries and data specifications.
57
+ """
58
+ body = {
59
+ "class": "RelationshipRequestBody", "properties": {
60
+ "class": "CollectionMembershipProperties", "membershipRationale": "User Specified",
61
+ "notes": "Added by Dr.Egeria"
62
+ }
63
+ }
64
+ try:
65
+ if collection_list is not None:
66
+ for collection in collection_list:
67
+ egeria_client.add_to_collection(collection, guid, body)
68
+ msg = f"Added `{display_name}` member to `{collection}`"
69
+ logger.info(msg)
70
+ else:
71
+ logger.info("There were no data collections to add.")
72
+ return
73
+
74
+ except Exception as e:
75
+ console.print_exception()
76
+
77
+
78
+ @logger.catch
79
+ def remove_member_from_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
80
+ guid: str) -> None:
81
+ try:
82
+ for collection in collection_list:
83
+ egeria_client.remove_from_collection(collection, guid)
84
+ msg = f"Removed `{display_name}` member from `{collection}`"
85
+ logger.info(msg)
86
+ return
87
+
88
+ except Exception as e:
89
+ console.print_exception()
90
+
91
+
92
+ @logger.catch
93
+ def update_data_collection_memberships(egeria_client: EgeriaTech, entity_type: str, guid_list: list,
94
+ collection_class: str, guid: str, display_name: str,
95
+ replace_all_props: bool = True) -> None:
96
+ """ update the collection membership of the element
97
+
98
+ If replace_all_props is set to True, all existing memberships are removed and new memberships are added.
99
+ If replace_all_props is set to False, only the new memberships are added.
100
+ """
101
+
102
+ if replace_all_props:
103
+ match entity_type:
104
+ case "Data Specification":
105
+ get_command = egeria_client.get_collection_by_guid
106
+ case "Data Structure":
107
+ get_command = egeria_client.get_data_structure_by_guid
108
+ case "Data Field":
109
+ get_command = egeria_client.get_data_field_by_guid
110
+ case "Data Class":
111
+ get_command = egeria_client.get_data_class_by_guid
112
+
113
+ coll_list = egeria_client.get_data_memberships(get_command, guid)
114
+ if coll_list is None:
115
+ logger.warning("Unexpected -> the collection list was None - assigning empty dict")
116
+ coll_list = {}
117
+ # compare the existing collections to desired collections
118
+ if collection_class == "DataDictionary":
119
+ as_is = set(coll_list.get("DictList", {}))
120
+ elif collection_class == "DataSpec":
121
+ as_is = set(coll_list.get("SpecList", {}))
122
+
123
+ dict_set = set(coll_list.get("DictList", {}))
124
+ spec_set = set(coll_list.get("SpecList", {}))
125
+ to_be_set = set(guid_list) if guid_list is not None else set()
126
+ logger.debug(f"as_is: {as_is}")
127
+ logger.debug(f"to_be_set: {to_be_set}")
128
+
129
+ # Remove membership for collections that are in the as-is but not in the to-be
130
+ to_remove = as_is - to_be_set
131
+ logger.debug(f"to_remove: {to_remove}")
132
+ if len(to_remove) > 0:
133
+ remove_member_from_collections(egeria_client, to_remove, display_name, guid)
134
+
135
+ # add membership for collections that are in the to-be but are not in the as-is
136
+ to_add = to_be_set - as_is
137
+ logger.debug(f"to_add: {to_add}")
138
+ if len(to_add) > 0:
139
+ add_member_to_collections(egeria_client, to_add, display_name, guid)
140
+ else:
141
+ add_member_to_collections(egeria_client, guid_list, display_name, guid)
142
+
143
+
144
+ # @logger.catch
145
+
146
+
147
+ @logger.catch
148
+ def add_field_to_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list, guid) -> None:
149
+ """
150
+ Add data field to data structures.
151
+ """
152
+
153
+ try:
154
+ for structure_guid in struct_list:
155
+ egeria_client.link_member_data_field(structure_guid, guid, None)
156
+ msg = f"Added `{display_name}` to structure `{structure_guid}`"
157
+ logger.info(msg)
158
+ return
159
+
160
+ except Exception as e:
161
+ console.print_exception()
162
+
163
+
164
+ @logger.catch
165
+ def remove_field_from_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list,
166
+ guid: str) -> None:
167
+ """Remove a data field from a list of data structures."""
168
+ try:
169
+ for structure_guid in struct_list:
170
+ egeria_client.detach_member_data_field(structure_guid, guid, None)
171
+ msg = f"Removed `{display_name}` from structure `{structure_guid}`"
172
+ logger.info(msg)
173
+ return
174
+
175
+ except Exception as e:
176
+ console.print_exception()
177
+
178
+
179
+ @logger.catch
180
+ def sync_data_field_rel_elements(egeria_client: EgeriaTech, structure_list: list, parent_field_list: list, terms: list,
181
+ data_class_guid: str, guid: str, display_name: str,
182
+ replace_all_props: bool = True) -> None:
183
+ """Sync a field's related elements.
184
+
185
+ TODO: Need to add data class support when ready and may need to revisit bodies.
186
+
187
+ """
188
+ if terms:
189
+ terms = [terms]
190
+
191
+ if replace_all_props:
192
+ rel_el_list = egeria_client.get_data_field_rel_elements(guid)
193
+ # should I throw an exception if empty?
194
+ if rel_el_list is None:
195
+ logger.warning("Unexpected -> the list was None - assigning empty list")
196
+ rel_el_list = {}
197
+
198
+ as_is_data_structs = set(rel_el_list.get("data_structure_guids", []))
199
+ as_is_parent_fields = set(rel_el_list.get("parent_guids", []))
200
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
201
+ as_is_data_classes = set(rel_el_list.get("data_class_guids", []))
202
+
203
+ to_be_data_structs = set(structure_list) if structure_list is not None else set()
204
+ to_be_parent_fields = set(parent_field_list) if parent_field_list is not None else set()
205
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
206
+ to_be_data_classes = set([data_class_guid]) if data_class_guid is not None else set()
207
+
208
+ logger.trace(f"as_is_data_structs: {list(as_is_data_structs)} to_be_data_struct: {list(to_be_data_structs)}")
209
+ logger.trace(
210
+ f"as_is_parent_fields: {list(as_is_parent_fields)} to_be_parent_fields: {list(to_be_parent_fields)}")
211
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
212
+ f"{list(to_be_assigned_meanings)}")
213
+ logger.trace(f"as_is_data_classes: {list(as_is_data_classes)} to_be_assigned_data_classes: "
214
+ f"{list(to_be_data_classes)}")
215
+
216
+ data_struct_to_remove = as_is_data_structs - to_be_data_structs
217
+ logger.trace(f"data_struct_to_remove: {list(data_struct_to_remove)}")
218
+ if len(data_struct_to_remove) > 0:
219
+ for ds in data_struct_to_remove:
220
+ egeria_client.detach_member_data_field(ds, guid, None)
221
+ msg = f"Removed `{display_name}` from structure `{ds}`"
222
+ logger.trace(msg)
223
+ data_struct_to_add = to_be_data_structs - as_is_data_structs
224
+ logger.trace(f"data_struct_to_add: {list(data_struct_to_add)}")
225
+ if len(data_struct_to_add) > 0:
226
+ for ds in data_struct_to_add:
227
+ egeria_client.link_member_data_field(ds, guid, None)
228
+ msg = f"Added `{display_name}` to structure `{ds}`"
229
+ logger.trace(msg)
230
+
231
+ parent_field_to_remove = to_be_parent_fields - as_is_parent_fields
232
+ logger.trace(f"parent_field_to_remove: {list(parent_field_to_remove)}")
233
+ if len(parent_field_to_remove) > 0:
234
+ for field in parent_field_to_remove:
235
+ egeria_client.detach_nested_data_field(field, guid, None)
236
+ msg = f"Removed `{display_name}` from field `{field}`"
237
+ logger.trace(msg)
238
+ parent_field_to_add = to_be_parent_fields - as_is_parent_fields
239
+ logger.trace(f"parent_field_to_add: {list(parent_field_to_add)}")
240
+ if len(parent_field_to_add) > 0:
241
+ for field in parent_field_to_add:
242
+ egeria_client.link_nested_data_field(field, guid, None)
243
+ msg = f"Added `{display_name}` to field `{field}`"
244
+ logger.trace(msg)
245
+
246
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
247
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
248
+ if terms:
249
+ for term in terms_to_remove:
250
+ egeria_client.detach_semantic_definition(guid, term, None)
251
+ msg = f"Removed `{term}` from `{display_name}`"
252
+ logger.trace(msg)
253
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
254
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
255
+ if len(terms_to_add) > 0:
256
+ for term in terms_to_add:
257
+ egeria_client.link_semantic_definition(guid, term, None)
258
+ msg = f"Added `{term}` to`{display_name}`"
259
+ logger.trace(msg)
260
+
261
+ classes_to_remove = as_is_data_classes - to_be_data_classes
262
+ logger.trace(f"classes_to_remove: {list(classes_to_remove)}")
263
+ if len(terms_to_remove) > 0:
264
+ for dc in classes_to_remove:
265
+ body = {
266
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
267
+ }
268
+ egeria_client.detach_data_class_definition(guid, dc, body)
269
+ msg = f"Removed `{dc}` from `{display_name}`"
270
+ logger.trace(msg)
271
+ classes_to_add = to_be_data_classes - as_is_data_classes
272
+ logger.trace(f"classes_to_add: {list(classes_to_add)}")
273
+ if len(terms_to_add) > 0:
274
+ for dc in classes_to_add:
275
+ body = {
276
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
277
+ }
278
+ egeria_client.link_data_class_definition(guid, dc, body)
279
+ msg = f"Added `{dc}` to`{display_name}`"
280
+ logger.trace(msg)
281
+
282
+
283
+ else: # merge - add field to related elements
284
+ if structure_list:
285
+ add_field_to_data_structures(egeria_client, display_name, structure_list, guid)
286
+ msg = f"Added `{display_name}` to `{structure_list}`"
287
+ logger.trace(msg)
288
+
289
+ if parent_field_list:
290
+ for field in parent_field_list:
291
+ egeria_client.link_nested_data_field(field, guid, None)
292
+ msg = f"Added `{display_name}` to `{field}`"
293
+ logger.trace(msg)
294
+ if terms:
295
+ for term in terms:
296
+ egeria_client.link_semantic_definition(guid, term, None)
297
+ msg = f"Added `{term}` to `{display_name}`"
298
+ logger.trace(msg)
299
+
300
+ if data_class_guid:
301
+ egeria_client.link_data_class_definition(guid, data_class_guid)
302
+ msg = f"Added `{data_class_guid}` to `{display_name}`"
303
+ logger.trace(msg)
304
+
305
+
306
+ @logger.catch
307
+ def sync_data_class_rel_elements(egeria_client: EgeriaTech, containing_data_class_guids: list, terms: list,
308
+ specializes_data_classes: list, guid: str, display_name: str,
309
+ replace_all_props: bool = True) -> None:
310
+ """Sync a data class' related elements.
311
+
312
+ """
313
+ if terms:
314
+ terms = [terms]
315
+
316
+ if replace_all_props:
317
+ rel_el_list = egeria_client.get_data_class_rel_elements(guid)
318
+ if rel_el_list is None:
319
+ logger.warning("Unexpected -> the list was None - assigning empty list")
320
+ rel_el_list = {}
321
+ if terms:
322
+ terms = [terms]
323
+
324
+ as_is_nested_classes = set(rel_el_list.get("nested_data_class_guids", []))
325
+ as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
326
+ as_is_specialized_classes = set(rel_el_list.get("specialized_data_class_guids", []))
327
+
328
+ to_be_nested_classes = set(containing_data_class_guids) if containing_data_class_guids is not None else set()
329
+ to_be_assigned_meanings = set(terms) if terms is not None else set()
330
+ to_be_specialized_classes = set([specializes_data_classes]) if specializes_data_classes is not None else set()
331
+
332
+ logger.trace(
333
+ f"as_is_nested_classes: {list(as_is_nested_classes)} to_be_nested_classes: {list(to_be_nested_classes)}")
334
+ logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
335
+ f"{list(to_be_assigned_meanings)}")
336
+ logger.trace(f"as_is_specialized_classes: {list(as_is_specialized_classes)} to_be_specizialized_data_classes: "
337
+ f"{list(to_be_specialized_classes)}")
338
+
339
+ nested_classes_to_remove = to_be_nested_classes - as_is_nested_classes
340
+ logger.trace(f"nested_classes_to_remove: {list(nested_classes_to_remove)}")
341
+ if len(nested_classes_to_remove) > 0:
342
+ for field in nested_classes_to_remove:
343
+ egeria_client.detach_nested_data_class(field, guid, None)
344
+ msg = f"Removed `{display_name}` from field `{field}`"
345
+ logger.trace(msg)
346
+ nested_classes_to_add = to_be_nested_classes - as_is_nested_classes
347
+ logger.trace(f"nested_classes_to_add: {list(nested_classes_to_add)}")
348
+ if len(nested_classes_to_add) > 0:
349
+ for field in nested_classes_to_add:
350
+ egeria_client.link_nested_data_class(field, guid, None)
351
+ msg = f"Added `{display_name}` to field `{field}`"
352
+ logger.trace(msg)
353
+
354
+ terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
355
+ logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
356
+ if len(terms_to_remove) > 0:
357
+ for term in terms_to_remove:
358
+ egeria_client.detach_semantic_definition(guid, term, None)
359
+ msg = f"Removed `{term}` from `{display_name}`"
360
+ logger.trace(msg)
361
+ terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
362
+ logger.trace(f"terms_to_add: {list(terms_to_add)}")
363
+ if len(terms_to_add) > 0:
364
+ for term in terms_to_add:
365
+ egeria_client.link_semantic_definition(guid, term, None)
366
+ msg = f"Added `{term}` to`{display_name}`"
367
+ logger.trace(msg)
368
+
369
+ specialized_classes_to_remove = as_is_specialized_classes - to_be_specialized_classes
370
+ logger.trace(f"classes_to_remove: {list(specialized_classes_to_remove)}")
371
+ if len(terms_to_remove) > 0:
372
+ for dc in specialized_classes_to_remove:
373
+ body = {
374
+ "class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
375
+ }
376
+ egeria_client.detach_specialist_data_class(guid, dc, body)
377
+ msg = f"Removed `{dc}` from `{display_name}`"
378
+ logger.trace(msg)
379
+ specialized_classes_to_add = to_be_specialized_classes - as_is_specialized_classes
380
+ logger.trace(f"classes_to_add: {list(specialized_classes_to_add)}")
381
+ if len(specialized_classes_to_add) > 0:
382
+ for dc in specialized_classes_to_add:
383
+ body = {
384
+ "class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
385
+ }
386
+ egeria_client.link_specialist_data_class(guid, dc, body)
387
+ msg = f"Added `{dc}` to`{display_name}`"
388
+ logger.trace(msg)
389
+
390
+
391
+ else: # merge - add field to related elements
392
+ if containing_data_class_guids:
393
+ for field in containing_data_class_guids:
394
+ egeria_client.link_nested_data_class(field, guid, None)
395
+ msg = f"Added `{display_name}` to `{field}`"
396
+ logger.trace(msg)
397
+
398
+ if terms:
399
+ for term in terms:
400
+ egeria_client.link_semantic_definition(guid, term, None)
401
+ msg = f"Added `{term}` to `{display_name}`"
402
+ logger.trace(msg)
403
+ if specializes_data_classes:
404
+ for el in specializes_data_classes:
405
+ egeria_client.link_specialist_data_class(guid, el)
406
+ msg = f"Linked `{el}` to `{display_name}`"
407
+ logger.trace(msg)
408
+ #
409
+ # Product Manager Commands
410
+ #
411
+
412
+ @logger.catch
413
+ def process_digital_product_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
414
+ """
415
+ Processes a digital product create or update object_action by extracting key attributes such as
416
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
417
+
418
+ :param txt: A string representing the input cell to be processed for
419
+ extracting glossary-related attributes.
420
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
421
+ :return: A string summarizing the outcome of the processing.
422
+ """
423
+
424
+ command, object_type, object_action = extract_command_plus(txt)
425
+ print(Markdown(f"# {command}\n"))
426
+
427
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
428
+
429
+ valid = parsed_output['valid']
430
+ exists = parsed_output['exists']
431
+
432
+ qualified_name = parsed_output.get('qualified_name', None)
433
+ guid = parsed_output.get('guid', None)
434
+
435
+ print(Markdown(parsed_output['display']))
436
+
437
+ logger.debug(json.dumps(parsed_output, indent=4))
438
+
439
+ attributes = parsed_output['attributes']
440
+
441
+ display_name = attributes['Display Name'].get('value', None)
442
+ description = attributes.get('Description',{}).get('value', None)
443
+ user_defined_status = attributes.get('User Defined Status',{}).get('value', None)
444
+ product_identifier = attributes.get('Product Identifier',{}).get('value', None)
445
+ product_name = attributes.get('Product Name',{}).get('value', None)
446
+ product_type = attributes.get('Product Type',{}).get('value', None)
447
+
448
+
449
+
450
+ product_description = attributes.get('Product Description',{}).get('value', None)
451
+ maturity = attributes.get('Maturity',{}).get('value', None)
452
+ service_life = attributes.get('Service Life',{}).get('value', None)
453
+ introduction_date = attributes.get('Introduction Date',{}).get('value', None)
454
+ next_version_date = attributes.get('Next Version Date',{}).get('value', None)
455
+ withdrawal_date = attributes.get('Withdrawal Date',{}).get('value', None)
456
+
457
+ collection_type = attributes.get('Collection Type', {}).get('value', None)
458
+ current_version = attributes.get('Version Identifier',{}).get('value', None)
459
+ product_manager = attributes.get('Product Manager',{}).get('value', None)
460
+
461
+
462
+ product_status = attributes.get('Status',{}).get('value', "ACTIVE")
463
+
464
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
465
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
466
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
467
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',"CollectionMembership")
468
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
469
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
470
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
471
+ if parent_guid is None:
472
+ is_own_anchor = True
473
+
474
+
475
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
476
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
477
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
478
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
479
+ external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
480
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
481
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
482
+ for_lineage = attributes.get('For Lineage', {}).get('value', None)
483
+ for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
484
+
485
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
486
+
487
+ if directive == "display":
488
+
489
+ return None
490
+ elif directive == "validate":
491
+ if valid:
492
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
493
+ else:
494
+ msg = f"Validation failed for object_action `{command}`\n"
495
+ return valid
496
+
497
+ elif directive == "process":
498
+ try:
499
+ if object_action == "Update":
500
+ if not exists:
501
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
502
+ f"object_action\n")
503
+ logger.error(msg)
504
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
505
+ elif not valid:
506
+ return None
507
+ else:
508
+ print(Markdown(
509
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
510
+ prop_body = set_prop_body(object_type,qualified_name,attributes)
511
+
512
+ body ={
513
+ "class": "UpdateElementRequestBody",
514
+ "properties": {
515
+ "class": "DigitalProductProperties",
516
+ "qualifiedName": qualified_name,
517
+ "userDefinedStatus": user_defined_status,
518
+ "name": display_name,
519
+ "description": description,
520
+ "identifier": product_identifier,
521
+ "productName": product_name,
522
+ "productType": product_type,
523
+ "maturity": maturity,
524
+ "serviceLife": service_life,
525
+ "introductionDate": introduction_date,
526
+ "nextVersionDate": next_version_date,
527
+ "withdrawDate": withdrawal_date,
528
+ "currentVersion": current_version,
529
+ "additionalProperties": additional_properties,
530
+ "extendedProperties": extended_properties,
531
+ },
532
+ "externalSourceGUID": external_source_guid,
533
+ "externalSourceName": external_source_name,
534
+ "effectiveTime": effective_time,
535
+ "forLineage": for_lineage,
536
+ "forDuplicateProcessing": for_duplicate_processing
537
+ }
538
+
539
+ egeria_client.update_digital_product(guid, body)
540
+ egeria_client.update_digital_product_status(guid, product_status)
541
+
542
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
543
+ update_element_dictionary(qualified_name, {
544
+ 'guid': guid, 'display_name': display_name
545
+ })
546
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Specification',
547
+ output_format='MD')
548
+
549
+
550
+ elif object_action == "Create":
551
+ if valid is False and exists:
552
+ msg = (f" Digital Product `{display_name}` already exists and result document updated changing "
553
+ f"`Create` to `Update` in processed output\n\n___")
554
+ logger.error(msg)
555
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
556
+
557
+ else:
558
+ body = {
559
+ "class": "NewDigitalProductRequestBody",
560
+ "isOwnAnchor": is_own_anchor,
561
+ "parentGUID": parent_guid,
562
+ "parentRelationshipTypeName": parent_relationship_type_name,
563
+ "parentAtEnd1": parent_at_end1,
564
+ "properties": {
565
+ "class": "DigitalProductProperties",
566
+ "qualifiedName": qualified_name,
567
+ "userDefinedStatus": user_defined_status,
568
+ "name": display_name,
569
+ "description" : description,
570
+ "identifier": product_identifier,
571
+ "productName": product_name,
572
+ "productType": product_type,
573
+ "maturity": maturity,
574
+ "serviceLife": service_life,
575
+ "introductionDate": introduction_date,
576
+ "nextVersionDate": next_version_date,
577
+ "withdrawDate": withdrawal_date,
578
+ "currentVersion": current_version,
579
+
580
+ "additionalProperties": additional_properties,
581
+ "extendedProperties": extended_properties,
582
+ },
583
+ "initialStatus": product_status,
584
+ "externalSourceGUID": external_source_guid,
585
+ "externalSourceName": external_source_name,
586
+ "effectiveTime" : effective_time,
587
+ "forLineage": for_lineage,
588
+ "forDuplicateProcessing": for_duplicate_processing
589
+ }
590
+
591
+
592
+
593
+ guid = egeria_client.create_digital_product(body)
594
+ if guid:
595
+ update_element_dictionary(qualified_name, {
596
+ 'guid': guid, 'display_name': display_name
597
+ })
598
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
599
+ logger.success(msg)
600
+ return egeria_client.get_collection_by_guid(guid, collection_type='Digital Product',
601
+ output_format='MD')
602
+ else:
603
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
604
+ logger.error(msg)
605
+ return None
606
+
607
+ except Exception as e:
608
+ logger.error(f"Error performing {command}: {e}")
609
+ return None
610
+ else:
611
+ return None
612
+
613
+
614
+ @logger.catch
615
+ def process_agreement_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
616
+ """
617
+ Processes an agreement create or update object_action by extracting key attributes such as
618
+ spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
619
+
620
+ :param txt: A string representing the input cell to be processed for
621
+ extracting glossary-related attributes.
622
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
623
+ :return: A string summarizing the outcome of the processing.
624
+ """
625
+
626
+ command, object_type, object_action = extract_command_plus(txt)
627
+ print(Markdown(f"# {command}\n"))
628
+
629
+ parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
630
+
631
+ valid = parsed_output['valid']
632
+ exists = parsed_output['exists']
633
+
634
+ qualified_name = parsed_output.get('qualified_name', None)
635
+ guid = parsed_output.get('guid', None)
636
+
637
+ print(Markdown(parsed_output['display']))
638
+
639
+ logger.debug(json.dumps(parsed_output, indent=4))
640
+
641
+ attributes = parsed_output['attributes']
642
+
643
+ display_name = attributes['Display Name'].get('value', None)
644
+ description = attributes.get('Description',{}).get('value', None)
645
+ user_defined_status = attributes.get('User Defined Status',{}).get('value', None)
646
+ agreement_status = attributes.get('Status',{}).get('value', None)
647
+ agreement_identifier = attributes.get('Agreement Identifier',{}).get('value', None)
648
+
649
+ version_identifier = attributes.get('Version Identifier',{}).get('value', None)
650
+
651
+ actors = attributes.get('Agreement Actors',{}).get('value', None)
652
+ actor_names = attributes.get('Agreement Actors',{}).get('name_list', None)
653
+ actor_guids = attributes.get('Agreement Actors',{}).get('guid_list', None)
654
+ anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
655
+ parent_guid = attributes.get('Parent ID', {}).get('guid', None)
656
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
657
+ parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',"CollectionMembership")
658
+ parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
659
+ anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
660
+ is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
661
+ if parent_guid is None:
662
+ is_own_anchor = True
663
+
664
+
665
+ additional_prop = attributes.get('Additional Properties', {}).get('value', None)
666
+ additional_properties = json.loads(additional_prop) if additional_prop is not None else None
667
+ extended_prop = attributes.get('Extended Properties', {}).get('value', None)
668
+ extended_properties = json.loads(extended_prop) if extended_prop is not None else None
669
+ external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
670
+ external_source_name = attributes.get('External Source Name', {}).get('value', None)
671
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
672
+ for_lineage = attributes.get('For Lineage', {}).get('value', None)
673
+ for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
674
+
675
+ replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
676
+
677
+ if directive == "display":
678
+
679
+ return None
680
+ elif directive == "validate":
681
+ if valid:
682
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
683
+ else:
684
+ msg = f"Validation failed for object_action `{command}`\n"
685
+ return valid
686
+
687
+ elif directive == "process":
688
+ try:
689
+ if object_action == "Update":
690
+ if not exists:
691
+ msg = (f" Element `{display_name}` does not exist! Updating result document with Create "
692
+ f"object_action\n")
693
+ logger.error(msg)
694
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
695
+ elif not valid:
696
+ return None
697
+ else:
698
+ print(Markdown(
699
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
700
+
701
+ product_body = {
702
+ "class": "AgreementProperties",
703
+ "qualifiedName": qualified_name,
704
+ "userDefinedStatus": user_defined_status,
705
+ "name": display_name,
706
+ "description": description,
707
+ "identifier": agreement_identifier,
708
+ "additionalProperties": additional_properties,
709
+ "extendedProperties": extended_properties,
710
+ }
711
+
712
+ body = set_update_body(object_type, attributes)
713
+ body['properties'] = product_body
714
+
715
+ egeria_client.update_agreement(guid, body, replace_all_props)
716
+ status_update_body = set_element_status_request_body(object_type, attributes)
717
+ egeria_client.update_agreement_status(guid, status_update_body)
718
+
719
+ logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
720
+ update_element_dictionary(qualified_name, {
721
+ 'guid': guid, 'display_name': display_name
722
+ })
723
+ return egeria_client.get_collection_by_guid(guid, collection_type='Data Specification',
724
+ output_format='MD')
725
+
726
+ elif object_action == "Create":
727
+ if valid is False and exists:
728
+ msg = (f" Digital Product `{display_name}` already exists and result document updated changing "
729
+ f"`Create` to `Update` in processed output\n\n___")
730
+ logger.error(msg)
731
+ return update_a_command(txt, object_action, object_type, qualified_name, guid)
732
+
733
+ else:
734
+ body = {
735
+ "class": "NewAgreementRequestBody",
736
+ "isOwnAnchor": is_own_anchor,
737
+ "parentGUID": parent_guid,
738
+ "parentRelationshipTypeName": parent_relationship_type_name,
739
+ "parentAtEnd1": parent_at_end1,
740
+ "properties": {
741
+ "class": "AgreementProperties",
742
+ "qualifiedName": qualified_name,
743
+ "userDefinedStatus": user_defined_status,
744
+ "name": display_name,
745
+ "description" : description,
746
+ "identifier" : agreement_identifier,
747
+ "additionalProperties": additional_properties,
748
+ "extendedProperties": extended_properties,
749
+ },
750
+ "initialStatus": agreement_status,
751
+ "externalSourceGUID": external_source_guid,
752
+ "externalSourceName": external_source_name,
753
+ "effectiveTime" : effective_time,
754
+ "forLineage": for_lineage,
755
+ "forDuplicateProcessing": for_duplicate_processing
756
+ }
757
+ if object_type == "Data Sharing Agreement":
758
+ guid = egeria_client.create_data_sharing_agreement(body)
759
+ elif object_type == "Agreement":
760
+ guid = egeria_client.create_agreement(body)
761
+
762
+ if guid:
763
+ update_element_dictionary(qualified_name, {
764
+ 'guid': guid, 'display_name': display_name
765
+ })
766
+ msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
767
+ logger.success(msg)
768
+ return egeria_client.get_collection_by_guid(guid, collection_type='Digital Product',
769
+ output_format='MD')
770
+ else:
771
+ msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
772
+ logger.error(msg)
773
+ return None
774
+
775
+ except Exception as e:
776
+ logger.error(f"Error performing {command}: {e}")
777
+ return None
778
+ else:
779
+ return None
780
+
781
+
782
+ def process_link_agreement_item_command(egeria_client: EgeriaTech, txt: str,
783
+ directive: str = "display") -> Optional[str]:
784
+ """
785
+ Processes a link or unlink command to associate or break up peer governance definitions.
786
+
787
+ :param txt: A string representing the input cell to be processed for
788
+ extracting blueprint-related attributes.
789
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
790
+ :return: A string summarizing the outcome of the processing.
791
+ """
792
+ command, object_type, object_action = extract_command_plus(txt)
793
+ print(Markdown(f"# {command}\n"))
794
+
795
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
796
+
797
+ print(Markdown(parsed_output['display']))
798
+
799
+ logger.debug(json.dumps(parsed_output, indent=4))
800
+
801
+ attributes = parsed_output['attributes']
802
+ agreement = attributes.get('Agreement Name',{}).get('value', None)
803
+ agreement_guid = attributes.get('Definition 1', {}).get('guid', None)
804
+ item = attributes.get('Item Name',{}).get('value', None)
805
+ item_guid = attributes.get('Definition 2', {}).get('guid', None)
806
+ label = attributes.get('Link Label', {}).get('value', None)
807
+ description = attributes.get('Description', {}).get('value', None)
808
+
809
+ valid = parsed_output['valid']
810
+ exists = agreement_guid is not None and item_guid is not None
811
+
812
+
813
+ if directive == "display":
814
+
815
+ return None
816
+ elif directive == "validate":
817
+ if valid:
818
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
819
+ else:
820
+ msg = f"Validation failed for object_action `{command}`\n"
821
+ return valid
822
+
823
+ elif directive == "process":
824
+ gov_peer_relationship_type = object_type[:-1].replace(" ","") + "Link"
825
+
826
+ try:
827
+ if object_action == "Detach":
828
+ if not exists:
829
+ msg = (f" Link `{label}` does not exist! Updating result document with Link "
830
+ f"object_action\n")
831
+ logger.error(msg)
832
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
833
+ return out
834
+ elif not valid:
835
+ return None
836
+ else:
837
+ print(Markdown(
838
+ f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
839
+ body = set_metadata_source_request_body(object_type, attributes)
840
+
841
+ egeria_client.detach_agreement_item(agreement_guid, item_guid,body)
842
+
843
+ logger.success(f"===> Detached agreement item `{item}` from agreement `{agreement}`\n")
844
+ out = parsed_output['display'].replace('Unlink', 'Link', 1)
845
+
846
+ return (out)
847
+
848
+ elif object_action == "Link":
849
+ if valid is False and exists:
850
+ msg = (f"--> Link called `{label}` already exists and result document updated changing "
851
+ f"`Link` to `Detach` in processed output\n")
852
+ logger.error(msg)
853
+
854
+ elif valid is False:
855
+ msg = f"==>{object_type} Link with label `{label}` is not valid and can't be created"
856
+ logger.error(msg)
857
+ return
858
+
859
+ else:
860
+ body = set_rel_request_body(object_type, attributes)
861
+ item_props = {
862
+ "class": "AgreementItemProperties",
863
+ "agreementItemId": attributes["Agreement Item Id"],
864
+ "agreementStart": attributes["Agreement Start"],
865
+ "agreementEnd": attributes["Agreement End"],
866
+ "restrictions": attributes["Restrictions"],
867
+ "obligations": attributes["Obligations"],
868
+ "entitlements": attributes["Entitlements"],
869
+ "usageMeasurements": attributes["Usage Measurements"],
870
+ "effectiveFrom": attributes["Effective From"],
871
+ "effectiveTo": attributes["Effective To"]
872
+
873
+ }
874
+ egeria_client.link_agreement_item(agreement_guid,
875
+ item_guid, body)
876
+ msg = f"==>Linked {object_type} `{agreement} to item {item}\n"
877
+ logger.success(msg)
878
+ out = parsed_output['display'].replace('Link', 'Detach', 1)
879
+ return out
880
+
881
+
882
+ except Exception as e:
883
+ logger.error(f"Error performing {command}: {e}")
884
+ return None
885
+ else:
886
+ return None
887
+
888
+
889
+
890
+ #
891
+ # View commands
892
+ #
893
+ @logger.catch
894
+ def process_data_collection_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
895
+ str]:
896
+ """
897
+ Processes a Data Dictionary list object_action by extracting key attributes such as
898
+ search string from the given text.
899
+
900
+ :param txt: A string representing the input cell to be processed for
901
+ extracting term-related attributes.
902
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
903
+ :return: A string summarizing the outcome of the processing.
904
+ """
905
+ command, object_type, object_action = extract_command_plus(txt)
906
+ print(Markdown(f"# {command}\n"))
907
+ if object_type in ["Data Dictionary", "Data Dictionaries", "DataDict", "DataDictionary"]:
908
+ col_type = "DataDictionary"
909
+ elif object_type in ["Data Specification", "Data Specifications", "Data Specs"]:
910
+ col_type = "DataSpec"
911
+ else:
912
+ col_type = "Collection"
913
+
914
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
915
+
916
+
917
+
918
+ valid = parsed_output['valid']
919
+ print(Markdown(f"Performing {command}"))
920
+ print(Markdown(parsed_output['display']))
921
+
922
+ attr = parsed_output.get('attributes',{})
923
+ effective_time = attr.get('effectiveTime', {}).get('value', None)
924
+ as_of_time = attr.get('asOfTime', {}).get('value', None)
925
+ for_duplicate_processing = attr.get('forDuplicateProcessing', {}).get('value', False)
926
+ for_lineage = attr.get('forLineage',{}).get('value', False)
927
+ limit_result_by_status = attr.get('limitResultsByStatus',{}).get('value', ['ACTIVE'])
928
+ sequencing_property = attr.get('sequencingProperty',{}).get('value',"qualifiedName" )
929
+ sequencing_order = attr.get('sequencingOrder',{}).get('value', "PROPERTY_ASCENDING")
930
+ search_string = attr.get('Search String', {}).get('value', '*')
931
+ output_format = attr.get('Output Format', {}).get('value', 'LIST')
932
+ detailed = attr.get('Detailed', {}).get('value', False)
933
+
934
+ if directive == "display":
935
+ return None
936
+ elif directive == "validate":
937
+ if valid:
938
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
939
+ else:
940
+ msg = f"Validation failed for object_action `{command}`\n"
941
+ logger.error(msg)
942
+ return valid
943
+
944
+ elif directive == "process":
945
+ try:
946
+ if not valid: # First validate the command before we process it
947
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
948
+ logger.error(msg)
949
+ return None
950
+
951
+ list_md = f"\n# `{col_type}` with filter: `{search_string}`\n\n"
952
+ body = {
953
+ "class": "FilterRequestBody",
954
+ "asOfTime": as_of_time,
955
+ "effectiveTime": effective_time,
956
+ "forLineage": for_lineage,
957
+ "forDuplicateProcessing": for_duplicate_processing,
958
+ "limitResultsByStatus": limit_result_by_status,
959
+ "sequencingOrder": sequencing_order,
960
+ "sequencingProperty": sequencing_property,
961
+ "filter": search_string,
962
+ }
963
+
964
+ struct = egeria_client.find_collections_w_body(body, col_type, output_format=output_format)
965
+ if output_format == "DICT":
966
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
967
+ else:
968
+ list_md += struct
969
+ logger.info(f"Wrote `{col_type}` for search string: `{search_string}`")
970
+
971
+ return list_md
972
+
973
+ except Exception as e:
974
+ logger.error(f"Error performing {command}: {e}")
975
+ console.print_exception(show_locals=True)
976
+ return None
977
+ else:
978
+ return None
979
+
980
+ # TODO
981
+ def process_data_agreement_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
982
+ str]:
983
+ """
984
+ Processes a Data Dictionary list object_action by extracting key attributes such as
985
+ search string from the given text.
986
+
987
+ :param txt: A string representing the input cell to be processed for
988
+ extracting term-related attributes.
989
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
990
+ :return: A string summarizing the outcome of the processing.
991
+ """
992
+ command, object_type, object_action = extract_command_plus(txt)
993
+ print(Markdown(f"# {command}\n"))
994
+
995
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
996
+
997
+ attributes = parsed_output['attributes']
998
+
999
+ valid = parsed_output['valid']
1000
+ print(Markdown(f"Performing {command}"))
1001
+ print(Markdown(parsed_output['display']))
1002
+
1003
+ if directive == "display":
1004
+ return None
1005
+ elif directive == "validate":
1006
+ if valid:
1007
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1008
+ else:
1009
+ msg = f"Validation failed for object_action `{command}`\n"
1010
+ logger.error(msg)
1011
+ return valid
1012
+
1013
+ elif directive == "process":
1014
+ attributes = parsed_output['attributes']
1015
+ search_string = attributes.get('Search String', {}).get('value', '*')
1016
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1017
+ detailed = attributes.get('Detailed', {}).get('value', False)
1018
+
1019
+ try:
1020
+ if not valid: # First validate the command before we process it
1021
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1022
+ logger.error(msg)
1023
+ return None
1024
+
1025
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1026
+ struct = egeria_client.find_data_structures(search_string, output_format=output_format)
1027
+
1028
+ if output_format == "DICT":
1029
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1030
+ else:
1031
+ list_md += struct
1032
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1033
+
1034
+ return list_md
1035
+
1036
+ except Exception as e:
1037
+ logger.error(f"Error performing {command}: {e}")
1038
+ console.print_exception(show_locals=True)
1039
+ return None
1040
+ else:
1041
+ return None
1042
+
1043
+ # TODO
1044
+ def process_subscription_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1045
+ """
1046
+ Processes a Data Dictionary list object_action by extracting key attributes such as
1047
+ search string from the given text.
1048
+
1049
+ :param txt: A string representing the input cell to be processed for
1050
+ extracting term-related attributes.
1051
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1052
+ :return: A string summarizing the outcome of the processing.
1053
+ """
1054
+ command, object_type, object_action = extract_command_plus(txt)
1055
+ print(Markdown(f"# {command}\n"))
1056
+
1057
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1058
+
1059
+ attributes = parsed_output['attributes']
1060
+
1061
+ valid = parsed_output['valid']
1062
+ print(Markdown(f"Performing {command}"))
1063
+ print(Markdown(parsed_output['display']))
1064
+
1065
+ if directive == "display":
1066
+ return None
1067
+ elif directive == "validate":
1068
+ if valid:
1069
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1070
+ else:
1071
+ msg = f"Validation failed for object_action `{command}`\n"
1072
+ logger.error(msg)
1073
+ return valid
1074
+
1075
+ elif directive == "process":
1076
+ attributes = parsed_output['attributes']
1077
+ search_string = attributes.get('Search String', {}).get('value', '*')
1078
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1079
+ detailed = attributes.get('Detailed', {}).get('value', False)
1080
+ as_of_time = attributes.get('AsOfTime', {}).get('value', None)
1081
+ effective_time = attributes.get('Effective Time', {}).get('value', None)
1082
+ sort_order = attributes.get('Sort Order', {}).get('value', None)
1083
+ order_property = attributes.get('Order Property', {}).get('value', None)
1084
+ starts_with = attributes.get('Start With', {}).get('value', True)
1085
+ ends_with = attributes.get('End With', {}).get('value', False)
1086
+ ignore_case = attributes.get('Ignore Case', {}).get('value', False)
1087
+ start_from = attributes.get('Start From', {}).get('value', 0)
1088
+ page_size = attributes.get('Page Size', {}).get('value', None)
1089
+
1090
+ try:
1091
+ if not valid: # First validate the command before we process it
1092
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1093
+ logger.error(msg)
1094
+ return None
1095
+
1096
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1097
+ body = {
1098
+ "class": "FilterRequestBody", "asOfTime": as_of_time, "effectiveTime": effective_time,
1099
+ "forLineage": False, "forDuplicateProcessing": False, "limitResultsByStatus": ["ACTIVE"],
1100
+ "sequencingOrder": sort_order, "sequencingProperty": order_property, "filter": search_string,
1101
+ }
1102
+ struct = egeria_client.find_data_fields_w_body(body, start_from, page_size, starts_with, ends_with,
1103
+ ignore_case, output_format)
1104
+
1105
+ if output_format == "DICT":
1106
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1107
+ else:
1108
+ list_md += struct
1109
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1110
+
1111
+ return list_md
1112
+
1113
+ except Exception as e:
1114
+ logger.error(f"Error performing {command}: {e}")
1115
+ console.print_exception(show_locals=True)
1116
+ return None
1117
+ else:
1118
+ return None
1119
+
1120
+ # TODO
1121
+ def process_digital_product_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
1122
+ """
1123
+ Processes a Data Dictionary list object_action by extracting key attributes such as
1124
+ search string from the given text.
1125
+
1126
+ :param txt: A string representing the input cell to be processed for
1127
+ extracting term-related attributes.
1128
+ :param directive: an optional string indicating the directive to be used - display, validate or execute
1129
+ :return: A string summarizing the outcome of the processing.
1130
+ """
1131
+ command, object_type, object_action = extract_command_plus(txt)
1132
+ print(Markdown(f"# {command}\n"))
1133
+
1134
+ parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
1135
+
1136
+ attributes = parsed_output['attributes']
1137
+
1138
+ valid = parsed_output['valid']
1139
+ print(Markdown(f"Performing {command}"))
1140
+ print(Markdown(parsed_output['display']))
1141
+
1142
+ if directive == "display":
1143
+ return None
1144
+ elif directive == "validate":
1145
+ if valid:
1146
+ print(Markdown(f"==> Validation of {command} completed successfully!\n"))
1147
+ else:
1148
+ msg = f"Validation failed for object_action `{command}`\n"
1149
+ logger.error(msg)
1150
+ return valid
1151
+
1152
+ elif directive == "process":
1153
+ attributes = parsed_output['attributes']
1154
+ search_string = attributes.get('Search String', {}).get('value', '*')
1155
+ output_format = attributes.get('Output Format', {}).get('value', 'LIST')
1156
+ detailed = attributes.get('Detailed', {}).get('value', False)
1157
+
1158
+ try:
1159
+ if not valid: # First validate the command before we process it
1160
+ msg = f"Validation failed for {object_action} `{object_type}`\n"
1161
+ logger.error(msg)
1162
+ return None
1163
+
1164
+ list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
1165
+ struct = egeria_client.find_data_classes(search_string, output_format=output_format)
1166
+
1167
+ if output_format == "DICT":
1168
+ list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
1169
+ else:
1170
+ list_md += struct
1171
+ logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
1172
+
1173
+ return list_md
1174
+
1175
+ except Exception as e:
1176
+ logger.error(f"Error performing {command}: {e}")
1177
+ console.print_exception(show_locals=True)
1178
+ return None
1179
+ else:
1180
+ return None