labfreed 0.2.6a6__py3-none-any.whl → 0.2.8__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.

Files changed (44) hide show
  1. labfreed/__init__.py +11 -11
  2. labfreed/labfreed_infrastructure.py +258 -258
  3. labfreed/pac_cat/__init__.py +19 -19
  4. labfreed/pac_cat/category_base.py +51 -51
  5. labfreed/pac_cat/pac_cat.py +150 -150
  6. labfreed/pac_cat/predefined_categories.py +200 -200
  7. labfreed/pac_id/__init__.py +19 -19
  8. labfreed/pac_id/extension.py +48 -48
  9. labfreed/pac_id/id_segment.py +89 -89
  10. labfreed/pac_id/pac_id.py +140 -140
  11. labfreed/pac_id/url_parser.py +155 -155
  12. labfreed/pac_id/url_serializer.py +84 -80
  13. labfreed/pac_id_resolver/__init__.py +2 -2
  14. labfreed/pac_id_resolver/cit_common.py +81 -81
  15. labfreed/pac_id_resolver/cit_v1.py +244 -247
  16. labfreed/pac_id_resolver/cit_v2.py +313 -313
  17. labfreed/pac_id_resolver/resolver.py +97 -98
  18. labfreed/pac_id_resolver/services.py +82 -79
  19. labfreed/qr/__init__.py +1 -1
  20. labfreed/qr/generate_qr.py +422 -422
  21. labfreed/trex/__init__.py +16 -16
  22. labfreed/trex/python_convenience/__init__.py +3 -3
  23. labfreed/trex/python_convenience/data_table.py +87 -87
  24. labfreed/trex/python_convenience/pyTREX.py +248 -248
  25. labfreed/trex/python_convenience/quantity.py +66 -66
  26. labfreed/trex/table_segment.py +245 -245
  27. labfreed/trex/trex.py +69 -69
  28. labfreed/trex/trex_base_models.py +209 -209
  29. labfreed/trex/value_segments.py +99 -99
  30. labfreed/utilities/base36.py +82 -82
  31. labfreed/well_known_extensions/__init__.py +4 -4
  32. labfreed/well_known_extensions/default_extension_interpreters.py +6 -6
  33. labfreed/well_known_extensions/display_name_extension.py +40 -40
  34. labfreed/well_known_extensions/trex_extension.py +30 -30
  35. labfreed/well_known_keys/gs1/__init__.py +5 -5
  36. labfreed/well_known_keys/gs1/gs1.py +3 -3
  37. labfreed/well_known_keys/labfreed/well_known_keys.py +15 -15
  38. labfreed/well_known_keys/unece/__init__.py +3 -3
  39. labfreed/well_known_keys/unece/unece_units.py +67 -67
  40. {labfreed-0.2.6a6.dist-info → labfreed-0.2.8.dist-info}/METADATA +36 -21
  41. labfreed-0.2.8.dist-info/RECORD +45 -0
  42. {labfreed-0.2.6a6.dist-info → labfreed-0.2.8.dist-info}/licenses/LICENSE +21 -21
  43. labfreed-0.2.6a6.dist-info/RECORD +0 -45
  44. {labfreed-0.2.6a6.dist-info → labfreed-0.2.8.dist-info}/WHEEL +0 -0
@@ -1,248 +1,245 @@
1
-
2
- from enum import Enum
3
- import logging
4
- import re
5
- import traceback
6
-
7
- from pydantic import Field, model_validator
8
- from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMessage, ValidationMsgLevel
9
- from labfreed.pac_id.pac_id import PAC_ID
10
- from labfreed.pac_id_resolver.services import Service, ServiceGroup
11
- from labfreed.pac_id_resolver.cit_common import ( _add_msg_to_cit_entry_model,
12
- _validate_service_name,
13
- _validate_application_intent,
14
- _validate_service_type,
15
- ServiceType)
16
-
17
-
18
-
19
- class CITEntry_v1(LabFREED_BaseModel):
20
- applicable_if: str = Field(..., min_length=1)
21
- service_name: str = Field(..., min_length=1)
22
- application_intent:str = Field(..., min_length=1)
23
- service_type:ServiceType|str
24
- template_url:str = Field(..., min_length=1)
25
-
26
-
27
- @model_validator(mode='after')
28
- def _validate_model(self):
29
- if self.applicable_if:
30
- conditions = self.applicable_if.split(';')
31
- for c in conditions:
32
- if '=' in c:
33
- query, expected = c.split('=')
34
- query = query.strip()
35
- else:
36
- query = c.strip()
37
-
38
- try:
39
- # use this function to check if the pattern is valid. it returns a PatternError if not
40
- _find_pattern_in_pac(query, '')
41
- except PatternError:
42
- self._add_validation_message(
43
- level=ValidationMsgLevel.ERROR,
44
- source=f'Service {self.service_name}',
45
- msg=f'Applicable if contains invalid pattern {query}',
46
- highlight_sub=query
47
- )
48
- except Exception:
49
- pass # if no PatternError everything is fine
50
- return self
51
-
52
- @model_validator(mode='after')
53
- def _validate_service_name(self):
54
- msg_dict= _validate_service_name(self.service_name)
55
- return _add_msg_to_cit_entry_model(msg_dict, self)
56
-
57
-
58
- @model_validator(mode='after')
59
- def _validate_application_intent(self):
60
- msg_dict= _validate_application_intent(self.application_intent)
61
- return _add_msg_to_cit_entry_model(msg_dict, self)
62
-
63
-
64
- @model_validator(mode='after')
65
- def _validate_service_type(self):
66
- msg_dict= _validate_service_type(self.service_type)
67
- return _add_msg_to_cit_entry_model(msg_dict, self)
68
-
69
-
70
-
71
-
72
-
73
-
74
- class CIT_v1(LabFREED_BaseModel):
75
- origin:str = ''
76
- entries:list[CITEntry_v1]
77
-
78
-
79
- @classmethod
80
- def from_csv(cls, csv:str, origin=''):
81
- lines = csv.splitlines()
82
- entries = list()
83
- errors = list()
84
- for line in lines:
85
- if not line: # empty line
86
- continue
87
- if line.strip()[0] == '#': #comment line
88
- continue
89
- if 'Service Name' in line.strip() : #header line
90
- continue
91
-
92
- cols = [c.strip() for c in line.split('\t')]
93
- if len(cols) < 5:
94
- logging.error(f'invalid line {line}')
95
- msg = ValidationMessage(
96
- level=ValidationMsgLevel.ERROR,
97
- source='CIT line',
98
- source_id=0,
99
- msg=f'Invalid line in CIT. There are {5 - len(cols)} columns missing.',
100
- highlight_sub_patterns=line
101
- )
102
- errors.append(msg)
103
- continue
104
- if len(cols) > 5:
105
- logging.error(f'invalid line {line}')
106
- msg = ValidationMessage(
107
- level=ValidationMsgLevel.ERROR,
108
- source='CIT line',
109
- source_id=0,
110
- msg=f'Invalid line in CIT. There are {len(cols) -5} too many columns',
111
- highlight_sub_patterns=line
112
- )
113
- errors.append(msg)
114
- continue
115
- try:
116
-
117
- entry = CITEntry_v1(
118
- service_name = cols[0],
119
- application_intent = cols[1],
120
- service_type = cols[2],
121
- applicable_if = cols[3],
122
- template_url = cols[4]
123
- )
124
- entries.append(entry)
125
- except ValueError:
126
- logging.error(f'invalid line {line}')
127
- msg = ValidationMessage(
128
- level=ValidationMsgLevel.ERROR,
129
- source='CIT line',
130
- source_id=0,
131
- msg='Invalid line in CIT.',
132
- highlight_sub_patterns=line
133
- )
134
- errors.append(msg)
135
-
136
- cit = CIT_v1(origin=origin, entries=entries)
137
- if not cit.is_valid:
138
- errors.insert(0,
139
- ValidationMessage(
140
- level=ValidationMsgLevel.WARNING,
141
- source='CIT ',
142
- source_id=0,
143
- msg='Invalid lines in CIT. The lines were ignored. The rest of the CIT is still functional',
144
- highlight_sub_patterns=''
145
- )
146
- )
147
- cit._validation_messages.extend(errors)
148
- cit._csv_original = csv
149
- return cit
150
-
151
- def evaluate_pac_id(self, pac:PAC_ID):
152
- if type(pac) is not PAC_ID:
153
- raise ValueError('CIT v1 does only handle PAC-IDs. PAC-CAT it does not know what to do')
154
- cit_evaluated = ServiceGroup(origin=self.origin)
155
- for e in self.entries:
156
- if e.errors():
157
- continue #make this stable against errors in the cit
158
-
159
- conditions = e.applicable_if.split(';')
160
- conditions_evaluated = list()
161
- for c in conditions:
162
- if '=' in c:
163
- query, expected = c.split('=')
164
- value = _find_pattern_in_pac(query.strip(), pac)
165
- conditions_evaluated.append(value == expected.strip())
166
- else:
167
- query = c.strip()
168
- found = _find_pattern_in_pac(query, pac)
169
- conditions_evaluated.append(found)
170
- is_applicable = all(conditions_evaluated)
171
-
172
- if not is_applicable:
173
- continue
174
-
175
- url = re.sub(r"\{([^}]+)\}", lambda v: _find_pattern_in_pac(v.group(0), pac), e.template_url)
176
- cit_evaluated.services.append(Service(
177
- service_name=e.service_name,
178
- application_intents= [ e.application_intent ],
179
- service_type=e.service_type,
180
- url = url
181
- )
182
- )
183
- return cit_evaluated
184
-
185
-
186
-
187
- def __str__(self):
188
- if csv:=self._csv_original:
189
- return csv
190
-
191
- s = "# coupling information table version: 1.0\n"
192
- s += "Service Name\tApplication Intent\tService Type\tApplicable If\tTemplate Url\n"
193
- for e in self.entries:
194
- s += '\t'.join([e.service_name, e.application_intent, e.service_type.value, e.applicable_if, e.template_url]) + '\n'
195
- return s
196
-
197
-
198
-
199
- def _find_pattern_in_pac(value, pac:PAC_ID|str):
200
- if not isinstance(pac, str):
201
- pac_url =pac.to_url()
202
- else:
203
- pac_url = pac
204
-
205
- if value == '{isu}':
206
- return pac.issuer
207
-
208
- elif value == '{pac}':
209
- return pac_url.split('*')[0]
210
-
211
- elif value == '{id}':
212
- m = re.match(r'^HTTPS://.+?/(.+?)(\*.*)*$', pac_url)
213
- return m.group(1) if m else None
214
-
215
- elif m := re.match(r'\{idSeg(\d+)\}', value):
216
- i = int(m.group(1)) - 1 # CIT is 1 based
217
- seg = pac.identifier[i] if i < len(pac.identifier) else None
218
- if seg:
219
- return f"{(seg.key + ':') if seg.key else ''}{seg.value}"
220
-
221
- elif m := re.match(r'\{idVal(\w+)\}', value):
222
- k = m.group(1)
223
- seg = [s for s in pac.identifier if s.key and s.key == k]
224
- if seg:
225
- seg = seg[0]
226
- return seg.value
227
- else:
228
- return None
229
-
230
- elif value == '{ext}':
231
- m = re.match(r'^.*?(\*.*)*$', pac_url)
232
- ext_str = m.group(1) if m else None
233
- return m.group(1)[1:] if ext_str else None
234
-
235
- elif m := re.match(r'\{ext(\d+)\}', value):
236
- i = int(m.group(1)) - 1 # CIT is 1 based
237
- extensions = pac_url.split('*')
238
- extensions.pop(0)# first element is not extension
239
- return extensions[i] if i < len(extensions) else None
240
- else:
241
- raise PatternError(f'{value} is not a recognized pattern for applicable if')
242
-
243
- class PatternError(ValueError):
244
- pass
245
-
246
-
247
-
1
+
2
+ from enum import Enum
3
+ import logging
4
+ import re
5
+ import traceback
6
+
7
+ from pydantic import Field, model_validator
8
+ from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMessage, ValidationMsgLevel
9
+ from labfreed.pac_id.pac_id import PAC_ID
10
+ from labfreed.pac_id_resolver.services import Service, ServiceGroup
11
+ from labfreed.pac_id_resolver.cit_common import ( _add_msg_to_cit_entry_model,
12
+ _validate_service_name,
13
+ _validate_application_intent,
14
+ _validate_service_type,
15
+ ServiceType)
16
+
17
+
18
+
19
+ class CITEntry_v1(LabFREED_BaseModel):
20
+ applicable_if: str = Field(..., min_length=1)
21
+ service_name: str = Field(..., min_length=1)
22
+ application_intent:str = Field(..., min_length=1)
23
+ service_type:ServiceType|str
24
+ template_url:str = Field(..., min_length=1)
25
+
26
+
27
+ @model_validator(mode='after')
28
+ def _validate_model(self):
29
+ if self.applicable_if:
30
+ conditions = self.applicable_if.split(';')
31
+ for c in conditions:
32
+ if '=' in c:
33
+ query, expected = c.split('=')
34
+ query = query.strip()
35
+ else:
36
+ query = c.strip()
37
+
38
+ try:
39
+ # use this function to check if the pattern is valid. it returns a PatternError if not
40
+ _find_pattern_in_pac(query, '')
41
+ except PatternError:
42
+ self._add_validation_message(
43
+ level=ValidationMsgLevel.ERROR,
44
+ source=f'Service {self.service_name}',
45
+ msg=f'Applicable if contains invalid pattern {query}',
46
+ highlight_sub=query
47
+ )
48
+ except Exception:
49
+ pass # if no PatternError everything is fine
50
+ return self
51
+
52
+ @model_validator(mode='after')
53
+ def _validate_service_name(self):
54
+ msg_dict= _validate_service_name(self.service_name)
55
+ return _add_msg_to_cit_entry_model(msg_dict, self)
56
+
57
+
58
+ @model_validator(mode='after')
59
+ def _validate_application_intent(self):
60
+ msg_dict= _validate_application_intent(self.application_intent)
61
+ return _add_msg_to_cit_entry_model(msg_dict, self)
62
+
63
+
64
+ @model_validator(mode='after')
65
+ def _validate_service_type(self):
66
+ msg_dict= _validate_service_type(self.service_type)
67
+ return _add_msg_to_cit_entry_model(msg_dict, self)
68
+
69
+
70
+
71
+
72
+
73
+
74
+ class CIT_v1(LabFREED_BaseModel):
75
+ origin:str = ''
76
+ entries:list[CITEntry_v1]
77
+
78
+
79
+ @classmethod
80
+ def from_csv(cls, csv:str, origin=''):
81
+ lines = csv.splitlines()
82
+ entries = list()
83
+ errors = list()
84
+ for line in lines:
85
+ if not line: # empty line
86
+ continue
87
+ if line.strip()[0] == '#': #comment line
88
+ continue
89
+ if 'Service Name' in line.strip() : #header line
90
+ continue
91
+
92
+ cols = [c.strip() for c in line.split('\t')]
93
+ if len(cols) < 5:
94
+ msg = ValidationMessage(
95
+ level=ValidationMsgLevel.ERROR,
96
+ source='CIT line',
97
+ source_id=0,
98
+ msg=f'Invalid line in CIT. There are {5 - len(cols)} columns missing.',
99
+ highlight_sub_patterns=line
100
+ )
101
+ errors.append(msg)
102
+ continue
103
+ if len(cols) > 5:
104
+ msg = ValidationMessage(
105
+ level=ValidationMsgLevel.ERROR,
106
+ source='CIT line',
107
+ source_id=0,
108
+ msg=f'Invalid line in CIT. There are {len(cols) -5} too many columns',
109
+ highlight_sub_patterns=line
110
+ )
111
+ errors.append(msg)
112
+ continue
113
+ try:
114
+
115
+ entry = CITEntry_v1(
116
+ service_name = cols[0],
117
+ application_intent = cols[1],
118
+ service_type = cols[2],
119
+ applicable_if = cols[3],
120
+ template_url = cols[4]
121
+ )
122
+ entries.append(entry)
123
+ except ValueError:
124
+ msg = ValidationMessage(
125
+ level=ValidationMsgLevel.ERROR,
126
+ source='CIT line',
127
+ source_id=0,
128
+ msg='Invalid line in CIT.',
129
+ highlight_sub_patterns=line
130
+ )
131
+ errors.append(msg)
132
+
133
+ cit = CIT_v1(origin=origin, entries=entries)
134
+ if not cit.is_valid:
135
+ errors.insert(0,
136
+ ValidationMessage(
137
+ level=ValidationMsgLevel.WARNING,
138
+ source='CIT ',
139
+ source_id=0,
140
+ msg='Invalid lines in CIT. The lines were ignored. The rest of the CIT is still functional',
141
+ highlight_sub_patterns=''
142
+ )
143
+ )
144
+ cit._validation_messages.extend(errors)
145
+ cit._csv_original = csv
146
+ return cit
147
+
148
+ def evaluate_pac_id(self, pac:PAC_ID):
149
+ if type(pac) is not PAC_ID:
150
+ raise ValueError('CIT v1 does only handle PAC-IDs. PAC-CAT it does not know what to do')
151
+ cit_evaluated = ServiceGroup(origin=self.origin)
152
+ for e in self.entries:
153
+ if e.errors():
154
+ continue #make this stable against errors in the cit
155
+
156
+ conditions = e.applicable_if.split(';')
157
+ conditions_evaluated = list()
158
+ for c in conditions:
159
+ if '=' in c:
160
+ query, expected = c.split('=')
161
+ value = _find_pattern_in_pac(query.strip(), pac)
162
+ conditions_evaluated.append(value == expected.strip())
163
+ else:
164
+ query = c.strip()
165
+ found = _find_pattern_in_pac(query, pac)
166
+ conditions_evaluated.append(found)
167
+ is_applicable = all(conditions_evaluated)
168
+
169
+ if not is_applicable:
170
+ continue
171
+
172
+ url = re.sub(r"\{([^}]+)\}", lambda v: _find_pattern_in_pac(v.group(0), pac), e.template_url)
173
+ cit_evaluated.services.append(Service(
174
+ service_name=e.service_name,
175
+ application_intents= [ e.application_intent ],
176
+ service_type=e.service_type,
177
+ url = url
178
+ )
179
+ )
180
+ return cit_evaluated
181
+
182
+
183
+
184
+ def __str__(self):
185
+ if csv:=self._csv_original:
186
+ return csv
187
+
188
+ s = "# coupling information table version: 1.0\n"
189
+ s += "Service Name\tApplication Intent\tService Type\tApplicable If\tTemplate Url\n"
190
+ for e in self.entries:
191
+ s += '\t'.join([e.service_name, e.application_intent, e.service_type.value, e.applicable_if, e.template_url]) + '\n'
192
+ return s
193
+
194
+
195
+
196
+ def _find_pattern_in_pac(value, pac:PAC_ID|str):
197
+ if not isinstance(pac, str):
198
+ pac_url =pac.to_url()
199
+ else:
200
+ pac_url = pac
201
+
202
+ if value == '{isu}':
203
+ return pac.issuer
204
+
205
+ elif value == '{pac}':
206
+ return pac_url.split('*')[0]
207
+
208
+ elif value == '{id}':
209
+ m = re.match(r'^HTTPS://.+?/(.+?)(\*.*)*$', pac_url)
210
+ return m.group(1) if m else None
211
+
212
+ elif m := re.match(r'\{idSeg(\d+)\}', value):
213
+ i = int(m.group(1)) - 1 # CIT is 1 based
214
+ seg = pac.identifier[i] if i < len(pac.identifier) else None
215
+ if seg:
216
+ return f"{(seg.key + ':') if seg.key else ''}{seg.value}"
217
+
218
+ elif m := re.match(r'\{idVal(\w+)\}', value):
219
+ k = m.group(1)
220
+ seg = [s for s in pac.identifier if s.key and s.key == k]
221
+ if seg:
222
+ seg = seg[0]
223
+ return seg.value
224
+ else:
225
+ return None
226
+
227
+ elif value == '{ext}':
228
+ m = re.match(r'^.*?(\*.*)*$', pac_url)
229
+ ext_str = m.group(1) if m else None
230
+ return m.group(1)[1:] if ext_str else None
231
+
232
+ elif m := re.match(r'\{ext(\d+)\}', value):
233
+ i = int(m.group(1)) - 1 # CIT is 1 based
234
+ extensions = pac_url.split('*')
235
+ extensions.pop(0)# first element is not extension
236
+ return extensions[i] if i < len(extensions) else None
237
+ else:
238
+ raise PatternError(f'{value} is not a recognized pattern for applicable if')
239
+
240
+ class PatternError(ValueError):
241
+ pass
242
+
243
+
244
+
248
245