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