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
labfreed/pac_id/url_parser.py
CHANGED
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import re
|
|
5
|
-
from types import MappingProxyType
|
|
6
|
-
|
|
7
|
-
from labfreed.labfreed_infrastructure import LabFREED_ValidationError
|
|
8
|
-
|
|
9
|
-
from labfreed.pac_id.id_segment import IDSegment
|
|
10
|
-
from labfreed.pac_id.extension import Extension
|
|
11
|
-
|
|
12
|
-
from labfreed.pac_cat import PAC_CAT
|
|
13
|
-
from labfreed.well_known_extensions import default_extension_interpreters
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from typing import TYPE_CHECKING
|
|
17
|
-
if TYPE_CHECKING:
|
|
18
|
-
# only imported during type checking
|
|
19
|
-
from labfreed.pac_id import PAC_ID
|
|
20
|
-
from labfreed.pac_cat import PAC_CAT
|
|
21
|
-
|
|
22
|
-
class PAC_Parser():
|
|
23
|
-
'''@private
|
|
24
|
-
Knows how to parse a PAC-ID.
|
|
25
|
-
From a SW engineering perspective it would be best to have no dependencies from other modules to pac_id.
|
|
26
|
-
However from a Python users convenience perspective it is better to have one place where a pac url can be parsed and magically the extensions are in a meaningful type (e.g. TREX in TREX aware format) and categories are known of possible.
|
|
27
|
-
|
|
28
|
-
>> We have given priority to convenient usage and therefore chose to have dependencies from pac_id to pac_cat and well_known_extensions
|
|
29
|
-
'''
|
|
30
|
-
|
|
31
|
-
@classmethod
|
|
32
|
-
def from_url(cls, pac_url:str,
|
|
33
|
-
*,
|
|
34
|
-
extension_interpreters = 'default',
|
|
35
|
-
try_pac_cat = True,
|
|
36
|
-
suppress_validation_errors=False
|
|
37
|
-
) -> "PAC_ID":
|
|
38
|
-
"""Parses a PAC-ID with extensions
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
pac_url (str): pac id with optional extensions: e.g. HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/ABC*SUM$TREX/A$T.A:ABC
|
|
42
|
-
|
|
43
|
-
Raises:
|
|
44
|
-
LabFREED_ValidationError: When validation fails. Note,that with suppress_errors no such error is raises
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
PACID including extensions. If possible PAC-CAT is applied and extensions are cast to a known type, which knows how to inetrprete the data
|
|
48
|
-
"""
|
|
49
|
-
if extension_interpreters == 'default':
|
|
50
|
-
extension_interpreters = default_extension_interpreters
|
|
51
|
-
|
|
52
|
-
if '*' in pac_url:
|
|
53
|
-
id_str, ext_str = pac_url.split('*', 1)
|
|
54
|
-
else:
|
|
55
|
-
id_str = pac_url
|
|
56
|
-
ext_str = ""
|
|
57
|
-
|
|
58
|
-
pac_id = cls._parse_pac_id(id_str)
|
|
59
|
-
|
|
60
|
-
# try converting to PAC-CAT. This can fail, in which case a regular PAC-ID is returned
|
|
61
|
-
if try_pac_cat:
|
|
62
|
-
try:
|
|
63
|
-
pac_cat = PAC_CAT.from_pac_id(pac_id)
|
|
64
|
-
if pac_cat.categories:
|
|
65
|
-
pac_id = pac_cat
|
|
66
|
-
except LabFREED_ValidationError:
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
extensions = cls._parse_extensions(ext_str)
|
|
70
|
-
if extensions and extension_interpreters:
|
|
71
|
-
for i, e in enumerate(extensions):
|
|
72
|
-
if interpreter := extension_interpreters.get(e.type):
|
|
73
|
-
extensions[i] = interpreter.from_extension(e)
|
|
74
|
-
pac_id.extensions = extensions
|
|
75
|
-
|
|
76
|
-
if not pac_id.is_valid and not suppress_validation_errors:
|
|
77
|
-
logging.error(pac_id.print_validation_messages())
|
|
78
|
-
raise LabFREED_ValidationError(validation_msgs = pac_id._get_nested_validation_messages())
|
|
79
|
-
|
|
80
|
-
return pac_id
|
|
81
|
-
|
|
82
|
-
@classmethod
|
|
83
|
-
def _parse_pac_id(cls,id_str:str) -> "PAC_ID":
|
|
84
|
-
# m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?\..+?)/(?P<identifier>.*)', id_str)
|
|
85
|
-
m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?)/(?P<identifier>.*)', id_str)
|
|
86
|
-
d = m.groupdict()
|
|
87
|
-
|
|
88
|
-
id_segments = list()
|
|
89
|
-
id_segments = cls._parse_id_segments(d.get('identifier'))
|
|
90
|
-
|
|
91
|
-
from labfreed.pac_id import PAC_ID
|
|
92
|
-
pac = PAC_ID(issuer= d.get('issuer'),
|
|
93
|
-
identifier=id_segments
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
return pac
|
|
97
|
-
|
|
98
|
-
@classmethod
|
|
99
|
-
def _parse_id_segments(cls, identifier:str):
|
|
100
|
-
if not identifier:
|
|
101
|
-
return []
|
|
102
|
-
|
|
103
|
-
id_segments = list()
|
|
104
|
-
if len(identifier) > 0 and identifier[0] == '/':
|
|
105
|
-
identifier = identifier[1:]
|
|
106
|
-
for s in identifier.split('/'):
|
|
107
|
-
tmp = s.split(':')
|
|
108
|
-
|
|
109
|
-
if len(tmp) == 1:
|
|
110
|
-
segment = IDSegment(value=tmp[0])
|
|
111
|
-
elif len(tmp) == 2:
|
|
112
|
-
segment = IDSegment(key=tmp[0], value=tmp[1])
|
|
113
|
-
else:
|
|
114
|
-
raise ValueError(f'invalid segment: {s}')
|
|
115
|
-
|
|
116
|
-
id_segments.append(segment)
|
|
117
|
-
return id_segments
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@classmethod
|
|
121
|
-
def _parse_extensions(cls, extensions_str:str|None) -> list["Extension"]:
|
|
122
|
-
|
|
123
|
-
extensions = list()
|
|
124
|
-
|
|
125
|
-
if not extensions_str:
|
|
126
|
-
return extensions
|
|
127
|
-
|
|
128
|
-
defaults = MappingProxyType(
|
|
129
|
-
{
|
|
130
|
-
0: { 'name': 'N', 'type': 'N'},
|
|
131
|
-
1: { 'name': 'SUM', 'type': 'TREX'}
|
|
132
|
-
}
|
|
133
|
-
)
|
|
134
|
-
for i, e in enumerate(extensions_str.split('*')):
|
|
135
|
-
if e == '': #this will happen if first extension starts with *
|
|
136
|
-
continue
|
|
137
|
-
d = re.match('((?P<name>.+)\$(?P<type>.+)/)?(?P<data>.+)', e).groupdict()
|
|
138
|
-
|
|
139
|
-
name = d.get('name')
|
|
140
|
-
type = d.get('type')
|
|
141
|
-
data = d.get('data')
|
|
142
|
-
|
|
143
|
-
if name:
|
|
144
|
-
defaults = None # once a name was specified no longer assign defaults
|
|
145
|
-
else:
|
|
146
|
-
if defaults:
|
|
147
|
-
name = defaults.get(i).get('name')
|
|
148
|
-
type = defaults.get(i).get('type')
|
|
149
|
-
else:
|
|
150
|
-
raise ValueError('extension number {i}, must have name and type')
|
|
151
|
-
|
|
152
|
-
#convert to subtype if they were given
|
|
153
|
-
e = Extension.create(name=name, type=type, data=data)
|
|
154
|
-
extensions.append(e)
|
|
155
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from types import MappingProxyType
|
|
6
|
+
|
|
7
|
+
from labfreed.labfreed_infrastructure import LabFREED_ValidationError
|
|
8
|
+
|
|
9
|
+
from labfreed.pac_id.id_segment import IDSegment
|
|
10
|
+
from labfreed.pac_id.extension import Extension
|
|
11
|
+
|
|
12
|
+
from labfreed.pac_cat import PAC_CAT
|
|
13
|
+
from labfreed.well_known_extensions import default_extension_interpreters
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
# only imported during type checking
|
|
19
|
+
from labfreed.pac_id import PAC_ID
|
|
20
|
+
from labfreed.pac_cat import PAC_CAT
|
|
21
|
+
|
|
22
|
+
class PAC_Parser():
|
|
23
|
+
'''@private
|
|
24
|
+
Knows how to parse a PAC-ID.
|
|
25
|
+
From a SW engineering perspective it would be best to have no dependencies from other modules to pac_id.
|
|
26
|
+
However from a Python users convenience perspective it is better to have one place where a pac url can be parsed and magically the extensions are in a meaningful type (e.g. TREX in TREX aware format) and categories are known of possible.
|
|
27
|
+
|
|
28
|
+
>> We have given priority to convenient usage and therefore chose to have dependencies from pac_id to pac_cat and well_known_extensions
|
|
29
|
+
'''
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_url(cls, pac_url:str,
|
|
33
|
+
*,
|
|
34
|
+
extension_interpreters = 'default',
|
|
35
|
+
try_pac_cat = True,
|
|
36
|
+
suppress_validation_errors=False
|
|
37
|
+
) -> "PAC_ID":
|
|
38
|
+
"""Parses a PAC-ID with extensions
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
pac_url (str): pac id with optional extensions: e.g. HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/ABC*SUM$TREX/A$T.A:ABC
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
LabFREED_ValidationError: When validation fails. Note,that with suppress_errors no such error is raises
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
PACID including extensions. If possible PAC-CAT is applied and extensions are cast to a known type, which knows how to inetrprete the data
|
|
48
|
+
"""
|
|
49
|
+
if extension_interpreters == 'default':
|
|
50
|
+
extension_interpreters = default_extension_interpreters
|
|
51
|
+
|
|
52
|
+
if '*' in pac_url:
|
|
53
|
+
id_str, ext_str = pac_url.split('*', 1)
|
|
54
|
+
else:
|
|
55
|
+
id_str = pac_url
|
|
56
|
+
ext_str = ""
|
|
57
|
+
|
|
58
|
+
pac_id = cls._parse_pac_id(id_str)
|
|
59
|
+
|
|
60
|
+
# try converting to PAC-CAT. This can fail, in which case a regular PAC-ID is returned
|
|
61
|
+
if try_pac_cat:
|
|
62
|
+
try:
|
|
63
|
+
pac_cat = PAC_CAT.from_pac_id(pac_id)
|
|
64
|
+
if pac_cat.categories:
|
|
65
|
+
pac_id = pac_cat
|
|
66
|
+
except LabFREED_ValidationError:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
extensions = cls._parse_extensions(ext_str)
|
|
70
|
+
if extensions and extension_interpreters:
|
|
71
|
+
for i, e in enumerate(extensions):
|
|
72
|
+
if interpreter := extension_interpreters.get(e.type):
|
|
73
|
+
extensions[i] = interpreter.from_extension(e)
|
|
74
|
+
pac_id.extensions = extensions
|
|
75
|
+
|
|
76
|
+
if not pac_id.is_valid and not suppress_validation_errors:
|
|
77
|
+
logging.error(pac_id.print_validation_messages())
|
|
78
|
+
raise LabFREED_ValidationError(validation_msgs = pac_id._get_nested_validation_messages())
|
|
79
|
+
|
|
80
|
+
return pac_id
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def _parse_pac_id(cls,id_str:str) -> "PAC_ID":
|
|
84
|
+
# m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?\..+?)/(?P<identifier>.*)', id_str)
|
|
85
|
+
m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?)/(?P<identifier>.*)', id_str)
|
|
86
|
+
d = m.groupdict()
|
|
87
|
+
|
|
88
|
+
id_segments = list()
|
|
89
|
+
id_segments = cls._parse_id_segments(d.get('identifier'))
|
|
90
|
+
|
|
91
|
+
from labfreed.pac_id import PAC_ID
|
|
92
|
+
pac = PAC_ID(issuer= d.get('issuer'),
|
|
93
|
+
identifier=id_segments
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return pac
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def _parse_id_segments(cls, identifier:str):
|
|
100
|
+
if not identifier:
|
|
101
|
+
return []
|
|
102
|
+
|
|
103
|
+
id_segments = list()
|
|
104
|
+
if len(identifier) > 0 and identifier[0] == '/':
|
|
105
|
+
identifier = identifier[1:]
|
|
106
|
+
for s in identifier.split('/'):
|
|
107
|
+
tmp = s.split(':')
|
|
108
|
+
|
|
109
|
+
if len(tmp) == 1:
|
|
110
|
+
segment = IDSegment(value=tmp[0])
|
|
111
|
+
elif len(tmp) == 2:
|
|
112
|
+
segment = IDSegment(key=tmp[0], value=tmp[1])
|
|
113
|
+
else:
|
|
114
|
+
raise ValueError(f'invalid segment: {s}')
|
|
115
|
+
|
|
116
|
+
id_segments.append(segment)
|
|
117
|
+
return id_segments
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def _parse_extensions(cls, extensions_str:str|None) -> list["Extension"]:
|
|
122
|
+
|
|
123
|
+
extensions = list()
|
|
124
|
+
|
|
125
|
+
if not extensions_str:
|
|
126
|
+
return extensions
|
|
127
|
+
|
|
128
|
+
defaults = MappingProxyType(
|
|
129
|
+
{
|
|
130
|
+
0: { 'name': 'N', 'type': 'N'},
|
|
131
|
+
1: { 'name': 'SUM', 'type': 'TREX'}
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
for i, e in enumerate(extensions_str.split('*')):
|
|
135
|
+
if e == '': #this will happen if first extension starts with *
|
|
136
|
+
continue
|
|
137
|
+
d = re.match('((?P<name>.+)\$(?P<type>.+)/)?(?P<data>.+)', e).groupdict()
|
|
138
|
+
|
|
139
|
+
name = d.get('name')
|
|
140
|
+
type = d.get('type')
|
|
141
|
+
data = d.get('data')
|
|
142
|
+
|
|
143
|
+
if name:
|
|
144
|
+
defaults = None # once a name was specified no longer assign defaults
|
|
145
|
+
else:
|
|
146
|
+
if defaults:
|
|
147
|
+
name = defaults.get(i).get('name')
|
|
148
|
+
type = defaults.get(i).get('type')
|
|
149
|
+
else:
|
|
150
|
+
raise ValueError('extension number {i}, must have name and type')
|
|
151
|
+
|
|
152
|
+
#convert to subtype if they were given
|
|
153
|
+
e = Extension.create(name=name, type=type, data=data)
|
|
154
|
+
extensions.append(e)
|
|
155
|
+
|
|
156
156
|
return extensions
|
|
@@ -1,84 +1,85 @@
|
|
|
1
|
-
from labfreed.pac_cat.pac_cat import PAC_CAT
|
|
2
|
-
from labfreed.pac_cat.predefined_categories import PredefinedCategory
|
|
3
|
-
from labfreed.pac_id.id_segment import IDSegment
|
|
4
|
-
from labfreed.pac_id.extension import Extension
|
|
5
|
-
from labfreed.pac_id import PAC_ID
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class PACID_Serializer():
|
|
9
|
-
'''Represents a PAC-ID including it's extensions'''
|
|
10
|
-
|
|
11
|
-
@classmethod
|
|
12
|
-
def to_url(cls, pac:PAC_ID, use_short_notation:bool|None=None, uppercase_only=False) -> str:
|
|
13
|
-
"""Serializes the PAC-ID including extensions.
|
|
14
|
-
|
|
15
|
-
Args:
|
|
16
|
-
use_short_notation (bool|None, optional): None (default): Preserves the identifier as is. Extensions use short form
|
|
17
|
-
True: forces short notation for categories and extensions
|
|
18
|
-
False: forces long notation for categories and extensions
|
|
19
|
-
uppercase_only (bool, optional): Forces all uppercase letters (results in smaller QR)..
|
|
20
|
-
|
|
21
|
-
Returns:
|
|
22
|
-
str: Something like this HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/ABC*SUM$TREX/A$T.A:ABC
|
|
23
|
-
|
|
24
|
-
"""
|
|
25
|
-
identifier_str = cls._serialize_identifier(pac, use_short_notation=use_short_notation)
|
|
26
|
-
|
|
27
|
-
use_short_notation_for_extensions = True if use_short_notation is None else use_short_notation
|
|
28
|
-
extensions_str = cls._serialize_extensions(pac.extensions, use_short_notation=use_short_notation_for_extensions)
|
|
29
|
-
out = f"HTTPS://PAC.{pac.issuer}{identifier_str}{extensions_str}"
|
|
30
|
-
|
|
31
|
-
if uppercase_only:
|
|
32
|
-
out = out.upper()
|
|
33
|
-
return out
|
|
34
|
-
|
|
35
|
-
@classmethod
|
|
36
|
-
def _serialize_identifier(cls, pac:PAC_ID|PAC_CAT, use_short_notation:None|bool=None):
|
|
37
|
-
''' Serializes the PAC-ID'''
|
|
38
|
-
|
|
39
|
-
if isinstance(pac, PAC_CAT) and use_short_notation is not None:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
1
|
+
from labfreed.pac_cat.pac_cat import PAC_CAT
|
|
2
|
+
from labfreed.pac_cat.predefined_categories import PredefinedCategory
|
|
3
|
+
from labfreed.pac_id.id_segment import IDSegment
|
|
4
|
+
from labfreed.pac_id.extension import Extension
|
|
5
|
+
from labfreed.pac_id import PAC_ID
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PACID_Serializer():
|
|
9
|
+
'''Represents a PAC-ID including it's extensions'''
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def to_url(cls, pac:PAC_ID, use_short_notation:bool|None=None, uppercase_only=False) -> str:
|
|
13
|
+
"""Serializes the PAC-ID including extensions.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
use_short_notation (bool|None, optional): None (default): Preserves the identifier as is. Extensions use short form
|
|
17
|
+
True: forces short notation for categories and extensions
|
|
18
|
+
False: forces long notation for categories and extensions
|
|
19
|
+
uppercase_only (bool, optional): Forces all uppercase letters (results in smaller QR)..
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: Something like this HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/ABC*SUM$TREX/A$T.A:ABC
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
identifier_str = cls._serialize_identifier(pac, use_short_notation=use_short_notation)
|
|
26
|
+
|
|
27
|
+
use_short_notation_for_extensions = True if use_short_notation is None else use_short_notation
|
|
28
|
+
extensions_str = cls._serialize_extensions(pac.extensions, use_short_notation=use_short_notation_for_extensions)
|
|
29
|
+
out = f"HTTPS://PAC.{pac.issuer}{identifier_str}{extensions_str}"
|
|
30
|
+
|
|
31
|
+
if uppercase_only:
|
|
32
|
+
out = out.upper()
|
|
33
|
+
return out
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def _serialize_identifier(cls, pac:PAC_ID|PAC_CAT, use_short_notation:None|bool=None):
|
|
37
|
+
''' Serializes the PAC-ID'''
|
|
38
|
+
|
|
39
|
+
if isinstance(pac, PAC_CAT) and use_short_notation is not None:
|
|
40
|
+
segments = []
|
|
41
|
+
for c in pac.categories:
|
|
42
|
+
segments.append(IDSegment(value=c.key))
|
|
43
|
+
if isinstance(c, PredefinedCategory):
|
|
44
|
+
segments += c._get_segments(use_short_notation=use_short_notation)
|
|
45
|
+
else:
|
|
46
|
+
segments += c.segments
|
|
47
|
+
else:
|
|
48
|
+
segments = pac.identifier
|
|
49
|
+
|
|
50
|
+
identifier_str = ''
|
|
51
|
+
for s in segments:
|
|
52
|
+
s:IDSegment = s
|
|
53
|
+
if s.key:
|
|
54
|
+
identifier_str += f'/{s.key}:{s.value}'
|
|
55
|
+
else:
|
|
56
|
+
identifier_str += f'/{s.value}'
|
|
57
|
+
return identifier_str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def _serialize_extensions(cls, extensions:list[Extension], use_short_notation):
|
|
62
|
+
out = ''
|
|
63
|
+
short_notation = use_short_notation
|
|
64
|
+
for i, e in enumerate(extensions):
|
|
65
|
+
|
|
66
|
+
if short_notation and i==0:
|
|
67
|
+
if e.name=='N':
|
|
68
|
+
out += f'*{e.data}'
|
|
69
|
+
continue
|
|
70
|
+
else:
|
|
71
|
+
short_notation = False
|
|
72
|
+
if short_notation and i==1:
|
|
73
|
+
if e.name=='SUM':
|
|
74
|
+
out += f'*{e.data}'
|
|
75
|
+
continue
|
|
76
|
+
else:
|
|
77
|
+
short_notation = False
|
|
78
|
+
|
|
79
|
+
out += f'*{e.name}${e.type}/{e.data}'
|
|
80
|
+
return out
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .resolver import PAC_ID_Resolver, load_cit # noqa: F401
|
|
2
|
-
from .services import ServiceGroup # noqa: F401
|
|
1
|
+
from .resolver import PAC_ID_Resolver, load_cit # noqa: F401
|
|
2
|
+
from .services import ServiceGroup # noqa: F401
|
|
@@ -1,82 +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
|
-
|
|
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
82
|
|