pyegeria 5.4.4.1__py3-none-any.whl → 5.4.4.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.

@@ -8,9 +8,11 @@ import re
8
8
  from typing import List, Optional
9
9
 
10
10
  from loguru import logger
11
+ from pydantic import ValidationError
11
12
  from rich import print
12
13
  from rich.markdown import Markdown
13
14
  from rich.console import Console
15
+ from pyegeria.utils import parse_to_dict
14
16
 
15
17
  from md_processing.md_processing_utils.common_md_utils import (get_current_datetime_string, get_element_dictionary,
16
18
  update_element_dictionary,
@@ -26,7 +28,8 @@ from md_processing.md_processing_utils.common_md_utils import (update_element_di
26
28
  from md_processing.md_processing_utils.extraction_utils import (extract_command_plus, update_a_command)
27
29
  from md_processing.md_processing_utils.md_processing_constants import (get_command_spec)
28
30
  from md_processing.md_processing_utils.message_constants import (ERROR, INFO, WARNING, ALWAYS, EXISTS_REQUIRED)
29
- from pyegeria import EgeriaTech, select_output_format_set
31
+ from pyegeria import EgeriaTech, select_output_format_set, PyegeriaException, print_basic_exception, \
32
+ print_validation_error
30
33
 
31
34
  from pyegeria._globals import DEBUG_LEVEL
32
35
 
@@ -93,131 +96,157 @@ def parse_upsert_command(egeria_client: EgeriaTech, object_type: str, object_act
93
96
 
94
97
  for attr in attributes:
95
98
  for key in attr:
96
- # Run some checks to see if the attribute is appropriate to the operation and usage level
97
- for_update = attr[key].get('inUpdate', True)
98
- level = attr[key].get('level', 'Basic')
99
- msg = (f"___\nProcessing `{key}` in `{object_action}` on a `{object_type}` "
100
- f"\n\twith usage level: `{EGERIA_USAGE_LEVEL}` and attribute level `{level}` and for_update `"
101
- f"{for_update}`\n")
102
- logger.trace(msg)
103
- if for_update is False and object_action == "Update":
104
- logger.trace(f"Attribute `{key}`is not allowed for `Update`", highlight=True)
105
- continue
106
- if EGERIA_USAGE_LEVEL == "Basic" and level != "Basic":
107
- logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
108
- highlight=True)
109
- continue
110
- if EGERIA_USAGE_LEVEL == "Advanced" and level in ["Expert", "Invisible"]:
111
- logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
112
- highlight=True)
113
- continue
114
- if EGERIA_USAGE_LEVEL == "Expert" and level == "Invisible":
115
- logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
116
- highlight=True)
117
- continue
118
-
119
- if attr[key].get('input_required', False) is True:
120
- if_missing = ERROR
121
- else:
122
- if_missing = INFO
123
-
124
- # lab = [item.strip() for item in re.split(r'[;,\n]+',attr[key]['attr_labels'])]
125
- lab = split_tb_string(attr[key]['attr_labels'])
126
- labels: set = set()
127
- labels.add(key.strip())
128
- if key == 'Display Name':
129
- labels.add(object_type.strip())
130
- if lab is not None and lab != [""]:
131
- labels.update(lab)
132
-
133
- default_value = attr[key].get('default_value', None)
134
-
135
- style = attr[key]['style']
136
- if style in ['Simple', 'Comment']:
137
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
138
- elif style == 'Dictionary':
139
- parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing, default_value)
140
- parsed_attributes[key]['name_list'] = json.dumps(parsed_attributes[key]['value'], indent=2)
141
-
142
- elif style == 'Valid Value':
143
- parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
144
- attr[key].get('valid_values', None), if_missing,
145
- default_value)
146
- elif style == 'QN':
147
- parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
148
- object_action, version, if_missing)
149
- if key == 'Qualified Name' and parsed_attributes[key]['value'] and parsed_attributes[key][
150
- 'exists'] is False:
151
- parsed_output['exists'] = False
152
- elif style == 'ID':
153
- parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
154
- object_action, version, if_missing)
155
-
156
- parsed_output['guid'] = parsed_attributes[key].get('guid', None)
157
- parsed_output['qualified_name'] = parsed_attributes[key].get('qualified_name', None)
158
- parsed_output['exists'] = parsed_attributes[key]['exists']
159
- if parsed_attributes[key]['valid'] is False:
160
- parsed_output['valid'] = False
161
- parsed_output['reason'] += parsed_attributes[key]['reason']
162
-
163
- elif style == 'Reference Name':
164
- parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
165
- if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) and parsed_attributes[key][
166
- 'exists'] is False):
167
- msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
168
- logger.error(msg)
169
- parsed_output['valid'] = False
170
- parsed_output['reason'] += msg
171
- elif parsed_attributes[key]['valid'] is False:
172
- parsed_output['valid'] = False
173
- parsed_output['reason'] += parsed_attributes[key]['reason']
174
-
175
- elif style == 'GUID':
176
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
177
- elif style == 'Ordered Int':
178
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
179
- elif style == 'Simple Int':
180
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value, "int")
181
- elif style == 'Simple List':
182
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
183
- name_list = parsed_attributes[key]['value']
184
- # attribute = re.split(r'[;,\n]+', name_list) if name_list is not None else None
185
- attribute = split_tb_string(name_list)
186
- parsed_attributes[key]['value'] = attribute
187
- parsed_attributes[key]['name_list'] = name_list
188
- elif style == 'Parent':
189
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
190
- elif style == 'Bool':
191
- parsed_attributes[key] = proc_bool_attribute(txt, object_action, labels, if_missing, default_value)
192
- elif style == "Dictionary List":
193
- parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
194
- parsed_attributes[key]['list'] = json.loads(parsed_attributes[key]['value'])
195
-
99
+ try:
100
+ # Run some checks to see if the attribute is appropriate to the operation and usage level
101
+ for_update = attr[key].get('inUpdate', True)
102
+ level = attr[key].get('level', 'Basic')
103
+ msg = (f"___\nProcessing `{key}` in `{object_action}` on a `{object_type}` "
104
+ f"\n\twith usage level: `{EGERIA_USAGE_LEVEL}` and attribute level `{level}` and for_update `"
105
+ f"{for_update}`\n")
106
+ logger.trace(msg)
107
+ if for_update is False and object_action == "Update":
108
+ logger.trace(f"Attribute `{key}`is not allowed for `Update`", highlight=True)
109
+ continue
110
+ if EGERIA_USAGE_LEVEL == "Basic" and level != "Basic":
111
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
112
+ highlight=True)
113
+ continue
114
+ if EGERIA_USAGE_LEVEL == "Advanced" and level in ["Expert", "Invisible"]:
115
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
116
+ highlight=True)
117
+ continue
118
+ if EGERIA_USAGE_LEVEL == "Expert" and level == "Invisible":
119
+ logger.trace(f"Attribute `{key}` is not supported for `{EGERIA_USAGE_LEVEL}` usage level. Skipping.",
120
+ highlight=True)
121
+ continue
196
122
 
197
- elif style == 'Reference Name List':
198
- parsed_attributes[key] = proc_name_list(egeria_client, key, txt, labels, if_missing)
199
- if (parsed_attributes[key].get("value", None) and (
200
- parsed_attributes[key]['exists'] is False or parsed_attributes[key]['valid'] is False)):
201
- msg = (f"A Reference Name in `{parsed_attributes[key].get('name_list', None)}` is specified but "
202
- f"does not exist")
123
+ if attr[key].get('input_required', False) is True:
124
+ if_missing = ERROR
125
+ else:
126
+ if_missing = INFO
127
+
128
+ # lab = [item.strip() for item in re.split(r'[;,\n]+',attr[key]['attr_labels'])]
129
+ lab = split_tb_string(attr[key]['attr_labels'])
130
+ labels: set = set()
131
+ labels.add(key.strip())
132
+ if key == 'Display Name':
133
+ labels.add(object_type.strip())
134
+ if lab is not None and lab != [""]:
135
+ labels.update(lab)
136
+
137
+ default_value = attr[key].get('default_value', None)
138
+
139
+ style = attr[key]['style']
140
+ if style in ['Simple', 'Comment']:
141
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
142
+ elif style == 'Dictionary':
143
+ parsed_attributes[key] = proc_dictionary_attribute(txt, object_action, labels, if_missing, default_value)
144
+ if key in parsed_attributes and parsed_attributes[key] is not None:
145
+ if parsed_attributes[key].get('value', None) is not None:
146
+ if isinstance(parsed_attributes[key]['value'], dict):
147
+ parsed_attributes[key]['dict'] = json.dumps(parsed_attributes[key]['value'], indent=2)
148
+ else:
149
+ continue
150
+ else:
151
+ continue
152
+
153
+ elif style == 'Valid Value':
154
+ parsed_attributes[key] = proc_valid_value(txt, object_action, labels,
155
+ attr[key].get('valid_values', None), if_missing,
156
+ default_value)
157
+ elif style == 'QN':
158
+ parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
159
+ object_action, version, if_missing)
160
+ if key == 'Qualified Name' and parsed_attributes[key]['value'] and parsed_attributes[key][
161
+ 'exists'] is False:
162
+ parsed_output['exists'] = False
163
+ elif style == 'ID':
164
+ parsed_attributes[key] = proc_el_id(egeria_client, command_display_name, command_qn_prefix, labels, txt,
165
+ object_action, version, if_missing)
166
+
167
+ parsed_output['guid'] = parsed_attributes[key].get('guid', None)
168
+ parsed_output['qualified_name'] = parsed_attributes[key].get('qualified_name', None)
169
+ parsed_output['exists'] = parsed_attributes[key]['exists']
170
+ if parsed_attributes[key]['valid'] is False:
171
+ parsed_output['valid'] = False
172
+ parsed_output['reason'] += parsed_attributes[key]['reason']
173
+
174
+ elif style == 'Reference Name':
175
+ parsed_attributes[key] = proc_ids(egeria_client, key, labels, txt, object_action, if_missing)
176
+ if ((if_missing == ERROR) and parsed_attributes[key].get("value", None) and parsed_attributes[key][
177
+ 'exists'] is False):
178
+ msg = f"Reference Name `{parsed_attributes[key]['value']}` is specified but does not exist"
179
+ logger.error(msg)
180
+ parsed_output['valid'] = False
181
+ parsed_output['reason'] += msg
182
+ elif parsed_attributes[key]['valid'] is False:
183
+ parsed_output['valid'] = False
184
+ parsed_output['reason'] += parsed_attributes[key]['reason']
185
+
186
+ elif style == 'GUID':
187
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
188
+ elif style == 'Ordered Int':
189
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing)
190
+ elif style == 'Simple Int':
191
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value, "int")
192
+ elif style == 'Simple List':
193
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value, "list")
194
+ name_list = parsed_attributes[key]['value']
195
+ # attribute = re.split(r'[;,\n]+', name_list) if name_list is not None else None
196
+ attribute = split_tb_string(name_list)
197
+ parsed_attributes[key]['value'] = attribute
198
+ parsed_attributes[key]['name_list'] = name_list
199
+ elif style == 'Parent':
200
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
201
+ elif style == 'Bool':
202
+ parsed_attributes[key] = proc_bool_attribute(txt, object_action, labels, if_missing, default_value)
203
+ elif style == "Dictionary List":
204
+ parsed_attributes[key] = proc_simple_attribute(txt, object_action, labels, if_missing, default_value)
205
+ parsed_attributes[key]['list'] = json.loads(parsed_attributes[key]['value'])
206
+
207
+
208
+ elif style == 'Reference Name List':
209
+ parsed_attributes[key] = proc_name_list(egeria_client, key, txt, labels, if_missing)
210
+ if (parsed_attributes[key].get("value", None) and (
211
+ parsed_attributes[key]['exists'] is False or parsed_attributes[key]['valid'] is False)):
212
+ msg = (f"A Reference Name in `{parsed_attributes[key].get('name_list', None)}` is specified but "
213
+ f"does not exist")
214
+ logger.error(msg)
215
+ parsed_output['valid'] = False
216
+ parsed_output['reason'] += msg
217
+ else:
218
+ msg = f"Unknown attribute style: {style} for key `{key}`"
203
219
  logger.error(msg)
204
- parsed_output['valid'] = False
205
- parsed_output['reason'] += msg
206
- else:
207
- msg = f"Unknown attribute style: {style} for key `{key}`"
208
- logger.error(msg)
209
- sys.exit(1)
220
+ sys.exit(1)
221
+ parsed_attributes[key]['valid'] = False
222
+ parsed_attributes[key]['value'] = None
223
+ if key == "Display Name":
224
+ display_name = parsed_attributes[key]['value']
225
+
226
+ value = parsed_attributes[key].get('value', None)
227
+
228
+ if value is not None:
229
+ if isinstance(value, list):
230
+ list_out = f"\n\t* {key}:\n\n"
231
+ for item in value:
232
+ list_out += f"\t{item}\n"
233
+ parsed_output['display'] += list_out
234
+ elif isinstance(value, dict):
235
+ list_out = f"\n\t* {key}:\n\n"
236
+ for k, v in value.items():
237
+ list_out += f"\t{k}: \n\t\t{v}\n"
238
+ parsed_output['display'] += list_out
239
+ else:
240
+ parsed_output['display'] += f"\n\t* {key}: \n`{value}`\n\t"
241
+ except PyegeriaException as e:
242
+ logger.error(f"PyegeriaException occurred: {e}")
243
+
244
+ print_basic_exception(e)
245
+
246
+ except ValidationError as e:
210
247
  parsed_attributes[key]['valid'] = False
211
248
  parsed_attributes[key]['value'] = None
212
- if key == "Display Name":
213
- display_name = parsed_attributes[key]['value']
214
-
215
- value = parsed_attributes[key].get('value', None)
216
-
217
- if value is not None:
218
- # if the value is a dict, get the flattened name list
219
- value = parsed_attributes[key].get('name_list', None) if isinstance(value, (dict, list)) else value
220
- parsed_output['display'] += f"\n\t* {key}: `{value}`\n\t"
249
+ print_validation_error(e)
221
250
 
222
251
 
223
252
  parsed_output['attributes'] = parsed_attributes
@@ -504,7 +533,8 @@ def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str =
504
533
 
505
534
  attribute = extract_attribute(txt, labels)
506
535
 
507
- attribute = default_value if attribute is None else attribute.replace('\n', '')
536
+ # attribute = default_value if attribute is None else attribute.replace('\n', '')
537
+ attribute = default_value if attribute is None else attribute
508
538
 
509
539
  if attribute is None:
510
540
  if if_missing == INFO or if_missing == WARNING:
@@ -519,8 +549,10 @@ def proc_simple_attribute(txt: str, action: str, labels: set, if_missing: str =
519
549
 
520
550
  if attribute and simp_type == "int" :
521
551
  attribute = int(attribute)
522
- elif attribute and simp_type == "list":
523
- attribute = list(attribute)
552
+ # elif attribute and simp_type == "list":
553
+ # if isinstance(attribute, str):
554
+ # attribute = [piece.strip() for piece in re.split(r'[,\n]', attribute) if piece.strip()]
555
+
524
556
 
525
557
 
526
558
  return {"status": INFO, "OK": None, "value": attribute, "valid": valid, "exists": True}
@@ -554,8 +586,8 @@ def proc_dictionary_attribute(txt: str, action: str, labels: set, if_missing: st
554
586
  default_value = None
555
587
 
556
588
  attr = extract_attribute(txt, labels)
557
- attribute = json.loads(attr) if attr is not None else default_value
558
-
589
+ # attribute = json.loads(attr) if attr is not None else default_value
590
+ attribute = parse_to_dict(attr)
559
591
 
560
592
  if attribute is None:
561
593
  if if_missing == INFO or if_missing == WARNING:
@@ -387,7 +387,7 @@ def set_gov_prop_body(object_type: str, qualified_name: str, attributes: dict)->
387
387
  prop_bod["importance"] = attributes.get('Importance', {}).get('value', None)
388
388
  prop_bod["implications"] = attributes.get('Implication', {}).get('value', [])
389
389
  prop_bod["outcomes"] = attributes.get('Outcomes', {}).get('value', [])
390
- prop_bod["results"] = attributes.get('Results', {}).get('value', [])
390
+ prop_bod["results"] = attributes.get('Results', {}).get('value', []) or []
391
391
  prop_bod["effectiveFrom"] = attributes.get('Effective From', {}).get('value', None),
392
392
  prop_bod["effectiveTo"] = attributes.get('Effective To', {}).get('value', None),
393
393
  prop_bod["additionalProperties"] = attributes.get('Additional Properties', {}).get('value', None),
@@ -425,9 +425,12 @@ def update_gov_body_for_type(object_type: str, body: dict, attributes: dict) ->
425
425
  body['namePatterns'] = attributes.get('Name Patterns', {}).get('value', [])
426
426
  return body
427
427
  elif object_type in ["TermsAndConditions", "Certification Type", "License Type"]:
428
- body['entitlements'] = attributes.get('Entitlementss', {}).get('value', {})
429
- body['restrictions'] = attributes.get('Restrictions', {}).get('value', {})
430
- body['obligations'] = attributes.get('Obligations', {}).get('value', {})
428
+ entitlements = attributes.get('Entitlementss', {}).get('value', {}) if attributes.get('Entitlementss',None) else None
429
+ restrictions = attributes.get('Restrictions', {}).get('value', {}) if attributes.get('Restrictions',None) else None
430
+ obligations = attributes.get('Obligations', {}).get('value', {}) if attributes.get('Obligations',None) else None
431
+ body['entitlements'] = entitlements
432
+ body['restrictions'] = restrictions
433
+ body['obligations'] = obligations
431
434
 
432
435
  return body
433
436
 
@@ -2,6 +2,7 @@
2
2
  This file contains functions for extracting data from text for Egeria Markdown processing
3
3
  """
4
4
  import re
5
+ import json
5
6
  from typing import Any
6
7
 
7
8
  from md_processing.md_processing_utils.common_md_utils import (print_msg, find_key_with_value, get_element_dictionary,
@@ -74,56 +75,94 @@ def extract_command(block: str) -> str | None:
74
75
  return None
75
76
 
76
77
 
77
- def extract_attribute(text: str, labels: set) -> str | None:
78
+ # def extract_attribute(text: str, labels: set) -> str | None:
79
+ # """
80
+ # Extracts the attribute value from a string.
81
+ #
82
+ # Args:
83
+ # text: The input string.
84
+ # labels: List of equivalent labels to search for
85
+ #
86
+ # Returns:
87
+ # The value of the attribute, or None if not found.
88
+ #
89
+ # Note:
90
+ # Lines beginning with '>' are ignored.
91
+ # """
92
+ # # Iterate over the list of labels
93
+ # for label in labels:
94
+ # # Construct pattern for the current label
95
+ # # text = re.sub(r'\s+', ' ', text).strip() # just added
96
+ # # text = re.sub(r'\n\n+', '\n\n', text).strip()
97
+ #
98
+ # # Replace multiple spaces or tabs with a single space
99
+ # normalized = re.sub(r'\s+', ' ', text)
100
+ # # Collapse multiple blank lines into a single one
101
+ # normalized = re.sub(r'\n\s*\n', '\n', normalized).strip()
102
+ #
103
+ # # label = label.strip()
104
+ # # pattern = rf"##\s*{re.escape(label)}\s*\n(?:\s*\n)*?(.*?)(?:#|___|$)"
105
+ # # Normalize the label
106
+ # normalized_label = re.sub(r'\s+', ' ', label.strip())
107
+ #
108
+ # # Construct the regex pattern
109
+ # pattern = rf"##\s*{re.escape(normalized_label)}\s*\n(?:\s*\n)*?(.*?)(?:#|___|$)"
110
+ # # pattern = rf"##\s+{re.escape(label)}\n(.*?)(?:#|___|$)" # modified from --- to enable embedded tables
111
+ # match = re.search(pattern, text, re.DOTALL)
112
+ # if match:
113
+ # # Extract matched text
114
+ # matched_text = match.group(1)
115
+ #
116
+ # # Filter out lines beginning with '>'
117
+ # filtered_lines = [line for line in matched_text.split('\n') if not line.strip().startswith('>')]
118
+ # filtered_text = '\n'.join(filtered_lines)
119
+ #
120
+ # # Replace consecutive \n with a single \n
121
+ # extracted_text = re.sub(r'\n+', '\n', filtered_text)
122
+ # if not extracted_text.isspace() and extracted_text:
123
+ # return extracted_text.strip() # Return the cleaned text - I removed the title casing
124
+ #
125
+ # return None
126
+
127
+
128
+ from typing import Optional, List
129
+
130
+ def extract_attribute(text: str, labels: List[str]) -> Optional[str]:
78
131
  """
79
- Extracts the attribute value from a string.
132
+ def extract_attribute(text: str, labels: List[str]) -> Optional[str]:
80
133
 
81
- Args:
82
- text: The input string.
83
- labels: List of equivalent labels to search for
134
+ Extracts the attribute value from a string while:
135
+ - Preserving single newlines within the matched text.
136
+ - Removing lines starting with '>'.
84
137
 
85
- Returns:
86
- The value of the attribute, or None if not found.
138
+ Args:
139
+ text: The input string containing labeled sections.
140
+ labels: List of equivalent labels to search for.
87
141
 
88
- Note:
89
- Lines beginning with '>' are ignored.
90
- """
91
- # Iterate over the list of labels
142
+ Returns:
143
+ The cleaned value of the attribute, or None if not found.
144
+ """
92
145
  for label in labels:
93
146
  # 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)
147
+ pattern = rf"## {re.escape(label)}\n(.*?)(?=^##|\Z)" # Captures content until the next '##' or end of text
148
+ match = re.search(pattern, text, re.DOTALL | re.MULTILINE)
111
149
  if match:
112
150
  # Extract matched text
113
- matched_text = match.group(1)
151
+ extracted_text = match.group(1)
114
152
 
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)
153
+ # Remove lines starting with '>'
154
+ filtered_lines = [line for line in extracted_text.splitlines() if not line.lstrip().startswith(">")]
118
155
 
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
156
+ # Join the lines back, preserving single newlines
157
+ cleaned_text = "\n".join(filtered_lines).strip()
123
158
 
159
+ if cleaned_text:
160
+ return cleaned_text # Return the cleaned and formatted text
124
161
  return None
125
162
 
126
163
 
164
+
165
+
127
166
  def process_simple_attribute(txt: str, labels: set, if_missing: str = INFO) -> str | None:
128
167
  """Process a simple attribute based on the provided labels and if_missing value.
129
168
  Extract the attribute value from the text and return it if it exists.
pyegeria/__init__.py CHANGED
@@ -62,7 +62,7 @@ from .registered_info import RegisteredInfo
62
62
  from .runtime_manager_omvs import RuntimeManager
63
63
  from .server_operations import ServerOps
64
64
  from .solution_architect import SolutionArchitect
65
- from .utils import body_slimmer, print_response, to_pascal_case, to_camel_case, camel_to_title_case
65
+ from .utils import body_slimmer,to_pascal_case, to_camel_case, camel_to_title_case
66
66
  from .valid_metadata_omvs import ValidMetadataManager
67
67
  from .x_action_author_omvs import ActionAuthor
68
68
  from .template_manager_omvs import TemplateManager