labfreed 0.0.20__py2.py3-none-any.whl → 0.1.1__py2.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 labfreed might be problematic. Click here for more details.

@@ -0,0 +1,221 @@
1
+ import os
2
+ import re
3
+ import yaml
4
+ import json
5
+ import jsonpath_ng.ext as jsonpath
6
+
7
+
8
+ from labfreed.IO.parse_pac import PAC_Parser, PACID_With_Extensions
9
+ from labfreed.PAC_ID_Resolver.data_types import CIT, CITEntry, CITEvaluated, Service
10
+
11
+ from labfreed.PAC_ID_Resolver.non_needed.query_tools import JSONPathTools
12
+
13
+
14
+ def load_cit(path):
15
+ with open(path, 'r') as f:
16
+ cit = yaml.safe_load(f)
17
+ cit = CIT.model_validate(cit)
18
+ return cit
19
+
20
+
21
+ class PAC_ID_Resolver():
22
+ def __init__(self, cits:list[CIT]=None):
23
+ if not cits:
24
+ cits = []
25
+ self.cits = cits
26
+
27
+ # load the default cit
28
+ dir = os.path.dirname(__file__)
29
+ fn ='cit.yaml'
30
+ p = os.path.join(dir, fn)
31
+ with open(p, 'r') as f:
32
+ cit = yaml.safe_load(f)
33
+ cit = CIT.model_validate(cit)
34
+ self.cits.append(cit)
35
+
36
+
37
+ def resolve(self, pac_id:PACID_With_Extensions|str):
38
+ if isinstance(pac_id, str):
39
+ pac_id = PAC_Parser().parse(pac_id)
40
+
41
+ pac_id_json = pac_id.model_dump(by_alias=True)
42
+
43
+
44
+ # dir = os.path.dirname(__file__)
45
+ # p = os.path.join(dir, 'pac-id.json')
46
+ # with open(p , 'r') as f:
47
+ # _json = f.read()
48
+ # pac_id_json = json.loads(_json)
49
+
50
+ matches = [self._evaluate_against_cit(pac_id_json, cit) for cit in self.cits]
51
+ return matches
52
+
53
+
54
+ def _evaluate_against_cit(self, pac_id_json, cit:CIT):
55
+ cit_evaluated = CITEvaluated(origin=cit.origin)
56
+ for block in cit.cit:
57
+ _, is_applicable = self._evaluate_applicable_if(pac_id_json, block.applicable_if)
58
+ if not is_applicable:
59
+ continue
60
+
61
+ for e in block.entries:
62
+ url = self.eval_url_template(pac_id_json, e.template_url)
63
+ cit_evaluated.services.append(Service(
64
+ service_name=e.service_name,
65
+ application_intents=e.application_intents,
66
+ service_type=e.service_type,
67
+ url = url
68
+ )
69
+ )
70
+ return cit_evaluated
71
+
72
+
73
+ def _evaluate_applicable_if(self, pac_id_json:str, expression) -> tuple[str, bool]:
74
+ expression = self._apply_convenience_substitutions(expression)
75
+
76
+ tokens = self._tokenize_jsonpath_expression(expression)
77
+ expression_for_eval = self._expression_from_tokens(pac_id_json, tokens)
78
+ applicable = eval(expression_for_eval, {}, {})
79
+
80
+ return expression_for_eval, applicable
81
+
82
+
83
+ def _apply_convenience_substitutions(self, query):
84
+ ''' applies a few substitutions, which enable abbreviated syntax.'''
85
+
86
+ # allow access to array elements by key
87
+ q_mod = re.sub(r"\[('.+?')\]", r"[?(@.key == \1)]", query )
88
+
89
+ # allow shorter path
90
+ # substitutions = [
91
+ # (r'(?<=^)id', 'pac.id'),
92
+ # (r'(?<=^)cat', 'pac.id.cat'),
93
+ # (r'(?<=\.)id(?=\.)', 'identifier'),
94
+ # (r'(?<=\.)cat$', 'categories'),
95
+ # (r'(?<=\.)cat(?=\[)', 'categories'),
96
+ # (r'(?<=\.)seg$', 'segments'),
97
+ # (r'(?<=\.)seg(?=\[)', 'segments'),
98
+ # (r'(?<=^)isu', 'pac.isu'),
99
+ # (r'(?<=\.)isu', 'issuer'),
100
+ # (r'(?<=^)ext', 'pac.ext'),
101
+ # (r'(?<=\.)ext(?=$)', 'extensions'),
102
+ # (r'(?<=\.)ext(?=\[)', 'extensions'),
103
+ # ]
104
+ # for sub in substitutions:
105
+ # q_mod = re.sub(sub[0], sub[1], q_mod)
106
+
107
+ return q_mod
108
+
109
+
110
+ def _tokenize_jsonpath_expression(self, expr: str):
111
+ token_pattern = re.compile(
112
+ r"""
113
+ (?P<LPAREN>\() |
114
+ (?P<RPAREN>\)) |
115
+ (?P<LOGIC>\bAND\b|\bOR\b|\bNOT\b) |
116
+ (?P<OPERATOR>==|!=|<=|>=|<|>) |
117
+ (?P<JSONPATH>
118
+ \$ # starts with $
119
+ (?:
120
+ [^\s\[\]()]+ # path segments, dots, etc.
121
+ |
122
+ \[ # open bracket
123
+ (?: # non-capturing group
124
+ [^\[\]]+ # anything but brackets
125
+ |
126
+ \[[^\[\]]*\] # nested brackets (1 level)
127
+ )*
128
+ \]
129
+ )+ # one or more bracket/segment blocks
130
+ ) |
131
+ (?P<LITERAL>
132
+ [A-Za-z_][\w\.\-]*[A-Za-z0-9] # domain-like literals
133
+ )
134
+ """,
135
+ re.VERBOSE
136
+ )
137
+
138
+ tokens = []
139
+ pos = 0
140
+ while pos < len(expr):
141
+ match = token_pattern.match(expr, pos)
142
+ if match:
143
+ group_type = match.lastgroup
144
+ value = match.group().strip()
145
+ tokens.append((value, group_type))
146
+ pos = match.end()
147
+ elif expr[pos].isspace():
148
+ pos += 1 # skip whitespace
149
+ else:
150
+ raise SyntaxError(f"Unexpected character at position {pos}: {expr[pos]}")
151
+
152
+ return tokens
153
+
154
+
155
+ def _expression_from_tokens(self, pac_id_json:str, tokens: tuple[str, str]):
156
+ out = []
157
+ for i in range(len(tokens)):
158
+ prev_token = tokens[i-1] if i > 0 else (None, None)
159
+ curr_token = tokens[i]
160
+ next_token = tokens[i+1] if i < len(tokens)-1 else (None, None)
161
+ if curr_token[1] == 'JSONPATH':
162
+ res = self._evaluate_jsonpath(pac_id_json, curr_token[0])
163
+
164
+ if prev_token[1] == 'OPERATOR' or next_token[1] == 'OPERATOR':
165
+ # if token is part of comparison return the value of the node
166
+ if len(res) == 0:
167
+ out.append('""')
168
+ else:
169
+ out.append(f'"{res[0].upper()}"')
170
+ else:
171
+ # if token is not part of comparison evaluate to boolean
172
+ if len(res) == 0:
173
+ out.append(False)
174
+ else:
175
+ out.append(True)
176
+
177
+ elif curr_token[1] == 'LOGIC':
178
+ out.append(curr_token[0].lower())
179
+
180
+ elif curr_token[1] == 'LITERAL':
181
+ t = curr_token[0]
182
+ if t[0] != '"':
183
+ t = '"' + t
184
+ if t[-1] != '"':
185
+ t = t + '"'
186
+ out.append(t.upper())
187
+ else:
188
+ out.append(curr_token[0])
189
+
190
+ s = ' '.join([str(e) for e in out])
191
+ return s
192
+
193
+
194
+
195
+
196
+ def eval_url_template(self, pac_id_json, url_template):
197
+ url = url_template
198
+ placeholders = re.findall(r'\{(.+?)\}', url_template)
199
+ for placeholder in placeholders:
200
+ expanded_placeholder = self._apply_convenience_substitutions(placeholder)
201
+ res = self._evaluate_jsonpath(pac_id_json, expanded_placeholder) or ['']
202
+ url = url.replace(f'{{{placeholder}}}', str(res[0]))
203
+ # res = self.substitute_jsonpath_expressions(expanded_placeholder, Patterns.jsonpath.value, as_bool=False)
204
+ # url = url.replace(f'{{{placeholder}}}', res)
205
+ return url
206
+
207
+
208
+
209
+
210
+ def _evaluate_jsonpath(self, pac_id_json, jp_query):
211
+ jsonpath_expr = jsonpath.parse(jp_query)
212
+ matches = [match.value for match in jsonpath_expr.find(pac_id_json)]
213
+ return matches
214
+
215
+
216
+
217
+
218
+
219
+ if __name__ == '__main__':
220
+ r = PAC_ID_Resolver()
221
+ r.resolve()
@@ -8,7 +8,7 @@ from typing import Annotated, Literal
8
8
  from pydantic import PrivateAttr, RootModel, ValidationError, field_validator, model_validator, Field
9
9
  from labfreed.TREX.unece_units import unece_unit, unece_unit_codes, unece_units, unit_name, unit_symbol
10
10
  from labfreed.utilities.utility_types import DataTable, Quantity, Unit, unece_unit_code_from_quantity
11
- from labfreed.validation import BaseModelWithValidationMessages
11
+ from labfreed.validation import BaseModelWithValidationMessages, ValidationMsgLevel
12
12
  from abc import ABC, abstractmethod
13
13
 
14
14
  from labfreed.PAC_ID.extensions import Extension
@@ -180,7 +180,7 @@ class BoolValue(ValueMixin):
180
180
  if not self.value in ['T', 'F']:
181
181
  self.add_validation_message(
182
182
  source=f"TREX boolean value {self.value}",
183
- type="Error",
183
+ level= ValidationMsgLevel.ERROR,
184
184
  msg=f'{self.value} is no valid boolean. Must be T or F',
185
185
  highlight_pattern = f'{self.value}',
186
186
  highlight_sub=[c for c in self.value]
@@ -207,7 +207,7 @@ class AlphanumericValue(ValueMixin):
207
207
  if re.match(r'[a-z]', self.value):
208
208
  self.add_validation_message(
209
209
  source=f"TREX value {self.value}",
210
- type="Error",
210
+ level= ValidationMsgLevel.ERROR,
211
211
  msg=f"Lower case characters are not allowed.",
212
212
  highlight_pattern = self.value
213
213
  )
@@ -215,7 +215,7 @@ class AlphanumericValue(ValueMixin):
215
215
  if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
216
216
  self.add_validation_message(
217
217
  source=f"TREX value {self.value}",
218
- type="Error",
218
+ level= ValidationMsgLevel.ERROR,
219
219
  msg=f"Characters {','.join(not_allowed_chars)} are not allowed in alphanumeric segment",
220
220
  highlight_pattern = self.value,
221
221
  highlight_sub=not_allowed_chars
@@ -242,7 +242,7 @@ class TextValue(ValueMixin):
242
242
  if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
243
243
  self.add_validation_message(
244
244
  source=f"TREX value {self.value}",
245
- type="Error",
245
+ level= ValidationMsgLevel.ERROR,
246
246
  msg=f"Characters {','.join(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
247
247
  highlight_pattern = self.value,
248
248
  highlight_sub=not_allowed_chars
@@ -268,7 +268,7 @@ class BinaryValue(ValueMixin):
268
268
  if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
269
269
  self.add_validation_message(
270
270
  source=f"TREX value {self.value}",
271
- type="Error",
271
+ tlevel= ValidationMsgLevel.ERROR,
272
272
  msg=f"Characters {','.join(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
273
273
  highlight_pattern = self.value,
274
274
  highlight_sub=not_allowed_chars
@@ -286,7 +286,7 @@ class ErrorValue(ValueMixin):
286
286
  if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
287
287
  self.add_validation_message(
288
288
  source=f"TREX value {self.value}",
289
- type="Error",
289
+ level= ValidationMsgLevel.ERROR,
290
290
  msg=f"Characters {','.join(not_allowed_chars)} are not allowed in error segment",
291
291
  highlight_pattern = self.value,
292
292
  highlight_sub=not_allowed_chars
@@ -309,7 +309,7 @@ class ValueSegment(TREX_Segment, ValueMixin, ABC):
309
309
  if not self.type in valid_types:
310
310
  self.add_validation_message(
311
311
  source=f"TREX value segment {self.key}",
312
- type="Error",
312
+ level= ValidationMsgLevel.ERROR,
313
313
  msg=f"Type {self.type} is invalid. Must be 'T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E' or a UNECE unit",
314
314
  highlight_pattern = self.type
315
315
  )
@@ -385,7 +385,7 @@ class ColumnHeader(BaseModelWithValidationMessages):
385
385
  if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.key)):
386
386
  self.add_validation_message(
387
387
  source=f"TREX table column {self.key}",
388
- type="Error",
388
+ level= ValidationMsgLevel.ERROR,
389
389
  msg=f"Column header key contains invalid characters: {','.join(not_allowed_chars)}",
390
390
  highlight_pattern = f'{self.key}$',
391
391
  highlight_sub=not_allowed_chars
@@ -398,7 +398,7 @@ class ColumnHeader(BaseModelWithValidationMessages):
398
398
  if not self.type in valid_types:
399
399
  self.add_validation_message(
400
400
  source=f"TREX table column {self.key}",
401
- type="Error",
401
+ level= ValidationMsgLevel.ERROR,
402
402
  msg=f"Type '{self.type}' is invalid. Must be 'T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E' or a UNECE unit",
403
403
  highlight_pattern = self.type
404
404
  )
@@ -435,7 +435,7 @@ class TREX_Table(TREX_Segment):
435
435
  if len(self.column_headers) != most_common_len:
436
436
  self.add_validation_message(
437
437
  source=f"Table {self.key}",
438
- type="Error",
438
+ level= ValidationMsgLevel.ERROR,
439
439
  msg=f"Size mismatch: Table header contains {self.column_names} keys, while most rows have {most_common_len}",
440
440
  highlight_pattern = self.key
441
441
  )
@@ -448,7 +448,7 @@ class TREX_Table(TREX_Segment):
448
448
  if len(row) != expected_row_len:
449
449
  self.add_validation_message(
450
450
  source=f"Table {self.key}",
451
- type="Error",
451
+ level= ValidationMsgLevel.ERROR,
452
452
  msg=f"Size mismatch: Table row {i} contains {len(row)} elements. Expected size is {expected_row_len}",
453
453
  highlight_pattern = row.serialize_for_trex()
454
454
  )
@@ -480,7 +480,7 @@ class TREX_Table(TREX_Segment):
480
480
  except AssertionError:
481
481
  self.add_validation_message(
482
482
  source=f"Table {self.key}",
483
- type="Error",
483
+ level= ValidationMsgLevel.ERROR,
484
484
  msg=f"Type mismatch: Table row {i}, column {nm} is of wrong type. According to the header it should be {t_expected}",
485
485
  highlight_pattern = row.serialize_for_trex(),
486
486
  highlight_sub=[c for c in e.value]
@@ -490,7 +490,7 @@ class TREX_Table(TREX_Segment):
490
490
  for m in msg:
491
491
  self.add_validation_message(
492
492
  source=f"Table {self.key}",
493
- type="Error",
493
+ level= ValidationMsgLevel.ERROR,
494
494
  msg=m.problem_msg,
495
495
  highlight_pattern = row.serialize_for_trex(),
496
496
  highlight_sub=[c for c in e.value]
labfreed/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.0.20"
5
+ __version__ = "0.1.1"
labfreed/validation.py CHANGED
@@ -1,37 +1,52 @@
1
+ from enum import Enum, auto
2
+ import re
1
3
  from pydantic import BaseModel, Field, PrivateAttr
2
4
  from typing import List, Set, Tuple
3
5
 
4
6
  from rich import print
5
7
  from rich.text import Text
8
+ from rich.table import Table
6
9
 
7
10
 
8
11
  domain_name_pattern = r"(?!-)([A-Za-z0-9-]{1,63}(?<!-)\.)+[A-Za-z]{2,63}"
9
12
  hsegment_pattern = r"[A-Za-z0-9_\-\.~!$&'()+,:;=@]|%[0-9A-Fa-f]{2}"
10
13
 
11
14
 
15
+ class ValidationMsgLevel(Enum):
16
+ ERROR = auto()
17
+ ERROR_AUTO_FIX = auto()
18
+ WARNING = auto()
19
+ RECOMMENDATION = auto()
20
+ INFO = auto()
21
+
12
22
  class ValidationMessage(BaseModel):
23
+ source_id:int
13
24
  source:str
14
- type: str
25
+ level: ValidationMsgLevel
15
26
  problem_msg:str
16
27
  recommendation_msg: str = ""
17
28
  highlight:str = "" #this can be used to highlight problematic parts
18
- highlight_sub:list[str] = Field(default_factory=list())
29
+ highlight_sub_patterns:list[str] = Field(default_factory=list)
30
+
31
+
32
+
19
33
 
20
- @property
21
- def emphazised_highlight(self):
22
- fmt = lambda s: f'[emph]{s}[/emph]'
23
34
 
24
- if not self.highlight_sub:
25
- return fmt(self.highlight)
35
+ # @property
36
+ # def emphazised_highlight(self):
37
+ # fmt = lambda s: f'[emph]{s}[/emph]'
38
+
39
+ # if not self.highlight_sub_patterns:
40
+ # return fmt(self.highlight)
26
41
 
27
- result = []
28
- for c in self.highlight:
29
- if c in self.highlight_sub:
30
- result.append(fmt(c))
31
- else:
32
- result.append(c)
42
+ # result = []
43
+ # for c in self.highlight:
44
+ # if c in self.highlight_sub_patterns:
45
+ # result.append(fmt(c))
46
+ # else:
47
+ # result.append(c)
33
48
 
34
- return ''.join(result)
49
+ # return ''.join(result)
35
50
 
36
51
 
37
52
  class LabFREEDValidationError(ValueError):
@@ -51,10 +66,10 @@ class BaseModelWithValidationMessages(BaseModel):
51
66
  The purpose of that is to allow only minimal validation but on top check for stricter recommendations"""
52
67
  _validation_messages: list[ValidationMessage] = PrivateAttr(default_factory=list)
53
68
 
54
- def add_validation_message(self, *, msg: str, type:str, recommendation:str="", source:str="", highlight_pattern="", highlight_sub=None):
69
+ def add_validation_message(self, *, msg: str, level:ValidationMsgLevel, recommendation:str="", source:str="", highlight_pattern="", highlight_sub=None):
55
70
  if not highlight_sub:
56
71
  highlight_sub = []
57
- w = ValidationMessage(problem_msg=msg, recommendation_msg=recommendation, source=source, type=type, highlight=highlight_pattern, highlight_sub=highlight_sub)
72
+ w = ValidationMessage(problem_msg=msg, recommendation_msg=recommendation, source=source, level=level, highlight=highlight_pattern, highlight_sub_patterns=highlight_sub, source_id=id(self))
58
73
 
59
74
  if not w in self._validation_messages:
60
75
  self._validation_messages.append(w)
@@ -113,43 +128,116 @@ class BaseModelWithValidationMessages(BaseModel):
113
128
  return filter_warnings(self.get_nested_validation_messages())
114
129
 
115
130
 
116
- def print_validation_messages(self, str_to_highlight_in=None, target='console'):
117
- if not str_to_highlight_in:
118
- str_to_highlight_in = str(self)
131
+ def str_for_validation_msg(self, validation_msg:ValidationMessage):
132
+ if validation_msg.source_id == id(self):
133
+ return validation_msg.source_id
134
+ #return validation_msg.emphasize_in(self(str))
135
+ else:
136
+ return str(self)
137
+
138
+ def str_highlighted(self):
139
+ raise NotImplementedError("Subclasses must implement format_special()")
140
+
141
+
142
+
143
+ def _emphasize_in(self, validation_msg, validation_node_str:str, fmt, color='black'):
144
+ if validation_msg.highlight_sub_patterns:
145
+ replacements = validation_msg.highlight_sub_patterns
146
+ else:
147
+ replacements = [validation_msg.highlight]
148
+ # Sort patterns by length descending to avoid subpattern clobbering
149
+ sorted_patterns = sorted(replacements, key=len, reverse=True)
150
+ # Escape the patterns for regex safety
151
+ escaped_patterns = [re.escape(p) for p in sorted_patterns]
152
+ # Create one regex pattern with alternation (longest first)
153
+ pattern = re.compile("|".join(escaped_patterns))
154
+
155
+ out = pattern.sub(lambda m: fmt(m.group(0)), validation_node_str)
156
+ return out
157
+
158
+
159
+ def print_validation_messages(self, target='console'):
119
160
  msgs = self.get_nested_validation_messages()
120
- print('\n'.join(['\n',
121
- '=======================================',
122
- 'Validation Results',
123
- '---------------------------------------'
124
- ]
125
- )
126
- )
161
+
162
+ table = Table(title=f"Validation Results", show_header=False)
163
+
164
+ col = lambda s: table.add_column(s, vertical='top')
165
+ col("-")
166
+
167
+
168
+ if not msgs:
169
+ table.add_row('All clear!', end_section=True)
170
+ return
127
171
 
128
172
  for m in msgs:
129
- if m.type.casefold() == "error":
173
+ if m.level == ValidationMsgLevel.ERROR:
130
174
  color = 'red'
131
175
  else:
132
176
  color = 'yellow'
133
177
 
134
- text = Text.from_markup(f'\n [bold {color}]{m.type} [/bold {color}] in \t {m.source}' )
135
- print(text)
136
178
  match target:
137
179
  case 'markdown':
138
- formatted_highlight = m.emphazised_highlight.replace('emph', f'🔸').replace('[/', '').replace('[', '').replace(']', '')
180
+ fmt = lambda s: f'🔸{s}🔸'
139
181
  case 'console':
140
- formatted_highlight = m.emphazised_highlight.replace('emph', f'bold {color}')
182
+ fmt = lambda s: f'[{color} bold]{s}[/{color} bold]'
141
183
  case 'html':
142
- formatted_highlight = m.emphazised_highlight.replace('emph', f'b').replace('[', '<').replace(']', '>')
143
- fmtd = str_to_highlight_in.replace(m.highlight, formatted_highlight)
144
- fmtd = Text.from_markup(fmtd)
145
- print(fmtd)
146
- print(Text.from_markup(f'{m.problem_msg}'))
184
+ fmt = lambda s: f'<span class="val_{color}">{s}</span>'
185
+ case 'html_styled':
186
+ fmt = lambda s: f'<b style="color:{color}>{s}</b>'
187
+
188
+ serialized = str(self)
189
+ emphazised_highlight = self._emphasize_in(m, serialized, fmt=fmt, color=color)
190
+
191
+ txt = f'[bold {color}]{m.level.name} [/bold {color}]'
192
+ txt += '\n' + f'{m.problem_msg}'
193
+ txt += '\n' + emphazised_highlight
194
+
195
+ table.add_row( txt)
196
+ table.add_section()
197
+
198
+ print(table)
199
+
200
+ # def print_validation_messages_(self, str_to_highlight_in=None, target='console'):
201
+ # if not str_to_highlight_in:
202
+ # str_to_highlight_in = str(self)
203
+ # msgs = self.get_nested_validation_messages()
204
+ # print('\n'.join(['\n',
205
+ # '=======================================',
206
+ # 'Validation Results',
207
+ # '---------------------------------------'
208
+ # ]
209
+ # )
210
+ # )
211
+
212
+ # if not msgs:
213
+ # print('All clear!')
214
+ # return
215
+
216
+ # for m in msgs:
217
+ # if m.level.casefold() == "error":
218
+ # color = 'red'
219
+ # else:
220
+ # color = 'yellow'
221
+
222
+ # text = Text.from_markup(f'\n [bold {color}]{m.level} [/bold {color}] in \t {m.source}' )
223
+ # print(text)
224
+ # match target:
225
+ # case 'markdown':
226
+ # formatted_highlight = m.emphazised_highlight.replace('emph', f'🔸').replace('[/', '').replace('[', '').replace(']', '')
227
+ # case 'console':
228
+ # formatted_highlight = m.emphazised_highlight.replace('emph', f'bold {color}')
229
+ # case 'html':
230
+ # formatted_highlight = m.emphazised_highlight.replace('emph', f'b').replace('[', '<').replace(']', '>')
231
+ # fmtd = str_to_highlight_in.replace(m.highlight, formatted_highlight)
232
+ # fmtd = Text.from_markup(fmtd)
233
+ # print(fmtd)
234
+ # print(Text.from_markup(f'{m.problem_msg}'))
147
235
 
148
236
 
149
237
 
150
238
  def filter_errors(val_msg:list[ValidationMessage]) -> list[ValidationMessage]:
151
- return [ m for m in val_msg if m.type.casefold() == "error" ]
239
+ return [ m for m in val_msg if m.level == ValidationMsgLevel.ERROR ]
152
240
 
153
241
  def filter_warnings(val_msg:list[ValidationMessage]) -> list[ValidationMessage]:
154
- return [ m for m in val_msg if m.type.casefold() != "error" ]
242
+ return [ m for m in val_msg if m.level != ValidationMsgLevel.ERROR ]
155
243