pyegeria 5.3.9.9.3__py3-none-any.whl → 5.5.3.3__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.
Potentially problematic release.
This version of pyegeria might be problematic. Click here for more details.
- commands/__init__.py +24 -0
- commands/cat/Dr-Egeria_md-orig.py +2 -2
- commands/cat/__init__.py +1 -17
- commands/cat/collection_actions.py +197 -0
- commands/cat/dr_egeria_command_help.py +372 -0
- commands/cat/dr_egeria_jupyter.py +7 -7
- commands/cat/dr_egeria_md.py +27 -182
- commands/cat/exp_list_glossaries.py +11 -14
- commands/cat/get_asset_graph.py +37 -267
- commands/cat/{get_collection.py → get_collection_tree.py} +10 -18
- commands/cat/get_project_dependencies.py +14 -14
- commands/cat/get_project_structure.py +15 -14
- commands/cat/get_tech_type_elements.py +16 -116
- commands/cat/glossary_actions.py +145 -298
- commands/cat/list_assets.py +3 -11
- commands/cat/list_cert_types.py +17 -63
- commands/cat/list_collections.py +46 -138
- commands/cat/list_deployed_catalogs.py +15 -27
- commands/cat/list_deployed_database_schemas.py +27 -43
- commands/cat/list_deployed_databases.py +16 -31
- commands/cat/list_deployed_servers.py +35 -54
- commands/cat/list_glossaries.py +18 -17
- commands/cat/list_projects.py +10 -12
- commands/cat/list_tech_type_elements.py +21 -37
- commands/cat/list_tech_types.py +13 -25
- commands/cat/list_terms.py +38 -79
- commands/cat/list_todos.py +4 -11
- commands/cat/list_user_ids.py +3 -10
- commands/cat/my_reports.py +559 -0
- commands/cat/run_report.py +394 -0
- commands/cat/run_report_orig.py +528 -0
- commands/cli/egeria.py +222 -247
- commands/cli/egeria_cat.py +68 -81
- commands/cli/egeria_my.py +13 -0
- commands/cli/egeria_ops.py +69 -74
- commands/cli/egeria_tech.py +17 -93
- commands/cli/ops_config.py +3 -6
- commands/{cat/list_categories.py → deprecated/list_data_designer.py} +53 -64
- commands/{cat/list_data_structures.py → deprecated/list_data_structures_full.py} +3 -6
- commands/deprecated/old_get_asset_graph.py +315 -0
- commands/my/__init__.py +0 -2
- commands/my/list_my_profile.py +27 -34
- commands/my/list_my_roles.py +1 -7
- commands/my/monitor_my_todos.py +1 -7
- commands/my/monitor_open_todos.py +6 -7
- commands/my/todo_actions.py +4 -5
- commands/ops/__init__.py +0 -2
- commands/ops/gov_server_actions.py +17 -21
- commands/ops/list_archives.py +17 -38
- commands/ops/list_catalog_targets.py +33 -40
- commands/ops/load_archive.py +35 -26
- commands/ops/{monitor_engine_activity_c.py → monitor_active_engine_activity.py} +51 -82
- commands/ops/{monitor_integ_daemon_status.py → monitor_daemon_status.py} +35 -55
- commands/ops/monitor_engine_activity.py +79 -77
- commands/ops/{monitor_gov_eng_status.py → monitor_engine_status.py} +10 -7
- commands/ops/monitor_platform_status.py +38 -50
- commands/ops/monitor_server_startup.py +6 -11
- commands/ops/monitor_server_status.py +7 -11
- commands/ops/orig_monitor_server_list.py +8 -8
- commands/ops/orig_monitor_server_status.py +1 -5
- commands/ops/refresh_integration_daemon.py +5 -5
- commands/ops/restart_integration_daemon.py +5 -5
- commands/ops/table_integ_daemon_status.py +6 -6
- commands/ops/x_engine_actions.py +7 -7
- commands/tech/__init__.py +0 -2
- commands/tech/{generic_actions.py → element_actions.py} +6 -11
- commands/tech/get_element_info.py +20 -29
- commands/tech/get_guid_info.py +23 -42
- commands/tech/get_tech_details.py +20 -35
- commands/tech/get_tech_type_template.py +28 -39
- commands/tech/list_all_om_type_elements.py +24 -30
- commands/tech/list_all_om_type_elements_x.py +22 -28
- commands/tech/list_all_related_elements.py +19 -28
- commands/tech/list_anchored_elements.py +22 -30
- commands/tech/list_asset_types.py +19 -24
- commands/tech/list_elements_by_classification_by_property_value.py +26 -32
- commands/tech/list_elements_by_property_value.py +19 -25
- commands/tech/list_elements_by_property_value_x.py +20 -28
- commands/tech/list_elements_for_classification.py +28 -41
- commands/tech/list_gov_action_processes.py +16 -27
- commands/tech/list_information_supply_chains.py +22 -30
- commands/tech/list_registered_services.py +14 -26
- commands/tech/list_related_elements_with_prop_value.py +15 -25
- commands/tech/list_related_specification.py +1 -4
- commands/tech/list_relationship_types.py +15 -25
- commands/tech/list_relationships.py +20 -36
- commands/tech/list_solution_blueprints.py +28 -33
- commands/tech/list_solution_components.py +23 -29
- commands/tech/list_solution_roles.py +21 -32
- commands/tech/list_tech_templates.py +51 -54
- commands/tech/list_valid_metadata_values.py +5 -9
- commands/tech/table_tech_templates.py +2 -6
- commands/tech/x_list_related_elements.py +1 -4
- examples/GeoSpatial Products Example.py +524 -0
- examples/Jupyter Notebooks/P-egeria-server-config.ipynb +2137 -0
- examples/Jupyter Notebooks/README.md +2 -0
- examples/Jupyter Notebooks/common/P-environment-check.ipynb +115 -0
- examples/Jupyter Notebooks/common/__init__.py +14 -0
- examples/Jupyter Notebooks/common/common-functions.ipynb +4694 -0
- examples/Jupyter Notebooks/common/environment-check.ipynb +52 -0
- examples/Jupyter Notebooks/common/globals.ipynb +184 -0
- examples/Jupyter Notebooks/common/globals.py +154 -0
- examples/Jupyter Notebooks/common/orig_globals.py +152 -0
- examples/format_sets/all_format_sets.json +910 -0
- examples/format_sets/custom_format_sets.json +268 -0
- examples/format_sets/subset_format_sets.json +187 -0
- examples/format_sets_save_load_example.py +291 -0
- examples/jacquard_data_sets.py +129 -0
- examples/output_formats_example.py +193 -0
- examples/test_jacquard_data_sets.py +54 -0
- examples/test_jacquard_data_sets_scenarios.py +94 -0
- md_processing/__init__.py +90 -0
- md_processing/command_dispatcher.py +33 -0
- md_processing/command_mapping.py +221 -0
- md_processing/data/commands/commands_data_designer.json +537 -0
- md_processing/data/commands/commands_external_reference.json +733 -0
- md_processing/data/commands/commands_feedback.json +155 -0
- md_processing/data/commands/commands_general.json +204 -0
- md_processing/data/commands/commands_glossary.json +218 -0
- md_processing/data/commands/commands_governance.json +3678 -0
- md_processing/data/commands/commands_product_manager.json +865 -0
- md_processing/data/commands/commands_project.json +642 -0
- md_processing/data/commands/commands_solution_architect.json +366 -0
- md_processing/data/commands.json +17568 -0
- md_processing/data/commands_working.json +30641 -0
- md_processing/data/gened_report_specs.py +6584 -0
- md_processing/data/generated_format_sets.json +6533 -0
- md_processing/data/generated_format_sets_old.json +4137 -0
- md_processing/data/generated_format_sets_old.py +45 -0
- md_processing/dr_egeria.py +182 -0
- md_processing/md_commands/__init__.py +3 -0
- md_processing/md_commands/data_designer_commands.py +1276 -0
- md_processing/md_commands/ext_ref_commands.py +530 -0
- md_processing/md_commands/feedback_commands.py +726 -0
- md_processing/md_commands/glossary_commands.py +684 -0
- md_processing/md_commands/governance_officer_commands.py +600 -0
- md_processing/md_commands/product_manager_commands.py +1266 -0
- md_processing/md_commands/project_commands.py +383 -0
- md_processing/md_commands/solution_architect_commands.py +1184 -0
- md_processing/md_commands/view_commands.py +295 -0
- md_processing/md_processing_utils/__init__.py +4 -0
- md_processing/md_processing_utils/common_md_proc_utils.py +1249 -0
- md_processing/md_processing_utils/common_md_utils.py +578 -0
- md_processing/md_processing_utils/determine_width.py +103 -0
- md_processing/md_processing_utils/extraction_utils.py +547 -0
- md_processing/md_processing_utils/gen_report_specs.py +643 -0
- md_processing/md_processing_utils/generate_dr_help.py +193 -0
- md_processing/md_processing_utils/generate_md_cmd_templates.py +144 -0
- md_processing/md_processing_utils/generate_md_templates.py +83 -0
- md_processing/md_processing_utils/md_processing_constants.py +1228 -0
- md_processing/md_processing_utils/message_constants.py +19 -0
- pyegeria/__init__.py +201 -443
- pyegeria/core/__init__.py +40 -0
- pyegeria/core/_base_platform_client.py +574 -0
- pyegeria/core/_base_server_client.py +573 -0
- pyegeria/core/_exceptions.py +457 -0
- pyegeria/core/_globals.py +60 -0
- pyegeria/core/_server_client.py +6073 -0
- pyegeria/core/_validators.py +257 -0
- pyegeria/core/config.py +654 -0
- pyegeria/{create_tech_guid_lists.py → core/create_tech_guid_lists.py} +0 -1
- pyegeria/core/load_config.py +37 -0
- pyegeria/core/logging_configuration.py +207 -0
- pyegeria/core/mcp_adapter.py +144 -0
- pyegeria/core/mcp_server.py +212 -0
- pyegeria/core/utils.py +405 -0
- pyegeria/deprecated/__init__.py +0 -0
- pyegeria/{_client.py → deprecated/_client.py} +62 -24
- pyegeria/{_deprecated_gov_engine.py → deprecated/_deprecated_gov_engine.py} +16 -16
- pyegeria/{classification_manager_omvs.py → deprecated/classification_manager_omvs.py} +1988 -1878
- pyegeria/deprecated/output_formatter_with_machine_keys.py +1127 -0
- pyegeria/{runtime_manager_omvs.py → deprecated/runtime_manager_omvs.py} +216 -229
- pyegeria/{valid_metadata_omvs.py → deprecated/valid_metadata_omvs.py} +93 -93
- pyegeria/{x_action_author_omvs.py → deprecated/x_action_author_omvs.py} +2 -3
- pyegeria/egeria_cat_client.py +25 -51
- pyegeria/egeria_client.py +140 -98
- pyegeria/egeria_config_client.py +48 -24
- pyegeria/egeria_tech_client.py +170 -83
- pyegeria/models/__init__.py +150 -0
- pyegeria/models/collection_models.py +168 -0
- pyegeria/models/models.py +654 -0
- pyegeria/omvs/__init__.py +84 -0
- pyegeria/omvs/action_author.py +342 -0
- pyegeria/omvs/actor_manager.py +5980 -0
- pyegeria/omvs/asset_catalog.py +842 -0
- pyegeria/omvs/asset_maker.py +2736 -0
- pyegeria/omvs/automated_curation.py +4403 -0
- pyegeria/omvs/classification_manager.py +11213 -0
- pyegeria/omvs/collection_manager.py +5780 -0
- pyegeria/omvs/community_matters_omvs.py +468 -0
- pyegeria/{core_omag_server_config.py → omvs/core_omag_server_config.py} +157 -157
- pyegeria/{data_designer_omvs.py → omvs/data_designer.py} +1991 -1691
- pyegeria/omvs/data_discovery.py +869 -0
- pyegeria/omvs/data_engineer.py +372 -0
- pyegeria/omvs/digital_business.py +1133 -0
- pyegeria/omvs/external_links.py +1752 -0
- pyegeria/omvs/feedback_manager.py +834 -0
- pyegeria/{full_omag_server_config.py → omvs/full_omag_server_config.py} +73 -69
- pyegeria/omvs/glossary_manager.py +3231 -0
- pyegeria/omvs/governance_officer.py +3009 -0
- pyegeria/omvs/lineage_linker.py +314 -0
- pyegeria/omvs/location_arena.py +1525 -0
- pyegeria/omvs/metadata_expert.py +668 -0
- pyegeria/omvs/metadata_explorer_omvs.py +2943 -0
- pyegeria/omvs/my_profile.py +1042 -0
- pyegeria/omvs/notification_manager.py +358 -0
- pyegeria/omvs/people_organizer.py +394 -0
- pyegeria/{platform_services.py → omvs/platform_services.py} +113 -193
- pyegeria/omvs/product_manager.py +1825 -0
- pyegeria/omvs/project_manager.py +1907 -0
- pyegeria/omvs/reference_data.py +1140 -0
- pyegeria/omvs/registered_info.py +334 -0
- pyegeria/omvs/runtime_manager.py +2817 -0
- pyegeria/omvs/schema_maker.py +446 -0
- pyegeria/{server_operations.py → omvs/server_operations.py} +27 -26
- pyegeria/omvs/solution_architect.py +6490 -0
- pyegeria/omvs/specification_properties.py +37 -0
- pyegeria/omvs/subject_area.py +1042 -0
- pyegeria/omvs/template_manager_omvs.py +236 -0
- pyegeria/omvs/time_keeper.py +1761 -0
- pyegeria/omvs/valid_metadata.py +3221 -0
- pyegeria/omvs/valid_metadata_lists.py +37 -0
- pyegeria/omvs/valid_type_lists.py +37 -0
- pyegeria/view/__init__.py +28 -0
- pyegeria/view/_output_format_models.py +514 -0
- pyegeria/view/_output_formats.py +14 -0
- pyegeria/view/base_report_formats.py +2719 -0
- pyegeria/view/dr_egeria_reports.py +56 -0
- pyegeria/view/format_set_executor.py +397 -0
- pyegeria/{md_processing_utils.py → view/md_processing_utils.py} +5 -5
- pyegeria/{mermaid_utilities.py → view/mermaid_utilities.py} +2 -154
- pyegeria/view/output_formatter.py +1297 -0
- pyegeria-5.5.3.3.dist-info/METADATA +218 -0
- pyegeria-5.5.3.3.dist-info/RECORD +241 -0
- {pyegeria-5.3.9.9.3.dist-info → pyegeria-5.5.3.3.dist-info}/WHEEL +2 -1
- pyegeria-5.5.3.3.dist-info/entry_points.txt +103 -0
- pyegeria-5.5.3.3.dist-info/top_level.txt +4 -0
- commands/cat/.DS_Store +0 -0
- commands/cat/README.md +0 -16
- commands/cli/txt_custom_v2.tcss +0 -19
- commands/my/README.md +0 -17
- commands/ops/README.md +0 -24
- commands/ops/monitor_asset_events.py +0 -108
- commands/tech/README.md +0 -24
- pyegeria/.DS_Store +0 -0
- pyegeria/README.md +0 -35
- pyegeria/_globals.py +0 -47
- pyegeria/_validators.py +0 -385
- pyegeria/asset_catalog_omvs.py +0 -864
- pyegeria/automated_curation_omvs.py +0 -3765
- pyegeria/collection_manager_omvs.py +0 -2744
- pyegeria/dr.egeria spec.md +0 -9
- pyegeria/egeria_my_client.py +0 -56
- pyegeria/feedback_manager_omvs.py +0 -4573
- pyegeria/glossary_browser_omvs.py +0 -3728
- pyegeria/glossary_manager_omvs.py +0 -2440
- pyegeria/m_test.py +0 -118
- pyegeria/md_processing_helpers.py +0 -58
- pyegeria/md_processing_utils_orig.py +0 -1103
- pyegeria/metadata_explorer_omvs.py +0 -2326
- pyegeria/my_profile_omvs.py +0 -1022
- pyegeria/output_formatter.py +0 -389
- pyegeria/project_manager_omvs.py +0 -1933
- pyegeria/registered_info.py +0 -167
- pyegeria/solution_architect_omvs.py +0 -2156
- pyegeria/template_manager_omvs.py +0 -1414
- pyegeria/utils.py +0 -197
- pyegeria-5.3.9.9.3.dist-info/METADATA +0 -72
- pyegeria-5.3.9.9.3.dist-info/RECORD +0 -143
- pyegeria-5.3.9.9.3.dist-info/entry_points.txt +0 -99
- /pyegeria/{_exceptions.py → deprecated/_exceptions.py} +0 -0
- {pyegeria-5.3.9.9.3.dist-info → pyegeria-5.5.3.3.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Determines the width of a markdown table
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import html
|
|
7
|
+
from wcwidth import wcswidth
|
|
8
|
+
|
|
9
|
+
def split_row(line: str) -> list[str]:
|
|
10
|
+
s = line.strip()
|
|
11
|
+
if s.startswith("|"):
|
|
12
|
+
s = s[1:]
|
|
13
|
+
if s.endswith("|"):
|
|
14
|
+
s = s[:-1]
|
|
15
|
+
|
|
16
|
+
parts = []
|
|
17
|
+
cur = []
|
|
18
|
+
escape = False
|
|
19
|
+
for ch in s:
|
|
20
|
+
if escape:
|
|
21
|
+
cur.append(ch)
|
|
22
|
+
escape = False
|
|
23
|
+
elif ch == "\\":
|
|
24
|
+
escape = True
|
|
25
|
+
elif ch == "|":
|
|
26
|
+
parts.append("".join(cur))
|
|
27
|
+
cur = []
|
|
28
|
+
else:
|
|
29
|
+
cur.append(ch)
|
|
30
|
+
parts.append("".join(cur))
|
|
31
|
+
return parts
|
|
32
|
+
|
|
33
|
+
IMG_RE = re.compile(r'!\[([^\]]*)\]\([^)]+\)')
|
|
34
|
+
LINK_RE = re.compile(r'\[([^\]]*)\]\([^)]+\)')
|
|
35
|
+
CODE_TICKS_RE = re.compile(r'`([^`]*)`')
|
|
36
|
+
EMPH_RE = re.compile(r'(\*\*|\*|__|_)')
|
|
37
|
+
|
|
38
|
+
def visible_text(md: str) -> str:
|
|
39
|
+
s = md
|
|
40
|
+
s = IMG_RE.sub(lambda m: m.group(1), s) # images → alt
|
|
41
|
+
s = LINK_RE.sub(lambda m: m.group(1), s) # links → text
|
|
42
|
+
s = CODE_TICKS_RE.sub(lambda m: m.group(1), s) # remove backticks
|
|
43
|
+
s = EMPH_RE.sub("", s) # remove emphasis markers
|
|
44
|
+
|
|
45
|
+
# unescape common backslash-escapes
|
|
46
|
+
s = (s
|
|
47
|
+
.replace("\\|", "|")
|
|
48
|
+
.replace("\\*", "*")
|
|
49
|
+
.replace("\\_", "_")
|
|
50
|
+
.replace("\\`", "`")
|
|
51
|
+
.replace("\\\\", "\\"))
|
|
52
|
+
|
|
53
|
+
s = html.unescape(s) # & → &
|
|
54
|
+
return s.strip()
|
|
55
|
+
|
|
56
|
+
def is_alignment_row(line: str) -> bool:
|
|
57
|
+
parts = split_row(line)
|
|
58
|
+
if not parts:
|
|
59
|
+
return False
|
|
60
|
+
def is_align_cell(c: str) -> bool:
|
|
61
|
+
c = c.strip()
|
|
62
|
+
return c != "" and all(ch in ":-" for ch in c)
|
|
63
|
+
return all(is_align_cell(p) for p in parts)
|
|
64
|
+
|
|
65
|
+
def column_widths(md_table: str) -> list[int]:
|
|
66
|
+
lines = [ln for ln in md_table.splitlines() if ln.strip()]
|
|
67
|
+
if not lines:
|
|
68
|
+
return []
|
|
69
|
+
|
|
70
|
+
lines_wo_align = [ln for ln in lines if not is_alignment_row(ln)]
|
|
71
|
+
|
|
72
|
+
rows = [split_row(ln) for ln in lines_wo_align]
|
|
73
|
+
if not rows:
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
max_cols = max(len(r) for r in rows)
|
|
77
|
+
for r in rows:
|
|
78
|
+
if len(r) < max_cols:
|
|
79
|
+
r.extend([""] * (max_cols - len(r)))
|
|
80
|
+
|
|
81
|
+
widths = [0] * max_cols
|
|
82
|
+
for r in rows:
|
|
83
|
+
for i, cell in enumerate(r):
|
|
84
|
+
text = visible_text(cell)
|
|
85
|
+
w = wcswidth(text)
|
|
86
|
+
if w < 0: # non-printables fallback
|
|
87
|
+
w = len(text)
|
|
88
|
+
widths[i] = max(widths[i], w)
|
|
89
|
+
print(widths)
|
|
90
|
+
return widths
|
|
91
|
+
|
|
92
|
+
# Example usage
|
|
93
|
+
if __name__ == "__main__":
|
|
94
|
+
table = """
|
|
95
|
+
| Attribute Name | Input Required | Read Only | Generated | Default Value | Notes | Unique Values | Valid Values |
|
|
96
|
+
| ------------------- | -------------- | --------- | --------- | ------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------- |
|
|
97
|
+
| Display Name | True | True | False | None | Name of the definition. | False | |
|
|
98
|
+
| Summary | False | True | False | None | Summary of the definition. | False | |
|
|
99
|
+
| Description | False | True | False | None | Description of the contents of the definition. | False | |
|
|
100
|
+
| Category | False | True | False | None | A user specified category name that can be used for example, to define product types or agreement types. | False | |
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
print(column_widths(table)) # e.g., [9, 28, 36] depending on characters
|
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file contains functions for extracting data from text for Egeria Markdown processing
|
|
3
|
+
"""
|
|
4
|
+
import re
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from md_processing.md_processing_utils.common_md_utils import (print_msg, find_key_with_value, get_element_dictionary,
|
|
8
|
+
update_element_dictionary)
|
|
9
|
+
from md_processing.md_processing_utils.message_constants import INFO, EXISTS_REQUIRED
|
|
10
|
+
from md_processing.md_processing_utils.md_processing_constants import debug_level
|
|
11
|
+
from pyegeria.core._globals import NO_ELEMENTS_FOUND
|
|
12
|
+
from pyegeria.egeria_tech_client import EgeriaTech
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def extract_command_plus(block: str) -> tuple[str, str, str] | None:
|
|
16
|
+
"""
|
|
17
|
+
Extracts a multi-word object and its associated action from the given block of text.
|
|
18
|
+
|
|
19
|
+
This function searches for a pattern in the format of `#...##` or `#...\n`
|
|
20
|
+
inside the provided string `block`. The matched pattern is split into
|
|
21
|
+
two parts: the action and the object type. The action is expected to
|
|
22
|
+
be the first part, while the rest is treated as the object type. If
|
|
23
|
+
no match is found, the function returns None.
|
|
24
|
+
|
|
25
|
+
Lines beginning with '>' are ignored.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
block: A string containing the block of text to search for the
|
|
29
|
+
object_action and action.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
A tuple containing the object_action, the object type, and the object action if a
|
|
33
|
+
match is found. Otherwise, returns None.
|
|
34
|
+
"""
|
|
35
|
+
# Filter out lines beginning with '>'
|
|
36
|
+
filtered_lines = [line for line in block.split('\n') if not line.strip().startswith('>')]
|
|
37
|
+
filtered_block = '\n'.join(filtered_lines)
|
|
38
|
+
|
|
39
|
+
match = re.search(r"#(.*?)(?:##|\n|$)", filtered_block) # Using a non capturing group
|
|
40
|
+
if match:
|
|
41
|
+
clean_match = match.group(1).strip()
|
|
42
|
+
if ' ' in clean_match:
|
|
43
|
+
parts = clean_match.split(' ')
|
|
44
|
+
object_action = parts[0].strip()
|
|
45
|
+
# Join the rest of the parts to allow object_type to be one or two words
|
|
46
|
+
object_type = ' '.join(parts[1:]).strip()
|
|
47
|
+
else:
|
|
48
|
+
object_type = clean_match.split(' ')[1].strip()
|
|
49
|
+
object_action = clean_match.split(' ')[0].strip()
|
|
50
|
+
|
|
51
|
+
return clean_match, object_type, object_action
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def extract_command(block: str) -> str | None:
|
|
56
|
+
"""
|
|
57
|
+
Extracts a object_action from a block of text that is contained between a single hash ('#') and
|
|
58
|
+
either a double hash ('##'), a newline character, or the end of the string.
|
|
59
|
+
|
|
60
|
+
The function searches for a specific pattern within the block of text and extracts the
|
|
61
|
+
content that appears immediately after a single hash ('#'). Ensures that the extracted
|
|
62
|
+
content is appropriately trimmed of leading or trailing whitespace, if present.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
block: A string representing the block of text to process. Contains the content
|
|
66
|
+
in which the object_action and delimiters are expected to be present.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The extracted object_action as a string if a match is found, otherwise None.
|
|
70
|
+
"""
|
|
71
|
+
match = re.search(r"#(.*?)(?:##|\n|$)", block) # Using a non-capturing group
|
|
72
|
+
if match:
|
|
73
|
+
return match.group(1).strip()
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# def extract_attribute(text: str, labels: set) -> str | None:
|
|
78
|
+
# """
|
|
79
|
+
# Extracts the attribute value from a string.
|
|
80
|
+
#
|
|
81
|
+
# Args:
|
|
82
|
+
# text: The input string.
|
|
83
|
+
# labels: List of equivalent labels to search for
|
|
84
|
+
#
|
|
85
|
+
# Returns:
|
|
86
|
+
# The value of the attribute, or None if not found.
|
|
87
|
+
#
|
|
88
|
+
# Note:
|
|
89
|
+
# Lines beginning with '>' are ignored.
|
|
90
|
+
# """
|
|
91
|
+
# # Iterate over the list of labels
|
|
92
|
+
# for label in labels:
|
|
93
|
+
# # Construct pattern for the current label
|
|
94
|
+
# # text = re.sub(r'\s+', ' ', text).strip() # just added
|
|
95
|
+
# # text = re.sub(r'\n\n+', '\n\n', text).strip()
|
|
96
|
+
#
|
|
97
|
+
# # Replace multiple spaces or tabs with a single space
|
|
98
|
+
# normalized = re.sub(r'\s+', ' ', text)
|
|
99
|
+
# # Collapse multiple blank lines into a single one
|
|
100
|
+
# normalized = re.sub(r'\n\s*\n', '\n', normalized).strip()
|
|
101
|
+
#
|
|
102
|
+
# # label = label.strip()
|
|
103
|
+
# # pattern = rf"##\s*{re.escape(label)}\s*\n(?:\s*\n)*?(.*?)(?:#|___|$)"
|
|
104
|
+
# # Normalize the label
|
|
105
|
+
# normalized_label = re.sub(r'\s+', ' ', label.strip())
|
|
106
|
+
#
|
|
107
|
+
# # Construct the regex pattern
|
|
108
|
+
# pattern = rf"##\s*{re.escape(normalized_label)}\s*\n(?:\s*\n)*?(.*?)(?:#|___|$)"
|
|
109
|
+
# # pattern = rf"##\s+{re.escape(label)}\n(.*?)(?:#|___|$)" # modified from --- to enable embedded tables
|
|
110
|
+
# match = re.search(pattern, text, re.DOTALL)
|
|
111
|
+
# if match:
|
|
112
|
+
# # Extract matched text
|
|
113
|
+
# matched_text = match.group(1)
|
|
114
|
+
#
|
|
115
|
+
# # Filter out lines beginning with '>'
|
|
116
|
+
# filtered_lines = [line for line in matched_text.split('\n') if not line.strip().startswith('>')]
|
|
117
|
+
# filtered_text = '\n'.join(filtered_lines)
|
|
118
|
+
#
|
|
119
|
+
# # Replace consecutive \n with a single \n
|
|
120
|
+
# extracted_text = re.sub(r'\n+', '\n', filtered_text)
|
|
121
|
+
# if not extracted_text.isspace() and extracted_text:
|
|
122
|
+
# return extracted_text.strip() # Return the cleaned text - I removed the title casing
|
|
123
|
+
#
|
|
124
|
+
# return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
from typing import Optional, List
|
|
128
|
+
|
|
129
|
+
def extract_attribute(text: str, labels: List[str]) -> Optional[str]:
|
|
130
|
+
"""
|
|
131
|
+
def extract_attribute(text: str, labels: List[str]) -> Optional[str]:
|
|
132
|
+
|
|
133
|
+
Extracts the attribute value from a string while:
|
|
134
|
+
- Preserving single newlines within the matched text.
|
|
135
|
+
- Removing lines starting with '>'.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
text: The input string containing labeled sections.
|
|
139
|
+
labels: List of equivalent labels to search for.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
The cleaned value of the attribute, or None if not found.
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
for label in labels:
|
|
147
|
+
# Construct pattern for the current label - stops at next ##, ___ separator, or end of text
|
|
148
|
+
pattern = rf"## {re.escape(label)}\n(.*?)(?=^##|^_{3,}|\Z)"
|
|
149
|
+
match = re.search(pattern, text, re.DOTALL | re.MULTILINE)
|
|
150
|
+
if match:
|
|
151
|
+
# Extract matched text
|
|
152
|
+
extracted_text = match.group(1)
|
|
153
|
+
|
|
154
|
+
# Remove lines starting with '>' and lines that are only underscores/whitespace
|
|
155
|
+
filtered_lines = [
|
|
156
|
+
line for line in extracted_text.splitlines()
|
|
157
|
+
if not line.lstrip().startswith(">") and not re.match(r'^\s*_+\s*$', line)
|
|
158
|
+
]
|
|
159
|
+
# Join the lines back, preserving single newlines
|
|
160
|
+
cleaned_text = "\n".join(filtered_lines).strip()
|
|
161
|
+
|
|
162
|
+
if cleaned_text:
|
|
163
|
+
return cleaned_text # Return the cleaned and formatted text
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def process_simple_attribute(txt: str, labels: set, if_missing: str = INFO) -> str | None:
|
|
170
|
+
"""Process a simple attribute based on the provided labels and if_missing value.
|
|
171
|
+
Extract the attribute value from the text and return it if it exists.
|
|
172
|
+
If it doesn`t exist, return None and print an error message with severity of if_missing.
|
|
173
|
+
|
|
174
|
+
Parameters:
|
|
175
|
+
----------
|
|
176
|
+
txt: str
|
|
177
|
+
The block of object_action text to extract attributes from.
|
|
178
|
+
labels: list
|
|
179
|
+
The possible attribute labels to search for. The first label will be used in messages.
|
|
180
|
+
if_missing: str, default is INFO
|
|
181
|
+
Can be one of "WARNING", "ERROR", "INFO". The severity of the missing attribute.
|
|
182
|
+
"""
|
|
183
|
+
if if_missing not in ["WARNING", "ERROR", "INFO"]:
|
|
184
|
+
print_msg("ERROR", "Invalid severity for missing attribute", debug_level)
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
attribute = extract_attribute(txt, labels)
|
|
188
|
+
|
|
189
|
+
if attribute is None:
|
|
190
|
+
if if_missing == INFO:
|
|
191
|
+
msg = f"Optional attribute with labels `{labels}` missing"
|
|
192
|
+
else:
|
|
193
|
+
msg = f"Missing attribute with labels `{labels}` "
|
|
194
|
+
print_msg(if_missing, msg, debug_level)
|
|
195
|
+
return None
|
|
196
|
+
return attribute.strip()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# def process_simple_attribute(txt: str, labels: list[str], if_missing: str = INFO) -> str | None:
|
|
200
|
+
# """
|
|
201
|
+
# Processes a simple attribute from a string.
|
|
202
|
+
#
|
|
203
|
+
# Args:
|
|
204
|
+
# txt: The input string.
|
|
205
|
+
# labels: List of equivalent labels to search for
|
|
206
|
+
# if_missing: The message level to use if the attribute is missing.
|
|
207
|
+
#
|
|
208
|
+
# Returns:
|
|
209
|
+
# The value of the attribute, or None if not found.
|
|
210
|
+
# """
|
|
211
|
+
# from md_processing.md_processing_utils.common_utils import debug_level, print_msg
|
|
212
|
+
#
|
|
213
|
+
# attribute = extract_attribute(txt, labels)
|
|
214
|
+
# if attribute is None and if_missing:
|
|
215
|
+
# msg = f"No {labels[0]} found"
|
|
216
|
+
# print_msg(if_missing, msg, debug_level)
|
|
217
|
+
# return attribute
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def process_name_list(egeria_client: EgeriaTech, element_type: str, txt: str, element_labels: set) -> tuple[str,
|
|
221
|
+
list[Any], bool | Any, bool | None | Any] | None:
|
|
222
|
+
"""
|
|
223
|
+
Processes a list of names specified in the given text, retrieves details for each
|
|
224
|
+
element based on the provided type, and generates a list of valid qualified names.
|
|
225
|
+
|
|
226
|
+
The function reads a text block, extracts a list of element names according to the specified
|
|
227
|
+
element type, looks them up using the provided Egeria client, and classifies them as valid or
|
|
228
|
+
invalid. It returns the processed names, a list of qualified names, and validity and existence
|
|
229
|
+
flags.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
|
|
233
|
+
egeria_client (EgeriaTech): The client instance to connect and query elements from an
|
|
234
|
+
external system.
|
|
235
|
+
Element_type (str): The type of element, such as schema or attribute, to process.
|
|
236
|
+
Txt (str): The raw input text containing element names to be processed.
|
|
237
|
+
element_labels: a list of equivalent label names to use in processing the element.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
tuple[str | None, list | None, bool, bool]: A tuple containing:
|
|
241
|
+
- Concatenated valid input names as a single string (or None if empty).
|
|
242
|
+
- A list of known qualified names extracted from the processed elements.
|
|
243
|
+
- A boolean indicating whether all elements are valid.
|
|
244
|
+
- A boolean indicating whether all elements exist.
|
|
245
|
+
"""
|
|
246
|
+
valid = True
|
|
247
|
+
exists = True
|
|
248
|
+
elements = ""
|
|
249
|
+
new_element_list = []
|
|
250
|
+
|
|
251
|
+
elements_txt = extract_attribute(txt, element_labels)
|
|
252
|
+
|
|
253
|
+
if elements_txt is None:
|
|
254
|
+
msg = f"No {element_type} found"
|
|
255
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
256
|
+
|
|
257
|
+
else:
|
|
258
|
+
element_list = re.split(r'[,\n]+', elements_txt)
|
|
259
|
+
|
|
260
|
+
for element in element_list:
|
|
261
|
+
element_el = element.strip()
|
|
262
|
+
|
|
263
|
+
# Get the element using the generalized function
|
|
264
|
+
known_q_name, known_guid, el_valid, el_exists = get_element_by_name(egeria_client, element_type, element_el)
|
|
265
|
+
# print_msg("DEBUG-INFO", status_msg, debug_level)
|
|
266
|
+
|
|
267
|
+
if el_exists and el_valid:
|
|
268
|
+
elements = f"{element_el} {elements}" # list of the input names
|
|
269
|
+
new_element_list.append(known_q_name) # list of qualified names
|
|
270
|
+
elif not el_exists:
|
|
271
|
+
msg = f"No {element_type} `{element_el}` found"
|
|
272
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
273
|
+
valid = False
|
|
274
|
+
valid = valid if el_valid is None else (valid and el_valid)
|
|
275
|
+
exists = exists and el_exists
|
|
276
|
+
|
|
277
|
+
if elements:
|
|
278
|
+
# elements += "\n"
|
|
279
|
+
msg = f"Found {element_type}: {elements}"
|
|
280
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
281
|
+
else:
|
|
282
|
+
msg = " Name list contains one or more invalid qualified names."
|
|
283
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
284
|
+
return elements, new_element_list, valid, exists
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# def process_name_list(egeria_client, element_type: str, txt: str, element_labels: list[str]) -> tuple[list, list,
|
|
288
|
+
# bool, bool]:
|
|
289
|
+
# """
|
|
290
|
+
# Processes a list of names from a string.
|
|
291
|
+
#
|
|
292
|
+
# Args:
|
|
293
|
+
# egeria_client: The Egeria client to use for validation.
|
|
294
|
+
# element_type: The type of element to process.
|
|
295
|
+
# txt: The input string.
|
|
296
|
+
# element_labels: List of equivalent labels to search for
|
|
297
|
+
#
|
|
298
|
+
# Returns:
|
|
299
|
+
# A tuple containing:
|
|
300
|
+
# - A list of element names
|
|
301
|
+
# - A list of element qualified names
|
|
302
|
+
# - A boolean indicating if all elements are valid
|
|
303
|
+
# - A boolean indicating if any elements exist
|
|
304
|
+
# """
|
|
305
|
+
# from md_processing.md_processing_utils.common_utils import debug_level, print_msg
|
|
306
|
+
#
|
|
307
|
+
# element_names = []
|
|
308
|
+
# element_q_names = []
|
|
309
|
+
# all_valid = True
|
|
310
|
+
# any_exist = False
|
|
311
|
+
#
|
|
312
|
+
# # Get the list of element names
|
|
313
|
+
# element_list = process_simple_attribute(txt, element_labels)
|
|
314
|
+
# if element_list:
|
|
315
|
+
# # Split the list by commas or newlines
|
|
316
|
+
# element_names = list(filter(None, re.split(r'[,\n]+', element_list.strip())))
|
|
317
|
+
#
|
|
318
|
+
# # Validate each element
|
|
319
|
+
# for element_name in element_names:
|
|
320
|
+
# element_name = element_name.strip()
|
|
321
|
+
# if element_name:
|
|
322
|
+
# element = get_element_by_name(egeria_client, element_type, element_name)
|
|
323
|
+
# if element:
|
|
324
|
+
# any_exist = True
|
|
325
|
+
# element_q_name = element.get('qualifiedName', None)
|
|
326
|
+
# if element_q_name:
|
|
327
|
+
# element_q_names.append(element_q_name)
|
|
328
|
+
# else:
|
|
329
|
+
# all_valid = False
|
|
330
|
+
# msg = f"Element {element_name} has no qualified name"
|
|
331
|
+
# print_msg("ERROR", msg, debug_level)
|
|
332
|
+
# else:
|
|
333
|
+
# all_valid = False
|
|
334
|
+
# msg = f"Element {element_name} not found"
|
|
335
|
+
# print_msg("ERROR", msg, debug_level)
|
|
336
|
+
#
|
|
337
|
+
# return element_names, element_q_names, all_valid, any_exist
|
|
338
|
+
|
|
339
|
+
def process_element_identifiers(egeria_client: EgeriaTech, element_type: str, element_labels: set, txt: str,
|
|
340
|
+
action: str, version: str = None) -> tuple[str, str, bool, bool]:
|
|
341
|
+
"""
|
|
342
|
+
Processes element identifiers by extracting display name and qualified name from the input text,
|
|
343
|
+
checking if the element exists in Egeria and validating the information.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
egeria_client: EgeriaTech
|
|
348
|
+
Client object for interacting with Egeria.
|
|
349
|
+
element_type: str
|
|
350
|
+
type of element to process (e.g., 'blueprint', 'category', 'term')
|
|
351
|
+
element_labels: a list of equivalent label names to use in processing the element.
|
|
352
|
+
txt: str
|
|
353
|
+
A string representing the input text to be processed for extracting element identifiers.
|
|
354
|
+
action: str
|
|
355
|
+
The action object_action to be executed (e.g., 'Create', 'Update', 'Display', ...)
|
|
356
|
+
version: str, optional = None
|
|
357
|
+
An optional version identifier used if we need to construct the qualified name
|
|
358
|
+
|
|
359
|
+
Returns: tuple[str, str, str, bool, bool]
|
|
360
|
+
A tuple containing:
|
|
361
|
+
- qualified_name: Empty string or element identifier
|
|
362
|
+
- guid: Empty string or additional element information
|
|
363
|
+
- Valid: Boolean indicating if the element information is valid
|
|
364
|
+
- Exists: Boolean indicating if the element exists in Egeria
|
|
365
|
+
"""
|
|
366
|
+
valid = True
|
|
367
|
+
|
|
368
|
+
element_name = extract_attribute(txt, element_labels)
|
|
369
|
+
qualified_name = extract_attribute(txt, ["Qualified Name"])
|
|
370
|
+
|
|
371
|
+
if qualified_name:
|
|
372
|
+
q_name, guid, unique, exists = get_element_by_name(egeria_client, element_type,
|
|
373
|
+
qualified_name) # Qualified name could be different if it
|
|
374
|
+
# is being updated
|
|
375
|
+
else:
|
|
376
|
+
q_name, guid, unique, exists = get_element_by_name(egeria_client, element_type, element_name)
|
|
377
|
+
if unique is False:
|
|
378
|
+
msg = f"Multiple elements named {element_name} found"
|
|
379
|
+
print_msg("DEBUG-ERROR", msg, debug_level)
|
|
380
|
+
valid = False
|
|
381
|
+
|
|
382
|
+
if action == "Update" and not exists:
|
|
383
|
+
msg = f"Element {element_name} does not exist"
|
|
384
|
+
print_msg("DEBUG-ERROR", msg, debug_level)
|
|
385
|
+
valid = False
|
|
386
|
+
|
|
387
|
+
elif action == "Update" and exists:
|
|
388
|
+
msg = f"Element {element_name} exists"
|
|
389
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
390
|
+
|
|
391
|
+
elif action == "Create" and exists:
|
|
392
|
+
msg = f"Element {element_name} already exists"
|
|
393
|
+
print_msg("DEBUG-ERROR", msg, debug_level)
|
|
394
|
+
valid = False
|
|
395
|
+
|
|
396
|
+
elif action == "Create" and not exists:
|
|
397
|
+
msg = f"{element_type} `{element_name}` does not exist"
|
|
398
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
399
|
+
|
|
400
|
+
if q_name is None and qualified_name is None:
|
|
401
|
+
q_name = egeria_client.__create_qualified_name__(element_type, element_name, version_identifier=version)
|
|
402
|
+
update_element_dictionary(q_name, {'display_name': element_name})
|
|
403
|
+
elif qualified_name:
|
|
404
|
+
update_element_dictionary(qualified_name, {'display_name': element_name})
|
|
405
|
+
elif action == EXISTS_REQUIRED:
|
|
406
|
+
if not exists:
|
|
407
|
+
msg = f"Required {element_type} `{element_name}` does not exist"
|
|
408
|
+
print_msg("DEBUG-ERROR", msg, debug_level)
|
|
409
|
+
valid = False
|
|
410
|
+
else:
|
|
411
|
+
msg = f"Required {element_type} `{element_name}` exists"
|
|
412
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
413
|
+
valid = True
|
|
414
|
+
|
|
415
|
+
return q_name, guid, valid, exists
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def get_element_by_name(egeria_client, element_type: str, element_name: str) -> tuple[
|
|
419
|
+
str | None, str | None, bool | None, bool | None]:
|
|
420
|
+
"""
|
|
421
|
+
Generalized function to retrieve an element by name based on its type.
|
|
422
|
+
|
|
423
|
+
Parameters:
|
|
424
|
+
egeria_client: Client
|
|
425
|
+
Client object for interacting with Egeria.
|
|
426
|
+
element_type: str
|
|
427
|
+
The type of element to retrieve (e.g., 'blueprint', 'category', 'term').
|
|
428
|
+
element_name: str
|
|
429
|
+
The name of the element to retrieve.
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
tuple of qualified_name, guid, uniqye, exists
|
|
433
|
+
"""
|
|
434
|
+
unique = None
|
|
435
|
+
|
|
436
|
+
element_dict = get_element_dictionary()
|
|
437
|
+
q_name = find_key_with_value(element_name)
|
|
438
|
+
if q_name: # use information from element_dictionary
|
|
439
|
+
guid = element_dict[q_name].get('guid', None)
|
|
440
|
+
unique = True
|
|
441
|
+
|
|
442
|
+
if guid is not None: # Found complete entry in element_dictionary
|
|
443
|
+
msg = f'Found {element_type} qualified name and guid in element_dictionary for `{element_name}`'
|
|
444
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
445
|
+
exists = True
|
|
446
|
+
return q_name, guid, unique, exists
|
|
447
|
+
|
|
448
|
+
else: # Missing guid from element_dictionary
|
|
449
|
+
guid = egeria_client.__get_guid__(qualified_name=q_name)
|
|
450
|
+
if guid == NO_ELEMENTS_FOUND:
|
|
451
|
+
guid = None
|
|
452
|
+
exists = False
|
|
453
|
+
msg = f"No {element_type} guid found with name {element_name} in Egeria"
|
|
454
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
455
|
+
|
|
456
|
+
return q_name, guid, unique, exists
|
|
457
|
+
else:
|
|
458
|
+
exists = True
|
|
459
|
+
update_element_dictionary(q_name, {'guid': guid})
|
|
460
|
+
msg = f"Found guid value of {guid} for {element_name} in Egeria"
|
|
461
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
462
|
+
|
|
463
|
+
return q_name, guid, unique, exists
|
|
464
|
+
|
|
465
|
+
# Haven't seen this element before
|
|
466
|
+
property_names = ['qualifiedName', 'displayName', 'title']
|
|
467
|
+
if element_type == "InformalTag":
|
|
468
|
+
open_metadata_type_name = element_type
|
|
469
|
+
else:
|
|
470
|
+
open_metadata_type_name = None
|
|
471
|
+
details = egeria_client.get_elements_by_property_value(element_name, property_names, open_metadata_type_name)
|
|
472
|
+
if isinstance(details, str):
|
|
473
|
+
msg = f"{element_type} `{element_name}` not found in Egeria"
|
|
474
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
475
|
+
exists = False
|
|
476
|
+
return None, None, unique, exists
|
|
477
|
+
if len(details) > 1:
|
|
478
|
+
if q_name is None:
|
|
479
|
+
q_name = egeria_client.__create_qualified_name__(element_type, element_name)
|
|
480
|
+
guid = egeria_client.__get_guid__(qualified_name=q_name)
|
|
481
|
+
update_element_dictionary(q_name, {'guid': guid})
|
|
482
|
+
exists = True if guid != "No elements found" else False
|
|
483
|
+
return q_name, guid, unique, exists
|
|
484
|
+
else:
|
|
485
|
+
msg = (f"More than one element with name {element_name} found, please specify a "
|
|
486
|
+
f"**Qualified Name**")
|
|
487
|
+
print_msg("DEBUG-ERROR", msg, debug_level)
|
|
488
|
+
unique = False
|
|
489
|
+
exists = None
|
|
490
|
+
return element_name, None, unique, exists
|
|
491
|
+
|
|
492
|
+
el_qname = details[0]["properties"].get('qualifiedName', None)
|
|
493
|
+
el_guid = details[0]['elementHeader']['guid']
|
|
494
|
+
el_display_name = details[0]["properties"].get('displayName', None)
|
|
495
|
+
if el_display_name is None:
|
|
496
|
+
el_display_name = details[0]["properties"].get('name', None)
|
|
497
|
+
update_element_dictionary(el_qname, {
|
|
498
|
+
'guid': el_guid, 'displayName': el_display_name
|
|
499
|
+
})
|
|
500
|
+
msg = f"Found {element_type} `{el_display_name}` with qualified name `{el_qname}`"
|
|
501
|
+
print_msg("DEBUG-INFO", msg, debug_level)
|
|
502
|
+
exists = True
|
|
503
|
+
unique = True
|
|
504
|
+
return el_qname, el_guid, unique, exists
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def update_a_command(txt: str, object_action: str, obj_type: str, q_name: str, u_guid: str) -> str:
|
|
508
|
+
"""
|
|
509
|
+
Updates a command in a string.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
txt: The input string.
|
|
513
|
+
object_action: The command to update.
|
|
514
|
+
obj_type: The type of object to update.
|
|
515
|
+
q_name: The qualified name of the object.
|
|
516
|
+
u_guid: The GUID of the object.
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
The updated string.
|
|
520
|
+
"""
|
|
521
|
+
|
|
522
|
+
# Determine the new action
|
|
523
|
+
new_action = "Update" if object_action == "Create" else "Create"
|
|
524
|
+
|
|
525
|
+
# Replace the object_action
|
|
526
|
+
new_command = f"{new_action} {obj_type}"
|
|
527
|
+
pattern = rf"#\s*{object_action}\s+{obj_type}"
|
|
528
|
+
replacement = f"# {new_command}"
|
|
529
|
+
updated_txt = re.sub(pattern, replacement, txt)
|
|
530
|
+
|
|
531
|
+
# Add qualified name and GUID if updating
|
|
532
|
+
if new_action == "Update" and q_name and u_guid:
|
|
533
|
+
# Check if Qualified Name section exists
|
|
534
|
+
if "## Qualified Name" not in updated_txt:
|
|
535
|
+
# Add Qualified Name section before the first ## that's not part of the object_action
|
|
536
|
+
pattern = r"(##\s+[^#\n]+)"
|
|
537
|
+
replacement = f"## Qualified Name\n{q_name}\n\n\\1"
|
|
538
|
+
updated_txt = re.sub(pattern, replacement, updated_txt, count=1)
|
|
539
|
+
|
|
540
|
+
# Check if GUID section exists
|
|
541
|
+
if "## GUID" not in updated_txt and "## guid" not in updated_txt:
|
|
542
|
+
# Add GUID section before the first ## that's not part of the object_action or Qualified Name
|
|
543
|
+
pattern = r"(##\s+(?!Qualified Name)[^#\n]+)"
|
|
544
|
+
replacement = f"## GUID\n{u_guid}\n\n\\1"
|
|
545
|
+
updated_txt = re.sub(pattern, replacement, updated_txt, count=1)
|
|
546
|
+
|
|
547
|
+
return updated_txt
|