pyegeria 5.4.0.dev10__py3-none-any.whl → 5.4.0.dev12__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.
- commands/cat/debug_log +6290 -6042
- commands/cat/debug_log.2025-07-01_15-22-20_102237.zip +0 -0
- commands/cat/debug_log.2025-07-04_15-43-28_460900.zip +0 -0
- commands/cat/debug_log.2025-07-06_20-48-04_338314.zip +0 -0
- commands/cat/debug_log.2025-07-09_10-17-09_526262.zip +0 -0
- commands/cat/dr_egeria_md.py +24 -14
- commands/cat/list_collections.py +11 -4
- md_processing/__init__.py +3 -1
- md_processing/data/commands.json +7842 -2231
- md_processing/md_commands/data_designer_commands.py +67 -80
- md_processing/md_commands/glossary_commands.py +3 -1
- md_processing/md_commands/product_manager_commands.py +1746 -0
- md_processing/md_commands/solution_architect_commands.py +390 -236
- md_processing/md_processing_utils/common_md_proc_utils.py +8 -6
- md_processing/md_processing_utils/md_processing_constants.py +25 -4
- pyegeria/__init__.py +1 -0
- pyegeria/_client.py +0 -1
- pyegeria/collection_manager_omvs.py +504 -546
- pyegeria/data_designer_omvs.py +16 -8
- pyegeria/egeria_tech_client.py +9 -25
- pyegeria/governance_officer_omvs.py +1446 -1343
- pyegeria/output_formatter.py +96 -8
- pyegeria/solution_architect_omvs.py +2278 -1728
- {pyegeria-5.4.0.dev10.dist-info → pyegeria-5.4.0.dev12.dist-info}/METADATA +1 -1
- {pyegeria-5.4.0.dev10.dist-info → pyegeria-5.4.0.dev12.dist-info}/RECORD +28 -25
- commands/cat/debug_log.2025-06-24_15-51-28_769553.zip +0 -0
- commands/cat/debug_log.2025-06-26_11-18-40_644650.zip +0 -0
- {pyegeria-5.4.0.dev10.dist-info → pyegeria-5.4.0.dev12.dist-info}/LICENSE +0 -0
- {pyegeria-5.4.0.dev10.dist-info → pyegeria-5.4.0.dev12.dist-info}/WHEEL +0 -0
- {pyegeria-5.4.0.dev10.dist-info → pyegeria-5.4.0.dev12.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1746 @@
|
|
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
|
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, ERROR)
|
18
|
+
from pyegeria import DEBUG_LEVEL, body_slimmer
|
19
|
+
from pyegeria.egeria_tech_client import EgeriaTech
|
20
|
+
|
21
|
+
GERIA_METADATA_STORE = os.environ.get("EGERIA_METADATA_STORE", "active-metadata-store")
|
22
|
+
EGERIA_KAFKA_ENDPOINT = os.environ.get("KAFKA_ENDPOINT", "localhost:9092")
|
23
|
+
EGERIA_PLATFORM_URL = os.environ.get("EGERIA_PLATFORM_URL", "https://localhost:9443")
|
24
|
+
EGERIA_VIEW_SERVER = os.environ.get("EGERIA_VIEW_SERVER", "view-server")
|
25
|
+
EGERIA_VIEW_SERVER_URL = os.environ.get("EGERIA_VIEW_SERVER_URL", "https://localhost:9443")
|
26
|
+
EGERIA_INTEGRATION_DAEMON = os.environ.get("EGERIA_INTEGRATION_DAEMON", "integration-daemon")
|
27
|
+
EGERIA_INTEGRATION_DAEMON_URL = os.environ.get("EGERIA_INTEGRATION_DAEMON_URL", "https://localhost:9443")
|
28
|
+
EGERIA_ADMIN_USER = os.environ.get("ADMIN_USER", "garygeeke")
|
29
|
+
EGERIA_ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "secret")
|
30
|
+
EGERIA_USER = os.environ.get("EGERIA_USER", "erinoverview")
|
31
|
+
EGERIA_USER_PASSWORD = os.environ.get("EGERIA_USER_PASSWORD", "secret")
|
32
|
+
EGERIA_WIDTH = os.environ.get("EGERIA_WIDTH", 220)
|
33
|
+
EGERIA_JUPYTER = os.environ.get("EGERIA_JUPYTER", False)
|
34
|
+
EGERIA_HOME_GLOSSARY_GUID = os.environ.get("EGERIA_HOME_GLOSSARY_GUID", None)
|
35
|
+
EGERIA_GLOSSARY_PATH = os.environ.get("EGERIA_GLOSSARY_PATH", None)
|
36
|
+
EGERIA_ROOT_PATH = os.environ.get("EGERIA_ROOT_PATH", "../../")
|
37
|
+
EGERIA_INBOX_PATH = os.environ.get("EGERIA_INBOX_PATH", "md_processing/dr_egeria_inbox")
|
38
|
+
EGERIA_OUTBOX_PATH = os.environ.get("EGERIA_OUTBOX_PATH", "md_processing/dr_egeria_outbox")
|
39
|
+
|
40
|
+
load_commands('commands.json')
|
41
|
+
debug_level = DEBUG_LEVEL
|
42
|
+
|
43
|
+
console = Console(width=int(200))
|
44
|
+
|
45
|
+
log_format = "D {time} | {level} | {function} | {line} | {message} | {extra}"
|
46
|
+
logger.remove()
|
47
|
+
logger.add(sys.stderr, level="INFO", format=log_format, colorize=True)
|
48
|
+
full_file_path = os.path.join(EGERIA_ROOT_PATH, EGERIA_INBOX_PATH, "data_designer_debug.log")
|
49
|
+
# logger.add(full_file_path, rotation="1 day", retention="1 week", compression="zip", level="TRACE", format=log_format,
|
50
|
+
# colorize=True)
|
51
|
+
logger.add("debug_log", rotation="1 day", retention="1 week", compression="zip", level="TRACE", format=log_format,
|
52
|
+
colorize=True)
|
53
|
+
|
54
|
+
|
55
|
+
#
|
56
|
+
# Helper functions for the data designer commands
|
57
|
+
#
|
58
|
+
@logger.catch
|
59
|
+
def add_member_to_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
|
60
|
+
guid: str) -> None:
|
61
|
+
"""
|
62
|
+
Add member to data dictionaries and data specifications.
|
63
|
+
"""
|
64
|
+
body = {
|
65
|
+
"class": "RelationshipRequestBody", "properties": {
|
66
|
+
"class": "CollectionMembershipProperties", "membershipRationale": "User Specified",
|
67
|
+
"notes": "Added by Dr.Egeria"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
try:
|
71
|
+
if collection_list is not None:
|
72
|
+
for collection in collection_list:
|
73
|
+
egeria_client.add_to_collection(collection, guid, body)
|
74
|
+
msg = f"Added `{display_name}` member to `{collection}`"
|
75
|
+
logger.info(msg)
|
76
|
+
else:
|
77
|
+
logger.info("There were no data collections to add.")
|
78
|
+
return
|
79
|
+
|
80
|
+
except Exception as e:
|
81
|
+
console.print_exception()
|
82
|
+
|
83
|
+
|
84
|
+
@logger.catch
|
85
|
+
def remove_member_from_collections(egeria_client: EgeriaTech, collection_list: list, display_name: str,
|
86
|
+
guid: str) -> None:
|
87
|
+
try:
|
88
|
+
for collection in collection_list:
|
89
|
+
egeria_client.remove_from_collection(collection, guid)
|
90
|
+
msg = f"Removed `{display_name}` member from `{collection}`"
|
91
|
+
logger.info(msg)
|
92
|
+
return
|
93
|
+
|
94
|
+
except Exception as e:
|
95
|
+
console.print_exception()
|
96
|
+
|
97
|
+
|
98
|
+
@logger.catch
|
99
|
+
def update_data_collection_memberships(egeria_client: EgeriaTech, entity_type: str, guid_list: list,
|
100
|
+
collection_class: str, guid: str, display_name: str,
|
101
|
+
replace_all_props: bool = True) -> None:
|
102
|
+
""" update the collection membership of the element
|
103
|
+
|
104
|
+
If replace_all_props is set to True, all existing memberships are removed and new memberships are added.
|
105
|
+
If replace_all_props is set to False, only the new memberships are added.
|
106
|
+
"""
|
107
|
+
|
108
|
+
if replace_all_props:
|
109
|
+
match entity_type:
|
110
|
+
case "Data Specification":
|
111
|
+
get_command = egeria_client.get_collection_by_guid
|
112
|
+
case "Data Structure":
|
113
|
+
get_command = egeria_client.get_data_structure_by_guid
|
114
|
+
case "Data Field":
|
115
|
+
get_command = egeria_client.get_data_field_by_guid
|
116
|
+
case "Data Class":
|
117
|
+
get_command = egeria_client.get_data_class_by_guid
|
118
|
+
|
119
|
+
coll_list = egeria_client.get_data_memberships(get_command, guid)
|
120
|
+
if coll_list is None:
|
121
|
+
logger.warning("Unexpected -> the collection list was None - assigning empty dict")
|
122
|
+
coll_list = {}
|
123
|
+
# compare the existing collections to desired collections
|
124
|
+
if collection_class == "DataDictionary":
|
125
|
+
as_is = set(coll_list.get("DictList", {}))
|
126
|
+
elif collection_class == "DataSpec":
|
127
|
+
as_is = set(coll_list.get("SpecList", {}))
|
128
|
+
|
129
|
+
dict_set = set(coll_list.get("DictList", {}))
|
130
|
+
spec_set = set(coll_list.get("SpecList", {}))
|
131
|
+
to_be_set = set(guid_list) if guid_list is not None else set()
|
132
|
+
logger.debug(f"as_is: {as_is}")
|
133
|
+
logger.debug(f"to_be_set: {to_be_set}")
|
134
|
+
|
135
|
+
# Remove membership for collections that are in the as-is but not in the to-be
|
136
|
+
to_remove = as_is - to_be_set
|
137
|
+
logger.debug(f"to_remove: {to_remove}")
|
138
|
+
if len(to_remove) > 0:
|
139
|
+
remove_member_from_collections(egeria_client, to_remove, display_name, guid)
|
140
|
+
|
141
|
+
# add membership for collections that are in the to-be but are not in the as-is
|
142
|
+
to_add = to_be_set - as_is
|
143
|
+
logger.debug(f"to_add: {to_add}")
|
144
|
+
if len(to_add) > 0:
|
145
|
+
add_member_to_collections(egeria_client, to_add, display_name, guid)
|
146
|
+
else:
|
147
|
+
add_member_to_collections(egeria_client, guid_list, display_name, guid)
|
148
|
+
|
149
|
+
|
150
|
+
# @logger.catch
|
151
|
+
|
152
|
+
|
153
|
+
@logger.catch
|
154
|
+
def add_field_to_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list, guid) -> None:
|
155
|
+
"""
|
156
|
+
Add data field to data structures.
|
157
|
+
"""
|
158
|
+
|
159
|
+
try:
|
160
|
+
for structure_guid in struct_list:
|
161
|
+
egeria_client.link_member_data_field(structure_guid, guid, None)
|
162
|
+
msg = f"Added `{display_name}` to structure `{structure_guid}`"
|
163
|
+
logger.info(msg)
|
164
|
+
return
|
165
|
+
|
166
|
+
except Exception as e:
|
167
|
+
console.print_exception()
|
168
|
+
|
169
|
+
|
170
|
+
@logger.catch
|
171
|
+
def remove_field_from_data_structures(egeria_client: EgeriaTech, display_name: str, struct_list: list,
|
172
|
+
guid: str) -> None:
|
173
|
+
"""Remove a data field from a list of data structures."""
|
174
|
+
try:
|
175
|
+
for structure_guid in struct_list:
|
176
|
+
egeria_client.detach_member_data_field(structure_guid, guid, None)
|
177
|
+
msg = f"Removed `{display_name}` from structure `{structure_guid}`"
|
178
|
+
logger.info(msg)
|
179
|
+
return
|
180
|
+
|
181
|
+
except Exception as e:
|
182
|
+
console.print_exception()
|
183
|
+
|
184
|
+
|
185
|
+
@logger.catch
|
186
|
+
def sync_data_field_rel_elements(egeria_client: EgeriaTech, structure_list: list, parent_field_list: list, terms: list,
|
187
|
+
data_class_guid: str, guid: str, display_name: str,
|
188
|
+
replace_all_props: bool = True) -> None:
|
189
|
+
"""Sync a field's related elements.
|
190
|
+
|
191
|
+
TODO: Need to add data class support when ready and may need to revisit bodies.
|
192
|
+
|
193
|
+
"""
|
194
|
+
if terms:
|
195
|
+
terms = [terms]
|
196
|
+
|
197
|
+
if replace_all_props:
|
198
|
+
rel_el_list = egeria_client.get_data_field_rel_elements(guid)
|
199
|
+
# should I throw an exception if empty?
|
200
|
+
if rel_el_list is None:
|
201
|
+
logger.warning("Unexpected -> the list was None - assigning empty list")
|
202
|
+
rel_el_list = {}
|
203
|
+
|
204
|
+
as_is_data_structs = set(rel_el_list.get("data_structure_guids", []))
|
205
|
+
as_is_parent_fields = set(rel_el_list.get("parent_guids", []))
|
206
|
+
as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
|
207
|
+
as_is_data_classes = set(rel_el_list.get("data_class_guids", []))
|
208
|
+
|
209
|
+
to_be_data_structs = set(structure_list) if structure_list is not None else set()
|
210
|
+
to_be_parent_fields = set(parent_field_list) if parent_field_list is not None else set()
|
211
|
+
to_be_assigned_meanings = set(terms) if terms is not None else set()
|
212
|
+
to_be_data_classes = set([data_class_guid]) if data_class_guid is not None else set()
|
213
|
+
|
214
|
+
logger.trace(f"as_is_data_structs: {list(as_is_data_structs)} to_be_data_struct: {list(to_be_data_structs)}")
|
215
|
+
logger.trace(
|
216
|
+
f"as_is_parent_fields: {list(as_is_parent_fields)} to_be_parent_fields: {list(to_be_parent_fields)}")
|
217
|
+
logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
|
218
|
+
f"{list(to_be_assigned_meanings)}")
|
219
|
+
logger.trace(f"as_is_data_classes: {list(as_is_data_classes)} to_be_assigned_data_classes: "
|
220
|
+
f"{list(to_be_data_classes)}")
|
221
|
+
|
222
|
+
data_struct_to_remove = as_is_data_structs - to_be_data_structs
|
223
|
+
logger.trace(f"data_struct_to_remove: {list(data_struct_to_remove)}")
|
224
|
+
if len(data_struct_to_remove) > 0:
|
225
|
+
for ds in data_struct_to_remove:
|
226
|
+
egeria_client.detach_member_data_field(ds, guid, None)
|
227
|
+
msg = f"Removed `{display_name}` from structure `{ds}`"
|
228
|
+
logger.trace(msg)
|
229
|
+
data_struct_to_add = to_be_data_structs - as_is_data_structs
|
230
|
+
logger.trace(f"data_struct_to_add: {list(data_struct_to_add)}")
|
231
|
+
if len(data_struct_to_add) > 0:
|
232
|
+
for ds in data_struct_to_add:
|
233
|
+
egeria_client.link_member_data_field(ds, guid, None)
|
234
|
+
msg = f"Added `{display_name}` to structure `{ds}`"
|
235
|
+
logger.trace(msg)
|
236
|
+
|
237
|
+
parent_field_to_remove = to_be_parent_fields - as_is_parent_fields
|
238
|
+
logger.trace(f"parent_field_to_remove: {list(parent_field_to_remove)}")
|
239
|
+
if len(parent_field_to_remove) > 0:
|
240
|
+
for field in parent_field_to_remove:
|
241
|
+
egeria_client.detach_nested_data_field(field, guid, None)
|
242
|
+
msg = f"Removed `{display_name}` from field `{field}`"
|
243
|
+
logger.trace(msg)
|
244
|
+
parent_field_to_add = to_be_parent_fields - as_is_parent_fields
|
245
|
+
logger.trace(f"parent_field_to_add: {list(parent_field_to_add)}")
|
246
|
+
if len(parent_field_to_add) > 0:
|
247
|
+
for field in parent_field_to_add:
|
248
|
+
egeria_client.link_nested_data_field(field, guid, None)
|
249
|
+
msg = f"Added `{display_name}` to field `{field}`"
|
250
|
+
logger.trace(msg)
|
251
|
+
|
252
|
+
terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
|
253
|
+
logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
|
254
|
+
if terms:
|
255
|
+
for term in terms_to_remove:
|
256
|
+
egeria_client.detach_semantic_definition(guid, term, None)
|
257
|
+
msg = f"Removed `{term}` from `{display_name}`"
|
258
|
+
logger.trace(msg)
|
259
|
+
terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
|
260
|
+
logger.trace(f"terms_to_add: {list(terms_to_add)}")
|
261
|
+
if len(terms_to_add) > 0:
|
262
|
+
for term in terms_to_add:
|
263
|
+
egeria_client.link_semantic_definition(guid, term, None)
|
264
|
+
msg = f"Added `{term}` to`{display_name}`"
|
265
|
+
logger.trace(msg)
|
266
|
+
|
267
|
+
classes_to_remove = as_is_data_classes - to_be_data_classes
|
268
|
+
logger.trace(f"classes_to_remove: {list(classes_to_remove)}")
|
269
|
+
if len(terms_to_remove) > 0:
|
270
|
+
for dc in classes_to_remove:
|
271
|
+
body = {
|
272
|
+
"class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
|
273
|
+
}
|
274
|
+
egeria_client.detach_data_class_definition(guid, dc, body)
|
275
|
+
msg = f"Removed `{dc}` from `{display_name}`"
|
276
|
+
logger.trace(msg)
|
277
|
+
classes_to_add = to_be_data_classes - as_is_data_classes
|
278
|
+
logger.trace(f"classes_to_add: {list(classes_to_add)}")
|
279
|
+
if len(terms_to_add) > 0:
|
280
|
+
for dc in classes_to_add:
|
281
|
+
body = {
|
282
|
+
"class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
|
283
|
+
}
|
284
|
+
egeria_client.link_data_class_definition(guid, dc, body)
|
285
|
+
msg = f"Added `{dc}` to`{display_name}`"
|
286
|
+
logger.trace(msg)
|
287
|
+
|
288
|
+
|
289
|
+
else: # merge - add field to related elements
|
290
|
+
if structure_list:
|
291
|
+
add_field_to_data_structures(egeria_client, display_name, structure_list, guid)
|
292
|
+
msg = f"Added `{display_name}` to `{structure_list}`"
|
293
|
+
logger.trace(msg)
|
294
|
+
|
295
|
+
if parent_field_list:
|
296
|
+
for field in parent_field_list:
|
297
|
+
egeria_client.link_nested_data_field(field, guid, None)
|
298
|
+
msg = f"Added `{display_name}` to `{field}`"
|
299
|
+
logger.trace(msg)
|
300
|
+
if terms:
|
301
|
+
for term in terms:
|
302
|
+
egeria_client.link_semantic_definition(guid, term, None)
|
303
|
+
msg = f"Added `{term}` to `{display_name}`"
|
304
|
+
logger.trace(msg)
|
305
|
+
|
306
|
+
if data_class_guid:
|
307
|
+
egeria_client.link_data_class_definition(guid, data_class_guid)
|
308
|
+
msg = f"Added `{data_class_guid}` to `{display_name}`"
|
309
|
+
logger.trace(msg)
|
310
|
+
|
311
|
+
|
312
|
+
@logger.catch
|
313
|
+
def sync_data_class_rel_elements(egeria_client: EgeriaTech, containing_data_class_guids: list, terms: list,
|
314
|
+
specializes_data_classes: list, guid: str, display_name: str,
|
315
|
+
replace_all_props: bool = True) -> None:
|
316
|
+
"""Sync a data class' related elements.
|
317
|
+
|
318
|
+
"""
|
319
|
+
if terms:
|
320
|
+
terms = [terms]
|
321
|
+
|
322
|
+
if replace_all_props:
|
323
|
+
rel_el_list = egeria_client.get_data_class_rel_elements(guid)
|
324
|
+
if rel_el_list is None:
|
325
|
+
logger.warning("Unexpected -> the list was None - assigning empty list")
|
326
|
+
rel_el_list = {}
|
327
|
+
if terms:
|
328
|
+
terms = [terms]
|
329
|
+
|
330
|
+
as_is_nested_classes = set(rel_el_list.get("nested_data_class_guids", []))
|
331
|
+
as_is_assigned_meanings = set(rel_el_list.get("assigned_meanings_guids", []))
|
332
|
+
as_is_specialized_classes = set(rel_el_list.get("specialized_data_class_guids", []))
|
333
|
+
|
334
|
+
to_be_nested_classes = set(containing_data_class_guids) if containing_data_class_guids is not None else set()
|
335
|
+
to_be_assigned_meanings = set(terms) if terms is not None else set()
|
336
|
+
to_be_specialized_classes = set([specializes_data_classes]) if specializes_data_classes is not None else set()
|
337
|
+
|
338
|
+
logger.trace(
|
339
|
+
f"as_is_nested_classes: {list(as_is_nested_classes)} to_be_nested_classes: {list(to_be_nested_classes)}")
|
340
|
+
logger.trace(f"as_is_assigned_meanings: {list(as_is_assigned_meanings)} to_be_assigned_meanings: "
|
341
|
+
f"{list(to_be_assigned_meanings)}")
|
342
|
+
logger.trace(f"as_is_specialized_classes: {list(as_is_specialized_classes)} to_be_specizialized_data_classes: "
|
343
|
+
f"{list(to_be_specialized_classes)}")
|
344
|
+
|
345
|
+
nested_classes_to_remove = to_be_nested_classes - as_is_nested_classes
|
346
|
+
logger.trace(f"nested_classes_to_remove: {list(nested_classes_to_remove)}")
|
347
|
+
if len(nested_classes_to_remove) > 0:
|
348
|
+
for field in nested_classes_to_remove:
|
349
|
+
egeria_client.detach_nested_data_class(field, guid, None)
|
350
|
+
msg = f"Removed `{display_name}` from field `{field}`"
|
351
|
+
logger.trace(msg)
|
352
|
+
nested_classes_to_add = to_be_nested_classes - as_is_nested_classes
|
353
|
+
logger.trace(f"nested_classes_to_add: {list(nested_classes_to_add)}")
|
354
|
+
if len(nested_classes_to_add) > 0:
|
355
|
+
for field in nested_classes_to_add:
|
356
|
+
egeria_client.link_nested_data_class(field, guid, None)
|
357
|
+
msg = f"Added `{display_name}` to field `{field}`"
|
358
|
+
logger.trace(msg)
|
359
|
+
|
360
|
+
terms_to_remove = as_is_assigned_meanings - to_be_assigned_meanings
|
361
|
+
logger.trace(f"terms_to_remove: {list(terms_to_remove)}")
|
362
|
+
if len(terms_to_remove) > 0:
|
363
|
+
for term in terms_to_remove:
|
364
|
+
egeria_client.detach_semantic_definition(guid, term, None)
|
365
|
+
msg = f"Removed `{term}` from `{display_name}`"
|
366
|
+
logger.trace(msg)
|
367
|
+
terms_to_add = to_be_assigned_meanings - as_is_assigned_meanings
|
368
|
+
logger.trace(f"terms_to_add: {list(terms_to_add)}")
|
369
|
+
if len(terms_to_add) > 0:
|
370
|
+
for term in terms_to_add:
|
371
|
+
egeria_client.link_semantic_definition(guid, term, None)
|
372
|
+
msg = f"Added `{term}` to`{display_name}`"
|
373
|
+
logger.trace(msg)
|
374
|
+
|
375
|
+
specialized_classes_to_remove = as_is_specialized_classes - to_be_specialized_classes
|
376
|
+
logger.trace(f"classes_to_remove: {list(specialized_classes_to_remove)}")
|
377
|
+
if len(terms_to_remove) > 0:
|
378
|
+
for dc in specialized_classes_to_remove:
|
379
|
+
body = {
|
380
|
+
"class": "MetadataSourceRequestBody", "forLineage": False, "forDuplicateProcessing": False
|
381
|
+
}
|
382
|
+
egeria_client.detach_specialist_data_class(guid, dc, body)
|
383
|
+
msg = f"Removed `{dc}` from `{display_name}`"
|
384
|
+
logger.trace(msg)
|
385
|
+
specialized_classes_to_add = to_be_specialized_classes - as_is_specialized_classes
|
386
|
+
logger.trace(f"classes_to_add: {list(specialized_classes_to_add)}")
|
387
|
+
if len(specialized_classes_to_add) > 0:
|
388
|
+
for dc in specialized_classes_to_add:
|
389
|
+
body = {
|
390
|
+
"class": "RelationshipRequestBody", "forLineage": False, "forDuplicateProcessing": False
|
391
|
+
}
|
392
|
+
egeria_client.link_specialist_data_class(guid, dc, body)
|
393
|
+
msg = f"Added `{dc}` to`{display_name}`"
|
394
|
+
logger.trace(msg)
|
395
|
+
|
396
|
+
|
397
|
+
else: # merge - add field to related elements
|
398
|
+
if containing_data_class_guids:
|
399
|
+
for field in containing_data_class_guids:
|
400
|
+
egeria_client.link_nested_data_class(field, guid, None)
|
401
|
+
msg = f"Added `{display_name}` to `{field}`"
|
402
|
+
logger.trace(msg)
|
403
|
+
|
404
|
+
if terms:
|
405
|
+
for term in terms:
|
406
|
+
egeria_client.link_semantic_definition(guid, term, None)
|
407
|
+
msg = f"Added `{term}` to `{display_name}`"
|
408
|
+
logger.trace(msg)
|
409
|
+
if specializes_data_classes:
|
410
|
+
for el in specializes_data_classes:
|
411
|
+
egeria_client.link_specialist_data_class(guid, el)
|
412
|
+
msg = f"Linked `{el}` to `{display_name}`"
|
413
|
+
logger.trace(msg)
|
414
|
+
|
415
|
+
|
416
|
+
@logger.catch
|
417
|
+
def process_digital_product_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
418
|
+
"""
|
419
|
+
Processes a data specification create or update object_action by extracting key attributes such as
|
420
|
+
spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
|
421
|
+
|
422
|
+
:param txt: A string representing the input cell to be processed for
|
423
|
+
extracting glossary-related attributes.
|
424
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
425
|
+
:return: A string summarizing the outcome of the processing.
|
426
|
+
"""
|
427
|
+
|
428
|
+
command, object_type, object_action = extract_command_plus(txt)
|
429
|
+
|
430
|
+
parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
|
431
|
+
|
432
|
+
valid = parsed_output['valid']
|
433
|
+
exists = parsed_output['exists']
|
434
|
+
|
435
|
+
qualified_name = parsed_output.get('qualified_name', None)
|
436
|
+
guid = parsed_output.get('guid', None)
|
437
|
+
|
438
|
+
print(Markdown(parsed_output['display']))
|
439
|
+
|
440
|
+
logger.debug(json.dumps(parsed_output, indent=4))
|
441
|
+
|
442
|
+
attributes = parsed_output['attributes']
|
443
|
+
|
444
|
+
display_name = attributes['Display Name'].get('value', None)
|
445
|
+
description = attributes['Description'].get('value', None)
|
446
|
+
user_defined_status = attributes['User Defined Status'].get('value', None)
|
447
|
+
product_identifier = attributes['Product Identifier'].get('value', None)
|
448
|
+
product_name = attributes['Product Name'].get('value', None)
|
449
|
+
product_type = attributes['Product Type'].get('value', None)
|
450
|
+
|
451
|
+
|
452
|
+
|
453
|
+
product_description = attributes['Product Description'].get('value', None)
|
454
|
+
maturity = attributes['Maturity'].get('value', None)
|
455
|
+
service_life = attributes['Service Life'].get('value', None)
|
456
|
+
introduction_date = attributes['Introduction Date'].get('value', None)
|
457
|
+
next_version_date = attributes['Next Version Date'].get('value', None)
|
458
|
+
withdrawal_date = attributes['Withdrawal Date'].get('value', None)
|
459
|
+
|
460
|
+
collection_type = attributes.get('Collection Type', {}).get('value', None)
|
461
|
+
current_version = attributes['Current Version'].get('value', None)
|
462
|
+
product_manager = attributes['Product Manager'].get('value', None)
|
463
|
+
|
464
|
+
agreements = attributes['Agreements'].get('value', None)
|
465
|
+
agreement_names = attributes['Agreements Names'].get('name_list', None)
|
466
|
+
agreement_guids = attributes['Agreements Guids'].get('guid_list', None)
|
467
|
+
|
468
|
+
subscriptions = attributes['Digital Subscriptions'].get('value', None)
|
469
|
+
subscription_names = attributes['Digital Subscriptions Names'].get('name_list', None)
|
470
|
+
subscription_guids = attributes['Digital Subscriptions Guids'].get('guid_list', None)
|
471
|
+
|
472
|
+
product_status = attributes['Product Status'].get('value', "ACTIVE")
|
473
|
+
|
474
|
+
anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
|
475
|
+
parent_guid = attributes.get('Parent ID', {}).get('guid', None)
|
476
|
+
parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', "CollectionMembership")
|
477
|
+
parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
|
478
|
+
anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
|
479
|
+
is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
|
480
|
+
if parent_guid is None:
|
481
|
+
is_own_anchor = True
|
482
|
+
|
483
|
+
|
484
|
+
additional_prop = attributes.get('Additional Properties', {}).get('value', None)
|
485
|
+
additional_properties = json.loads(additional_prop) if additional_prop is not None else None
|
486
|
+
extended_prop = attributes.get('Extended Properties', {}).get('value', None)
|
487
|
+
extended_properties = json.loads(extended_prop) if extended_prop is not None else None
|
488
|
+
external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
|
489
|
+
external_source_name = attributes.get('External Source Name', {}).get('value', None)
|
490
|
+
effective_time = attributes.get('Effective Time', {}).get('value', None)
|
491
|
+
for_lineage = attributes.get('For Lineage', {}).get('value', None)
|
492
|
+
for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
|
493
|
+
|
494
|
+
replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
|
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
|
+
return None
|
516
|
+
else:
|
517
|
+
print(Markdown(
|
518
|
+
f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
|
519
|
+
|
520
|
+
body ={
|
521
|
+
"class": "UpdateElementRequestBody",
|
522
|
+
"properties": {
|
523
|
+
"class": "DigitalProductProperties",
|
524
|
+
"qualifiedName": qualified_name,
|
525
|
+
"userDefinedStatus": user_defined_status,
|
526
|
+
"name": display_name,
|
527
|
+
"description": description,
|
528
|
+
"identifier": product_identifier,
|
529
|
+
"productName": product_name,
|
530
|
+
"productType": product_type,
|
531
|
+
"maturity": maturity,
|
532
|
+
"serviceLife": service_life,
|
533
|
+
"introductionDate": introduction_date,
|
534
|
+
"nextVersionDate": next_version_date,
|
535
|
+
"withdrawDate": withdrawal_date,
|
536
|
+
"currentVersion": current_version,
|
537
|
+
|
538
|
+
"additionalProperties": additional_properties,
|
539
|
+
"extendedProperties": extended_properties,
|
540
|
+
},
|
541
|
+
"externalSourceGUID": external_source_guid,
|
542
|
+
"externalSourceName": external_source_name,
|
543
|
+
"effectiveTime": effective_time,
|
544
|
+
"forLineage": for_lineage,
|
545
|
+
"forDuplicateProcessing": for_duplicate_processing
|
546
|
+
}
|
547
|
+
|
548
|
+
egeria_client.update_digital_product(guid, body)
|
549
|
+
egeria_client.update_digital_product_status(guid, product_status)
|
550
|
+
|
551
|
+
logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
|
552
|
+
update_element_dictionary(qualified_name, {
|
553
|
+
'guid': guid, 'display_name': display_name
|
554
|
+
})
|
555
|
+
return egeria_client.get_collection_by_guid(guid, collection_type='Data Specification',
|
556
|
+
output_format='MD')
|
557
|
+
|
558
|
+
|
559
|
+
elif object_action == "Create":
|
560
|
+
if valid is False and exists:
|
561
|
+
msg = (f" Digital Product `{display_name}` already exists and result document updated changing "
|
562
|
+
f"`Create` to `Update` in processed output\n\n___")
|
563
|
+
logger.error(msg)
|
564
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
565
|
+
|
566
|
+
else:
|
567
|
+
body = {
|
568
|
+
"class": "NewDigitalProductRequestBody",
|
569
|
+
"isOwnAnchor": is_own_anchor,
|
570
|
+
"parentGUID": parent_guid,
|
571
|
+
"parentRelationshipTypeName": parent_relationship_type_name,
|
572
|
+
"parentAtEnd1": parent_at_end1,
|
573
|
+
"properties": {
|
574
|
+
"class": "DigitalProductProperties",
|
575
|
+
"qualifiedName": qualified_name,
|
576
|
+
"userDefinedStatus": user_defined_status,
|
577
|
+
"name": display_name,
|
578
|
+
"description" : description,
|
579
|
+
"identifier": product_identifier,
|
580
|
+
"productName": product_name,
|
581
|
+
"productType": product_type,
|
582
|
+
"maturity": maturity,
|
583
|
+
"serviceLife": service_life,
|
584
|
+
"introductionDate": introduction_date,
|
585
|
+
"nextVersionDate": next_version_date,
|
586
|
+
"withdrawDate": withdrawal_date,
|
587
|
+
"currentVersion": current_version,
|
588
|
+
|
589
|
+
"additionalProperties": additional_properties,
|
590
|
+
"extendedProperties": extended_properties,
|
591
|
+
},
|
592
|
+
"initialStatus": product_status,
|
593
|
+
"externalSourceGUID": external_source_guid,
|
594
|
+
"externalSourceName": external_source_name,
|
595
|
+
"effectiveTime" : effective_time,
|
596
|
+
"forLineage": for_lineage,
|
597
|
+
"forDuplicateProcessing": for_duplicate_processing
|
598
|
+
}
|
599
|
+
|
600
|
+
|
601
|
+
|
602
|
+
guid = egeria_client.create_digital_product(body)
|
603
|
+
if guid:
|
604
|
+
update_element_dictionary(qualified_name, {
|
605
|
+
'guid': guid, 'display_name': display_name
|
606
|
+
})
|
607
|
+
msg = f"Created Element `{display_name}` with GUID {guid}\n\n___"
|
608
|
+
logger.success(msg)
|
609
|
+
return egeria_client.get_collection_by_guid(guid, collection_type='Digital Product',
|
610
|
+
output_format='MD')
|
611
|
+
else:
|
612
|
+
msg = f"Failed to create element `{display_name}` with GUID {guid}\n\n___"
|
613
|
+
logger.error(msg)
|
614
|
+
return None
|
615
|
+
|
616
|
+
except Exception as e:
|
617
|
+
logger.error(f"Error performing {command}: {e}")
|
618
|
+
return None
|
619
|
+
else:
|
620
|
+
return None
|
621
|
+
|
622
|
+
|
623
|
+
@logger.catch
|
624
|
+
def process_data_dict_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
625
|
+
"""
|
626
|
+
Processes a data dictionary create or update object_action by extracting key attributes such as
|
627
|
+
spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
|
628
|
+
|
629
|
+
:param txt: A string representing the input cell to be processed for
|
630
|
+
extracting glossary-related attributes.
|
631
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
632
|
+
:return: A string summarizing the outcome of the processing.
|
633
|
+
"""
|
634
|
+
|
635
|
+
command, object_type, object_action = extract_command_plus(txt)
|
636
|
+
|
637
|
+
parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
|
638
|
+
|
639
|
+
valid = parsed_output['valid']
|
640
|
+
exists = parsed_output['exists']
|
641
|
+
|
642
|
+
qualified_name = parsed_output.get('qualified_name', None)
|
643
|
+
guid = parsed_output.get('guid', None)
|
644
|
+
|
645
|
+
print(Markdown(parsed_output['display']))
|
646
|
+
logger.debug(json.dumps(parsed_output, indent=4))
|
647
|
+
|
648
|
+
attributes = parsed_output['attributes']
|
649
|
+
description = attributes['Description'].get('value', None)
|
650
|
+
display_name = attributes.get('Display Name', {}).get('value', "None Found")
|
651
|
+
display_name = display_name if display_name is not None else "None Found"
|
652
|
+
anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
|
653
|
+
parent_guid = attributes.get('Parent ID', {}).get('guid', None)
|
654
|
+
parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value',
|
655
|
+
"CollectionMembership")
|
656
|
+
parent_at_end1 = attributes.get('Parent at End1', {}).get('value', True)
|
657
|
+
|
658
|
+
anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
|
659
|
+
is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', True)
|
660
|
+
if parent_guid is None:
|
661
|
+
is_own_anchor = True
|
662
|
+
collection_type = attributes.get('Collection Type', {}).get('value', None)
|
663
|
+
replace_all_props = not attributes.get('Merge Update', {}).get('value', True)
|
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
|
+
|
670
|
+
if directive == "display":
|
671
|
+
return None
|
672
|
+
elif directive == "validate":
|
673
|
+
if valid:
|
674
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
675
|
+
else:
|
676
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
677
|
+
return valid
|
678
|
+
|
679
|
+
elif directive == "process":
|
680
|
+
|
681
|
+
try:
|
682
|
+
if object_action == "Update":
|
683
|
+
|
684
|
+
if not exists:
|
685
|
+
logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
|
686
|
+
f"object_action\n\n___")
|
687
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
688
|
+
elif not valid:
|
689
|
+
logger.error(f"Element `{display_name}` does not have a valid specification? Review..\n\n___ ")
|
690
|
+
return None
|
691
|
+
else:
|
692
|
+
print(Markdown(
|
693
|
+
f"==> Validation of {command} completed successfully! Proceeding to apply the changes."))
|
694
|
+
|
695
|
+
egeria_client.update_collection(guid, qualified_name, display_name, description, collection_type,
|
696
|
+
additional_properties,
|
697
|
+
extended_properties, replace_all_props)
|
698
|
+
logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
|
699
|
+
update_element_dictionary(qualified_name, {
|
700
|
+
'guid': guid, 'display_name': display_name
|
701
|
+
})
|
702
|
+
return egeria_client.get_collection_by_guid(guid, collection_type='Data Dictionary', output_format='MD')
|
703
|
+
|
704
|
+
elif object_action == "Create":
|
705
|
+
if valid is False and exists:
|
706
|
+
logger.error(f"\nElement `{display_name}` already exists and result document updated changing "
|
707
|
+
f"`Create` to `Update` in processed output\n\n___")
|
708
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
709
|
+
else:
|
710
|
+
guid = egeria_client.create_data_dictionary_collection(display_name, description, qualified_name,
|
711
|
+
is_own_anchor, anchor_guid, parent_guid,
|
712
|
+
parent_relationship_type_name,
|
713
|
+
parent_at_end1, collection_type,
|
714
|
+
anchor_scope_guid, additional_properties,
|
715
|
+
extended_properties)
|
716
|
+
if guid:
|
717
|
+
update_element_dictionary(qualified_name, {
|
718
|
+
'guid': guid, 'display_name': display_name
|
719
|
+
})
|
720
|
+
logger.success(f"Created Element `{display_name}` with GUID {guid}\n\n___")
|
721
|
+
|
722
|
+
return egeria_client.get_collection_by_guid(guid, collection_type='Data Dictionary',
|
723
|
+
output_format='MD')
|
724
|
+
else:
|
725
|
+
logger.error(f"Failed to create Term `{display_name}`\n\n___")
|
726
|
+
return None
|
727
|
+
|
728
|
+
except Exception as e:
|
729
|
+
logger.error(f"{ERROR}Error performing {command}: {e}")
|
730
|
+
Console().print_exception(show_locals=True)
|
731
|
+
return None
|
732
|
+
else:
|
733
|
+
return None
|
734
|
+
|
735
|
+
|
736
|
+
@logger.catch
|
737
|
+
def process_data_structure_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
|
738
|
+
str]:
|
739
|
+
"""
|
740
|
+
Processes a data structure create or update object_action by extracting key attributes such as
|
741
|
+
spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
|
742
|
+
|
743
|
+
:param txt: A string representing the input cell to be processed for
|
744
|
+
extracting glossary-related attributes.
|
745
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
746
|
+
:return: A string summarizing the outcome of the processing.
|
747
|
+
"""
|
748
|
+
from md_processing.md_processing_utils.common_md_utils import set_debug_level
|
749
|
+
|
750
|
+
set_debug_level(directive)
|
751
|
+
|
752
|
+
command, object_type, object_action = extract_command_plus(txt)
|
753
|
+
|
754
|
+
parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
|
755
|
+
|
756
|
+
valid = parsed_output['valid']
|
757
|
+
exists = parsed_output['exists']
|
758
|
+
|
759
|
+
qualified_name = parsed_output.get('qualified_name', None)
|
760
|
+
guid = parsed_output.get('guid', None)
|
761
|
+
|
762
|
+
print(Markdown(parsed_output['display']))
|
763
|
+
|
764
|
+
if directive == "display":
|
765
|
+
return None
|
766
|
+
|
767
|
+
elif directive == "validate":
|
768
|
+
if valid:
|
769
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
770
|
+
else:
|
771
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
772
|
+
return valid
|
773
|
+
|
774
|
+
elif directive == "process":
|
775
|
+
logger.debug(json.dumps(parsed_output, indent=4))
|
776
|
+
attributes = parsed_output['attributes']
|
777
|
+
|
778
|
+
external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
|
779
|
+
external_source_name = attributes.get('External Source Name', {}).get('value', None)
|
780
|
+
effective_time = attributes.get('Effective Time', {}).get('value', None)
|
781
|
+
for_lineage = attributes.get('For Lineage', {}).get('value', None)
|
782
|
+
for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
|
783
|
+
anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
|
784
|
+
is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
|
785
|
+
parent_id = attributes.get('Parent ID', {}).get('value', None)
|
786
|
+
parent_guid = attributes.get('Parent ID', {}).get('guid', None)
|
787
|
+
parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
|
788
|
+
parent_relationship_properties = attributes.get('Parent Relationship Properties', {}).get('value', None)
|
789
|
+
parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
|
790
|
+
|
791
|
+
display_name = attributes['Display Name'].get('value', None)
|
792
|
+
|
793
|
+
namespace = attributes.get('Namespace', {}).get('value', None)
|
794
|
+
description = attributes.get('Description', {}).get('value', None)
|
795
|
+
version_id = attributes.get('Version Identifier', {}).get('value', None)
|
796
|
+
aliases = attributes.get('Aliases', {}).get('value', None)
|
797
|
+
name_patterns = attributes.get('Name Patterns', {}).get('value', None)
|
798
|
+
is_nullable = attributes.get('Is Nullable', {}).get('value', None)
|
799
|
+
default_value = attributes.get('Default Value', {}).get('value', None)
|
800
|
+
data_type = attributes.get('Data Type', {}).get('value', None)
|
801
|
+
min_length = attributes.get('Minimum Length', {}).get('value', None)
|
802
|
+
length = attributes.get('Length', {}).get('value', None)
|
803
|
+
precision = attributes.get('Precision', {}).get('value', None)
|
804
|
+
ordered_values = attributes.get('Ordered Values', {}).get('value', None)
|
805
|
+
sort_order = attributes.get('Sort Order', {}).get('value', None)
|
806
|
+
additional_properties = attributes.get('Additional Properties', {}).get('value', None)
|
807
|
+
effective_from = attributes.get('Effective From', {}).get('value', None)
|
808
|
+
effective_to = attributes.get('Effective To', {}).get('value', None)
|
809
|
+
|
810
|
+
position = attributes.get('Position', {}).get('value', None)
|
811
|
+
min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
|
812
|
+
max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
|
813
|
+
in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
|
814
|
+
data_class = attributes.get('Data Class', {}).get('value', None)
|
815
|
+
glossary_term = attributes.get('Glossary Term', {}).get('value', None)
|
816
|
+
glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
|
817
|
+
|
818
|
+
# name_details_list = attributes.get("dict_list", None)
|
819
|
+
|
820
|
+
data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", "")
|
821
|
+
data_spec_value = attributes.get("In Data Specification", {}).get("value", None)
|
822
|
+
data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
|
823
|
+
|
824
|
+
in_data_dictionary = attributes.get('In Data Dictionary', {}).get('dict_list', None)
|
825
|
+
data_dict_name_list = attributes.get('In Data Dictionary', {}).get('name_list', "")
|
826
|
+
data_dict_value_list = attributes.get('In Data Dictionary', {}).get('value', None)
|
827
|
+
data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
|
828
|
+
|
829
|
+
parent_data_field = attributes.get('Parent Data Field', {}).get('value', None)
|
830
|
+
parent_data_field_guid = attributes.get('Parent Data Field', {}).get('guid', None)
|
831
|
+
|
832
|
+
anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
|
833
|
+
|
834
|
+
collection_type = object_type
|
835
|
+
replace_all_props = True
|
836
|
+
if not valid:
|
837
|
+
if exists and object_action == "Create":
|
838
|
+
msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
|
839
|
+
f"processed output \n\n___")
|
840
|
+
logger.error(msg)
|
841
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
842
|
+
else:
|
843
|
+
return None
|
844
|
+
elif object_action == "Update" and not exists:
|
845
|
+
logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
|
846
|
+
f"object_action\n\n___")
|
847
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
848
|
+
|
849
|
+
else:
|
850
|
+
print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
|
851
|
+
|
852
|
+
try:
|
853
|
+
if object_action == "Update":
|
854
|
+
body = {
|
855
|
+
"class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
|
856
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
857
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
|
858
|
+
"class": "DataStructureProperties", "qualifiedName": qualified_name,
|
859
|
+
"displayName": display_name, "description": description, "namespace": namespace,
|
860
|
+
"versionIdentifier": version_id, "additionalProperties": additional_properties,
|
861
|
+
"effectiveFrom": effective_from, "effectiveTo": effective_to
|
862
|
+
}
|
863
|
+
}
|
864
|
+
egeria_client.update_data_structure_w_body(guid, body, replace_all_props)
|
865
|
+
logger.info(f"Updated element `{display_name}` with GUID {guid}")
|
866
|
+
core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD')
|
867
|
+
|
868
|
+
update_element_dictionary(qualified_name, {
|
869
|
+
'guid': guid, 'display_name': display_name
|
870
|
+
})
|
871
|
+
|
872
|
+
update_data_collection_memberships(egeria_client, object_type, data_spec_guid_list, "DataSpec", guid,
|
873
|
+
display_name, replace_all_props)
|
874
|
+
core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
|
875
|
+
core_props += f"## In Data Specification\n\n{data_spec_name_list}\n\n"
|
876
|
+
logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}\n\n___")
|
877
|
+
return core_props
|
878
|
+
|
879
|
+
elif object_action == "Create":
|
880
|
+
if exists:
|
881
|
+
logger.warning(f"\nTerm `{display_name}` already exists and result document updated\n\n___")
|
882
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
883
|
+
else:
|
884
|
+
|
885
|
+
body = {
|
886
|
+
"class": "NewElementRequestBody", "externalSourceGUID": external_source_guid,
|
887
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
888
|
+
"forLineage": False, "forDuplicateProcessing": False, "anchorGUID": anchor_guid,
|
889
|
+
"isOwnAnchor": is_own_anchor, "parentGUID": parent_guid,
|
890
|
+
"parentRelationshipTypeName": parent_relationship_type_name,
|
891
|
+
"parentRelationshipProperties": parent_relationship_properties, "parentAtEnd1": parent_at_end1,
|
892
|
+
"properties": {
|
893
|
+
"class": "DataStructureProperties", "qualifiedName": qualified_name,
|
894
|
+
"displayName": display_name, "description": description, "namespace": namespace,
|
895
|
+
"versionIdentifier": version_id, "additionalProperties": additional_properties,
|
896
|
+
"effectiveFrom": effective_from, "effectiveTo": effective_to
|
897
|
+
}
|
898
|
+
}
|
899
|
+
|
900
|
+
guid = egeria_client.create_data_structure_w_body(body_slimmer(body))
|
901
|
+
if guid:
|
902
|
+
update_element_dictionary(qualified_name, {
|
903
|
+
'guid': guid, 'display_name': display_name
|
904
|
+
})
|
905
|
+
|
906
|
+
core_props = egeria_client.get_data_structure_by_guid(guid, output_format='MD')
|
907
|
+
|
908
|
+
if in_data_dictionary:
|
909
|
+
logger.info(f"Will add to data dictionary(s) `{in_data_dictionary}`")
|
910
|
+
result = add_member_to_collections(egeria_client, in_data_dictionary, display_name,
|
911
|
+
guid)
|
912
|
+
core_props += f"## In Data Dictionary\n\n{data_dict_name_list}\n\n"
|
913
|
+
|
914
|
+
if data_spec_guid_list:
|
915
|
+
result = add_member_to_collections(egeria_client, data_spec_guid_list, display_name,
|
916
|
+
guid)
|
917
|
+
core_props += f"## In Data Specifications\n\n`{data_spec_name_list}`\n\n"
|
918
|
+
|
919
|
+
logger.info(f"Created Element `{display_name}` with GUID {guid}\n\n___")
|
920
|
+
|
921
|
+
return core_props
|
922
|
+
else:
|
923
|
+
logger.error(f"Failed to create Data Structure `{display_name}`\n\n___")
|
924
|
+
return None
|
925
|
+
|
926
|
+
|
927
|
+
except Exception as e:
|
928
|
+
logger.error(f"Error performing {object_action}: {e}\n\n___")
|
929
|
+
return None
|
930
|
+
else:
|
931
|
+
return None
|
932
|
+
|
933
|
+
|
934
|
+
@logger.catch
|
935
|
+
def process_data_field_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
936
|
+
"""
|
937
|
+
Processes a data field create or update object_action by extracting key attributes such as
|
938
|
+
spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
|
939
|
+
|
940
|
+
:param txt: A string representing the input cell to be processed for
|
941
|
+
extracting glossary-related attributes.
|
942
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
943
|
+
:return: A string summarizing the outcome of the processing.
|
944
|
+
"""
|
945
|
+
from md_processing.md_processing_utils.common_md_utils import set_debug_level
|
946
|
+
|
947
|
+
set_debug_level(directive)
|
948
|
+
|
949
|
+
command, object_type, object_action = extract_command_plus(txt)
|
950
|
+
|
951
|
+
parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
|
952
|
+
attributes = parsed_output['attributes']
|
953
|
+
display_name = attributes['Display Name'].get('value', None)
|
954
|
+
qualified_name = parsed_output.get('qualified_name', None)
|
955
|
+
guid = parsed_output.get('guid', None)
|
956
|
+
valid = parsed_output['valid']
|
957
|
+
exists = parsed_output['exists']
|
958
|
+
|
959
|
+
print(Markdown(parsed_output['display']))
|
960
|
+
|
961
|
+
if directive == "display":
|
962
|
+
|
963
|
+
return None
|
964
|
+
elif directive == "validate":
|
965
|
+
if valid:
|
966
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
967
|
+
else:
|
968
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
969
|
+
logger.error(msg)
|
970
|
+
return valid
|
971
|
+
|
972
|
+
elif directive == "process":
|
973
|
+
logger.debug(json.dumps(parsed_output, indent=4))
|
974
|
+
|
975
|
+
external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
|
976
|
+
external_source_name = attributes.get('External Source Name', {}).get('value', None)
|
977
|
+
effective_time = attributes.get('Effective Time', {}).get('value', None)
|
978
|
+
for_lineage = attributes.get('For Lineage', {}).get('value', None)
|
979
|
+
for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', None)
|
980
|
+
anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
|
981
|
+
is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
|
982
|
+
# parent_id = attributes.get('Parent ID', {}).get('value', None)
|
983
|
+
# parent_guid = attributes['Parent ID'].get('guid', None)
|
984
|
+
# parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
|
985
|
+
# parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
|
986
|
+
# parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
|
987
|
+
|
988
|
+
namespace = attributes.get('Namespace', {}).get('value', None)
|
989
|
+
description = attributes.get('Description', {}).get('value', None)
|
990
|
+
version_id = attributes.get('Version Identifier', {}).get('value', None)
|
991
|
+
aliases = attributes.get('Aliases', {}).get('value', None)
|
992
|
+
name_patterns = attributes.get('Name Patterns', {}).get('value', None)
|
993
|
+
is_nullable = attributes.get('Is Nullable', {}).get('value', None)
|
994
|
+
default_value = attributes.get('Default Value', {}).get('value', None)
|
995
|
+
data_type = attributes.get('Data Type', {}).get('value', None)
|
996
|
+
min_length = attributes.get('Minimum Length', {}).get('value', None)
|
997
|
+
length = attributes.get('Length', {}).get('value', None)
|
998
|
+
precision = attributes.get('Precision', {}).get('value', None)
|
999
|
+
ordered_values = attributes.get('Ordered Values', {}).get('value', None)
|
1000
|
+
sort_order = attributes.get('Sort Order', {}).get('value', None)
|
1001
|
+
additional_properties = attributes.get('Additional Properties', {}).get('value', None)
|
1002
|
+
effective_from = attributes.get('Effective From', {}).get('value', None)
|
1003
|
+
effective_to = attributes.get('Effective To', {}).get('value', None)
|
1004
|
+
|
1005
|
+
glossary_term = attributes['Glossary Term'].get('value', None)
|
1006
|
+
glossary_term_guid = attributes['Glossary Term'].get('guid', None)
|
1007
|
+
|
1008
|
+
merge_update = attributes.get('Merge Update', {}).get('value', None)
|
1009
|
+
|
1010
|
+
position = attributes.get('Position', {}).get('value', None)
|
1011
|
+
min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
|
1012
|
+
max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
|
1013
|
+
|
1014
|
+
in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
|
1015
|
+
data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
|
1016
|
+
in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
|
1017
|
+
|
1018
|
+
data_class = attributes.get('Data Class', {}).get('value', None)
|
1019
|
+
data_class_guid = attributes.get('Data Class', {}).get('guid', None)
|
1020
|
+
|
1021
|
+
glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
|
1022
|
+
if glossary_term_guid:
|
1023
|
+
glossary_term_guid = [glossary_term_guid]
|
1024
|
+
|
1025
|
+
glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
|
1026
|
+
|
1027
|
+
# name_details_list = attributes.get("dict_list", None)
|
1028
|
+
|
1029
|
+
in_data_spec = attributes.get("In Data Specification", {}).get("value", None) # this is a [dict]
|
1030
|
+
data_spec_name_list = attributes.get("In Data Specification", {}).get("name_list", None)
|
1031
|
+
data_spec_guid_list = attributes.get("In Data Specification", {}).get("guid_list", None)
|
1032
|
+
|
1033
|
+
in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
|
1034
|
+
in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
|
1035
|
+
data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
|
1036
|
+
|
1037
|
+
parent_data_field = attributes.get('Parent Data Field', {}).get('value', None)
|
1038
|
+
parent_data_field_guids = attributes.get('Parent Data Field', {}).get('guid_list', None)
|
1039
|
+
parent_data_field_names = attributes.get('Parent Data Field', {}).get('name_list', None)
|
1040
|
+
|
1041
|
+
anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
|
1042
|
+
|
1043
|
+
replace_all_props = not merge_update
|
1044
|
+
|
1045
|
+
if not valid:
|
1046
|
+
if exists and object_action == "Create":
|
1047
|
+
msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
|
1048
|
+
f"processed output\n\n___")
|
1049
|
+
logger.error(msg)
|
1050
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1051
|
+
else:
|
1052
|
+
msg = f"Invalid specification - please review\n\n___"
|
1053
|
+
logger.error(msg)
|
1054
|
+
return None
|
1055
|
+
else:
|
1056
|
+
print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
|
1057
|
+
|
1058
|
+
try:
|
1059
|
+
if object_action == "Update":
|
1060
|
+
if not exists:
|
1061
|
+
logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
|
1062
|
+
f"object_action\n\n___")
|
1063
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1064
|
+
|
1065
|
+
# first update the base data field
|
1066
|
+
body = {
|
1067
|
+
"class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
|
1068
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1069
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
|
1070
|
+
"class": "DataFieldProperties", "qualifiedName": qualified_name, "displayName": display_name,
|
1071
|
+
"namespace": namespace, "description": description, "versionIdentifier": version_id,
|
1072
|
+
"aliases": aliases, "namePatterns": name_patterns, "isDeprecated": False,
|
1073
|
+
"isNullable": is_nullable, "defaultValue": default_value, "dataType": data_type,
|
1074
|
+
"minimumLength": min_length, "length": length, "precision": precision,
|
1075
|
+
"orderedValues": ordered_values, "sortOrder": sort_order,
|
1076
|
+
"additionalProperties": additional_properties, "effectiveFrom": effective_from,
|
1077
|
+
"effectiveTo": effective_to
|
1078
|
+
}
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
egeria_client.update_data_field(guid, body, not merge_update)
|
1082
|
+
logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
|
1083
|
+
# Update data dictionary membership
|
1084
|
+
update_element_dictionary(qualified_name, {
|
1085
|
+
'guid': guid, 'display_name': display_name
|
1086
|
+
})
|
1087
|
+
core_props = egeria_client.find_data_fields(qualified_name,
|
1088
|
+
output_format='MD') ## update back to by_guid?
|
1089
|
+
|
1090
|
+
# existing_data_field = egeria_client.get_data_field_by_guid(guid, output_format='JSON')
|
1091
|
+
|
1092
|
+
# Sync membership in data dictionaries
|
1093
|
+
update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
|
1094
|
+
guid, display_name, replace_all_props)
|
1095
|
+
logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
|
1096
|
+
core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
|
1097
|
+
|
1098
|
+
# Sync data field related elements (data structure, parent data fields, terms, data classes
|
1099
|
+
sync_data_field_rel_elements(egeria_client, data_structure_guid_list, parent_data_field_guids,
|
1100
|
+
glossary_term_guid, data_class_guid, guid, display_name, replace_all_props)
|
1101
|
+
core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
|
1102
|
+
core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
|
1103
|
+
core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
|
1104
|
+
core_props += f"\n\n## Data Class\n\n{data_class}\n\n"
|
1105
|
+
core_props += "\n_______________________________________________________________________________\n\n"
|
1106
|
+
|
1107
|
+
# Update data classes
|
1108
|
+
logger.success(f"Updated Element `{display_name}`\n\n___")
|
1109
|
+
return core_props
|
1110
|
+
|
1111
|
+
elif object_action == "Create":
|
1112
|
+
if valid is False and exists:
|
1113
|
+
logger.error(
|
1114
|
+
f"\nData Field `{display_name}` already exists and result document updated changing `Create` "
|
1115
|
+
f"to `Update` in processed output\n\n___")
|
1116
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1117
|
+
else:
|
1118
|
+
# First lets create the data field
|
1119
|
+
body = {
|
1120
|
+
"class": "NewElementRequestBody", "properties": {
|
1121
|
+
"class": "DataFieldProperties", "qualifiedName": qualified_name,
|
1122
|
+
"displayName": display_name, "namespace": namespace, "description": description,
|
1123
|
+
"versionIdentifier": version_id, "aliases": aliases, "namePatterns": name_patterns,
|
1124
|
+
"isDeprecated": False, "isNullable": is_nullable, "defaultValue": default_value,
|
1125
|
+
"dataType": data_type, "minimumLength": min_length, "length": length,
|
1126
|
+
"precision": precision, "orderedValues": ordered_values, "sortOrder": sort_order,
|
1127
|
+
"additionalProperties": additional_properties
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
guid = egeria_client.create_data_field(body)
|
1131
|
+
if guid:
|
1132
|
+
# Now update our element dictionary with the new information
|
1133
|
+
update_element_dictionary(qualified_name, {
|
1134
|
+
'guid': guid, 'display_name': display_name
|
1135
|
+
})
|
1136
|
+
# Start assembling the information we will present back out
|
1137
|
+
core_props = egeria_client.get_data_field_by_guid(guid, None, 'MD')
|
1138
|
+
|
1139
|
+
# Add the field to any data dictionaries
|
1140
|
+
if in_data_dictionary:
|
1141
|
+
logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
|
1142
|
+
add_member_to_collections(egeria_client, data_dict_guid_list, display_name, guid)
|
1143
|
+
core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
|
1144
|
+
|
1145
|
+
# Add the field to any data structures
|
1146
|
+
if in_data_structure:
|
1147
|
+
core_props += f"\n\n## In Data Structure\n\n{in_data_structure_names}\n\n"
|
1148
|
+
for ds_guid in data_structure_guid_list:
|
1149
|
+
# todo This is too naive? - need to better accommodate the relationship
|
1150
|
+
df_body = {
|
1151
|
+
"class": "RelationshipRequestBody", "properties": {
|
1152
|
+
"class": "MemberDataFieldProperties", "dataFieldPosition": position,
|
1153
|
+
"minCardinality": min_cardinality, "maxCardinality": max_cardinality,
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
msg = f"Adding field to structure {ds_guid}"
|
1158
|
+
logger.info(msg)
|
1159
|
+
egeria_client.link_member_data_field(ds_guid, guid, df_body)
|
1160
|
+
core_props += f"\n\n## In Data Structure {in_data_structure_names}\n\n"
|
1161
|
+
|
1162
|
+
if glossary_term:
|
1163
|
+
if glossary_term_guid:
|
1164
|
+
glossary_body = {
|
1165
|
+
"class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
|
1166
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1167
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
|
1168
|
+
}
|
1169
|
+
core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
|
1170
|
+
egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
|
1171
|
+
|
1172
|
+
if parent_data_field_guids:
|
1173
|
+
# parent_df_body = {
|
1174
|
+
# "class": "MetadataSourceRequestBody", "externalSourceGUID": external_source_guid,
|
1175
|
+
# "externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1176
|
+
# "forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
|
1177
|
+
# }
|
1178
|
+
|
1179
|
+
# egeria_client.link_nested_data_field(parent_data_field_guid, guid, parent_df_body)
|
1180
|
+
for parent_guid in parent_data_field_guids:
|
1181
|
+
egeria_client.link_nested_data_field(parent_guid, guid)
|
1182
|
+
core_props += f"\n\n## Parent Data Field\n\n{parent_data_field_names}\n\n"
|
1183
|
+
|
1184
|
+
# Link data class
|
1185
|
+
if data_class:
|
1186
|
+
body = {
|
1187
|
+
"class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
|
1188
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1189
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
|
1190
|
+
}
|
1191
|
+
egeria_client.link_data_class_definition(guid, data_class_guid, body)
|
1192
|
+
msg = f"Adding data class `{data_class}` to data field {display_name}"
|
1193
|
+
logger.info(msg)
|
1194
|
+
|
1195
|
+
logger.success(f"Created Element `{display_name}` with guid `{guid}`")
|
1196
|
+
logger.success("=====================================================\n\n")
|
1197
|
+
core_props += "\n___\n\n"
|
1198
|
+
return core_props
|
1199
|
+
|
1200
|
+
else:
|
1201
|
+
logger.error(f"Failed to create Term `{display_name}`\n\n___")
|
1202
|
+
return None
|
1203
|
+
|
1204
|
+
except Exception as e:
|
1205
|
+
logger.error(f"Error performing {command}: {e}\n\n___")
|
1206
|
+
return None
|
1207
|
+
else:
|
1208
|
+
return None
|
1209
|
+
|
1210
|
+
|
1211
|
+
@logger.catch
|
1212
|
+
def process_data_class_upsert_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
1213
|
+
"""
|
1214
|
+
Processes a data class create or update object_action by extracting key attributes such as
|
1215
|
+
spec name, parent_guid, parent_relationship_type, parent_at_end_1, collection_type
|
1216
|
+
|
1217
|
+
:param txt: A string representing the input cell to be processed for
|
1218
|
+
extracting glossary-related attributes.
|
1219
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
1220
|
+
:return: A string summarizing the outcome of the processing.
|
1221
|
+
"""
|
1222
|
+
|
1223
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1224
|
+
|
1225
|
+
parsed_output = parse_upsert_command(egeria_client, object_type, object_action, txt, directive)
|
1226
|
+
|
1227
|
+
attributes = parsed_output['attributes']
|
1228
|
+
display_name = attributes['Display Name'].get('value', None)
|
1229
|
+
qualified_name = parsed_output.get('qualified_name', None)
|
1230
|
+
guid = parsed_output.get('guid', None)
|
1231
|
+
valid = parsed_output['valid']
|
1232
|
+
exists = parsed_output['exists']
|
1233
|
+
|
1234
|
+
print(Markdown(parsed_output['display']))
|
1235
|
+
|
1236
|
+
if directive == "display":
|
1237
|
+
|
1238
|
+
return None
|
1239
|
+
elif directive == "validate":
|
1240
|
+
if valid:
|
1241
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1242
|
+
else:
|
1243
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
1244
|
+
logger.error(msg)
|
1245
|
+
return valid
|
1246
|
+
|
1247
|
+
elif directive == "process":
|
1248
|
+
logger.debug(json.dumps(parsed_output, indent=4))
|
1249
|
+
|
1250
|
+
external_source_guid = attributes.get('External Source Name', {}).get('guid', None)
|
1251
|
+
external_source_name = attributes.get('External Source Name', {}).get('value', None)
|
1252
|
+
effective_time = attributes.get('Effective Time', {}).get('value', None)
|
1253
|
+
for_lineage = attributes.get('For Lineage', {}).get('value', False)
|
1254
|
+
for_duplicate_processing = attributes.get('For Duplicate Processing', {}).get('value', False)
|
1255
|
+
anchor_guid = attributes.get('Anchor ID', {}).get('guid', None)
|
1256
|
+
is_own_anchor = attributes.get('Is Own Anchor', {}).get('value', None)
|
1257
|
+
# parent_id = attributes.get('Parent ID', {}).get('value', None)
|
1258
|
+
# parent_guid = attributes['Parent ID'].get('guid', None)
|
1259
|
+
# parent_relationship_type_name = attributes.get('Parent Relationship Type Name', {}).get('value', None)
|
1260
|
+
# parent_relationship_properties = attributes.get('Parent Relationship Properties',{}).get('value', None)
|
1261
|
+
# parent_at_end1 = attributes.get('Parent at End1', {}).get('value', None)
|
1262
|
+
|
1263
|
+
namespace = attributes.get('Namespace', {}).get('value', None)
|
1264
|
+
description = attributes.get('Description', {}).get('value', None)
|
1265
|
+
version_id = attributes.get('Version Identifier', {}).get('value', None)
|
1266
|
+
|
1267
|
+
###############
|
1268
|
+
match_property_names = attributes.get('Match Property Names', {}).get('value', [])
|
1269
|
+
specification_details = attributes.get('Specification Details', {}).get('value', {})
|
1270
|
+
match_threshold = attributes.get('Match Threshold', {}).get('value', 0)
|
1271
|
+
specification = attributes.get('Specification', {}).get('value', None)
|
1272
|
+
data_type = attributes.get('Data Type', {}).get('value', None)
|
1273
|
+
is_nullable = attributes.get('Is Nullable', {}).get('value', True)
|
1274
|
+
allow_duplicates = attributes.get('Allow Duplicates', {}).get('value', True)
|
1275
|
+
default_value = attributes.get('Default Value', {}).get('value', None)
|
1276
|
+
average_value = attributes.get('Average Value', {}).get('value', None)
|
1277
|
+
value_list = attributes.get('Value List', {}).get('value', None)
|
1278
|
+
value_range_from = attributes.get('Value Range From', {}).get('value', None)
|
1279
|
+
value_range_to = attributes.get('Value Range To', {}).get('value', None)
|
1280
|
+
sample_values = attributes.get('Sample Values', {}).get('value', [])
|
1281
|
+
data_patterns = attributes.get('Data Patterns', {}).get('value', [])
|
1282
|
+
additional_properties = attributes.get('Additional Properties', {}).get('value', {})
|
1283
|
+
|
1284
|
+
###############
|
1285
|
+
aliases = attributes.get('Aliases', {}).get('value', None)
|
1286
|
+
name_patterns = attributes.get('Name Patterns', {}).get('value', None)
|
1287
|
+
|
1288
|
+
min_length = attributes.get('Minimum Length', {}).get('value', None)
|
1289
|
+
length = attributes.get('Length', {}).get('value', None)
|
1290
|
+
precision = attributes.get('Precision', {}).get('value', None)
|
1291
|
+
ordered_values = attributes.get('Ordered Values', {}).get('value', None)
|
1292
|
+
sort_order = attributes.get('Sort Order', {}).get('value', None)
|
1293
|
+
effective_from = attributes.get('Effective From', {}).get('value', None)
|
1294
|
+
effective_to = attributes.get('Effective To', {}).get('value', None)
|
1295
|
+
|
1296
|
+
glossary_term = attributes.get('Glossary Term', {}).get('value', None)
|
1297
|
+
glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
|
1298
|
+
|
1299
|
+
merge_update = attributes.get('Merge Update', {}).get('value', True)
|
1300
|
+
|
1301
|
+
position = attributes.get('Position', {}).get('value', None)
|
1302
|
+
min_cardinality = attributes.get('Minimum Cardinality', {}).get('value', None)
|
1303
|
+
max_cardinality = attributes.get('Maximum Cardinality', {}).get('value', None)
|
1304
|
+
|
1305
|
+
in_data_structure = attributes.get('In Data Structure', {}).get('value', None)
|
1306
|
+
data_structure_guid_list = attributes.get('In Data Structure', {}).get('guid_list', None)
|
1307
|
+
in_data_structure_names = attributes.get('In Data Structure Names', {}).get('name_list', None)
|
1308
|
+
|
1309
|
+
data_class = attributes.get('Data Class', {}).get('value', None)
|
1310
|
+
glossary_term = attributes.get('Glossary Term', {}).get('value', None)
|
1311
|
+
|
1312
|
+
glossary_term_guid = attributes.get('Glossary Term', {}).get('guid', None)
|
1313
|
+
|
1314
|
+
in_data_dictionary = attributes.get('In Data Dictionary', {}).get('value', None)
|
1315
|
+
in_data_dictionary_names = attributes.get('In Data Dictionary', {}).get('name_list', None)
|
1316
|
+
data_dict_guid_list = attributes.get("In Data Dictionary", {}).get("guid_list", None)
|
1317
|
+
|
1318
|
+
containing_data_class = attributes.get('Containing Data Class', {}).get('value', None)
|
1319
|
+
containing_data_class_guids = attributes.get('Containing Data Class', {}).get('guid_list', None)
|
1320
|
+
containing_data_class_names = attributes.get('Containing Data Class', {}).get('name_list', None)
|
1321
|
+
|
1322
|
+
specializes_data_class = attributes.get('Specializes Data Class', {}).get('value', None)
|
1323
|
+
specializes_data_class_guid = attributes.get('Specializes Data Class', {}).get('guid', None)
|
1324
|
+
specializes_data_class_name = attributes.get('Specializes Data Class', {}).get('name', None)
|
1325
|
+
|
1326
|
+
anchor_scope_guid = attributes.get('Anchor Scope GUID', {}).get('value', None)
|
1327
|
+
|
1328
|
+
replace_all_props = not merge_update
|
1329
|
+
|
1330
|
+
if not valid:
|
1331
|
+
if exists and object_action == "Create":
|
1332
|
+
msg = (f"Create failed because Element `{display_name}` exists - changing `Create` to `Update` in "
|
1333
|
+
f"processed output\n\n___")
|
1334
|
+
logger.error(msg)
|
1335
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1336
|
+
else:
|
1337
|
+
msg = f"Invalid specification - please review\n\n___"
|
1338
|
+
return None
|
1339
|
+
else:
|
1340
|
+
print(Markdown(f"==> Validation of {command} completed successfully! Proceeding to apply the changes.\n"))
|
1341
|
+
|
1342
|
+
try:
|
1343
|
+
if object_action == "Update":
|
1344
|
+
if not exists:
|
1345
|
+
logger.error(f"Element `{display_name}` does not exist! Updating result document with Create "
|
1346
|
+
f"object_action\n\n___")
|
1347
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1348
|
+
|
1349
|
+
# first update the base data class
|
1350
|
+
body = {
|
1351
|
+
"class": "UpdateElementRequestBody", "externalSourceGUID": external_source_guid,
|
1352
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1353
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing, "properties": {
|
1354
|
+
"class": "DataClassProperties", "qualifiedName": qualified_name, "displayName": display_name,
|
1355
|
+
"description": description, "namespace": namespace, "matchPropertyNames": match_property_names,
|
1356
|
+
"matchThreshold": match_threshold, "specification": specification,
|
1357
|
+
"specificationDetails": specification_details, "dataType": data_type,
|
1358
|
+
"allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
|
1359
|
+
"defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
|
1360
|
+
"valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
|
1361
|
+
"sampleValues": sample_values, "dataPatterns": data_patterns,
|
1362
|
+
"additionalProperties": additional_properties
|
1363
|
+
}
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
egeria_client.update_data_class(guid, body, not merge_update)
|
1367
|
+
logger.success(f"Updated {object_type} `{display_name}` with GUID {guid}")
|
1368
|
+
# Update data dictionary membership
|
1369
|
+
update_element_dictionary(qualified_name, {
|
1370
|
+
'guid': guid, 'display_name': display_name
|
1371
|
+
})
|
1372
|
+
core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD')
|
1373
|
+
|
1374
|
+
# Sync membership in data dictionaries
|
1375
|
+
update_data_collection_memberships(egeria_client, object_type, data_dict_guid_list, "DataDictionary",
|
1376
|
+
guid, display_name, replace_all_props)
|
1377
|
+
logger.success(f"Updating data dictionaries `{in_data_dictionary_names}`")
|
1378
|
+
core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
|
1379
|
+
|
1380
|
+
# Sync data field related elements (data structure, parent data fields, terms, data classes
|
1381
|
+
sync_data_class_rel_elements(egeria_client, containing_data_class_guids, glossary_term_guid,
|
1382
|
+
specializes_data_class_guid, guid, display_name, replace_all_props)
|
1383
|
+
|
1384
|
+
core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
|
1385
|
+
core_props += f"\n\n## Containing Data Class\n\n{containing_data_class_names}\n\n"
|
1386
|
+
core_props += "\n___\n\n"
|
1387
|
+
|
1388
|
+
# Update data classes
|
1389
|
+
logger.success(f"Updated Element `{display_name}`\n\n___")
|
1390
|
+
return core_props
|
1391
|
+
|
1392
|
+
elif object_action == "Create":
|
1393
|
+
if valid is False and exists:
|
1394
|
+
logger.error(
|
1395
|
+
f"\nData Class `{display_name}` already exists and result document updated changing `Create` "
|
1396
|
+
f"to `Update` in processed output\n\n___")
|
1397
|
+
return update_a_command(txt, object_action, object_type, qualified_name, guid)
|
1398
|
+
else:
|
1399
|
+
# First lets create the data class
|
1400
|
+
body = {
|
1401
|
+
"class": "NewElementRequestBody", "properties": {
|
1402
|
+
"class": "DataClassProperties", "qualifiedName": qualified_name,
|
1403
|
+
"displayName": display_name, "description": description, "namespace": namespace,
|
1404
|
+
"matchPropertyNames": match_property_names, "matchThreshold": match_threshold,
|
1405
|
+
"specification": specification, "specificationDetails": specification_details,
|
1406
|
+
"dataType": data_type, "allowsDuplicateValues": allow_duplicates, "isNullable": is_nullable,
|
1407
|
+
"defaultValue": default_value, "averageValue": average_value, "valueList": value_list,
|
1408
|
+
"valueRangeFrom": value_range_from, "valueRangeTo": value_range_to,
|
1409
|
+
"sampleValues": sample_values, "dataPatterns": data_patterns,
|
1410
|
+
"additionalProperties": additional_properties
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
guid = egeria_client.create_data_class(body)
|
1414
|
+
if guid:
|
1415
|
+
# Now update our element dictionary with the new information
|
1416
|
+
update_element_dictionary(qualified_name, {
|
1417
|
+
'guid': guid, 'display_name': display_name
|
1418
|
+
})
|
1419
|
+
# Start assembling the information we will present back out
|
1420
|
+
core_props = egeria_client.get_data_class_by_guid(guid, None, 'MD')
|
1421
|
+
|
1422
|
+
# Add the field to any data dictionaries
|
1423
|
+
if in_data_dictionary:
|
1424
|
+
logger.info(f"Will add to data dictionary `{in_data_dictionary}`")
|
1425
|
+
add_member_to_collections(egeria_client, data_dict_guid_list, display_name, guid)
|
1426
|
+
core_props += f"\n\n## In Data Dictionary\n\n{in_data_dictionary_names}\n\n"
|
1427
|
+
|
1428
|
+
if glossary_term:
|
1429
|
+
if glossary_term_guid:
|
1430
|
+
glossary_body = {
|
1431
|
+
"class": "RelationshipRequestBody", "externalSourceGUID": external_source_guid,
|
1432
|
+
"externalSourceName": external_source_name, "effectiveTime": effective_time,
|
1433
|
+
"forLineage": for_lineage, "forDuplicateProcessing": for_duplicate_processing
|
1434
|
+
}
|
1435
|
+
|
1436
|
+
core_props += f"\n\n## Glossary Term \n\n{glossary_term}\n\n"
|
1437
|
+
egeria_client.link_semantic_definition(guid, glossary_term_guid, glossary_body)
|
1438
|
+
|
1439
|
+
if containing_data_class_guids:
|
1440
|
+
for dc_guid in containing_data_class_guids:
|
1441
|
+
egeria_client.link_nested_data_class(dc_guid, guid)
|
1442
|
+
core_props += f"\n\n## Parent Data Field\n\n{containing_data_class_names}\n\n"
|
1443
|
+
|
1444
|
+
if specializes_data_class_guid:
|
1445
|
+
egeria_client.link_specialist_data_class(specializes_data_class_guid, guid)
|
1446
|
+
core_props += f"\n\n## Specialized Data Field\n\n{specializes_data_class_name}\n\n"
|
1447
|
+
|
1448
|
+
logger.success(f"Created Element `{display_name}`")
|
1449
|
+
core_props += "\n___\n\n"
|
1450
|
+
return core_props
|
1451
|
+
|
1452
|
+
else:
|
1453
|
+
logger.error(f"Failed to create Term `{display_name}`\n\n___")
|
1454
|
+
return None
|
1455
|
+
|
1456
|
+
except Exception as e:
|
1457
|
+
logger.error(f"Error performing {command}: {e}\n\n___")
|
1458
|
+
return None
|
1459
|
+
else:
|
1460
|
+
return None
|
1461
|
+
|
1462
|
+
|
1463
|
+
@logger.catch
|
1464
|
+
def process_data_collection_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
|
1465
|
+
str]:
|
1466
|
+
"""
|
1467
|
+
Processes a Data Dictionary list object_action by extracting key attributes such as
|
1468
|
+
search string from the given text.
|
1469
|
+
|
1470
|
+
:param txt: A string representing the input cell to be processed for
|
1471
|
+
extracting term-related attributes.
|
1472
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
1473
|
+
:return: A string summarizing the outcome of the processing.
|
1474
|
+
"""
|
1475
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1476
|
+
if object_type in ["Data Dictionary", "Data Dictionaries", "DataDict", "DataDictionary"]:
|
1477
|
+
col_type = "DataDictionary"
|
1478
|
+
elif object_type in ["Data Specification", "Data Specifications", "Data Specs"]:
|
1479
|
+
col_type = "DataSpec"
|
1480
|
+
else:
|
1481
|
+
col_type = "Collection"
|
1482
|
+
|
1483
|
+
parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
|
1484
|
+
|
1485
|
+
|
1486
|
+
|
1487
|
+
valid = parsed_output['valid']
|
1488
|
+
print(Markdown(f"Performing {command}"))
|
1489
|
+
print(Markdown(parsed_output['display']))
|
1490
|
+
|
1491
|
+
attr = parsed_output.get('attributes',{})
|
1492
|
+
effective_time = attr.get('effectiveTime', {}).get('value', None)
|
1493
|
+
as_of_time = attr.get('asOfTime', {}).get('value', None)
|
1494
|
+
for_duplicate_processing = attr.get('forDuplicateProcessing', {}).get('value', False)
|
1495
|
+
for_lineage = attr.get('forLineage',{}).get('value', False)
|
1496
|
+
limit_result_by_status = attr.get('limitResultsByStatus',{}).get('value', ['ACTIVE'])
|
1497
|
+
sequencing_property = attr.get('sequencingProperty',{}).get('value',"qualifiedName" )
|
1498
|
+
sequencing_order = attr.get('sequencingOrder',{}).get('value', "PROPERTY_ASCENDING")
|
1499
|
+
search_string = attr.get('Search String', {}).get('value', '*')
|
1500
|
+
output_format = attr.get('Output Format', {}).get('value', 'LIST')
|
1501
|
+
detailed = attr.get('Detailed', {}).get('value', False)
|
1502
|
+
|
1503
|
+
if directive == "display":
|
1504
|
+
return None
|
1505
|
+
elif directive == "validate":
|
1506
|
+
if valid:
|
1507
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1508
|
+
else:
|
1509
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
1510
|
+
logger.error(msg)
|
1511
|
+
return valid
|
1512
|
+
|
1513
|
+
elif directive == "process":
|
1514
|
+
try:
|
1515
|
+
if not valid: # First validate the command before we process it
|
1516
|
+
msg = f"Validation failed for {object_action} `{object_type}`\n"
|
1517
|
+
logger.error(msg)
|
1518
|
+
return None
|
1519
|
+
|
1520
|
+
list_md = f"\n# `{col_type}` with filter: `{search_string}`\n\n"
|
1521
|
+
body = {
|
1522
|
+
"class": "FilterRequestBody",
|
1523
|
+
"asOfTime": as_of_time,
|
1524
|
+
"effectiveTime": effective_time,
|
1525
|
+
"forLineage": for_lineage,
|
1526
|
+
"forDuplicateProcessing": for_duplicate_processing,
|
1527
|
+
"limitResultsByStatus": limit_result_by_status,
|
1528
|
+
"sequencingOrder": sequencing_order,
|
1529
|
+
"sequencingProperty": sequencing_property,
|
1530
|
+
"filter": search_string,
|
1531
|
+
}
|
1532
|
+
|
1533
|
+
struct = egeria_client.find_collections_w_body(body, col_type, output_format=output_format)
|
1534
|
+
if output_format == "DICT":
|
1535
|
+
list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
|
1536
|
+
else:
|
1537
|
+
list_md += struct
|
1538
|
+
logger.info(f"Wrote `{col_type}` for search string: `{search_string}`")
|
1539
|
+
|
1540
|
+
return list_md
|
1541
|
+
|
1542
|
+
except Exception as e:
|
1543
|
+
logger.error(f"Error performing {command}: {e}")
|
1544
|
+
console.print_exception(show_locals=True)
|
1545
|
+
return None
|
1546
|
+
else:
|
1547
|
+
return None
|
1548
|
+
|
1549
|
+
|
1550
|
+
def process_data_structure_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[
|
1551
|
+
str]:
|
1552
|
+
"""
|
1553
|
+
Processes a Data Dictionary list object_action by extracting key attributes such as
|
1554
|
+
search string from the given text.
|
1555
|
+
|
1556
|
+
:param txt: A string representing the input cell to be processed for
|
1557
|
+
extracting term-related attributes.
|
1558
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
1559
|
+
:return: A string summarizing the outcome of the processing.
|
1560
|
+
"""
|
1561
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1562
|
+
|
1563
|
+
parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
|
1564
|
+
|
1565
|
+
attributes = parsed_output['attributes']
|
1566
|
+
|
1567
|
+
valid = parsed_output['valid']
|
1568
|
+
print(Markdown(f"Performing {command}"))
|
1569
|
+
print(Markdown(parsed_output['display']))
|
1570
|
+
|
1571
|
+
if directive == "display":
|
1572
|
+
return None
|
1573
|
+
elif directive == "validate":
|
1574
|
+
if valid:
|
1575
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1576
|
+
else:
|
1577
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
1578
|
+
logger.error(msg)
|
1579
|
+
return valid
|
1580
|
+
|
1581
|
+
elif directive == "process":
|
1582
|
+
attributes = parsed_output['attributes']
|
1583
|
+
search_string = attributes.get('Search String', {}).get('value', '*')
|
1584
|
+
output_format = attributes.get('Output Format', {}).get('value', 'LIST')
|
1585
|
+
detailed = attributes.get('Detailed', {}).get('value', False)
|
1586
|
+
|
1587
|
+
try:
|
1588
|
+
if not valid: # First validate the command before we process it
|
1589
|
+
msg = f"Validation failed for {object_action} `{object_type}`\n"
|
1590
|
+
logger.error(msg)
|
1591
|
+
return None
|
1592
|
+
|
1593
|
+
list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
|
1594
|
+
struct = egeria_client.find_data_structures(search_string, output_format=output_format)
|
1595
|
+
|
1596
|
+
if output_format == "DICT":
|
1597
|
+
list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
|
1598
|
+
else:
|
1599
|
+
list_md += struct
|
1600
|
+
logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
|
1601
|
+
|
1602
|
+
return list_md
|
1603
|
+
|
1604
|
+
except Exception as e:
|
1605
|
+
logger.error(f"Error performing {command}: {e}")
|
1606
|
+
console.print_exception(show_locals=True)
|
1607
|
+
return None
|
1608
|
+
else:
|
1609
|
+
return None
|
1610
|
+
|
1611
|
+
|
1612
|
+
def process_data_field_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
1613
|
+
"""
|
1614
|
+
Processes a Data Dictionary list object_action by extracting key attributes such as
|
1615
|
+
search string from the given text.
|
1616
|
+
|
1617
|
+
:param txt: A string representing the input cell to be processed for
|
1618
|
+
extracting term-related attributes.
|
1619
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
1620
|
+
:return: A string summarizing the outcome of the processing.
|
1621
|
+
"""
|
1622
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1623
|
+
|
1624
|
+
parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
|
1625
|
+
|
1626
|
+
attributes = parsed_output['attributes']
|
1627
|
+
|
1628
|
+
valid = parsed_output['valid']
|
1629
|
+
print(Markdown(f"Performing {command}"))
|
1630
|
+
print(Markdown(parsed_output['display']))
|
1631
|
+
|
1632
|
+
if directive == "display":
|
1633
|
+
return None
|
1634
|
+
elif directive == "validate":
|
1635
|
+
if valid:
|
1636
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1637
|
+
else:
|
1638
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
1639
|
+
logger.error(msg)
|
1640
|
+
return valid
|
1641
|
+
|
1642
|
+
elif directive == "process":
|
1643
|
+
attributes = parsed_output['attributes']
|
1644
|
+
search_string = attributes.get('Search String', {}).get('value', '*')
|
1645
|
+
output_format = attributes.get('Output Format', {}).get('value', 'LIST')
|
1646
|
+
detailed = attributes.get('Detailed', {}).get('value', False)
|
1647
|
+
as_of_time = attributes.get('AsOfTime', {}).get('value', None)
|
1648
|
+
effective_time = attributes.get('Effective Time', {}).get('value', None)
|
1649
|
+
sort_order = attributes.get('Sort Order', {}).get('value', None)
|
1650
|
+
order_property = attributes.get('Order Property', {}).get('value', None)
|
1651
|
+
starts_with = attributes.get('Start With', {}).get('value', True)
|
1652
|
+
ends_with = attributes.get('End With', {}).get('value', False)
|
1653
|
+
ignore_case = attributes.get('Ignore Case', {}).get('value', False)
|
1654
|
+
start_from = attributes.get('Start From', {}).get('value', 0)
|
1655
|
+
page_size = attributes.get('Page Size', {}).get('value', None)
|
1656
|
+
|
1657
|
+
try:
|
1658
|
+
if not valid: # First validate the command before we process it
|
1659
|
+
msg = f"Validation failed for {object_action} `{object_type}`\n"
|
1660
|
+
logger.error(msg)
|
1661
|
+
return None
|
1662
|
+
|
1663
|
+
list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
|
1664
|
+
body = {
|
1665
|
+
"class": "FilterRequestBody", "asOfTime": as_of_time, "effectiveTime": effective_time,
|
1666
|
+
"forLineage": False, "forDuplicateProcessing": False, "limitResultsByStatus": ["ACTIVE"],
|
1667
|
+
"sequencingOrder": sort_order, "sequencingProperty": order_property, "filter": search_string,
|
1668
|
+
}
|
1669
|
+
struct = egeria_client.find_data_fields_w_body(body, start_from, page_size, starts_with, ends_with,
|
1670
|
+
ignore_case, output_format)
|
1671
|
+
|
1672
|
+
if output_format == "DICT":
|
1673
|
+
list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
|
1674
|
+
else:
|
1675
|
+
list_md += struct
|
1676
|
+
logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
|
1677
|
+
|
1678
|
+
return list_md
|
1679
|
+
|
1680
|
+
except Exception as e:
|
1681
|
+
logger.error(f"Error performing {command}: {e}")
|
1682
|
+
console.print_exception(show_locals=True)
|
1683
|
+
return None
|
1684
|
+
else:
|
1685
|
+
return None
|
1686
|
+
|
1687
|
+
|
1688
|
+
def process_data_class_list_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
1689
|
+
"""
|
1690
|
+
Processes a Data Dictionary list object_action by extracting key attributes such as
|
1691
|
+
search string from the given text.
|
1692
|
+
|
1693
|
+
:param txt: A string representing the input cell to be processed for
|
1694
|
+
extracting term-related attributes.
|
1695
|
+
:param directive: an optional string indicating the directive to be used - display, validate or execute
|
1696
|
+
:return: A string summarizing the outcome of the processing.
|
1697
|
+
"""
|
1698
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1699
|
+
|
1700
|
+
parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
|
1701
|
+
|
1702
|
+
attributes = parsed_output['attributes']
|
1703
|
+
|
1704
|
+
valid = parsed_output['valid']
|
1705
|
+
print(Markdown(f"Performing {command}"))
|
1706
|
+
print(Markdown(parsed_output['display']))
|
1707
|
+
|
1708
|
+
if directive == "display":
|
1709
|
+
return None
|
1710
|
+
elif directive == "validate":
|
1711
|
+
if valid:
|
1712
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1713
|
+
else:
|
1714
|
+
msg = f"Validation failed for object_action `{command}`\n"
|
1715
|
+
logger.error(msg)
|
1716
|
+
return valid
|
1717
|
+
|
1718
|
+
elif directive == "process":
|
1719
|
+
attributes = parsed_output['attributes']
|
1720
|
+
search_string = attributes.get('Search String', {}).get('value', '*')
|
1721
|
+
output_format = attributes.get('Output Format', {}).get('value', 'LIST')
|
1722
|
+
detailed = attributes.get('Detailed', {}).get('value', False)
|
1723
|
+
|
1724
|
+
try:
|
1725
|
+
if not valid: # First validate the command before we process it
|
1726
|
+
msg = f"Validation failed for {object_action} `{object_type}`\n"
|
1727
|
+
logger.error(msg)
|
1728
|
+
return None
|
1729
|
+
|
1730
|
+
list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
|
1731
|
+
struct = egeria_client.find_data_classes(search_string, output_format=output_format)
|
1732
|
+
|
1733
|
+
if output_format == "DICT":
|
1734
|
+
list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
|
1735
|
+
else:
|
1736
|
+
list_md += struct
|
1737
|
+
logger.info(f"Wrote `{object_type}` for search string: `{search_string}`")
|
1738
|
+
|
1739
|
+
return list_md
|
1740
|
+
|
1741
|
+
except Exception as e:
|
1742
|
+
logger.error(f"Error performing {command}: {e}")
|
1743
|
+
console.print_exception(show_locals=True)
|
1744
|
+
return None
|
1745
|
+
else:
|
1746
|
+
return None
|