labfreed 0.2.8__py3-none-any.whl → 0.2.9__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.
- labfreed/__init__.py +11 -11
- labfreed/labfreed_infrastructure.py +258 -258
- labfreed/pac_cat/__init__.py +19 -19
- labfreed/pac_cat/category_base.py +51 -51
- labfreed/pac_cat/pac_cat.py +150 -150
- labfreed/pac_cat/predefined_categories.py +200 -200
- labfreed/pac_id/__init__.py +19 -19
- labfreed/pac_id/extension.py +48 -48
- labfreed/pac_id/id_segment.py +89 -89
- labfreed/pac_id/pac_id.py +140 -140
- labfreed/pac_id/url_parser.py +155 -155
- labfreed/pac_id/url_serializer.py +85 -84
- labfreed/pac_id_resolver/__init__.py +2 -2
- labfreed/pac_id_resolver/cit_common.py +81 -81
- labfreed/pac_id_resolver/cit_v1.py +244 -244
- labfreed/pac_id_resolver/cit_v2.py +313 -313
- labfreed/pac_id_resolver/resolver.py +97 -97
- labfreed/pac_id_resolver/services.py +82 -82
- labfreed/qr/__init__.py +1 -1
- labfreed/qr/generate_qr.py +422 -422
- labfreed/trex/__init__.py +16 -16
- labfreed/trex/python_convenience/__init__.py +3 -3
- labfreed/trex/python_convenience/data_table.py +87 -87
- labfreed/trex/python_convenience/pyTREX.py +248 -248
- labfreed/trex/python_convenience/quantity.py +66 -66
- labfreed/trex/table_segment.py +245 -245
- labfreed/trex/trex.py +69 -69
- labfreed/trex/trex_base_models.py +209 -209
- labfreed/trex/value_segments.py +99 -99
- labfreed/utilities/base36.py +82 -82
- labfreed/well_known_extensions/__init__.py +4 -4
- labfreed/well_known_extensions/default_extension_interpreters.py +6 -6
- labfreed/well_known_extensions/display_name_extension.py +40 -40
- labfreed/well_known_extensions/trex_extension.py +30 -30
- labfreed/well_known_keys/gs1/__init__.py +5 -5
- labfreed/well_known_keys/gs1/gs1.py +3 -3
- labfreed/well_known_keys/labfreed/well_known_keys.py +15 -15
- labfreed/well_known_keys/unece/__init__.py +3 -3
- labfreed/well_known_keys/unece/unece_units.py +67 -67
- {labfreed-0.2.8.dist-info → labfreed-0.2.9.dist-info}/METADATA +11 -8
- labfreed-0.2.9.dist-info/RECORD +45 -0
- {labfreed-0.2.8.dist-info → labfreed-0.2.9.dist-info}/licenses/LICENSE +21 -21
- labfreed-0.2.8.dist-info/RECORD +0 -45
- {labfreed-0.2.8.dist-info → labfreed-0.2.9.dist-info}/WHEEL +0 -0
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
from datetime import datetime, time
|
|
2
|
-
import re
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
from pydantic import PrivateAttr, model_validator
|
|
7
|
-
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMsgLevel, _quote_texts
|
|
8
|
-
from abc import ABC, abstractmethod
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
''' Configure pdoc'''
|
|
13
|
-
v_segs = ["NumericSegment",
|
|
14
|
-
"DateSegment",
|
|
15
|
-
"BoolSegment",
|
|
16
|
-
"AlphanumericSegment",
|
|
17
|
-
"TextSegment",
|
|
18
|
-
"BinarySegment"]
|
|
19
|
-
__all__ = ["TREX"] + v_segs + ["TableSegment"] # noqa: F822
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Value(LabFREED_BaseModel, ABC):
|
|
25
|
-
'''@private
|
|
26
|
-
Helper to add validation for various types to ValueSegments and Tables
|
|
27
|
-
'''
|
|
28
|
-
value:str
|
|
29
|
-
|
|
30
|
-
def serialize(self):
|
|
31
|
-
return self.value
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class NumericValue(Value):
|
|
36
|
-
|
|
37
|
-
@model_validator(mode='after')
|
|
38
|
-
def _validate(self):
|
|
39
|
-
value = self.value
|
|
40
|
-
if not_allowed_chars := set(re.sub(r'[0-9\.\-E]', '', value)):
|
|
41
|
-
self._add_validation_message(
|
|
42
|
-
source=f"TREX numeric value {value}",
|
|
43
|
-
level=ValidationMsgLevel.ERROR,
|
|
44
|
-
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in quantity segment. Must be a number.",
|
|
45
|
-
highlight_pattern = f'{value}',
|
|
46
|
-
highlight_sub=not_allowed_chars
|
|
47
|
-
)
|
|
48
|
-
if not re.fullmatch(r'-?\d+(\.\d+)?(E-?\d+)?', value):
|
|
49
|
-
self._add_validation_message(
|
|
50
|
-
source=f"TREX numeric value {value}",
|
|
51
|
-
level=ValidationMsgLevel.ERROR,
|
|
52
|
-
msg=f"{value} cannot be converted to number",
|
|
53
|
-
highlight_pattern = f'{value}'
|
|
54
|
-
)
|
|
55
|
-
return self
|
|
56
|
-
|
|
57
|
-
class DateValue(Value):
|
|
58
|
-
_date_time_dict:dict|None = PrivateAttr(default=None)
|
|
59
|
-
|
|
60
|
-
@model_validator(mode='after')
|
|
61
|
-
def _validate(self):
|
|
62
|
-
pattern:str = r'((?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2}))?(T(?P<hour>\d{2})(?P<minute>\d{2})(?P<second>\d{2})?(\.(?P<millisecond>\d{3}))?)?'
|
|
63
|
-
value=self.value
|
|
64
|
-
if not re.fullmatch(pattern, value):
|
|
65
|
-
self._add_validation_message(
|
|
66
|
-
source=f"TREX date value {value}",
|
|
67
|
-
level=ValidationMsgLevel.ERROR,
|
|
68
|
-
msg=f'{value} is not in a valid format. Valid format for date: YYYYMMDD; Valid for time: THHMM, THHMMSS, THHMMSS.SSS; Datetime any combination of valid date and time',
|
|
69
|
-
highlight_pattern = f'{value}'
|
|
70
|
-
)
|
|
71
|
-
return self
|
|
72
|
-
|
|
73
|
-
matches = re.match(pattern, value)
|
|
74
|
-
d = matches.groupdict()
|
|
75
|
-
d = {k: int(v) for k,v in d.items() if v }
|
|
76
|
-
if 'millisecond' in d.keys():
|
|
77
|
-
ms = d.pop('millisecond')
|
|
78
|
-
d.update({'microsecond': ms * 1000})
|
|
79
|
-
try:
|
|
80
|
-
if d.get('year'): # input is only a time
|
|
81
|
-
datetime(**d)
|
|
82
|
-
else:
|
|
83
|
-
time(**d)
|
|
84
|
-
except ValueError:
|
|
85
|
-
self._add_validation_message(
|
|
86
|
-
source=f"TREX date value {value}",
|
|
87
|
-
level=ValidationMsgLevel.ERROR,
|
|
88
|
-
msg=f'{value} is no valid date or time.',
|
|
89
|
-
highlight_pattern = f'{value}'
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
self._date_time_dict = d
|
|
93
|
-
return self
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
class BoolValue(Value):
|
|
97
|
-
|
|
98
|
-
@model_validator(mode='after')
|
|
99
|
-
def _validate(self):
|
|
100
|
-
if self.value not in ['T', 'F']:
|
|
101
|
-
self._add_validation_message(
|
|
102
|
-
source=f"TREX boolean value {self.value}",
|
|
103
|
-
level= ValidationMsgLevel.ERROR,
|
|
104
|
-
msg=f'{self.value} is no valid boolean. Must be T or F',
|
|
105
|
-
highlight_pattern = f'{self.value}',
|
|
106
|
-
highlight_sub=[c for c in self.value]
|
|
107
|
-
)
|
|
108
|
-
return self
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class AlphanumericValue(Value):
|
|
112
|
-
|
|
113
|
-
@model_validator(mode='after')
|
|
114
|
-
def _validate(self):
|
|
115
|
-
if re.match(r'[a-z]', self.value):
|
|
116
|
-
self._add_validation_message(
|
|
117
|
-
source=f"TREX value {self.value}",
|
|
118
|
-
level= ValidationMsgLevel.ERROR,
|
|
119
|
-
msg="Lower case characters are not allowed.",
|
|
120
|
-
highlight_pattern = self.value
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
|
|
124
|
-
self._add_validation_message(
|
|
125
|
-
source=f"TREX value {self.value}",
|
|
126
|
-
level= ValidationMsgLevel.ERROR,
|
|
127
|
-
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in alphanumeric segment",
|
|
128
|
-
highlight_pattern = self.value,
|
|
129
|
-
highlight_sub=not_allowed_chars
|
|
130
|
-
)
|
|
131
|
-
return self
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class TextValue(Value):
|
|
135
|
-
|
|
136
|
-
@model_validator(mode='after')
|
|
137
|
-
def _validate(self):
|
|
138
|
-
if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
|
|
139
|
-
self._add_validation_message(
|
|
140
|
-
source=f"TREX value {self.value}",
|
|
141
|
-
level= ValidationMsgLevel.ERROR,
|
|
142
|
-
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
|
|
143
|
-
highlight_pattern = self.value,
|
|
144
|
-
highlight_sub=not_allowed_chars
|
|
145
|
-
)
|
|
146
|
-
return self
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
class BinaryValue(Value):
|
|
150
|
-
|
|
151
|
-
@model_validator(mode='after')
|
|
152
|
-
def _validate(self):
|
|
153
|
-
if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
|
|
154
|
-
self._add_validation_message(
|
|
155
|
-
source=f"TREX value {self.value}",
|
|
156
|
-
level= ValidationMsgLevel.ERROR,
|
|
157
|
-
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
|
|
158
|
-
highlight_pattern = self.value,
|
|
159
|
-
highlight_sub=not_allowed_chars
|
|
160
|
-
)
|
|
161
|
-
return self
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
class ErrorValue(Value):
|
|
165
|
-
|
|
166
|
-
@model_validator(mode='after')
|
|
167
|
-
def _validate(self):
|
|
168
|
-
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
|
|
169
|
-
self._add_validation_message(
|
|
170
|
-
source=f"TREX value {self.value}",
|
|
171
|
-
level= ValidationMsgLevel.ERROR,
|
|
172
|
-
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in error segment",
|
|
173
|
-
highlight_pattern = self.value,
|
|
174
|
-
highlight_sub=not_allowed_chars
|
|
175
|
-
)
|
|
176
|
-
return self
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
class TREX_Segment(LabFREED_BaseModel, ABC):
|
|
180
|
-
'''@private
|
|
181
|
-
Abstract class representing a TREX_Segment
|
|
182
|
-
'''
|
|
183
|
-
key: str
|
|
184
|
-
|
|
185
|
-
@abstractmethod
|
|
186
|
-
def serialize(self):
|
|
187
|
-
raise NotImplementedError("Subclasses must implement 'serialize_as_trex()' method")
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
@model_validator(mode='after')
|
|
191
|
-
def _validate_key(self):
|
|
192
|
-
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.key)):
|
|
193
|
-
self._add_validation_message(
|
|
194
|
-
source=f"TREX segment key {self.key}",
|
|
195
|
-
level=ValidationMsgLevel.ERROR,
|
|
196
|
-
msg=f"Segment key contains invalid characters: {_quote_texts(not_allowed_chars)}",
|
|
197
|
-
highlight_pattern = f'{self.key}$',
|
|
198
|
-
highlight_sub=not_allowed_chars
|
|
199
|
-
)
|
|
200
|
-
return self
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
1
|
+
from datetime import datetime, time
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from pydantic import PrivateAttr, model_validator
|
|
7
|
+
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMsgLevel, _quote_texts
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
''' Configure pdoc'''
|
|
13
|
+
v_segs = ["NumericSegment",
|
|
14
|
+
"DateSegment",
|
|
15
|
+
"BoolSegment",
|
|
16
|
+
"AlphanumericSegment",
|
|
17
|
+
"TextSegment",
|
|
18
|
+
"BinarySegment"]
|
|
19
|
+
__all__ = ["TREX"] + v_segs + ["TableSegment"] # noqa: F822
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Value(LabFREED_BaseModel, ABC):
|
|
25
|
+
'''@private
|
|
26
|
+
Helper to add validation for various types to ValueSegments and Tables
|
|
27
|
+
'''
|
|
28
|
+
value:str
|
|
29
|
+
|
|
30
|
+
def serialize(self):
|
|
31
|
+
return self.value
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NumericValue(Value):
|
|
36
|
+
|
|
37
|
+
@model_validator(mode='after')
|
|
38
|
+
def _validate(self):
|
|
39
|
+
value = self.value
|
|
40
|
+
if not_allowed_chars := set(re.sub(r'[0-9\.\-E]', '', value)):
|
|
41
|
+
self._add_validation_message(
|
|
42
|
+
source=f"TREX numeric value {value}",
|
|
43
|
+
level=ValidationMsgLevel.ERROR,
|
|
44
|
+
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in quantity segment. Must be a number.",
|
|
45
|
+
highlight_pattern = f'{value}',
|
|
46
|
+
highlight_sub=not_allowed_chars
|
|
47
|
+
)
|
|
48
|
+
if not re.fullmatch(r'-?\d+(\.\d+)?(E-?\d+)?', value):
|
|
49
|
+
self._add_validation_message(
|
|
50
|
+
source=f"TREX numeric value {value}",
|
|
51
|
+
level=ValidationMsgLevel.ERROR,
|
|
52
|
+
msg=f"{value} cannot be converted to number",
|
|
53
|
+
highlight_pattern = f'{value}'
|
|
54
|
+
)
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
class DateValue(Value):
|
|
58
|
+
_date_time_dict:dict|None = PrivateAttr(default=None)
|
|
59
|
+
|
|
60
|
+
@model_validator(mode='after')
|
|
61
|
+
def _validate(self):
|
|
62
|
+
pattern:str = r'((?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2}))?(T(?P<hour>\d{2})(?P<minute>\d{2})(?P<second>\d{2})?(\.(?P<millisecond>\d{3}))?)?'
|
|
63
|
+
value=self.value
|
|
64
|
+
if not re.fullmatch(pattern, value):
|
|
65
|
+
self._add_validation_message(
|
|
66
|
+
source=f"TREX date value {value}",
|
|
67
|
+
level=ValidationMsgLevel.ERROR,
|
|
68
|
+
msg=f'{value} is not in a valid format. Valid format for date: YYYYMMDD; Valid for time: THHMM, THHMMSS, THHMMSS.SSS; Datetime any combination of valid date and time',
|
|
69
|
+
highlight_pattern = f'{value}'
|
|
70
|
+
)
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
matches = re.match(pattern, value)
|
|
74
|
+
d = matches.groupdict()
|
|
75
|
+
d = {k: int(v) for k,v in d.items() if v }
|
|
76
|
+
if 'millisecond' in d.keys():
|
|
77
|
+
ms = d.pop('millisecond')
|
|
78
|
+
d.update({'microsecond': ms * 1000})
|
|
79
|
+
try:
|
|
80
|
+
if d.get('year'): # input is only a time
|
|
81
|
+
datetime(**d)
|
|
82
|
+
else:
|
|
83
|
+
time(**d)
|
|
84
|
+
except ValueError:
|
|
85
|
+
self._add_validation_message(
|
|
86
|
+
source=f"TREX date value {value}",
|
|
87
|
+
level=ValidationMsgLevel.ERROR,
|
|
88
|
+
msg=f'{value} is no valid date or time.',
|
|
89
|
+
highlight_pattern = f'{value}'
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self._date_time_dict = d
|
|
93
|
+
return self
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class BoolValue(Value):
|
|
97
|
+
|
|
98
|
+
@model_validator(mode='after')
|
|
99
|
+
def _validate(self):
|
|
100
|
+
if self.value not in ['T', 'F']:
|
|
101
|
+
self._add_validation_message(
|
|
102
|
+
source=f"TREX boolean value {self.value}",
|
|
103
|
+
level= ValidationMsgLevel.ERROR,
|
|
104
|
+
msg=f'{self.value} is no valid boolean. Must be T or F',
|
|
105
|
+
highlight_pattern = f'{self.value}',
|
|
106
|
+
highlight_sub=[c for c in self.value]
|
|
107
|
+
)
|
|
108
|
+
return self
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AlphanumericValue(Value):
|
|
112
|
+
|
|
113
|
+
@model_validator(mode='after')
|
|
114
|
+
def _validate(self):
|
|
115
|
+
if re.match(r'[a-z]', self.value):
|
|
116
|
+
self._add_validation_message(
|
|
117
|
+
source=f"TREX value {self.value}",
|
|
118
|
+
level= ValidationMsgLevel.ERROR,
|
|
119
|
+
msg="Lower case characters are not allowed.",
|
|
120
|
+
highlight_pattern = self.value
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
|
|
124
|
+
self._add_validation_message(
|
|
125
|
+
source=f"TREX value {self.value}",
|
|
126
|
+
level= ValidationMsgLevel.ERROR,
|
|
127
|
+
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in alphanumeric segment",
|
|
128
|
+
highlight_pattern = self.value,
|
|
129
|
+
highlight_sub=not_allowed_chars
|
|
130
|
+
)
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class TextValue(Value):
|
|
135
|
+
|
|
136
|
+
@model_validator(mode='after')
|
|
137
|
+
def _validate(self):
|
|
138
|
+
if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
|
|
139
|
+
self._add_validation_message(
|
|
140
|
+
source=f"TREX value {self.value}",
|
|
141
|
+
level= ValidationMsgLevel.ERROR,
|
|
142
|
+
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
|
|
143
|
+
highlight_pattern = self.value,
|
|
144
|
+
highlight_sub=not_allowed_chars
|
|
145
|
+
)
|
|
146
|
+
return self
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class BinaryValue(Value):
|
|
150
|
+
|
|
151
|
+
@model_validator(mode='after')
|
|
152
|
+
def _validate(self):
|
|
153
|
+
if not_allowed_chars := set(re.sub(r'[A-Z0-9]', '', self.value)):
|
|
154
|
+
self._add_validation_message(
|
|
155
|
+
source=f"TREX value {self.value}",
|
|
156
|
+
level= ValidationMsgLevel.ERROR,
|
|
157
|
+
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in text segment. Base36 encoding only allows A-Z0-9",
|
|
158
|
+
highlight_pattern = self.value,
|
|
159
|
+
highlight_sub=not_allowed_chars
|
|
160
|
+
)
|
|
161
|
+
return self
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class ErrorValue(Value):
|
|
165
|
+
|
|
166
|
+
@model_validator(mode='after')
|
|
167
|
+
def _validate(self):
|
|
168
|
+
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.value)):
|
|
169
|
+
self._add_validation_message(
|
|
170
|
+
source=f"TREX value {self.value}",
|
|
171
|
+
level= ValidationMsgLevel.ERROR,
|
|
172
|
+
msg=f"Characters {_quote_texts(not_allowed_chars)} are not allowed in error segment",
|
|
173
|
+
highlight_pattern = self.value,
|
|
174
|
+
highlight_sub=not_allowed_chars
|
|
175
|
+
)
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class TREX_Segment(LabFREED_BaseModel, ABC):
|
|
180
|
+
'''@private
|
|
181
|
+
Abstract class representing a TREX_Segment
|
|
182
|
+
'''
|
|
183
|
+
key: str
|
|
184
|
+
|
|
185
|
+
@abstractmethod
|
|
186
|
+
def serialize(self):
|
|
187
|
+
raise NotImplementedError("Subclasses must implement 'serialize_as_trex()' method")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@model_validator(mode='after')
|
|
191
|
+
def _validate_key(self):
|
|
192
|
+
if not_allowed_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.key)):
|
|
193
|
+
self._add_validation_message(
|
|
194
|
+
source=f"TREX segment key {self.key}",
|
|
195
|
+
level=ValidationMsgLevel.ERROR,
|
|
196
|
+
msg=f"Segment key contains invalid characters: {_quote_texts(not_allowed_chars)}",
|
|
197
|
+
highlight_pattern = f'{self.key}$',
|
|
198
|
+
highlight_sub=not_allowed_chars
|
|
199
|
+
)
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
labfreed/trex/value_segments.py
CHANGED
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
from abc import ABC
|
|
2
|
-
import re
|
|
3
|
-
from typing import Literal
|
|
4
|
-
from pydantic import Field, model_validator
|
|
5
|
-
from labfreed.well_known_keys.unece.unece_units import unece_unit_codes
|
|
6
|
-
from labfreed.labfreed_infrastructure import ValidationMsgLevel
|
|
7
|
-
from labfreed.trex.trex_base_models import AlphanumericValue, BinaryValue, BoolValue, DateValue, ErrorValue, NumericValue, TREX_Segment, TextValue, Value
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class ValueSegment(TREX_Segment, Value, ABC):
|
|
12
|
-
'''@private: Abstract base class for value segments'''
|
|
13
|
-
type:str
|
|
14
|
-
|
|
15
|
-
@model_validator(mode='after')
|
|
16
|
-
def _validate_type(self):
|
|
17
|
-
valid_types = valid_types = unece_unit_codes() + ['T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E']
|
|
18
|
-
if self.type not in valid_types:
|
|
19
|
-
self._add_validation_message(
|
|
20
|
-
source=f"TREX value segment {self.key}",
|
|
21
|
-
level= ValidationMsgLevel.ERROR,
|
|
22
|
-
msg=f"Type {self.type} is invalid. Must be 'T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E' or a UNECE unit",
|
|
23
|
-
highlight_pattern = self.type
|
|
24
|
-
)
|
|
25
|
-
return self
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def serialize(self) -> str:
|
|
29
|
-
return f'{self.key}${self.type}:{self.value}'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class NumericSegment(ValueSegment, NumericValue):
|
|
33
|
-
'''Represents a TREX segment holding a numeric value'''
|
|
34
|
-
type: str
|
|
35
|
-
key:str
|
|
36
|
-
value:str
|
|
37
|
-
|
|
38
|
-
class DateSegment(ValueSegment, DateValue):
|
|
39
|
-
'''Represents a TREX segment holding a date'''
|
|
40
|
-
type: Literal['T.D'] = Field('T.D', frozen=True)
|
|
41
|
-
key:str
|
|
42
|
-
value:str
|
|
43
|
-
|
|
44
|
-
class BoolSegment(ValueSegment, BoolValue):
|
|
45
|
-
'''Represents a TREX segment holding a boolean value'''
|
|
46
|
-
type: Literal['T.B'] = Field('T.B', frozen=True)
|
|
47
|
-
key:str
|
|
48
|
-
value:str
|
|
49
|
-
class AlphanumericSegment(ValueSegment, AlphanumericValue):
|
|
50
|
-
'''Represents a TREX segment holding a alphanumeric text'''
|
|
51
|
-
type: Literal['T.A'] = Field('T.A', frozen=True)
|
|
52
|
-
key:str
|
|
53
|
-
value:str
|
|
54
|
-
class TextSegment(ValueSegment, TextValue):
|
|
55
|
-
'''Represents a TREX segment holding a text with arbitrary characters'''
|
|
56
|
-
type: Literal['T.T'] = Field('T.T', frozen=True)
|
|
57
|
-
key:str
|
|
58
|
-
value:str
|
|
59
|
-
|
|
60
|
-
class BinarySegment(ValueSegment, BinaryValue):
|
|
61
|
-
'''Represents a TREX segment holding binary data'''
|
|
62
|
-
type: Literal['T.X'] = Field('T.X', frozen=True)
|
|
63
|
-
key:str
|
|
64
|
-
value:str
|
|
65
|
-
|
|
66
|
-
class ErrorSegment(ValueSegment, ErrorValue):
|
|
67
|
-
'''Represents a TREX segment which has erroneous content'''
|
|
68
|
-
type: Literal['E'] = Field('E', frozen=True)
|
|
69
|
-
key:str
|
|
70
|
-
value:str
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _deserialize_value_segment_from_trex_segment_str(trex_segment_str) -> ValueSegment:
|
|
74
|
-
#re_scalar_pattern = re.compile(f"(?P<name>[\w\.-]*?)\$(?P<unit>[\w\.]*?):(?P<value>.*)")
|
|
75
|
-
re_scalar_pattern = re.compile("(?P<name>.+?)\$(?P<unit>.+?):(?P<value>.+)")
|
|
76
|
-
matches = re_scalar_pattern.match(trex_segment_str)
|
|
77
|
-
if not matches:
|
|
78
|
-
return None
|
|
79
|
-
|
|
80
|
-
key, type_, value = matches.groups()
|
|
81
|
-
|
|
82
|
-
match type_:
|
|
83
|
-
case 'T.D':
|
|
84
|
-
out = DateSegment(key=key, value=value, type=type_)
|
|
85
|
-
case 'T.B':
|
|
86
|
-
out = BoolSegment(key=key, value=value, type=type_)
|
|
87
|
-
case 'T.A':
|
|
88
|
-
out = AlphanumericSegment(key=key, value=value, type=type_)
|
|
89
|
-
case 'T.T':
|
|
90
|
-
out = TextSegment(key=key, value=value, type=type_)
|
|
91
|
-
case 'T.X':
|
|
92
|
-
out = BinarySegment(key=key, value=value, type=type_)
|
|
93
|
-
case 'E':
|
|
94
|
-
out = ErrorSegment(key=key, value=value, type=type_)
|
|
95
|
-
case _:
|
|
96
|
-
out = NumericSegment(value=value, key=key, type=type_)
|
|
97
|
-
|
|
98
|
-
return out
|
|
99
|
-
|
|
1
|
+
from abc import ABC
|
|
2
|
+
import re
|
|
3
|
+
from typing import Literal
|
|
4
|
+
from pydantic import Field, model_validator
|
|
5
|
+
from labfreed.well_known_keys.unece.unece_units import unece_unit_codes
|
|
6
|
+
from labfreed.labfreed_infrastructure import ValidationMsgLevel
|
|
7
|
+
from labfreed.trex.trex_base_models import AlphanumericValue, BinaryValue, BoolValue, DateValue, ErrorValue, NumericValue, TREX_Segment, TextValue, Value
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ValueSegment(TREX_Segment, Value, ABC):
|
|
12
|
+
'''@private: Abstract base class for value segments'''
|
|
13
|
+
type:str
|
|
14
|
+
|
|
15
|
+
@model_validator(mode='after')
|
|
16
|
+
def _validate_type(self):
|
|
17
|
+
valid_types = valid_types = unece_unit_codes() + ['T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E']
|
|
18
|
+
if self.type not in valid_types:
|
|
19
|
+
self._add_validation_message(
|
|
20
|
+
source=f"TREX value segment {self.key}",
|
|
21
|
+
level= ValidationMsgLevel.ERROR,
|
|
22
|
+
msg=f"Type {self.type} is invalid. Must be 'T.D', 'T.B', 'T.A', 'T.T', 'T.X', 'E' or a UNECE unit",
|
|
23
|
+
highlight_pattern = self.type
|
|
24
|
+
)
|
|
25
|
+
return self
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def serialize(self) -> str:
|
|
29
|
+
return f'{self.key}${self.type}:{self.value}'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class NumericSegment(ValueSegment, NumericValue):
|
|
33
|
+
'''Represents a TREX segment holding a numeric value'''
|
|
34
|
+
type: str
|
|
35
|
+
key:str
|
|
36
|
+
value:str
|
|
37
|
+
|
|
38
|
+
class DateSegment(ValueSegment, DateValue):
|
|
39
|
+
'''Represents a TREX segment holding a date'''
|
|
40
|
+
type: Literal['T.D'] = Field('T.D', frozen=True)
|
|
41
|
+
key:str
|
|
42
|
+
value:str
|
|
43
|
+
|
|
44
|
+
class BoolSegment(ValueSegment, BoolValue):
|
|
45
|
+
'''Represents a TREX segment holding a boolean value'''
|
|
46
|
+
type: Literal['T.B'] = Field('T.B', frozen=True)
|
|
47
|
+
key:str
|
|
48
|
+
value:str
|
|
49
|
+
class AlphanumericSegment(ValueSegment, AlphanumericValue):
|
|
50
|
+
'''Represents a TREX segment holding a alphanumeric text'''
|
|
51
|
+
type: Literal['T.A'] = Field('T.A', frozen=True)
|
|
52
|
+
key:str
|
|
53
|
+
value:str
|
|
54
|
+
class TextSegment(ValueSegment, TextValue):
|
|
55
|
+
'''Represents a TREX segment holding a text with arbitrary characters'''
|
|
56
|
+
type: Literal['T.T'] = Field('T.T', frozen=True)
|
|
57
|
+
key:str
|
|
58
|
+
value:str
|
|
59
|
+
|
|
60
|
+
class BinarySegment(ValueSegment, BinaryValue):
|
|
61
|
+
'''Represents a TREX segment holding binary data'''
|
|
62
|
+
type: Literal['T.X'] = Field('T.X', frozen=True)
|
|
63
|
+
key:str
|
|
64
|
+
value:str
|
|
65
|
+
|
|
66
|
+
class ErrorSegment(ValueSegment, ErrorValue):
|
|
67
|
+
'''Represents a TREX segment which has erroneous content'''
|
|
68
|
+
type: Literal['E'] = Field('E', frozen=True)
|
|
69
|
+
key:str
|
|
70
|
+
value:str
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _deserialize_value_segment_from_trex_segment_str(trex_segment_str) -> ValueSegment:
|
|
74
|
+
#re_scalar_pattern = re.compile(f"(?P<name>[\w\.-]*?)\$(?P<unit>[\w\.]*?):(?P<value>.*)")
|
|
75
|
+
re_scalar_pattern = re.compile("(?P<name>.+?)\$(?P<unit>.+?):(?P<value>.+)")
|
|
76
|
+
matches = re_scalar_pattern.match(trex_segment_str)
|
|
77
|
+
if not matches:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
key, type_, value = matches.groups()
|
|
81
|
+
|
|
82
|
+
match type_:
|
|
83
|
+
case 'T.D':
|
|
84
|
+
out = DateSegment(key=key, value=value, type=type_)
|
|
85
|
+
case 'T.B':
|
|
86
|
+
out = BoolSegment(key=key, value=value, type=type_)
|
|
87
|
+
case 'T.A':
|
|
88
|
+
out = AlphanumericSegment(key=key, value=value, type=type_)
|
|
89
|
+
case 'T.T':
|
|
90
|
+
out = TextSegment(key=key, value=value, type=type_)
|
|
91
|
+
case 'T.X':
|
|
92
|
+
out = BinarySegment(key=key, value=value, type=type_)
|
|
93
|
+
case 'E':
|
|
94
|
+
out = ErrorSegment(key=key, value=value, type=type_)
|
|
95
|
+
case _:
|
|
96
|
+
out = NumericSegment(value=value, key=key, type=type_)
|
|
97
|
+
|
|
98
|
+
return out
|
|
99
|
+
|