pyegeria 5.3.10__py3-none-any.whl → 5.4.0.dev2__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 (69) hide show
  1. commands/cat/debug_log.2025-06-05_20-24-18_123924.log.zip +0 -0
  2. commands/cat/debug_log.2025-06-10_08-45-03_929921.log.zip +0 -0
  3. commands/cat/debug_log.2025-06-11_09-57-21_247890.log.zip +0 -0
  4. commands/cat/debug_log.2025-06-12_16-14-31_212042.log.zip +0 -0
  5. commands/cat/dr_egeria_md.py +32 -5
  6. commands/cat/list_collections.py +10 -4
  7. commands/cat/list_data_designer.py +171 -0
  8. md_processing/__init__.py +7 -2
  9. md_processing/data/commands.json +4666 -848
  10. md_processing/md_commands/data_designer_commands.py +840 -557
  11. md_processing/md_commands/solution_architect_commands.py +985 -0
  12. md_processing/md_processing_utils/common_md_proc_utils.py +262 -89
  13. md_processing/md_processing_utils/common_md_utils.py +11 -4
  14. md_processing/md_processing_utils/md_processing_constants.py +18 -16
  15. pyegeria/_client.py +39 -0
  16. pyegeria/classification_manager_omvs.py +1 -1
  17. pyegeria/collection_manager_omvs.py +248 -188
  18. pyegeria/data_designer_omvs.py +217 -9
  19. pyegeria/governance_officer_omvs.py +2349 -0
  20. pyegeria/output_formatter.py +24 -12
  21. pyegeria/solution_architect_omvs.py +4219 -1084
  22. pyegeria/utils.py +15 -2
  23. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dev2.dist-info}/METADATA +2 -1
  24. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dev2.dist-info}/RECORD +27 -62
  25. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dev2.dist-info}/entry_points.txt +3 -0
  26. commands/cat/.DS_Store +0 -0
  27. md_processing/dr_egeria_inbox/archive/dr_egeria_intro.md +0 -254
  28. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_more_terms.md +0 -696
  29. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part1.md +0 -254
  30. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part2.md +0 -298
  31. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part3.md +0 -608
  32. md_processing/dr_egeria_inbox/archive/dr_egeria_intro_part4.md +0 -94
  33. md_processing/dr_egeria_inbox/archive/freddie_intro.md +0 -284
  34. md_processing/dr_egeria_inbox/archive/freddie_intro_orig.md +0 -275
  35. md_processing/dr_egeria_inbox/archive/test-term.md +0 -110
  36. md_processing/dr_egeria_inbox/cat_test.md +0 -100
  37. md_processing/dr_egeria_inbox/data_field.md +0 -54
  38. md_processing/dr_egeria_inbox/data_spec.md +0 -77
  39. md_processing/dr_egeria_inbox/data_spec_test.md +0 -2406
  40. md_processing/dr_egeria_inbox/data_test.md +0 -86
  41. md_processing/dr_egeria_inbox/dr_egeria_intro_categories.md +0 -168
  42. md_processing/dr_egeria_inbox/dr_egeria_intro_part1.md +0 -280
  43. md_processing/dr_egeria_inbox/dr_egeria_intro_part2.md +0 -313
  44. md_processing/dr_egeria_inbox/dr_egeria_intro_part3.md +0 -1073
  45. md_processing/dr_egeria_inbox/dr_egeria_isc1.md +0 -44
  46. md_processing/dr_egeria_inbox/glossary_test1.md +0 -324
  47. md_processing/dr_egeria_inbox/rel.md +0 -8
  48. md_processing/dr_egeria_inbox/sb.md +0 -119
  49. md_processing/dr_egeria_inbox/search_test.md +0 -39
  50. md_processing/dr_egeria_inbox/solution-components.md +0 -154
  51. md_processing/dr_egeria_inbox/solution_blueprints.md +0 -118
  52. md_processing/dr_egeria_inbox/synonym_test.md +0 -42
  53. md_processing/dr_egeria_inbox/t1.md +0 -0
  54. md_processing/dr_egeria_inbox/t2.md +0 -268
  55. md_processing/dr_egeria_outbox/processed-2025-05-15 19:52-data_test.md +0 -94
  56. md_processing/dr_egeria_outbox/processed-2025-05-16 07:39-data_test.md +0 -88
  57. md_processing/dr_egeria_outbox/processed-2025-05-17 16:01-data_field.md +0 -56
  58. md_processing/dr_egeria_outbox/processed-2025-05-18 15:51-data_test.md +0 -103
  59. md_processing/dr_egeria_outbox/processed-2025-05-18 16:47-data_test.md +0 -94
  60. md_processing/dr_egeria_outbox/processed-2025-05-19 07:14-data_test.md +0 -96
  61. md_processing/dr_egeria_outbox/processed-2025-05-19 07:20-data_test.md +0 -100
  62. md_processing/dr_egeria_outbox/processed-2025-05-19 07:22-data_test.md +0 -88
  63. md_processing/dr_egeria_outbox/processed-2025-05-19 09:26-data_test.md +0 -91
  64. md_processing/dr_egeria_outbox/processed-2025-05-19 10:27-data_test.md +0 -91
  65. md_processing/dr_egeria_outbox/processed-2025-05-19 14:04-data_test.md +0 -91
  66. md_processing/md_commands/blueprint_commands.py +0 -303
  67. pyegeria/.DS_Store +0 -0
  68. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dev2.dist-info}/LICENSE +0 -0
  69. {pyegeria-5.3.10.dist-info → pyegeria-5.4.0.dev2.dist-info}/WHEEL +0 -0
@@ -5,13 +5,12 @@ import os
5
5
  import sys
6
6
  from typing import List
7
7
 
8
- from rich.console import Console
8
+ from loguru import logger
9
9
  from rich import print
10
+ from rich.console import Console
10
11
 
11
-
12
-
13
- from md_processing.md_processing_utils.common_md_utils import (get_current_datetime_string, print_msg,
14
- get_element_dictionary, update_element_dictionary,
12
+ from md_processing.md_processing_utils.common_md_utils import (get_current_datetime_string, get_element_dictionary,
13
+ update_element_dictionary,
15
14
  split_tb_string, str_to_bool, )
16
15
  from md_processing.md_processing_utils.extraction_utils import (process_simple_attribute, extract_attribute,
17
16
  get_element_by_name)
@@ -20,6 +19,11 @@ from md_processing.md_processing_utils.message_constants import (ERROR, INFO, WA
20
19
  from pyegeria import EgeriaTech
21
20
  from pyegeria._globals import DEBUG_LEVEL
22
21
 
22
+ log_format = "P {time} | {level} | {function} | {line} | {message} | {extra}"
23
+ logger.remove()
24
+ logger.add(sys.stderr, level="SUCCESS", format=log_format, colorize=True)
25
+ logger.add("debug_log.log", rotation="1 day", retention="1 week", compression="zip", level="TRACE", format=log_format,
26
+ colorize=True)
23
27
  # Constants
24
28
  EGERIA_WIDTH = int(os.environ.get("EGERIA_WIDTH", "200"))
25
29
  EGERIA_USAGE_LEVEL = os.environ.get("EGERIA_USAGE_LEVEL", "Basic")
@@ -29,6 +33,7 @@ debug_level = DEBUG_LEVEL
29
33
  global COMMAND_DEFINITIONS
30
34
 
31
35
 
36
+ @logger.catch
32
37
  def process_provenance_command(file_path: str, txt: [str]) -> str:
33
38
  """
34
39
  Processes a provenance object_action by extracting the file path and current datetime.
@@ -46,7 +51,8 @@ def process_provenance_command(file_path: str, txt: [str]) -> str:
46
51
  return provenance
47
52
 
48
53
 
49
- def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_action: str, txt: str,
54
+ @logger.catch
55
+ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_action: str, txt: str,
50
56
  directive: str = "display") -> dict:
51
57
  parsed_attributes, parsed_output = {}, {}
52
58
 
@@ -69,7 +75,7 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
69
75
  parsed_output['reason'] = ""
70
76
 
71
77
  msg = f"\tProcessing {object_action} on a {object_type} \n"
72
- print_msg(ALWAYS, msg, debug_level)
78
+ logger.info(msg)
73
79
 
74
80
  # get the version early because we may need it to construct qualified names.
75
81
  version = process_simple_attribute(txt, {'Version', "Version Identifier", "Published Version"}, INFO)
@@ -81,29 +87,32 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
81
87
  for_update = attr[key].get('inUpdate', True)
82
88
  level = attr[key].get('level', 'Basic')
83
89
  msg = (f"___\nProcessing `{key}` in `{object_action}` on a `{object_type}` "
84
- f"\n\twith usage level: `{EGERIA_USAGE_LEVEL}` and attribute level `{level}` and for_update `{for_update}`\n")
85
- print_msg(INFO, msg, debug_level)
90
+ f"\n\twith usage level: `{EGERIA_USAGE_LEVEL}` and attribute level `{level}` and for_update `"
91
+ f"{for_update}`\n")
92
+ logger.trace(msg)
86
93
  if for_update is False and object_action == "Update":
87
- console.print(f"Attribute `{key}`is not allowed for `Update`", highlight=True)
94
+ logger.trace(f"Attribute `{key}`is not allowed for `Update`", highlight=True)
88
95
  continue
89
96
  if EGERIA_USAGE_LEVEL == "Basic" and level != "Basic":
90
- console.print(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.", highlight=True)
97
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
98
+ highlight=True)
91
99
  continue
92
- if EGERIA_USAGE_LEVEL == "Advanced" and level in [ "Expert", "Invisible"]:
93
- console.print(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.", highlight=True)
100
+ if EGERIA_USAGE_LEVEL == "Advanced" and level in ["Expert", "Invisible"]:
101
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
102
+ highlight=True)
94
103
  continue
95
104
  if EGERIA_USAGE_LEVEL == "Expert" and level == "Invisible":
96
- console.print(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.", highlight=True)
105
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
106
+ highlight=True)
97
107
  continue
98
108
 
99
-
100
109
  if attr[key].get('input_required', False) is True:
101
110
  if_missing = ERROR
102
111
  else:
103
112
  if_missing = INFO
104
113
 
105
114
  # lab = [item.strip() for item in re.split(r'[;,\n]+',attr[key]['attr_labels'])]
106
- lab =split_tb_string(attr[key]['attr_labels'] )
115
+ lab = split_tb_string(attr[key]['attr_labels'])
107
116
  labels: set = set()
108
117
  labels.add(key.strip())
109
118
  if key == 'Display Name':
@@ -111,7 +120,6 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
111
120
  if lab is not None and lab != [""]:
112
121
  labels.update(lab)
113
122
 
114
-
115
123
  default_value = attr[key].get('default_value', None)
116
124
 
117
125
  style = attr[key]['style']
@@ -124,7 +132,8 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
124
132
  elif style == 'QN':
125
133
  parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
126
134
  object_action, version, if_missing)
127
- if key == 'Qualified Name' and parsed_attributes[key]['value'] and parsed_attributes[key]['exists'] is False:
135
+ if key == 'Qualified Name' and parsed_attributes[key]['value'] and parsed_attributes[key][
136
+ 'exists'] is False:
128
137
  parsed_output['exists'] = False
129
138
  elif style == 'ID':
130
139
  parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
@@ -139,10 +148,10 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
139
148
 
140
149
  elif style == 'Reference Name':
141
150
  parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
142
- if ((if_missing==ERROR) and parsed_attributes[key].get("value", None) and
143
- parsed_attributes[key]['exists'] is False):
151
+ if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) and parsed_attributes[key][
152
+ 'exists'] is False):
144
153
  msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
145
- print_msg(ERROR, msg, debug_level)
154
+ logger.error(msg)
146
155
  parsed_output['valid'] = False
147
156
  parsed_output['reason'] += msg
148
157
 
@@ -167,64 +176,232 @@ def parse_user_command(egeria_client: EgeriaTech, object_type: str, object_actio
167
176
 
168
177
  elif style == 'Reference Name List':
169
178
  parsed_attributes[key] = proc_name_list(egeria_client, key, txt, labels, if_missing)
170
-
179
+ if (parsed_attributes[key].get("value", None) and (
180
+ parsed_attributes[key]['exists'] is False or parsed_attributes[key]['valid'] is False)):
181
+ msg = (f"A Reference Name in `{parsed_attributes[key].get('name_list', None)}` is specified but "
182
+ f"does not exist")
183
+ logger.error(msg)
184
+ parsed_output['valid'] = False
185
+ parsed_output['reason'] += msg
171
186
  else:
172
187
  msg = f"Unknown attribute style: {style}"
173
- print_msg(ERROR, msg, debug_level)
188
+ logger.error(msg)
174
189
  sys.exit(1)
175
190
  parsed_attributes[key]['valid'] = False
176
191
  parsed_attributes[key]['value'] = None
177
192
  if key == "Display Name":
178
193
  display_name = parsed_attributes[key]['value']
179
194
 
180
-
181
-
182
- value = parsed_attributes[key].get('value',None)
195
+ value = parsed_attributes[key].get('value', None)
183
196
 
184
197
  if value is not None:
185
198
  # if the value is a dict, get the flattened name list
186
- value = parsed_attributes[key].get('name_list', None) if isinstance(value,(dict, list)) else value
187
-
199
+ value = parsed_attributes[key].get('name_list', None) if isinstance(value, (dict, list)) else value
188
200
  parsed_output['display'] += f"\n\t* {key}: `{value}`\n\t"
189
201
 
190
202
 
203
+ parsed_output['attributes'] = parsed_attributes
204
+
205
+ if display_name is None:
206
+ msg = f"No display name or name identifier found"
207
+ logger.error(msg)
208
+ parsed_output['valid'] = False
209
+ parsed_output['reason'] = msg
210
+ return parsed_output
211
+
212
+
191
213
  if parsed_attributes.get('Parent ID', {}).get('value', None) is not None:
192
214
  if (parsed_attributes['Parent Relationship Type Name']['value'] is None) or (
193
215
  parsed_attributes['Parent at End1']['value'] is None):
194
216
  msg = "Parent ID was found but either Parent `Relationship Type Name` or `Parent at End1` are missing"
195
- print_msg(ERROR, msg, debug_level)
217
+ logger.error(msg)
196
218
  parsed_output['valid'] = False
197
219
  parsed_output['reason'] = msg
198
220
  if parsed_attributes['Parent Relationship Type Name'].get('exists', False) is False:
199
221
  msg = "Parent ID was found but does not exist"
200
- print_msg(ERROR, msg, debug_level)
222
+ logger.error(msg)
201
223
  parsed_output['valid'] = False
202
224
  parsed_output['reason'] = msg
203
225
 
204
226
  if directive in ["validate", "process"] and object_action == "Update" and not parsed_output[
205
227
  'exists']: # check to see if provided information exists and is consistent with existing info
206
- msg = f"Update request invalid, Term {display_name} does not exist\n"
207
- print_msg(ERROR, msg, debug_level)
228
+ msg = f"Update request invalid, element `{display_name}` does not exist\n"
229
+ logger.error(msg)
208
230
  parsed_output['valid'] = False
209
231
  if directive in ["validate", "process"] and not parsed_output['valid'] and object_action == "Update":
210
232
  msg = f"Request is invalid, `{object_action} {object_type}` is not valid - see previous messages\n"
211
- print_msg(ERROR, msg, debug_level)
233
+ logger.error(msg)
212
234
 
213
235
  elif directive in ["validate",
214
236
  "process"] and object_action == 'Create': # if the object_action is create, check that it
215
237
  # doesn't already exist
216
238
  if parsed_output['exists']:
217
239
  msg = f"Element `{display_name}` cannot be created since it already exists\n"
218
- print_msg(ERROR, msg, debug_level)
240
+ logger.error(msg)
219
241
  parsed_output['valid'] = False
220
242
  else:
221
- msg = f"It is valid to create Element `{display_name}`"
222
- print_msg(ALWAYS, msg, debug_level)
243
+ msg = f"Element `{display_name}` does not exist so it can be created\n"
244
+ logger.info(msg)
245
+
246
+
247
+ if parsed_output.get('qualified_name',None):
248
+ parsed_output['display'] += f"\n\t* Qualified Name: `{parsed_output['qualified_name']}`\n\t"
249
+ if parsed_output.get('guid',None):
250
+ parsed_output['display'] += f"\n\t* GUID: `{parsed_output['guid']}`\n\t"
251
+
252
+ return parsed_output
253
+
254
+
255
+ @logger.catch
256
+ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_action: str, txt: str,
257
+ directive: str = "display") -> dict:
258
+ parsed_attributes, parsed_output = {}, {}
259
+
260
+ parsed_output['valid'] = True
261
+ parsed_output['exists'] = False
262
+
263
+ labels = {}
264
+
265
+ command_spec = get_command_spec(f"{object_action} {object_type}")
266
+ attributes = command_spec.get('Attributes', [])
267
+ command_display_name = command_spec.get('display_name', None)
268
+
269
+ parsed_output['reason'] = ""
270
+ parsed_output['display'] = ""
271
+
272
+ msg = f"\tProcessing {object_action} on {object_type} \n"
273
+ logger.info(msg)
274
+
275
+ # get the version early because we may need it to construct qualified names.
276
+
277
+ for attr in attributes:
278
+ for key in attr:
279
+ # Run some checks to see if the attribute is appropriate to the operation and usage level
280
+
281
+ level = attr[key].get('level', 'Basic')
282
+ msg = (f"___\nProcessing `{key}` in `{object_action}` on a `{object_type}` "
283
+ f"\n\twith usage level: `{EGERIA_USAGE_LEVEL}` ")
284
+ logger.trace(msg)
285
+
286
+ if EGERIA_USAGE_LEVEL == "Basic" and level != "Basic":
287
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
288
+ highlight=True)
289
+ continue
290
+ if EGERIA_USAGE_LEVEL == "Advanced" and level in ["Expert", "Invisible"]:
291
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
292
+ highlight=True)
293
+ continue
294
+ if EGERIA_USAGE_LEVEL == "Expert" and level == "Invisible":
295
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
296
+ highlight=True)
297
+ continue
298
+
299
+ if attr[key].get('input_required', False) is True:
300
+ if_missing = ERROR
301
+ else:
302
+ if_missing = INFO
303
+
304
+ # lab = [item.strip() for item in re.split(r'[;,\n]+',attr[key]['attr_labels'])]
305
+ lab = split_tb_string(attr[key]['attr_labels'])
306
+ labels: set = set()
307
+ labels.add(key.strip())
308
+
309
+ if lab is not None and lab != [""]:
310
+ labels.update(lab)
311
+
312
+ # set these to none since not needed for view commands
313
+ version = None
314
+ command_qn_prefix = None
315
+
316
+ default_value = attr[key].get('default_value', None)
317
+
318
+ style = attr[key]['style']
319
+ if style in ['Simple', 'Dictionary', 'Comment']:
320
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
321
+ elif style == 'Valid Value':
322
+ parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
323
+ attr[key].get('valid_values', None), if_missing,
324
+ default_value)
325
+ elif style == 'QN':
326
+ parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
327
+ object_action, version, if_missing)
328
+ if key == 'Qualified Name' and parsed_attributes[key]['value'] and parsed_attributes[key][
329
+ 'exists'] is False:
330
+ parsed_output['exists'] = False
331
+ elif style == 'ID':
332
+ parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
333
+ object_action, version, if_missing)
334
+
335
+ parsed_output['guid'] = parsed_attributes[key].get('guid', None)
336
+ parsed_output['qualified_name'] = parsed_attributes[key].get('qualified_name', None)
337
+ parsed_output['exists'] = parsed_attributes[key]['exists']
338
+ if parsed_attributes[key]['valid'] is False:
339
+ parsed_output['valid'] = False
340
+ parsed_output['reason'] += parsed_attributes[key]['reason']
341
+
342
+ elif style == 'Reference Name':
343
+ parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
344
+ if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) and parsed_attributes[key][
345
+ 'exists'] is False):
346
+ msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
347
+ logger.error(msg)
348
+ parsed_output['valid'] = False
349
+ parsed_output['reason'] += msg
350
+
351
+ elif style == 'GUID':
352
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
353
+ elif style == 'Ordered Int':
354
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
355
+ elif style == 'Simple Int':
356
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
357
+ elif style == 'Simple List':
358
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
359
+ name_list = parsed_attributes[key]['value']
360
+ # attribute = re.split(r'[;,\n]+', name_list) if name_list is not None else None
361
+ attribute = split_tb_string(name_list)
362
+ parsed_attributes[key]['value'] = attribute
363
+ parsed_attributes[key]['name_list'] = name_list
364
+ elif style == 'Parent':
365
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
366
+ elif style == 'Bool':
367
+ parsed_attributes[key] = proc_bool_attribute(txt, object_action, labels, if_missing, default_value)
368
+
369
+
370
+ elif style == 'Reference Name List':
371
+ parsed_attributes[key] = proc_name_list(egeria_client, key, txt, labels, if_missing)
372
+ if (parsed_attributes[key].get("value", None) and (
373
+ parsed_attributes[key]['exists'] is False or parsed_attributes[key]['valid'] is False)):
374
+ msg = (f"A Reference Name in `{parsed_attributes[key].get('name_list', None)}` is specified but "
375
+ f"does not exist")
376
+ logger.error(msg)
377
+ parsed_output['valid'] = False
378
+ parsed_output['reason'] += msg
379
+ else:
380
+ msg = f"Unknown attribute style: {style}"
381
+ logger.error(msg)
382
+ sys.exit(1)
383
+ parsed_attributes[key]['valid'] = False
384
+ parsed_attributes[key]['value'] = None
385
+
386
+ value = parsed_attributes[key].get('value', None)
387
+
388
+ if value is not None:
389
+ # if the value is a dict, get the flattened name list
390
+ value = parsed_attributes[key].get('name_list', None) if isinstance(value, (dict, list)) else value
391
+ parsed_output['display'] += f"\n\t* {key}: `{value}`\n\t"
223
392
 
224
393
  parsed_output['attributes'] = parsed_attributes
394
+
395
+
396
+ if directive in ["validate", "process"] and not parsed_output['valid'] and object_action == "Update":
397
+ msg = f"Request is invalid, `{object_action} {object_type}` is not valid - see previous messages\n"
398
+ logger.error(msg)
399
+
400
+
225
401
  return parsed_output
226
402
 
227
403
 
404
+ @logger.catch
228
405
  def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str = INFO, default_value=None) -> dict:
229
406
  """Process a simple attribute based on the provided labels and if_missing value.
230
407
  Extract the attribute value from the text and store it in a dictionary along with valid.
@@ -245,27 +422,30 @@ def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str =
245
422
 
246
423
  if if_missing not in ["WARNING", "ERROR", "INFO"]:
247
424
  msg = "Invalid severity for missing attribute"
248
- print_msg("ERROR", msg, debug_level)
425
+ logger.error(msg)
249
426
  return {"status": ERROR, "reason": msg, "value": None, "valid": False}
250
427
 
251
428
  attribute = extract_attribute(txt, labels)
429
+
252
430
  if default_value == "":
253
431
  default_value = None
254
- attribute = default_value if attribute is None else attribute
432
+ attribute = default_value if attribute is None else attribute.replace('\n','')
255
433
 
256
434
  if attribute is None:
257
435
 
258
436
  if if_missing == INFO or if_missing == WARNING:
259
437
  msg = f"Optional attribute with labels: `{labels}` missing"
260
438
  valid = True
439
+ logger.info(msg)
261
440
  else:
262
441
  msg = f"Missing attribute with labels `{labels}` "
263
442
  valid = False
264
- print_msg(if_missing, msg, debug_level)
443
+ logger.error(msg)
265
444
  return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
266
445
  return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
267
446
 
268
447
 
448
+ @logger.catch
269
449
  def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_missing: str = INFO,
270
450
  default_value=None) -> dict:
271
451
  """Process a string attribute to check that it is a member of the associated value values list.
@@ -288,22 +468,22 @@ def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_mi
288
468
 
289
469
  if if_missing not in ["WARNING", "ERROR", "INFO"]:
290
470
  msg = "Invalid severity for missing attribute"
291
- print_msg("ERROR", msg, debug_level)
471
+ logger.error(msg)
292
472
  return {"status": ERROR, "reason": msg, "value": None, "valid": False}
293
473
  if valid_values is None:
294
474
  msg = "Missing valid values list"
295
- print_msg("ERROR", msg, debug_level)
475
+ logger.error(msg)
296
476
  return {"status": WARNING, "reason": msg, "value": None, "valid": False}
297
477
  if isinstance(valid_values, str):
298
478
  # v_values = [item.strip() for item in re.split(r'[;,\n]+', valid_values)]
299
479
  v_values = split_tb_string(valid_values)
300
480
  if not isinstance(v_values, list):
301
481
  msg = "Valid values list is not a list"
302
- print_msg("ERROR", msg, debug_level)
482
+ logger.error(msg)
303
483
  return {"status": WARNING, "reason": msg, "value": None, "valid": False}
304
484
  if len(v_values) == 0:
305
485
  msg = "Valid values list is empty"
306
- print_msg("ERROR", msg, debug_level)
486
+ logger.error(msg)
307
487
  return {"status": WARNING, "reason": msg, "value": None, "valid": False}
308
488
 
309
489
  attribute = extract_attribute(txt, labels)
@@ -314,21 +494,23 @@ def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_mi
314
494
  if attribute is None:
315
495
  if if_missing == INFO or if_missing == WARNING:
316
496
  msg = f"Optional attribute with labels: `{labels}` missing"
497
+ logger.info(msg)
317
498
  valid = True
318
499
  else:
319
500
  msg = f"Missing attribute with labels `{labels}` "
320
501
  valid = False
321
- print_msg(if_missing, msg, debug_level)
502
+ logger.error(msg)
322
503
  return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
323
504
  else:
324
505
  if attribute not in v_values:
325
506
  msg = f"Invalid value for attribute `{labels}`"
326
- print_msg(WARNING, msg, debug_level)
507
+ logger.warning(msg)
327
508
  return {"status": WARNING, "reason": msg, "value": attribute, "valid": False, "exists": True}
328
509
 
329
510
  return {"status": INFO, "OK": "OK", "value": attribute, "valid": valid, "exists": True}
330
511
 
331
512
 
513
+ @logger.catch
332
514
  def proc_bool_attribute(txt: str, action: str, labels: set, if_missing: str = INFO, default_value=None) -> dict:
333
515
  """Process a boolean attribute based on the provided labels and if_missing value.
334
516
  Extract the attribute value from the text and store it in a dictionary along with valid.
@@ -349,7 +531,7 @@ def proc_bool_attribute(txt: str, action: str, labels: set, if_missing: str = IN
349
531
 
350
532
  if if_missing not in ["WARNING", "ERROR", "INFO"]:
351
533
  msg = "Invalid severity for missing attribute"
352
- print_msg("ERROR", msg, debug_level)
534
+ logger.error(msg)
353
535
  return {"status": ERROR, "reason": msg, "value": None, "valid": False}
354
536
 
355
537
  attribute = extract_attribute(txt, labels)
@@ -362,11 +544,12 @@ def proc_bool_attribute(txt: str, action: str, labels: set, if_missing: str = IN
362
544
  if attribute is None:
363
545
  if if_missing == INFO or if_missing == WARNING:
364
546
  msg = f"Optional attribute with labels: `{labels}` missing"
547
+ logger.info(msg)
365
548
  valid = True
366
549
  else:
367
550
  msg = f"Missing attribute with labels `{labels}` "
368
551
  valid = False
369
- print_msg(if_missing, msg, debug_level)
552
+ logger.error(msg)
370
553
  return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
371
554
 
372
555
  if isinstance(attribute, str):
@@ -377,12 +560,13 @@ def proc_bool_attribute(txt: str, action: str, labels: set, if_missing: str = IN
377
560
  attribute = False
378
561
  else:
379
562
  msg = f"Invalid value for boolean attribute `{labels}`"
380
- print_msg("ERROR", msg, debug_level)
563
+ logger.error(msg)
381
564
  return {"status": ERROR, "reason": msg, "value": attribute, "valid": False, "exists": True}
382
565
 
383
566
  return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
384
567
 
385
568
 
569
+ @logger.catch
386
570
  def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, element_labels: list[str], txt: str,
387
571
  action: str, version: str = None, if_missing: str = INFO) -> dict:
388
572
  """
@@ -422,7 +606,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
422
606
 
423
607
  if element_name is None:
424
608
  msg = f"Optional attribute with label`{element_type}` missing"
425
- print_msg("INFO", msg, debug_level)
609
+ logger.info(msg)
426
610
  identifier_output = {"status": INFO, "reason": msg, "value": None, "valid": False, "exists": False, }
427
611
  return identifier_output
428
612
 
@@ -436,18 +620,18 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
436
620
 
437
621
  if unique is False:
438
622
  msg = f"Multiple elements named {element_name} found"
439
- print_msg("DEBUG-ERROR", msg, debug_level)
623
+ logger.error(msg)
440
624
  identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": True, }
441
625
  valid = False
442
626
 
443
627
  if action == "Update" and not exists:
444
628
  msg = f"Element {element_name} does not exist"
445
- print_msg("DEBUG-ERROR", msg, debug_level)
629
+ logger.error(msg)
446
630
  identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": False, }
447
631
 
448
632
  elif action == "Update" and exists:
449
633
  msg = f"Element {element_name} exists"
450
- print_msg("DEBUG-INFO", msg, debug_level)
634
+ logger.info(msg)
451
635
  identifier_output = {
452
636
  "status": INFO, "reason": msg, "value": element_name, "valid": True, "exists": True,
453
637
  'qualified_name': q_name, 'guid': guid
@@ -455,7 +639,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
455
639
 
456
640
  elif action == "Create" and exists:
457
641
  msg = f"Element {element_name} already exists"
458
- print_msg("DEBUG-ERROR", msg, debug_level)
642
+ logger.error(msg)
459
643
  identifier_output = {
460
644
  "status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": True,
461
645
  'qualified_name': qualified_name, 'guid': guid,
@@ -463,7 +647,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
463
647
 
464
648
  elif action == "Create" and not exists and valid:
465
649
  msg = f"{element_type} `{element_name}` does not exist"
466
- print_msg("DEBUG-INFO", msg, debug_level)
650
+ logger.info(msg)
467
651
 
468
652
  if q_name is None and qualified_name is None:
469
653
  q_name = egeria_client.__create_qualified_name__(qn_prefix, element_name, version_identifier=version)
@@ -481,6 +665,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
481
665
  return identifier_output
482
666
 
483
667
 
668
+ @logger.catch
484
669
  def proc_ids(egeria_client: EgeriaTech, element_type: str, element_labels: set, txt: str, action: str,
485
670
  if_missing: str = INFO, version: str = None) -> dict:
486
671
  """
@@ -530,30 +715,30 @@ def proc_ids(egeria_client: EgeriaTech, element_type: str, element_labels: set,
530
715
  if exists is True and unique is False:
531
716
  # Multiple elements found - so need to respecify with qualified name
532
717
  msg = f"Multiple elements named {element_name} found"
533
- print_msg("DEBUG-ERROR", msg, debug_level)
718
+ logger.error(msg)
534
719
  identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": True, }
535
720
 
536
721
 
537
722
  elif action == EXISTS_REQUIRED or if_missing == ERROR and not exists:
538
723
  # a required identifier doesn't exist
539
724
  msg = f"Required {element_type} `{element_name}` does not exist"
540
- print_msg("DEBUG-ERROR", msg, debug_level)
725
+ logger.error(msg)
541
726
  identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": False, }
542
- elif value is None and if_missing == INFO:
727
+ elif value is None and if_missing == INFO:
543
728
  # an optional identifier is empty
544
729
  msg = f"Optional attribute with label`{element_type}` missing"
545
- print_msg("INFO", msg, debug_level)
730
+ logger.info(msg)
546
731
  identifier_output = {"status": INFO, "reason": msg, "value": None, "valid": True, "exists": False, }
547
732
  elif value and exists is False:
548
733
  # optional identifier specified but doesn't exist
549
734
  msg = f"Optional attribute with label`{element_type}` specified but doesn't exist"
550
- print_msg("ERROR", msg, debug_level)
735
+ logger.error(msg)
551
736
  identifier_output = {"status": ERROR, "reason": msg, "value": value, "valid": False, "exists": False, }
552
737
 
553
738
  else:
554
739
  # all good.
555
740
  msg = f"Element {element_type} `{element_name}` exists"
556
- print_msg("DEBUG-INFO", msg, debug_level)
741
+ logger.info(msg)
557
742
  identifier_output = {
558
743
  "status": INFO, "reason": msg, "value": element_name, "valid": True, "exists": True,
559
744
  "qualified_name": q_name, 'guid': guid
@@ -562,6 +747,7 @@ def proc_ids(egeria_client: EgeriaTech, element_type: str, element_labels: set,
562
747
  return identifier_output
563
748
 
564
749
 
750
+ @logger.catch
565
751
  def proc_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, element_labels: set,
566
752
  if_missing: str = INFO) -> dict:
567
753
  """
@@ -595,12 +781,12 @@ def proc_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, eleme
595
781
  id_list_output = {}
596
782
  elements = ""
597
783
  new_element_list = []
598
-
784
+ guid_list = []
599
785
  elements_txt = extract_attribute(txt, element_labels)
600
786
 
601
787
  if elements_txt is None:
602
788
  msg = f"Attribute with labels `{{element_type}}` missing"
603
- print_msg("DEBUG-INFO", msg, debug_level)
789
+ logger.debug(msg)
604
790
  return {"status": if_missing, "reason": msg, "value": None, "valid": False, "exists": False, }
605
791
  else:
606
792
  # element_list = re.split(r'[;,\n]+', elements_txt)
@@ -610,13 +796,14 @@ def proc_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, eleme
610
796
  # Get the element using the generalized function
611
797
  known_q_name, known_guid, el_valid, el_exists = get_element_by_name(egeria_client, element_type, element)
612
798
  details = {"known_q_name": known_q_name, "known_guid": known_guid, "el_valid": el_valid}
613
- elements = f"{element} {elements}" # list of the input names
799
+ elements += element + ", " # list of the input names
614
800
 
615
801
  if el_exists and el_valid:
616
802
  new_element_list.append(known_q_name) # list of qualified names
803
+ guid_list.append(known_guid)
617
804
  elif not el_exists:
618
805
  msg = f"No {element_type} `{element}` found"
619
- print_msg("DEBUG-INFO", msg, debug_level)
806
+ logger.debug(msg)
620
807
  valid = False
621
808
  valid = valid if el_valid is None else (valid and el_valid)
622
809
  exists = exists and el_exists
@@ -624,19 +811,22 @@ def proc_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, eleme
624
811
 
625
812
  if elements:
626
813
  msg = f"Found {element_type}: {elements}"
627
- print_msg("DEBUG-INFO", msg, debug_level)
814
+ logger.debug(msg)
628
815
  id_list_output = {
629
816
  "status": INFO, "reason": msg, "value": element_details, "valid": valid, "exists": exists,
630
- "name_list": new_element_list,
817
+ "name_list": new_element_list, "guid_list": guid_list,
631
818
  }
632
819
  else:
633
820
  msg = f" Name list contains one or more invalid qualified names."
634
- print_msg("DEBUG-INFO", msg, debug_level)
635
- id_list_output = {"status": if_missing, "reason": msg, "value": elements, "valid": valid,
636
- "exists": exists, "dict_list" : element_details}
821
+ logger.debug(msg)
822
+ id_list_output = {
823
+ "status": if_missing, "reason": msg, "value": elements, "valid": valid, "exists": exists,
824
+ "dict_list": element_details, "guid_list": guid_list
825
+ }
637
826
  return id_list_output
638
827
 
639
828
 
829
+ @logger.catch
640
830
  def update_term_categories(egeria_client: EgeriaTech, term_guid: str, categories_exist: bool,
641
831
  categories_list: List[str]) -> None:
642
832
  """
@@ -689,36 +879,19 @@ def update_term_categories(egeria_client: EgeriaTech, term_guid: str, categories
689
879
  egeria_client.add_term_to_category(term_guid, cat)
690
880
  current_categories.append(cat)
691
881
  msg = f"Added term {term_guid} to category {cat}"
692
- print_msg("DEBUG-INFO", msg, debug_level)
882
+ logger.info(msg)
693
883
 
694
884
  for cat in current_categories:
695
885
  if cat not in to_be_cat_guids:
696
886
  egeria_client.remove_term_from_category(term_guid, cat)
697
887
  msg = f"Removed term {term_guid} from category {cat}"
698
- print_msg("DEBUG-INFO", msg, debug_level)
888
+ logger.info(msg)
699
889
  else: # No categories specified - so remove any categories a term is in
700
890
  for cat in current_categories:
701
891
  egeria_client.remove_term_from_category(term_guid, cat)
702
892
  msg = f"Removed term {term_guid} from category {cat}"
703
- print_msg("DEBUG-INFO", msg, debug_level)
704
-
705
- def sync_data_dict_membership(egeria_client: EgeriaTech, in_data_dictionary_names: list , in_data_dictionary: dict,
706
- guid:str, object_type:str)->dict:
707
- pass
708
-
709
- def sync_data_structure_membership(egeria_client: EgeriaTech, in_data_structure_names: list , in_data_structure: dict,
710
- guid:str, object_type:str)->dict:
893
+ logger.info(msg)
711
894
 
712
- pass
713
895
 
714
- def sync_data_spec_membership(egeria_client: EgeriaTech, in_data_spec_names: list , in_data_spec: dict,
715
- guid:str, object_type:str)->dict:
716
- pass
717
896
 
718
- def sync_term_links(egeria_client: EgeriaTech, term_guid: str, links_exist: bool,
719
- links_list: List[str]) -> None:
720
- pass
721
897
 
722
- def sync_parent_data_field(egeria_client: EgeriaTech, term_guid: str, links_exist: bool,
723
- links_list: List[str]) -> None:
724
- pass