labfreed 0.2.6a3__tar.gz → 0.2.6a4__tar.gz
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-0.2.6a3 → labfreed-0.2.6a4}/PKG-INFO +1 -1
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/__init__.py +1 -1
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/labfreed_infrastructure.py +2 -2
- labfreed-0.2.6a4/labfreed/pac_id_resolver/cit_common.py +82 -0
- labfreed-0.2.6a4/labfreed/pac_id_resolver/cit_v1.py +245 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id_resolver/cit_v2.py +6 -3
- labfreed-0.2.6a3/labfreed/pac_id_resolver/cit_v1.py +0 -152
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/.github/workflows/pypi-publish.yml +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/.github/workflows/run-tests.yml +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/CHANGELOG.md +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/LICENSE +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/README.md +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_cat/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_cat/category_base.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_cat/pac_cat.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_cat/predefined_categories.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/extension.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/id_segment.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/pac_id.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/url_parser.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id/url_serializer.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id_resolver/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id_resolver/resolver.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/pac_id_resolver/services.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/qr/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/qr/generate_qr.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/python_convenience/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/python_convenience/data_table.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/python_convenience/pyTREX.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/python_convenience/quantity.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/table_segment.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/trex.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/trex_base_models.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/trex/value_segments.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/utilities/base36.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_extensions/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_extensions/default_extension_interpreters.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_extensions/display_name_extension.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_extensions/trex_extension.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/gs1/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/gs1/gs1.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/gs1/gs1_ai_enum_sorted.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/labfreed/well_known_keys.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/unece/UneceUnits.json +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/unece/__init__.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_keys/unece/unece_units.py +0 -0
- {labfreed-0.2.6a3 → labfreed-0.2.6a4}/pyproject.toml +0 -0
|
@@ -194,9 +194,9 @@ class LabFREED_BaseModel(PDOC_Workaround_Base):
|
|
|
194
194
|
formatted_msg = list()
|
|
195
195
|
for m in self.validation_messages():
|
|
196
196
|
if m.level == ValidationMsgLevel.ERROR:
|
|
197
|
-
color = '
|
|
197
|
+
color = '#d70000'
|
|
198
198
|
else:
|
|
199
|
-
color = '
|
|
199
|
+
color = '#d78700'
|
|
200
200
|
|
|
201
201
|
match target:
|
|
202
202
|
case 'markdown':
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
import re
|
|
3
|
+
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMsgLevel, _quote_texts
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ServiceType(Enum):
|
|
8
|
+
USER_HANDOVER_GENERIC = 'userhandover-generic'
|
|
9
|
+
ATTRIBUTE_SERVICE_GENERIC = 'attributes-generic'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _validate_service_name(service_name):
|
|
13
|
+
msg_dict = []
|
|
14
|
+
if not_allowed_chars := set(re.sub(r'[A-Za-z0-9\-\x20]', '', service_name)):
|
|
15
|
+
msg_dict.append( {
|
|
16
|
+
"level": ValidationMsgLevel.ERROR,
|
|
17
|
+
"msg": f'Service name ontains invalid characters {_quote_texts(not_allowed_chars)}',
|
|
18
|
+
"highlight_sub": not_allowed_chars
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if len(service_name) == 0 or len(service_name) > 255:
|
|
23
|
+
msg_dict.append( {
|
|
24
|
+
"level": ValidationMsgLevel.ERROR,
|
|
25
|
+
"msg": 'Service name must be at least one and maximum 255 characters long'
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
return msg_dict
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _validate_application_intent(intent):
|
|
32
|
+
msg_dict = []
|
|
33
|
+
if re.fullmatch('.*-generic$', intent):
|
|
34
|
+
msg_dict.append( {
|
|
35
|
+
"level": ValidationMsgLevel.ERROR,
|
|
36
|
+
"msg": "Application intent ends with '-generic'. This is not permitted, since it is reserved for future uses'",
|
|
37
|
+
"highlight_sub": [intent]
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if not_allowed_chars := set(re.sub(r'[A-Za-z0-9\-]', '', intent)):
|
|
42
|
+
msg_dict.append( {
|
|
43
|
+
"level": ValidationMsgLevel.ERROR,
|
|
44
|
+
"msg": f'Application intent contains invalid characters {_quote_texts(not_allowed_chars)}',
|
|
45
|
+
"highlight_sub": not_allowed_chars
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if len(intent) == 0 or len(intent) > 255:
|
|
50
|
+
msg_dict.append( {
|
|
51
|
+
"level": ValidationMsgLevel.ERROR,
|
|
52
|
+
"source": f'Application intent {intent}',
|
|
53
|
+
"msg": 'Must be at least one and maximum 255 characters long'
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
return msg_dict
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _validate_service_type(service_type):
|
|
60
|
+
msg_dict = []
|
|
61
|
+
if isinstance(service_type, ServiceType):
|
|
62
|
+
service_type= service_type.value
|
|
63
|
+
else:
|
|
64
|
+
service_type= service_type
|
|
65
|
+
allowed_types = [ServiceType.ATTRIBUTE_SERVICE_GENERIC.value, ServiceType.USER_HANDOVER_GENERIC.value]
|
|
66
|
+
if service_type not in allowed_types:
|
|
67
|
+
msg_dict.append( {
|
|
68
|
+
"level": ValidationMsgLevel.ERROR,
|
|
69
|
+
"msg": f'Invalid service type. Must be {_quote_texts(allowed_types)} must be at least one and maximum 255 characters long',
|
|
70
|
+
"highlight_sub": service_type
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
return msg_dict
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _add_msg_to_cit_entry_model(msg_dict, model):
|
|
77
|
+
for m in msg_dict:
|
|
78
|
+
m.update({"source": model.service_name})
|
|
79
|
+
model._add_validation_message(**m)
|
|
80
|
+
return model
|
|
81
|
+
|
|
82
|
+
|
|
@@ -0,0 +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
|
+
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
|
+
|
|
245
|
+
|
|
@@ -9,6 +9,12 @@ import jsonpath_ng.ext as jsonpath
|
|
|
9
9
|
|
|
10
10
|
from labfreed.pac_id_resolver.services import Service, ServiceGroup
|
|
11
11
|
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMsgLevel, _quote_texts
|
|
12
|
+
from labfreed.pac_id_resolver.cit_common import ( _add_msg_to_cit_entry_model,
|
|
13
|
+
_validate_service_name,
|
|
14
|
+
_validate_application_intent,
|
|
15
|
+
_validate_service_type,
|
|
16
|
+
ServiceType)
|
|
17
|
+
|
|
12
18
|
|
|
13
19
|
__all__ = [
|
|
14
20
|
"CIT_v2",
|
|
@@ -16,9 +22,6 @@ __all__ = [
|
|
|
16
22
|
"CITEntry_v2"
|
|
17
23
|
]
|
|
18
24
|
|
|
19
|
-
class ServiceType(Enum):
|
|
20
|
-
USER_HANDOVER_GENERIC = 'userhandover-generic'
|
|
21
|
-
ATTRIBUTE_SERVICE_GENERIC = 'attributes-generic'
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
class CITEntry_v2(LabFREED_BaseModel):
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from enum import Enum
|
|
3
|
-
import logging
|
|
4
|
-
import re
|
|
5
|
-
|
|
6
|
-
from pydantic import Field
|
|
7
|
-
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, ValidationMessage, ValidationMsgLevel
|
|
8
|
-
from labfreed.pac_id.pac_id import PAC_ID
|
|
9
|
-
from labfreed.pac_id_resolver.services import Service, ServiceGroup
|
|
10
|
-
|
|
11
|
-
class ServiceType(Enum):
|
|
12
|
-
USER_HANDOVER_GENERIC = 'userhandover-generic'
|
|
13
|
-
ATTRIBUTE_SERVICE_GENERIC = 'attributes-generic'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class CITEntry_v1(LabFREED_BaseModel):
|
|
17
|
-
applicable_if: str = Field(..., min_length=1)
|
|
18
|
-
service_name: str = Field(..., min_length=1)
|
|
19
|
-
application_intent:str = Field(..., min_length=1)
|
|
20
|
-
service_type:ServiceType
|
|
21
|
-
template_url:str = Field(..., min_length=1)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class CIT_v1(LabFREED_BaseModel):
|
|
25
|
-
origin:str = ''
|
|
26
|
-
entries:list[CITEntry_v1]
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@classmethod
|
|
30
|
-
def from_csv(cls, csv:str, origin=''):
|
|
31
|
-
lines = csv.splitlines()
|
|
32
|
-
entries = list()
|
|
33
|
-
errors = list()
|
|
34
|
-
for line in lines:
|
|
35
|
-
if not line: # empty line
|
|
36
|
-
continue
|
|
37
|
-
if line.strip()[0] == '#': #comment line
|
|
38
|
-
continue
|
|
39
|
-
if 'Service Name' in line.strip() : #header line
|
|
40
|
-
continue
|
|
41
|
-
|
|
42
|
-
cols = [c.strip() for c in line.split('\t')]
|
|
43
|
-
try:
|
|
44
|
-
entry = CITEntry_v1(
|
|
45
|
-
service_name = cols[0],
|
|
46
|
-
application_intent = cols[1],
|
|
47
|
-
service_type = ServiceType(cols[2]),
|
|
48
|
-
applicable_if = cols[3],
|
|
49
|
-
template_url = cols[4]
|
|
50
|
-
)
|
|
51
|
-
entries.append(entry)
|
|
52
|
-
except ValueError:
|
|
53
|
-
logging.error(f'invalid line {line}')
|
|
54
|
-
msg = ValidationMessage(
|
|
55
|
-
level=ValidationMsgLevel.WARNING,
|
|
56
|
-
source='CIT line',
|
|
57
|
-
source_id=0,
|
|
58
|
-
msg='Invalid line in CIT. Line was ignored. Remaining CIT is functional.',
|
|
59
|
-
highlight_sub_patterns=line
|
|
60
|
-
)
|
|
61
|
-
errors.append(msg)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
cit = CIT_v1(origin=origin, entries=entries)
|
|
65
|
-
cit._validation_messages.extend(errors)
|
|
66
|
-
cit._csv_original = csv
|
|
67
|
-
return cit
|
|
68
|
-
|
|
69
|
-
def evaluate_pac_id(self, pac:PAC_ID):
|
|
70
|
-
if not type(pac) is PAC_ID:
|
|
71
|
-
raise ValueError(f'CIT v1 does only handle PAC-IDs. PAC-CAT it does not know what to do')
|
|
72
|
-
cit_evaluated = ServiceGroup(origin=self.origin)
|
|
73
|
-
for e in self.entries:
|
|
74
|
-
conditions = e.applicable_if.split(';')
|
|
75
|
-
conditions_evaluated = list()
|
|
76
|
-
for c in conditions:
|
|
77
|
-
if '=' in c:
|
|
78
|
-
query, expected = c.split('=')
|
|
79
|
-
value = self._find_in_pac(query.strip(), pac)
|
|
80
|
-
conditions_evaluated.append(value == expected.strip())
|
|
81
|
-
else:
|
|
82
|
-
query = c.strip()
|
|
83
|
-
found = self._find_in_pac(query, pac)
|
|
84
|
-
conditions_evaluated.append(found)
|
|
85
|
-
is_applicable = all(conditions_evaluated)
|
|
86
|
-
|
|
87
|
-
if not is_applicable:
|
|
88
|
-
continue
|
|
89
|
-
|
|
90
|
-
url = re.sub(r"\{([^}]+)\}", lambda v: self._find_in_pac(v.group(0), pac), e.template_url)
|
|
91
|
-
cit_evaluated.services.append(Service(
|
|
92
|
-
service_name=e.service_name,
|
|
93
|
-
application_intents= [ e.application_intent ],
|
|
94
|
-
service_type=e.service_type,
|
|
95
|
-
url = url
|
|
96
|
-
)
|
|
97
|
-
)
|
|
98
|
-
return cit_evaluated
|
|
99
|
-
|
|
100
|
-
def _find_in_pac(self, value, pac:PAC_ID):
|
|
101
|
-
pac_url =pac.to_url()
|
|
102
|
-
if value == '{isu}':
|
|
103
|
-
return pac.issuer
|
|
104
|
-
|
|
105
|
-
elif value == '{pac}':
|
|
106
|
-
return pac_url.split('*')[0]
|
|
107
|
-
|
|
108
|
-
elif value == '{id}':
|
|
109
|
-
m = re.match(r'^HTTPS://.+?/(.+?)(\*.*)*$', pac_url)
|
|
110
|
-
return m.group(1) if m else None
|
|
111
|
-
|
|
112
|
-
elif m := re.match(r'\{idSeg(\d+)\}', value):
|
|
113
|
-
i = int(m.group(1)) - 1 # CIT is 1 based
|
|
114
|
-
seg = pac.identifier[i] if i < len(pac.identifier) else None
|
|
115
|
-
if seg:
|
|
116
|
-
return f"{(seg.key + ':') if seg.key else ''}{seg.value}"
|
|
117
|
-
|
|
118
|
-
elif m := re.match(r'\{idVal(\w+)\}', value):
|
|
119
|
-
k = m.group(1)
|
|
120
|
-
seg = [s for s in pac.identifier if s.key and s.key == k]
|
|
121
|
-
if seg:
|
|
122
|
-
seg = seg[0]
|
|
123
|
-
return seg.value
|
|
124
|
-
else:
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
elif value == '{ext}':
|
|
128
|
-
m = re.match(r'^.*?(\*.*)*$', pac_url)
|
|
129
|
-
ext_str = m.group(1) if m else None
|
|
130
|
-
return m.group(1)[1:] if ext_str else None
|
|
131
|
-
|
|
132
|
-
elif m := re.match(r'\{ext(\d+)\}', value):
|
|
133
|
-
i = int(m.group(1)) - 1 # CIT is 1 based
|
|
134
|
-
extensions = pac_url.split('*')
|
|
135
|
-
extensions.pop(0)# first element is not extension
|
|
136
|
-
return extensions[i] if i < len(extensions) else None
|
|
137
|
-
else:
|
|
138
|
-
return None
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def __str__(self):
|
|
145
|
-
if csv:=self._csv_original:
|
|
146
|
-
return csv
|
|
147
|
-
|
|
148
|
-
s = "# coupling information table version: 1.0\n"
|
|
149
|
-
s += "Service Name\tApplication Intent\tService Type\tApplicable If\tTemplate Url\n"
|
|
150
|
-
for e in self.entries:
|
|
151
|
-
s += '\t'.join([e.service_name, e.application_intent, e.service_type.value, e.applicable_if, e.template_url]) + '\n'
|
|
152
|
-
return s
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{labfreed-0.2.6a3 → labfreed-0.2.6a4}/labfreed/well_known_extensions/display_name_extension.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|