pyegeria 5.4.0.23__py3-none-any.whl → 5.4.0.25__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 +7967 -465
- commands/cat/debug_log.2025-08-15_09-14-07_444802.zip +0 -0
- commands/cat/debug_log.2025-08-16_10-21-59_388912.zip +0 -0
- commands/cat/debug_log.2025-08-17_11-34-27_981852.zip +0 -0
- commands/cat/dr_egeria_md.py +36 -6
- commands/cat/logs/pyegeria.log +3 -135
- md_processing/.DS_Store +0 -0
- md_processing/__init__.py +12 -6
- md_processing/data/commands.json +8523 -2234
- md_processing/dr_egeria_inbox/gov_def.md +76 -18
- md_processing/dr_egeria_inbox/img.png +0 -0
- md_processing/dr_egeria_inbox/product.md +185 -24
- md_processing/dr_egeria_outbox/.obsidian/workspace.json +5 -5
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:05-product.md +426 -0
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 07:56-product.md +212 -0
- md_processing/dr_egeria_outbox/monday/processed-2025-08-19 09:43-product.md +201 -0
- md_processing/dr_egeria_outbox/tuesday/processed-2025-08-19 10:55-product.md +209 -0
- md_processing/md_commands/governance_officer_commands.py +247 -178
- md_processing/md_commands/product_manager_commands.py +730 -580
- md_processing/md_processing_utils/common_md_proc_utils.py +170 -12
- md_processing/md_processing_utils/common_md_utils.py +126 -28
- md_processing/md_processing_utils/extraction_utils.py +2 -2
- md_processing/md_processing_utils/md_processing_constants.py +14 -10
- pyegeria/.DS_Store +0 -0
- pyegeria/__init__.py +1 -1
- pyegeria/_client_new.py +61 -12
- pyegeria/_exceptions_new.py +6 -0
- pyegeria/_output_formats.py +42 -2
- pyegeria/collection_manager.py +79 -14
- pyegeria/{data_designer_omvs.py → data_designer.py} +1171 -1675
- pyegeria/glossary_browser.py +1259 -0
- pyegeria/{glossary_manager_omvs.py → glossary_manager.py} +1181 -1099
- pyegeria/governance_officer.py +1 -3
- pyegeria/load_config.py +1 -1
- pyegeria/models.py +37 -4
- pyegeria/output_formatter.py +2 -1
- pyegeria/project_manager.py +1952 -0
- pyegeria/utils.py +5 -2
- {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/METADATA +1 -1
- {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/RECORD +43 -44
- md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:00-product.md +0 -62
- md_processing/dr_egeria_outbox/friday/processed-2025-07-18 15:13-product.md +0 -62
- md_processing/dr_egeria_outbox/friday/processed-2025-07-20 13:23-product.md +0 -47
- md_processing/dr_egeria_outbox/friday/processed-2025-08-01 11:55-data_test3.md +0 -503
- md_processing/dr_egeria_outbox/monday/processed-2025-07-14 12:38-data_designer_out.md +0 -663
- md_processing/dr_egeria_outbox/monday/processed-2025-07-21 10:52-generated_help_report.md +0 -2744
- md_processing/dr_egeria_outbox/monday/processed-2025-07-21 18:38-collections.md +0 -62
- md_processing/dr_egeria_outbox/monday/processed-2025-08-01 11:34-gov_def.md +0 -444
- md_processing/dr_egeria_outbox/processed-2025-08-03 16:05-glossary_list.md +0 -37
- pyegeria/glossary_browser_omvs.py +0 -3840
- pyegeria/governance_officer_omvs.py +0 -2367
- {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/LICENSE +0 -0
- {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/WHEEL +0 -0
- {pyegeria-5.4.0.23.dist-info → pyegeria-5.4.0.25.dist-info}/entry_points.txt +0 -0
@@ -4,10 +4,11 @@ This file contains general utility functions for processing Egeria Markdown
|
|
4
4
|
import json
|
5
5
|
import os
|
6
6
|
import sys
|
7
|
-
from typing import List
|
7
|
+
from typing import List, Optional
|
8
8
|
|
9
9
|
from loguru import logger
|
10
10
|
from rich import print
|
11
|
+
from rich.markdown import Markdown
|
11
12
|
from rich.console import Console
|
12
13
|
|
13
14
|
from md_processing.md_processing_utils.common_md_utils import (get_current_datetime_string, get_element_dictionary,
|
@@ -15,16 +16,20 @@ from md_processing.md_processing_utils.common_md_utils import (get_current_datet
|
|
15
16
|
split_tb_string, str_to_bool, )
|
16
17
|
from md_processing.md_processing_utils.extraction_utils import (process_simple_attribute, extract_attribute,
|
17
18
|
get_element_by_name)
|
19
|
+
from md_processing.md_processing_utils.common_md_utils import (update_element_dictionary, set_gov_prop_body, \
|
20
|
+
set_update_body, set_create_body,
|
21
|
+
set_peer_gov_def_request_body, set_rel_request_body,
|
22
|
+
set_delete_request_body,set_rel_request_body,
|
23
|
+
set_filter_request_body, setup_log,
|
24
|
+
ALL_GOVERNANCE_DEFINITIONS, set_find_body)
|
25
|
+
from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
|
18
26
|
from md_processing.md_processing_utils.md_processing_constants import (get_command_spec)
|
19
27
|
from md_processing.md_processing_utils.message_constants import (ERROR, INFO, WARNING, ALWAYS, EXISTS_REQUIRED)
|
20
|
-
from pyegeria import EgeriaTech
|
28
|
+
from pyegeria import EgeriaTech, select_output_format_set
|
29
|
+
|
21
30
|
from pyegeria._globals import DEBUG_LEVEL
|
22
31
|
|
23
|
-
|
24
|
-
logger.remove()
|
25
|
-
logger.add(sys.stderr, level="INFO", format=log_format, colorize=True)
|
26
|
-
logger.add("debug_log.log", rotation="1 day", retention="1 week", compression="zip", level="TRACE", format=log_format,
|
27
|
-
colorize=True)
|
32
|
+
|
28
33
|
# Constants
|
29
34
|
EGERIA_WIDTH = int(os.environ.get("EGERIA_WIDTH", "200"))
|
30
35
|
EGERIA_USAGE_LEVEL = os.environ.get("EGERIA_USAGE_LEVEL", "Basic")
|
@@ -124,8 +129,12 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
|
|
124
129
|
default_value = attr[key].get('default_value', None)
|
125
130
|
|
126
131
|
style = attr[key]['style']
|
127
|
-
if style in ['Simple', '
|
132
|
+
if style in ['Simple', 'Comment']:
|
128
133
|
parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
|
134
|
+
elif style == 'Dictionary':
|
135
|
+
parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing, default_value)
|
136
|
+
parsed_attributes[key]['name_list'] = json.dumps(parsed_attributes[key]['value'], indent=2)
|
137
|
+
|
129
138
|
elif style == 'Valid Value':
|
130
139
|
parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
|
131
140
|
attr[key].get('valid_values', None), if_missing,
|
@@ -325,8 +334,12 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
|
|
325
334
|
default_value = attr[key].get('default_value', None)
|
326
335
|
|
327
336
|
style = attr[key]['style']
|
328
|
-
if style in ['Simple', '
|
337
|
+
if style in ['Simple', 'Comment']:
|
329
338
|
parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
|
339
|
+
elif style == 'Dictionary':
|
340
|
+
parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing,
|
341
|
+
default_value)
|
342
|
+
parsed_attributes[key]['name_list'] = json.dumps(parsed_attributes[key]['value'], indent=2)
|
330
343
|
elif style == 'Valid Value':
|
331
344
|
parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
|
332
345
|
attr[key].get('valid_values', None), if_missing,
|
@@ -401,7 +414,7 @@ def parse_view_command(egeria_client: EgeriaTech, object_type: str, object_actio
|
|
401
414
|
value = parsed_attributes[key].get('value', None)
|
402
415
|
|
403
416
|
if value is not None:
|
404
|
-
# if the value is a dict, get the
|
417
|
+
# if the value is a dict or list, get the stringifiedt
|
405
418
|
value = parsed_attributes[key].get('name_list', None) if isinstance(value, (dict, list)) else value
|
406
419
|
parsed_output['display'] += f"\n\t* {key}: `{value}`\n\t"
|
407
420
|
|
@@ -464,6 +477,50 @@ def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str =
|
|
464
477
|
|
465
478
|
return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
|
466
479
|
|
480
|
+
@logger.catch
|
481
|
+
def proc_dictionary_attribute(txt: str, action: str, labels: set, if_missing: str = INFO, default_value=None,
|
482
|
+
simp_type: str = None) -> dict:
|
483
|
+
"""Process a dictionary attribute based on the provided labels and if_missing value.
|
484
|
+
Extract the attribute value from the text and store it in a dictionary along with valid.
|
485
|
+
If it doesn`t exist, mark the dictionary entry as invalid and print an error message with severity of if_missing.
|
486
|
+
|
487
|
+
Parameters:
|
488
|
+
----------
|
489
|
+
txt: str
|
490
|
+
The block of object_action text to extract attributes from.
|
491
|
+
labels: list
|
492
|
+
The possible attribute labels to search for. The first label will be used in messages.
|
493
|
+
if_missing: str, default is INFO
|
494
|
+
Can be one of "WARNING", "ERROR", "INFO". The severity of the missing attribute.
|
495
|
+
default_value: default is None
|
496
|
+
The default value to return if the attribute is missing.
|
497
|
+
"""
|
498
|
+
valid = True
|
499
|
+
|
500
|
+
if if_missing not in ["WARNING", "ERROR", "INFO"]:
|
501
|
+
msg = "Invalid severity for missing attribute"
|
502
|
+
logger.error(msg)
|
503
|
+
return {"status": ERROR, "reason": msg, "value": None, "valid": False}
|
504
|
+
|
505
|
+
if default_value == "":
|
506
|
+
default_value = None
|
507
|
+
|
508
|
+
attr = extract_attribute(txt, labels)
|
509
|
+
attribute = json.loads(attr) if attr is not None else default_value
|
510
|
+
|
511
|
+
|
512
|
+
if attribute is None:
|
513
|
+
if if_missing == INFO or if_missing == WARNING:
|
514
|
+
msg = f"Optional attribute with labels: `{labels}` missing"
|
515
|
+
valid = True
|
516
|
+
logger.info(msg)
|
517
|
+
else:
|
518
|
+
msg = f"Missing attribute with labels `{labels}` "
|
519
|
+
valid = False
|
520
|
+
logger.error(msg)
|
521
|
+
return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
|
522
|
+
|
523
|
+
return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
|
467
524
|
|
468
525
|
@logger.catch
|
469
526
|
def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_missing: str = INFO,
|
@@ -524,8 +581,11 @@ def proc_valid_value(txt: str, action: str, labels: set, valid_values: [], if_mi
|
|
524
581
|
logger.error(msg)
|
525
582
|
return {"status": if_missing, "reason": msg, "value": None, "valid": valid, "exists": False}
|
526
583
|
else:
|
584
|
+
# Todo: look at moving validation into pydantic or another style...
|
585
|
+
if "Status" in labels:
|
586
|
+
attribute = attribute.upper()
|
527
587
|
if attribute not in v_values:
|
528
|
-
msg = f"Invalid value for attribute `{labels}`"
|
588
|
+
msg = f"Invalid value for attribute `{labels}` attribute is `{attribute}`"
|
529
589
|
logger.warning(msg)
|
530
590
|
return {"status": WARNING, "reason": msg, "value": attribute, "valid": False, "exists": True}
|
531
591
|
|
@@ -651,7 +711,7 @@ def proc_el_id(egeria_client: EgeriaTech, element_type: str, qn_prefix: str, ele
|
|
651
711
|
logger.error(msg)
|
652
712
|
identifier_output = {"status": ERROR, "reason": msg, "value": element_name, "valid": False, "exists": False, }
|
653
713
|
|
654
|
-
elif action in ["Update", "View"] and exists:
|
714
|
+
elif action in ["Update", "View", "Link", "Detach"] and exists:
|
655
715
|
msg = f"Element {element_name} exists"
|
656
716
|
logger.info(msg)
|
657
717
|
identifier_output = {
|
@@ -923,3 +983,101 @@ def update_term_categories(egeria_client: EgeriaTech, term_guid: str, categories
|
|
923
983
|
|
924
984
|
|
925
985
|
|
986
|
+
|
987
|
+
@logger.catch
|
988
|
+
def process_output_command(egeria_client: EgeriaTech, txt: str, directive: str = "display") -> Optional[str]:
|
989
|
+
"""
|
990
|
+
Processes a generic output request by extracting attributes (including Output Format and
|
991
|
+
Output Format Set) and dynamically invoking the find function specified by the
|
992
|
+
output_format_set, following the approach used in commands/cat/list_format_set.
|
993
|
+
|
994
|
+
This is modeled on process_gov_definition_list_command but uses the dynamic
|
995
|
+
dispatch via the output format set rather than directly calling a specific
|
996
|
+
egeria_client method.
|
997
|
+
|
998
|
+
:param egeria_client: EgeriaTech composite client instance
|
999
|
+
:param txt: The command text (e.g., parsed from a markdown cell)
|
1000
|
+
:param directive: display | validate | process
|
1001
|
+
:return: Markdown string for processed output or None
|
1002
|
+
"""
|
1003
|
+
command, object_type, object_action = extract_command_plus(txt)
|
1004
|
+
print(Markdown(f"# {command}\n"))
|
1005
|
+
|
1006
|
+
parsed_output = parse_view_command(egeria_client, object_type, object_action, txt, directive)
|
1007
|
+
|
1008
|
+
valid = parsed_output['valid']
|
1009
|
+
print(Markdown(f"Performing {command}"))
|
1010
|
+
print(Markdown(parsed_output['display']))
|
1011
|
+
|
1012
|
+
attr = parsed_output.get('attributes', {})
|
1013
|
+
|
1014
|
+
search_string = attr.get('Search String', {}).get('value', '*')
|
1015
|
+
output_format = attr.get('Output Format', {}).get('value', 'LIST')
|
1016
|
+
output_format_set = attr.get('Output Format Set', {}).get('value', object_type)
|
1017
|
+
|
1018
|
+
if directive == "display":
|
1019
|
+
return None
|
1020
|
+
elif directive == "validate":
|
1021
|
+
# Validate that the format set exists and has an action
|
1022
|
+
fmt = select_output_format_set(output_format_set, "ANY") if valid else None
|
1023
|
+
if valid and fmt and fmt.get("action"):
|
1024
|
+
print(Markdown(f"==> Validation of {command} completed successfully!\n"))
|
1025
|
+
return True
|
1026
|
+
else:
|
1027
|
+
msg = f"Validation failed for object_action `{command}`"
|
1028
|
+
logger.error(msg)
|
1029
|
+
return False
|
1030
|
+
|
1031
|
+
elif directive == "process":
|
1032
|
+
try:
|
1033
|
+
if not valid:
|
1034
|
+
msg = f"Validation failed for {object_action} `{object_type}`"
|
1035
|
+
logger.error(msg)
|
1036
|
+
return None
|
1037
|
+
|
1038
|
+
# Resolve the find function from the output format set
|
1039
|
+
fmt = select_output_format_set(output_format_set, output_format)
|
1040
|
+
if not fmt:
|
1041
|
+
logger.error(f"Output format set '{output_format_set}' not found or not compatible with '{output_format}'.")
|
1042
|
+
return None
|
1043
|
+
action = fmt.get("action", {})
|
1044
|
+
func_spec = action.get("function")
|
1045
|
+
if not func_spec or "." not in func_spec:
|
1046
|
+
func_spec = f"EgeriaTech.find_{object_type.replace(' ', '_').lower()}"
|
1047
|
+
|
1048
|
+
|
1049
|
+
# Extract method name and get it from the composite client
|
1050
|
+
_, method_name = func_spec.split(".", 1)
|
1051
|
+
if not hasattr(egeria_client, method_name):
|
1052
|
+
logger.error(f"Method '{method_name}' not available on EgeriaTech client.")
|
1053
|
+
return None
|
1054
|
+
method = getattr(egeria_client, method_name)
|
1055
|
+
|
1056
|
+
# Build body and params
|
1057
|
+
list_md = f"\n# `{object_type}` with filter: `{search_string}`\n\n"
|
1058
|
+
body = set_find_body(object_type, attr)
|
1059
|
+
|
1060
|
+
params = {
|
1061
|
+
'search_string': search_string,
|
1062
|
+
'body': body,
|
1063
|
+
'output_format': output_format,
|
1064
|
+
'output_format_set': output_format_set,
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
# Call the resolved method
|
1068
|
+
struct = method(**params)
|
1069
|
+
|
1070
|
+
if output_format.upper() == "DICT":
|
1071
|
+
list_md += f"```\n{json.dumps(struct, indent=4)}\n```\n"
|
1072
|
+
else:
|
1073
|
+
list_md += struct
|
1074
|
+
logger.info(f"Wrote `{object_type}` for search string: `{search_string}` using format set '{output_format_set}'")
|
1075
|
+
|
1076
|
+
return list_md
|
1077
|
+
|
1078
|
+
except Exception as e:
|
1079
|
+
logger.error(f"Error performing {command}: {e}")
|
1080
|
+
console.print_exception(show_locals=True)
|
1081
|
+
return None
|
1082
|
+
else:
|
1083
|
+
return None
|
@@ -11,7 +11,7 @@ from loguru import logger
|
|
11
11
|
from rich import print
|
12
12
|
from rich.console import Console
|
13
13
|
from rich.markdown import Markdown
|
14
|
-
from pyegeria.utils import (camel_to_title_case)
|
14
|
+
from pyegeria.utils import (camel_to_title_case, body_slimmer)
|
15
15
|
from pyegeria._globals import DEBUG_LEVEL
|
16
16
|
from md_processing.md_processing_utils.message_constants import message_types
|
17
17
|
|
@@ -38,11 +38,22 @@ LOG_FORMAT = "D <green> {time} </green> | {level} | {function} | {line} | {messa
|
|
38
38
|
CONSOLE_LOG_FORMAT = "<green>{time}</green> | {message}"
|
39
39
|
|
40
40
|
console = Console(width=EGERIA_WIDTH)
|
41
|
-
GENERAL_GOVERNANCE_DEFINITIONS = ["Business Imperative", "Regulation Article", "Threat",
|
42
|
-
"Governance
|
41
|
+
GENERAL_GOVERNANCE_DEFINITIONS = ["Governance Definition", "Business Imperative", "Regulation Article", "Threat",
|
42
|
+
"Governance Policy", "Governance Principle", "Governance Obligation",
|
43
|
+
"Governance Approach",
|
44
|
+
"Governance Processing Purpose"]
|
45
|
+
GOVERNANCE_DRIVERS = ["Governance Driver", "Governance Strategy", "Governance Imperative", "Regulation",
|
46
|
+
"Regulation Article", "Threat"]
|
47
|
+
GOVERNANCE_POLICIES = ["Governance Policy", "Governance Principle", "Governance Obligation", "Governance Approach"]
|
43
48
|
|
44
|
-
|
45
|
-
|
49
|
+
|
50
|
+
GOVERNANCE_CONTROLS = ["Governance Control", "Governance Rule", "Service Level Objective", "Governance Action",
|
51
|
+
"Security Access Control", "Governance Procedure","Governance Responsibility",
|
52
|
+
"Subject Area Definition", "Data Processing Purposes", "Methodology"]
|
53
|
+
|
54
|
+
ALL_GOVERNANCE_DEFINITIONS = GENERAL_GOVERNANCE_DEFINITIONS + GOVERNANCE_CONTROLS + ["Governance Strategy", "Regulation",
|
55
|
+
"Security Group", "GovernanceMetric",
|
56
|
+
"Naming Standard Rule", "TermsAndConditions", "Certification Type", "License Type"]
|
46
57
|
|
47
58
|
debug_level = DEBUG_LEVEL
|
48
59
|
global COMMAND_DEFINITIONS
|
@@ -216,13 +227,46 @@ def find_key_with_value(value: str) -> str | None:
|
|
216
227
|
return None # If value not found
|
217
228
|
|
218
229
|
|
230
|
+
def set_find_body(object_type: str, attributes: dict)->dict:
|
231
|
+
prop_name = object_type.replace(" ", "")
|
232
|
+
|
233
|
+
start = attributes.get('Start From', {}).get('value', 0)
|
234
|
+
start_from = int(start) if start else 0
|
235
|
+
page = attributes.get('Page Size', {}).get('value', 0)
|
236
|
+
page_size = int(page) if page else 0
|
237
|
+
depth = attributes.get('Graph Query Depth', {}).get('value', 0)
|
238
|
+
depth = int(depth) if depth else 0
|
239
|
+
|
240
|
+
|
241
|
+
|
242
|
+
body = {
|
243
|
+
"class": "SearchStringRequestBody",
|
244
|
+
"searchString": attributes.get('Search String', {}).get('value', None),
|
245
|
+
"startsWith": attributes.get('Start With', {}).get('value', True),
|
246
|
+
"endWith": attributes.get('End With', {}).get('value', False),
|
247
|
+
"ignoreCase": attributes.get('Ignore Case', {}).get('value', False),
|
248
|
+
"limitResultsByStatus": attributes.get('Limit Results By Status', {}).get('value', False),
|
249
|
+
"startFrom": int(attributes.get('Start From', {}).get('value', 0)),
|
250
|
+
"pageSize": int(attributes.get('Page Size', {}).get('value', 0)),
|
251
|
+
# "metadataElementSubtypeNames": attributes.get('Metadata Element Subtype Name', {}).get('value', None),
|
252
|
+
"metadataElementTypeName": attributes.get('Metadata Element Type Name', {}).get('value', None),
|
253
|
+
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
254
|
+
"governanceZoneFilter" : attributes.get('Governance Zone Filter', {}).get('value', None),
|
255
|
+
"graphQueryDepth": int(attributes.get('Graph Query Depth', {}).get('value', 0)),
|
256
|
+
"initialStatus": attributes.get('Status', {}).get('value', "ACTIVE"),
|
257
|
+
"initialClassifications": {}}
|
258
|
+
|
259
|
+
return body
|
260
|
+
|
261
|
+
|
219
262
|
def set_create_body(object_type: str, attributes: dict)->dict:
|
220
263
|
prop_name = object_type.replace(" ", "")
|
221
264
|
body = {
|
222
|
-
"class": "
|
265
|
+
"class": "NewElementRequestBody",
|
223
266
|
"externalSourceGUID": attributes.get('External Source GUID', {}).get('guid', None),
|
224
267
|
"externalSourceName": attributes.get('External Source Name', {}).get('value', None),
|
225
268
|
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
269
|
+
"governanceZoneFilter" : attributes.get('Governance Zone Filter', {}).get('value', None),
|
226
270
|
"forLineage": attributes.get('For Lineage', {}).get('value', False),
|
227
271
|
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False),
|
228
272
|
"anchorGUID": attributes.get('Anchor ID', {}).get('guid', None),
|
@@ -245,6 +289,7 @@ def set_update_body(object_type: str, attributes: dict)->dict:
|
|
245
289
|
"class" : "UpdateElementRequestBody",
|
246
290
|
"externalSourceGUID": attributes.get('External Source GUID', {}).get('guid', None),
|
247
291
|
"externalSourceName": attributes.get('External Source Name', {}).get('value', None),
|
292
|
+
"governanceZoneFilter": attributes.get('Governance Zone Filter', {}).get('value', None),
|
248
293
|
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
249
294
|
"forLineage": attributes.get('For Lineage', {}).get('value', False),
|
250
295
|
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False),
|
@@ -261,35 +306,66 @@ def set_prop_body(object_type: str, qualified_name: str, attributes: dict)->dict
|
|
261
306
|
"displayName": attributes['Display Name'].get('value', None),
|
262
307
|
"qualifiedName" : qualified_name,
|
263
308
|
"description": attributes['Description'].get('value', None),
|
264
|
-
"
|
309
|
+
"category": attributes.get('Category', {}).get('value', None),
|
310
|
+
"identifier": attributes.get('Identifier', {}).get('value', None),
|
265
311
|
"userDefinedStatus": attributes.get('User Defined Status', {}).get('value', None),
|
266
312
|
"versionIdentifier": attributes.get('Version Identifier', {}).get('value', None),
|
267
313
|
"effectiveFrom": attributes.get('Effective From', {}).get('value', None),
|
268
314
|
"effectiveTo": attributes.get('Effective To', {}).get('value', None),
|
269
315
|
"additionalProperties": attributes.get('Additional Properties', {}).get('value', None),
|
270
|
-
"extendedProperties": attributes.get('Extended Properties', {}).get('value', None)
|
316
|
+
"extendedProperties": attributes.get('Extended Properties', {}).get('value', None),
|
317
|
+
"supportLevel": attributes.get('Support Level', {}).get('value', None),
|
318
|
+
"serviceLevels": attributes.get('Service Levels', {}).get('value', None),
|
271
319
|
}
|
272
320
|
|
321
|
+
def set_product_body(object_type: str, qualified_name: str, attributes: dict)->dict:
|
322
|
+
prop_bod = set_prop_body(object_type, qualified_name, attributes)
|
323
|
+
prop_bod["identifier"] = attributes.get('Identifier', {}).get('value', None)
|
324
|
+
prop_bod["productName"] = attributes.get('Product Name', {}).get('value', None)
|
325
|
+
prop_bod["maturity"] = attributes.get('Maturity', {}).get('value', None)
|
326
|
+
prop_bod["serviceLife"] = attributes.get('Service Life', {}).get('value', None)
|
327
|
+
prop_bod["introductionDate"] = attributes.get('Introduction Date', {}).get('value', [])
|
328
|
+
prop_bod["withdrawalDate"] = attributes.get('Withdrawal Date', {}).get('value', [])
|
329
|
+
prop_bod["nextVersion"] = attributes.get('Next Version Date', {}).get('value', [])
|
330
|
+
return prop_bod
|
331
|
+
|
332
|
+
|
333
|
+
|
334
|
+
def set_update_status_body(object_type: str, attributes: dict)->dict:
|
335
|
+
return {
|
336
|
+
"class" : "UpdateStatusRequestBody",
|
337
|
+
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
338
|
+
"forLineage": attributes.get('For Lineage', {}).get('value', False),
|
339
|
+
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False),
|
340
|
+
"mergeUpdate": attributes.get('Merge Update', {}).get('value', True),
|
341
|
+
}
|
342
|
+
|
273
343
|
def set_gov_prop_body(object_type: str, qualified_name: str, attributes: dict)->dict:
|
274
344
|
prop_name = object_type.replace(" ", "")
|
275
345
|
prop_bod = set_prop_body(object_type, qualified_name, attributes)
|
276
346
|
prop_bod["domainIdentifier"] = attributes.get('Domain Identifier', {}).get('value', None)
|
277
|
-
|
278
|
-
prop_bod[
|
279
|
-
prop_bod['documentIdentifier'] = qualified_name
|
347
|
+
prop_bod["displayName"]= attributes.get('Display Name', {}).get('value', None)
|
348
|
+
prop_bod['qualifiedName'] = qualified_name
|
280
349
|
prop_bod["versionIdentifier"] = attributes.get('Version Identifier', {}).get('value', None)
|
281
350
|
prop_bod["summary"] = attributes.get('Summary', {}).get('value', None)
|
351
|
+
prop_bod["description"] = attributes.get('Description', {}).get('value', None)
|
352
|
+
|
282
353
|
prop_bod["scope"] = attributes.get('Scope', {}).get('value', None)
|
283
354
|
prop_bod["importance"] = attributes.get('Importance', {}).get('value', None)
|
284
355
|
prop_bod["implications"] = attributes.get('Implication', {}).get('value', [])
|
285
356
|
prop_bod["outcomes"] = attributes.get('Outcomes', {}).get('value', [])
|
286
357
|
prop_bod["results"] = attributes.get('Results', {}).get('value', [])
|
358
|
+
prop_bod["effectiveFrom"] = attributes.get('Effective From', {}).get('value', None),
|
359
|
+
prop_bod["effectiveTo"] = attributes.get('Effective To', {}).get('value', None),
|
360
|
+
prop_bod["additionalProperties"] = attributes.get('Additional Properties', {}).get('value', None),
|
361
|
+
prop_bod["extendedProperties"] = attributes.get('Extended Properties', {}).get('value', None)
|
287
362
|
|
288
|
-
|
363
|
+
|
364
|
+
body = update_gov_body_for_type(object_type, prop_bod, attributes)
|
289
365
|
return body
|
290
366
|
|
291
367
|
|
292
|
-
def
|
368
|
+
def update_gov_body_for_type(object_type: str, body: dict, attributes: dict) -> dict:
|
293
369
|
gov_def_name = object_type.replace(" ", "")
|
294
370
|
if object_type in GENERAL_GOVERNANCE_DEFINITIONS:
|
295
371
|
return body
|
@@ -298,7 +374,7 @@ def update_body_for_type(object_type: str, body: dict, attributes: dict) -> dict
|
|
298
374
|
return body
|
299
375
|
|
300
376
|
elif object_type == "Regulation":
|
301
|
-
body['
|
377
|
+
body['regulationSource'] = attributes.get('Regulation Source', {}).get('value', None)
|
302
378
|
body['regulators'] = attributes.get('Regulators', {}).get('value', [])
|
303
379
|
return body
|
304
380
|
|
@@ -308,17 +384,24 @@ def update_body_for_type(object_type: str, body: dict, attributes: dict) -> dict
|
|
308
384
|
elif object_type == "Security Group":
|
309
385
|
body['distinguishedName'] = attributes.get('Distinguished Name', {}).get('value', None)
|
310
386
|
return body
|
387
|
+
elif object_type == "GovernanceMetric":
|
388
|
+
body['measurement'] = attributes.get('Measurement', {}).get('value', None)
|
389
|
+
body['target'] = attributes.get('Target', {}).get('value', None)
|
390
|
+
return body
|
311
391
|
elif object_type == "Naming Standard Rule":
|
312
392
|
body['namePatterns'] = attributes.get('Name Patterns', {}).get('value', [])
|
313
393
|
return body
|
314
|
-
elif object_type in ["Certification Type", "License Type"]:
|
315
|
-
body['
|
394
|
+
elif object_type in ["TermsAndConditions", "Certification Type", "License Type"]:
|
395
|
+
body['entitlements'] = attributes.get('Entitlementss', {}).get('value', {})
|
396
|
+
body['restrictions'] = attributes.get('Restrictions', {}).get('value', {})
|
397
|
+
body['obligations'] = attributes.get('Obligations', {}).get('value', {})
|
398
|
+
|
316
399
|
return body
|
317
400
|
|
318
401
|
|
319
402
|
def set_rel_request_body(object_type: str, attributes: dict)->dict:
|
320
403
|
return {
|
321
|
-
"class" : "
|
404
|
+
"class" : "NewRelationshipRequestBody",
|
322
405
|
"externalSourceGUID": attributes.get('External Source GUID', {}).get('guid', None),
|
323
406
|
"externalSourceName": attributes.get('External Source Name', {}).get('value', None),
|
324
407
|
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
@@ -338,9 +421,9 @@ def set_peer_gov_def_request_body(object_type: str, attributes: dict)->dict:
|
|
338
421
|
}
|
339
422
|
return rel_body
|
340
423
|
|
341
|
-
def
|
424
|
+
def set_delete_request_body(object_type: str, attributes: dict)->dict:
|
342
425
|
return {
|
343
|
-
"class": "
|
426
|
+
"class": "DeleteRequestBody",
|
344
427
|
"externalSourceGUID": attributes.get('External Source GUID', {}).get('guid', None),
|
345
428
|
"externalSourceName": attributes.get('External Source Name', {}).get('value', None),
|
346
429
|
"effectiveTime": attributes.get('Effective Time', {}).get('value', None),
|
@@ -348,6 +431,8 @@ def set_metadata_source_request_body(object_type: str, attributes: dict)->dict:
|
|
348
431
|
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False)
|
349
432
|
}
|
350
433
|
|
434
|
+
|
435
|
+
|
351
436
|
def set_filter_request_body(object_type: str, attributes: dict)->dict:
|
352
437
|
return {
|
353
438
|
"class": "FilterRequestBody",
|
@@ -371,14 +456,27 @@ def set_element_status_request_body(object_type: str, attributes: dict)->dict:
|
|
371
456
|
"forLineage": attributes.get('For Lineage', {}).get('value', False),
|
372
457
|
"forDuplicateProcessing": attributes.get('For Duplicate Processing', {}).get('value', False)
|
373
458
|
}
|
374
|
-
def set_collection_property_body(object_type: str, qualified_name:str, attributes: dict)->dict:
|
375
|
-
body = set_prop_body("Collection", qualified_name,attributes)
|
376
|
-
body["category"] = attributes.get('Category', {}).get('value', None)
|
377
|
-
return body
|
378
459
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
460
|
+
|
461
|
+
def set_classifications(object_type: str, attributes: dict)->dict:
|
462
|
+
classifications = attributes.get('Classifications', {}).get('name_list', None)
|
463
|
+
body = None
|
464
|
+
if classifications:
|
465
|
+
body = {classification: {} for classification in classifications} if cclassifications else {}
|
384
466
|
return body
|
467
|
+
|
468
|
+
def set_collection_classifications(object_type: str, attributes: dict, obj_types: list[str])->dict:
|
469
|
+
classifications = attributes.get('Classifications', {}).get('name_list', None)
|
470
|
+
obj = object_type.replace(" ", "")
|
471
|
+
if object_type in obj_types:
|
472
|
+
if classifications:
|
473
|
+
if object_type not in classifications:
|
474
|
+
classifications.append(obj)
|
475
|
+
else:
|
476
|
+
classifications = [obj]
|
477
|
+
|
478
|
+
body = {}
|
479
|
+
if classifications:
|
480
|
+
for classification in classifications:
|
481
|
+
body[classification] = {"class" : f"{classification}Properties"}
|
482
|
+
return body
|
@@ -91,7 +91,7 @@ def extract_attribute(text: str, labels: set) -> str | None:
|
|
91
91
|
# Iterate over the list of labels
|
92
92
|
for label in labels:
|
93
93
|
# Construct pattern for the current label
|
94
|
-
# text = re.sub(r'\s+', ' ', text).strip()
|
94
|
+
# text = re.sub(r'\s+', ' ', text).strip() # just added
|
95
95
|
text = re.sub(r'\n\n+', '\n\n', text).strip()
|
96
96
|
|
97
97
|
label = label.strip()
|
@@ -395,7 +395,7 @@ def get_element_by_name(egeria_client, element_type: str, element_name: str) ->
|
|
395
395
|
return q_name, guid, unique, exists
|
396
396
|
|
397
397
|
else: # Missing guid from element_dictionary
|
398
|
-
guid = egeria_client.
|
398
|
+
guid = egeria_client.__get_guid__(qualified_name=q_name)
|
399
399
|
if guid == NO_ELEMENTS_FOUND:
|
400
400
|
guid = None
|
401
401
|
exists = False
|
@@ -51,9 +51,10 @@ TERM_RELATIONSHPS = ["Synonym", "Translation", "PreferredTerm", "TermISATYPEOFRe
|
|
51
51
|
"ISARelationship"]
|
52
52
|
|
53
53
|
# List of supported md_commands
|
54
|
-
GOV_LINK_LIST = [ "Link Governance Drivers", "Detach Governance Drivers",
|
55
|
-
"Link Governance Policies", "Detach Governance Policies",
|
56
|
-
"Link Governance Controls", "Detach Governance Controls",
|
54
|
+
GOV_LINK_LIST = [ "Link Governance Drivers", "Link Drivers", "Detach Governance Drivers", "Detach Drivers",
|
55
|
+
"Link Governance Policies", "Link Policies", "Detach Governance Policies", "Detach Policies",
|
56
|
+
"Link Governance Controls", "Link Controls", "Detach Governance Controls", "Detach Controls",
|
57
|
+
]
|
57
58
|
|
58
59
|
GOV_COM_LIST = [ "Create Business Imperative", "Update Business Imperative",
|
59
60
|
"Create Regulation Article Definition", "Update Regulation Article Definition",
|
@@ -130,20 +131,21 @@ command_list = ["Provenance", "Create Glossary", "Update Glossary", "Create Term
|
|
130
131
|
"View Dataa Classes", "View Data Class", "Create Data Class", "Update Data Class",
|
131
132
|
"Create Digital Product", "Create Data Product", "Update Digital Product", "Update Data Product",
|
132
133
|
"Create Agreement", "Update Agreement",
|
133
|
-
"Link Digital Products", "Link
|
134
|
-
|
134
|
+
"Link Digital Products", "Link Product-Product", "Detach Digital Products", "Detach Product-Product",
|
135
|
+
"Create Data Sharing Agreement", "Update Data Sharing Agreement",
|
135
136
|
"Create Digital Subscription", "Create Product Subscription", "Update Digital Subscription", "Update Product Subscription",
|
136
|
-
"
|
137
|
+
"Link Agreement->Item", "Detach Agreement->Item",
|
137
138
|
"Attach Contract", "Detach Contract",
|
138
|
-
"
|
139
|
-
"Link Collection
|
140
|
-
"Unlink Collection
|
139
|
+
"Link Subscriber->Subscription", "Detach Subscriber->Subscription",
|
140
|
+
"Link Collection->Resource", "Attach Collection->Resource",
|
141
|
+
"Unlink Collection->Resource", "Detach Collection->Resource",
|
141
142
|
"Add Member to Collection", "Add Member", "Member->Collection",
|
142
|
-
"Remove Member from Collection","Remove Member
|
143
|
+
"Remove Member from Collection","Remove Member->Collection",
|
143
144
|
"View Governance Definitions", "View Gov Definitions",
|
144
145
|
"List Governance Definitions", "List Gov Definitions",
|
145
146
|
"View Governance Definition Context","List Governance Definition Context",
|
146
147
|
"View Governance Def Context", "List Governance Def Context",
|
148
|
+
"View Report",
|
147
149
|
# "Create Business Imperative", "Update Business Imperative",
|
148
150
|
# "Create Regulation Article Definition", "Update Regulation Article Definition",
|
149
151
|
# "Create Threat Definition", "Update Threat Definition",
|
@@ -173,6 +175,8 @@ command_list.extend(GOV_COM_LIST)
|
|
173
175
|
command_list.extend(GOV_LINK_LIST)
|
174
176
|
command_list.extend(COLLECTIONS_LIST)
|
175
177
|
command_list.extend(SIMPLE_COLLECTIONS)
|
178
|
+
command_list.extend(["Link Governance Response", "Detach Governance Response",
|
179
|
+
"Link Governance Mechanism", "Detach Governance Mechanism"])
|
176
180
|
|
177
181
|
pre_command = "\n---\n==> Processing object_action:"
|
178
182
|
command_seperator = Markdown("\n---\n")
|
pyegeria/.DS_Store
CHANGED
Binary file
|
pyegeria/__init__.py
CHANGED
@@ -30,7 +30,7 @@ from ._client_new import Client2
|
|
30
30
|
from ._exceptions_new import (PyegeriaInvalidParameterException,PyegeriaAPIException, PyegeriaException,
|
31
31
|
PyegeriaUnauthorizedException, PyegeriaClientException, PyegeriaUnknownException,
|
32
32
|
PyegeriaConnectionException, PyegeriaNotFoundException,
|
33
|
-
print_exception_table, print_basic_exception)
|
33
|
+
print_exception_table, print_basic_exception, print_validation_error)
|
34
34
|
from .load_config import load_app_config, get_app_config
|
35
35
|
from .logging_configuration import config_logging, console_log_filter, init_logging
|
36
36
|
from ._exceptions import (InvalidParameterException, PropertyServerException, UserNotAuthorizedException,
|