labfreed 0.0.5__py3-none-any.whl → 0.2.0b0__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.
Files changed (56) hide show
  1. labfreed/PAC_CAT/__init__.py +16 -0
  2. labfreed/PAC_CAT/category_base.py +51 -0
  3. labfreed/PAC_CAT/pac_cat.py +159 -0
  4. labfreed/PAC_CAT/predefined_categories.py +190 -0
  5. labfreed/PAC_ID/__init__.py +19 -0
  6. labfreed/PAC_ID/extension.py +48 -0
  7. labfreed/PAC_ID/id_segment.py +90 -0
  8. labfreed/PAC_ID/pac_id.py +140 -0
  9. labfreed/PAC_ID/url_parser.py +154 -0
  10. labfreed/PAC_ID/url_serializer.py +80 -0
  11. labfreed/PAC_ID_Resolver/__init__.py +2 -0
  12. labfreed/PAC_ID_Resolver/cit_v1.py +149 -0
  13. labfreed/PAC_ID_Resolver/cit_v2.py +303 -0
  14. labfreed/PAC_ID_Resolver/resolver.py +81 -0
  15. labfreed/PAC_ID_Resolver/services.py +80 -0
  16. labfreed/__init__.py +4 -1
  17. labfreed/labfreed_infrastructure.py +276 -0
  18. labfreed/qr/__init__.py +1 -0
  19. labfreed/qr/generate_qr.py +422 -0
  20. labfreed/trex/__init__.py +16 -0
  21. labfreed/trex/python_convenience/__init__.py +3 -0
  22. labfreed/trex/python_convenience/data_table.py +45 -0
  23. labfreed/trex/python_convenience/pyTREX.py +242 -0
  24. labfreed/trex/python_convenience/quantity.py +46 -0
  25. labfreed/trex/table_segment.py +227 -0
  26. labfreed/trex/trex.py +69 -0
  27. labfreed/trex/trex_base_models.py +336 -0
  28. labfreed/trex/value_segments.py +111 -0
  29. labfreed/{DisplayNameExtension → utilities}/base36.py +29 -13
  30. labfreed/well_known_extensions/__init__.py +5 -0
  31. labfreed/well_known_extensions/default_extension_interpreters.py +7 -0
  32. labfreed/well_known_extensions/display_name_extension.py +40 -0
  33. labfreed/well_known_extensions/trex_extension.py +31 -0
  34. labfreed/well_known_keys/gs1/__init__.py +6 -0
  35. labfreed/well_known_keys/gs1/gs1.py +4 -0
  36. labfreed/well_known_keys/gs1/gs1_ai_enum_sorted.py +57 -0
  37. labfreed/{PAC_ID/well_known_segment_keys.py → well_known_keys/labfreed/well_known_keys.py} +1 -1
  38. labfreed/well_known_keys/unece/UneceUnits.json +33730 -0
  39. labfreed/well_known_keys/unece/__init__.py +4 -0
  40. labfreed/well_known_keys/unece/unece_units.py +68 -0
  41. labfreed-0.2.0b0.dist-info/METADATA +329 -0
  42. labfreed-0.2.0b0.dist-info/RECORD +44 -0
  43. {labfreed-0.0.5.dist-info → labfreed-0.2.0b0.dist-info}/WHEEL +1 -1
  44. labfreed/DisplayNameExtension/DisplayNameExtension.py +0 -34
  45. labfreed/PAC_CAT/data_model.py +0 -109
  46. labfreed/PAC_ID/data_model.py +0 -215
  47. labfreed/PAC_ID/parse.py +0 -142
  48. labfreed/PAC_ID/serialize.py +0 -60
  49. labfreed/TREXExtension/data_model.py +0 -239
  50. labfreed/TREXExtension/parse.py +0 -46
  51. labfreed/TREXExtension/uncertainty.py +0 -32
  52. labfreed/TREXExtension/unit_utilities.py +0 -143
  53. labfreed/validation.py +0 -71
  54. labfreed-0.0.5.dist-info/METADATA +0 -34
  55. labfreed-0.0.5.dist-info/RECORD +0 -19
  56. {labfreed-0.0.5.dist-info → labfreed-0.2.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,4 @@
1
+ '''
2
+ Data from
3
+ https://github.com/quadient/unece-units/blob/main/python/src/unece_excel_parser/parsedUneceUnits.json
4
+ '''
@@ -0,0 +1,68 @@
1
+ from functools import cache
2
+ import json
3
+ from pathlib import Path
4
+
5
+
6
+
7
+
8
+ @cache
9
+ def unece_units() -> list[dict]:
10
+ p = Path(__file__).parent / 'UneceUnits.json'
11
+ with open(p) as f:
12
+ l = json.load(f) # noqa: E741
13
+ return l
14
+
15
+ @cache
16
+ def unece_unit_codes():
17
+ codes= [u.get('commonCode') for u in unece_units() if u.get('state') == 'ACTIVE']
18
+ return codes
19
+
20
+
21
+ def unece_unit(unit_code):
22
+ unit = [u for u in unece_units() if u['commonCode'] == unit_code]
23
+ if len(unit) == 0:
24
+ return None
25
+ else:
26
+ return unit[0]
27
+
28
+ def unit_symbol(unit:dict) ->str:
29
+ return unit.get('symbol')
30
+
31
+ def unit_name(unit:dict) ->str:
32
+ return unit.get('name')
33
+
34
+
35
+
36
+ # def check_compatibility_unece_quantities():
37
+ # unece = unece_units()
38
+ # print(f'Number of units in file: {len(unece)}')
39
+
40
+ # failed = list()
41
+ # success = list()
42
+ # for u in unece:
43
+ # if u.get('state') == 'ACTIVE':
44
+ # try:
45
+ # if not u.get('symbol'):
46
+ # assert False
47
+ # u.get('name')
48
+ # validate_unit(u.get('symbol'))
49
+ # success.append(u)
50
+ # except AssertionError:
51
+ # failed.append(u)
52
+ # else:
53
+ # pass
54
+
55
+
56
+
57
+ # print('[blue] FAILED [/blue]')
58
+ # for u in failed:
59
+ # print(f'{u.get('commonCode')}: {u.get('name')}')
60
+
61
+ # print('[yellow] SUCCESSFUL [/yellow]')
62
+ # for u in success:
63
+ # print(u)
64
+
65
+ # print(f'{len(failed)} / {len(unece)} failed to convert')
66
+
67
+
68
+
@@ -0,0 +1,329 @@
1
+ Metadata-Version: 2.4
2
+ Name: labfreed
3
+ Version: 0.2.0b0
4
+ Summary: Python implementation of LabFREED building blocks
5
+ Author-email: Reto Thürer <thuerer.r@buchi.com>
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Topic :: Scientific/Engineering
14
+ Classifier: Topic :: Utilities
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy>=2.2.4
19
+ Requires-Dist: pydantic>=2.11.3
20
+ Requires-Dist: segno>=1.6.6
21
+ Requires-Dist: typer>=0.15.2
22
+ Requires-Dist: PyYAML>=6.0.2
23
+ Requires-Dist: jsonpath-ng>=1.7.0
24
+ Requires-Dist: pytest>=8.3.5 ; extra == "dev"
25
+ Requires-Dist: pdoc>=15.0.1 ; extra == "dev"
26
+ Requires-Dist: flit>=3.12.0 ; extra == "dev"
27
+ Requires-Dist: ruff>=0.11.5 ; extra == "dev"
28
+ Provides-Extra: dev
29
+
30
+ # LabFREED for Python
31
+
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/labfreed.svg)](https://pypi.org/project/labfreed/) ![Python Version](https://img.shields.io/pypi/pyversions/labfreed)
33
+
34
+ <!--
35
+ [![Tests](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml/badge.svg)](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml)
36
+ -->
37
+
38
+ This is a Python implementation of [LabFREED](https://labfreed.wega-it.com) building blocks.
39
+
40
+ ## Supported Building Blocks
41
+ - PAC-ID
42
+ - Parsing
43
+ - Serialization
44
+ - PAC-CAT
45
+ - Interpretation of PAC-ID as categories
46
+ - T-REX
47
+ - Parsing
48
+ - Serialization
49
+ - Display Extension
50
+ - base36 <> str conversions
51
+ - PAC-ID Resolver
52
+ - support for CIT v1
53
+ - draft support for CIT v1 (improved version)
54
+ - combined use of multiple cit in any combination of version
55
+ - Generation of QR codes (PAC-ID with extensions)
56
+
57
+ - Validation (with Errors Recommendations)
58
+
59
+ ## Installation
60
+ You can install LabFREED from [PyPI](https://pypi.org/project/labfreed/) using pip:
61
+
62
+ ```bash
63
+ pip install labfreed
64
+ ```
65
+
66
+
67
+ ## Usage Examples
68
+ > ⚠️ **Note:** These examples are building on each other. Imports and parsing are not repeated in each example.
69
+ <!-- BEGIN EXAMPLES -->
70
+ ```python
71
+ # import built ins
72
+ import os
73
+
74
+ target = 'console'
75
+ ```
76
+ ### Parse a simple PAC-ID
77
+
78
+ ```python
79
+ # Parse the PAC-ID
80
+ from labfreed.labfreed_infrastructure import LabFREED_ValidationError # noqa: E402
81
+ from labfreed import PAC_ID, LabFREED_ValidationError # noqa: E402, F811
82
+
83
+ pac_str = 'HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234'
84
+ try:
85
+ pac = PAC_ID.from_url(pac_str)
86
+ except LabFREED_ValidationError:
87
+ pass
88
+ # Check validity of this PAC-ID
89
+ is_valid = pac.is_valid
90
+ print(f'PAC-ID is valid: {is_valid}')
91
+ ```
92
+ ```text
93
+ >> PAC-ID is valid: True
94
+ ```
95
+ ### Show recommendations:
96
+ Note that the PAC-ID -- while valid -- uses characters which are not recommended (results in larger QR code).
97
+ There is a nice function to highlight problems
98
+
99
+ ```python
100
+ pac.print_validation_messages(target=target)
101
+ ```
102
+ ```text
103
+ >> Validation Results
104
+ >> ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
105
+ >> │ RECOMMENDATION in id segment value bal500 │
106
+ >> │ Characters 'b','a','l' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
107
+ >> │ │
108
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:@1234 │
109
+ >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
110
+ >> │ RECOMMENDATION in id segment value @1234 │
111
+ >> │ Characters '@' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
112
+ >> │ │
113
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:@1234 │
114
+ >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
115
+ >> │ RECOMMENDATION in id segment value bal500 │
116
+ >> │ Characters 'b','a','l' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
117
+ >> │ │
118
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:@1234 │
119
+ >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
120
+ >> │ RECOMMENDATION in id segment value @1234 │
121
+ >> │ Characters '@' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
122
+ >> │ │
123
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:@1234 │
124
+ >> └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
125
+ ```
126
+ ### Save as QR Code
127
+
128
+ ```python
129
+ from labfreed.qr import save_qr_with_markers # noqa: E402
130
+
131
+ save_qr_with_markers(pac_str, fmt='png')
132
+ ```
133
+ ```text
134
+ >> Large QR: Provided URL is not alphanumeric!
135
+ >> Size: 29
136
+ >> Version: 3
137
+ >> Error Level: M
138
+ ```
139
+ ### PAC-CAT
140
+ PAC-CAT defines a (optional) way how the identifier is structured.
141
+ PAC_ID.from_url() automatically converts to PAC-CAT if possible.
142
+
143
+ ```python
144
+ from labfreed.pac_cat import PAC_CAT # noqa: E402
145
+ pac_str = 'HTTPS://PAC.METTORIUS.COM/-DR/XQ908756/-MD/bal500/@1234'
146
+ pac = PAC_ID.from_url(pac_str)
147
+ if isinstance(pac, PAC_CAT):
148
+ categories = pac.categories
149
+ pac.print_categories()
150
+ ```
151
+ ```text
152
+ >> Categories in
153
+ >> HTTPS://PAC.METTORIUS.COM/-MD/240:
154
+ >> bal500/21:@1234
155
+ >> ┌────────────────────┬───────────┐
156
+ >> │ Main Category │ │
157
+ >> │ key () │ -DR │
158
+ >> │ id (21) │ XQ908756 │
159
+ >> ├────────────────────┼───────────┤
160
+ >> │ Category │ │
161
+ >> │ key () │ -MD │
162
+ >> │ model_number (240) │ bal500 │
163
+ >> │ serial_number (21) │ @1234 │
164
+ >> └────────────────────┴───────────┘
165
+ ```
166
+ ### Parse a PAC-ID with extensions
167
+ PAC-ID can have extensions. Here we parse a PAC-ID with attached display names and summary.
168
+
169
+ ```python
170
+ pac_str = 'HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/WM633OV3E5DGJW2BEG0PDM1EA7*SUM$TREX/WEIGHT$GRM:67.89'
171
+ pac = PAC_ID.from_url(pac_str)
172
+ ```
173
+ #### Display Name
174
+ Note that the Extension is automatically converted to a DisplayNameExtension
175
+
176
+ ```python
177
+ display_name = pac.get_extension('N') # display name has name 'N'
178
+ print(display_name)
179
+ ```
180
+ ```text
181
+ >> Display name: My Balance ❤️
182
+ ```
183
+ #### TREX
184
+
185
+ ```python
186
+ trexes = pac.get_extension_of_type('TREX')
187
+ trex_extension = trexes[0] # there could be multiple trexes. In this example there is only one, though
188
+ trex = trex_extension.trex
189
+ v = trex.get_segment('WEIGHT')
190
+ print(f'WEIGHT = {v.value}')
191
+ ```
192
+ ```text
193
+ >> WEIGHT = 67.89
194
+ ```
195
+ ### Create a PAC-ID with Extensions
196
+
197
+ #### Create PAC-ID
198
+
199
+ ```python
200
+ from labfreed.pac_id import PAC_ID, IDSegment # noqa: E402
201
+ from labfreed.well_known_keys.labfreed.well_known_keys import WellKnownKeys # noqa: E402
202
+
203
+ pac = PAC_ID(issuer='METTORIUS.COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
204
+ pac_str = pac.to_url()
205
+ print(pac_str)
206
+ ```
207
+ ```text
208
+ >> HTTPS://PAC.METTORIUS.COM/21:1234
209
+ ```
210
+ #### Create a TREX
211
+ TREX can conveniently be created from a python dictionary.
212
+ Note that utility types for Quantity (number with unit) and table are needed
213
+
214
+ ```python
215
+ from datetime import datetime # noqa: E402
216
+ from labfreed.trex.python_convenience.pyTREX import pyTREX # noqa: E402
217
+ from labfreed.trex.python_convenience.data_table import DataTable # noqa: E402
218
+ from labfreed.trex.python_convenience.quantity import Quantity # noqa: E402
219
+
220
+ # Value segments of different type
221
+ segments = {
222
+ 'STOP': datetime(year=2024,month=5,day=5,hour=13,minute=6),
223
+ 'TEMP': Quantity(value=10.15, unit= 'K'),
224
+ 'OK':False,
225
+ 'COMMENT': 'FOO',
226
+ 'COMMENT2':'£'
227
+ }
228
+ mydata = pyTREX(segments)
229
+
230
+ # Create a table
231
+ table = DataTable(col_names=['DURATION', 'Date', 'OK', 'COMMENT'])
232
+ table.append([Quantity(value=1, unit= 'hour'), datetime.now(), True, 'FOO'])
233
+ table.append([ 1.1, datetime.now(), True, 'BAR'])
234
+ table.append([ 1.3, datetime.now(), False, 'BLUBB'])
235
+ #add the table to the pytrex
236
+ mydata.update({'TABLE': table})
237
+
238
+ # Create TREX
239
+ trex = mydata.to_trex()
240
+
241
+
242
+ # Validation also works the same way for TREX
243
+ trex.print_validation_messages(target=target)
244
+ ```
245
+ ```text
246
+ >> Validation Results
247
+ >> ┌────────────────────────────────────────────────────────────┐
248
+ >> │ ERROR in TREX table column Date │
249
+ >> │ Column header key contains invalid characters: 'a','t','e' │
250
+ >> │ │
251
+ >> │ STOP$T.D:20240505T1306 │
252
+ >> │ +TEMP$KEL:10.15 │
253
+ >> │ +OK$T.B:F │
254
+ >> │ +COMMENT$T.A:FOO │
255
+ >> │ +COMMENT2$T.T:QMDTNXIKU │
256
+ >> │ +TABLE$$DURATION$HUR:Date$T.D:OK$T.B:COMMENT$T.A:: │
257
+ >> │ 1:20250423T142912.783:T:FOO:: │
258
+ >> │ 1.1:20250423T142912.783:T:BAR:: │
259
+ >> │ 1.3:20250423T142912.783:F:BLUBB │
260
+ >> └────────────────────────────────────────────────────────────┘
261
+ ```
262
+ #### Combine PAC-ID and TREX and serialize
263
+
264
+ ```python
265
+ from labfreed.well_known_extensions import TREX_Extension # noqa: E402
266
+ pac.extensions = [TREX_Extension(name='MYTREX', trex=trex)]
267
+ pac_str = pac.to_url()
268
+ print(pac_str)
269
+ ```
270
+ ```text
271
+ >> HTTPS://PAC.METTORIUS.COM/21:1234*MYTREX$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:QMDTNXIKU+TABLE$$DURATION$HUR:Date$T.D:OK$T.B:COMMENT$T.A::1:20250423T142912.783:T:FOO::1.1:20250423T142912.783:T:BAR::1.3:20250423T142912.783:F:BLUBB
272
+ ```
273
+ ## PAC-ID Resolver
274
+
275
+ ```python
276
+ from labfreed.pac_id_resolver import PAC_ID_Resolver, load_cit # noqa: E402
277
+ # Get a CIT
278
+ dir = os.path.join(os.getcwd(), 'examples')
279
+ p = os.path.join(dir, 'cit_mine.yaml')
280
+ cit = load_cit(p)
281
+
282
+ # validate the CIT
283
+ cit.is_valid
284
+ cit.print_validation_messages(target=target)
285
+ ```
286
+ ```python
287
+ # get a second cit
288
+ p = os.path.join(dir, 'coupling-information-table')
289
+ cit2 = load_cit(p)
290
+ cit2.origin = 'MY_COMPANY'
291
+ ```
292
+ ```python
293
+ # resolve a pac id
294
+ pac_str = 'HTTPS://PAC.METTORIUS.COM/-MS/X3511/CAS:7732-18-5'
295
+ service_groups = PAC_ID_Resolver(cits=[cit, cit2]).resolve(pac_str)
296
+ for sg in service_groups:
297
+ sg.update_states()
298
+ sg.print()
299
+
300
+ ```
301
+ ```text
302
+ >> Services from origin 'PERSONAL
303
+ >> ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
304
+ >> ┃ Service Name ┃ URL ┃ Reachable ┃
305
+ >> ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
306
+ >> │ CAS Search │ https://pubchem.ncbi.nlm.nih.gov/#query=7732-18-5 │ ACTIVE │
307
+ >> └──────────────┴───────────────────────────────────────────────────┴───────────┘
308
+ >> Services from origin 'MY_COMPANY
309
+ >> ┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
310
+ >> ┃ Service Name ┃ URL ┃ Reachable ┃
311
+ >> ┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
312
+ >> │ Chemical Management │ https://chem-manager.com/METTORIUS.COM/-MS/240:X3511/CAS:7732-18-5 │ INACTIVE │
313
+ >> └─────────────────────┴────────────────────────────────────────────────────────────────────┴───────────┘
314
+ >> Services from origin 'METTORIUS.COM
315
+ >> ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
316
+ >> ┃ Service Name ┃ URL ┃ Reachable ┃
317
+ >> ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
318
+ >> │ CoA │ https://mettorius.com/CoA.pdf │ ACTIVE │
319
+ >> │ MSDS │ https://mettorius.com/MSDS.pdf │ ACTIVE │
320
+ >> │ Shop │ https://mettorius.com/shop.html │ ACTIVE │
321
+ >> └──────────────┴─────────────────────────────────┴───────────┘
322
+ ```
323
+ <!-- END EXAMPLES -->
324
+
325
+
326
+
327
+ ## Change Log
328
+ [> Change Log](/CHANGELOG.md)
329
+
@@ -0,0 +1,44 @@
1
+ labfreed/__init__.py,sha256=2TONirDl7uJbvNSmgaVqTB7M8HFqtagQT4dV9cc1iWg,226
2
+ labfreed/labfreed_infrastructure.py,sha256=V-5sLhqKkfckKim5VxlB_D1qIzk-Ztxfx4VIlwaR6Jc,10850
3
+ labfreed/PAC_CAT/__init__.py,sha256=rJ2dFTN8aErTvGf4xwcNZ04xrbTieLAE2v5C2bmgPOA,507
4
+ labfreed/PAC_CAT/category_base.py,sha256=gx3c5xLrwJw5EXQtV70m8cV0E1scO4Kan02f8p7xLDo,1801
5
+ labfreed/PAC_CAT/pac_cat.py,sha256=UxWyPsuZsekq3ZmHSQLBdB1tocvVlxz_FOQXxHg_dlU,5800
6
+ labfreed/PAC_CAT/predefined_categories.py,sha256=BEf7rxN5IcKVhuxMNhdfQ_1xnkax5l8Z1pJMRIROKpw,8510
7
+ labfreed/PAC_ID/__init__.py,sha256=NGMbzkwQ4txKeT5pxdIZordwHO8J3_q84jzPanjKoHg,675
8
+ labfreed/PAC_ID/extension.py,sha256=uIs_9aasJ_n7ua067wR7XvtL05H-JZP4f_HtW4qnQDw,1114
9
+ labfreed/PAC_ID/id_segment.py,sha256=r5JU1SJuRXhZJJxy5T3xjrb598wIDTLpivSJhIUAzjQ,4526
10
+ labfreed/PAC_ID/pac_id.py,sha256=IWXYlKFjQKB_9U5bINWC5_Lb5pcVbuleocvGs79A28w,5300
11
+ labfreed/PAC_ID/url_parser.py,sha256=016Gd-V2OORDN2toAZEPmnXobrWNVVXM_zICBrQtqGY,5863
12
+ labfreed/PAC_ID/url_serializer.py,sha256=3D5pwcAP4ZrCQ22BRtxIwqWrFtZuY9913hCLPJNeyPI,2845
13
+ labfreed/PAC_ID_Resolver/__init__.py,sha256=RNBlrDOSR42gmSNH9wJVhK_xwEX45cvTKVgWW2bjh7Q,113
14
+ labfreed/PAC_ID_Resolver/cit_v1.py,sha256=9dwbQLaRwGq_SDxuuuyDFtpUfx9mZrgGSM0Ed9kFbHE,5800
15
+ labfreed/PAC_ID_Resolver/cit_v2.py,sha256=J7KsYUKSz4k7lqSHmLnouRY-etEbwmcj35O5SqVRm-o,11594
16
+ labfreed/PAC_ID_Resolver/resolver.py,sha256=x0XR0aWQVLptjtEwft8VPjggJEd8leTypQPUdzSyBaI,2160
17
+ labfreed/PAC_ID_Resolver/services.py,sha256=TPoH6YlSwa0hmawHpOiMwIpBAinhoRhMSoexop0YscI,2462
18
+ labfreed/qr/__init__.py,sha256=fdKwP6W2Js--yMbBUdn-g_2uq2VqPpfQJeDLHsMDO-Y,61
19
+ labfreed/qr/generate_qr.py,sha256=mSt-U872O3ReHB_UdS-MzYu0wRgdlKcAOEfTxg5CLRk,16616
20
+ labfreed/trex/__init__.py,sha256=r0MYrGk_XxsqSKo9c2i9jRXApTDeTZD8QRXcRpkOVXY,428
21
+ labfreed/trex/table_segment.py,sha256=nfUPbzzqFdkkOCZ73Qsb32iE8Ev0eMBBK5FhAxk51D8,8707
22
+ labfreed/trex/trex.py,sha256=WDoPvuhiilLtRSIkntCmDGkFBnD6oRZg0E6hhoV-I2g,2400
23
+ labfreed/trex/trex_base_models.py,sha256=OLMRyCUNLIwFVpUataGC4PbS3pW6LM2dApjBYVYeHFQ,11625
24
+ labfreed/trex/value_segments.py,sha256=X-IGUj4oyLAPbmbFfSdm8-RI1G2JiMEUN3lUT4bc4pU,4462
25
+ labfreed/trex/python_convenience/__init__.py,sha256=dyAQG7t-uYN6VfGXbWIq2bHxGcGI63l7FS2-VPYs2RQ,137
26
+ labfreed/trex/python_convenience/data_table.py,sha256=aUQWvsWZ_zAYc2s1iU4Bvl9b-SB5MSY42z69twLxWJ0,1730
27
+ labfreed/trex/python_convenience/pyTREX.py,sha256=qiOJ6PGAfsbnfpQBI_G2_C-3DaKqTfIW5xdZReQVxI8,9824
28
+ labfreed/trex/python_convenience/quantity.py,sha256=d3w-ThY4Cp7n3fde8pct-X5kHc7vbVe1xsJQKROnLks,1470
29
+ labfreed/utilities/base36.py,sha256=_yX8aQ1OwrK5tnJU1NUEzQSFGr9xAVnNvPObpNzCPYs,2895
30
+ labfreed/well_known_extensions/__init__.py,sha256=CjZTjx8Cn8763Hhnv_--Wj1LcFpFs2cyQwWrrzOS4xM,246
31
+ labfreed/well_known_extensions/default_extension_interpreters.py,sha256=3-BkJrAyBa99NN5Q2QPAm59CcWmPket-rvLzgltp8KY,201
32
+ labfreed/well_known_extensions/display_name_extension.py,sha256=xDw6ue54b6BPy1PA-ccCvrbmVLTW4I9Za7tlEWEeLlo,1461
33
+ labfreed/well_known_extensions/trex_extension.py,sha256=tffklaambkFPExcIDRAG9GJ7CHXeuFAagl6FuwS-2kI,929
34
+ labfreed/well_known_keys/gs1/__init__.py,sha256=LOFycgqS6OuV8t22TmtHy-ZI2iuXc3jJfVFwRFVDM3I,103
35
+ labfreed/well_known_keys/gs1/gs1.py,sha256=LIyy-W89m9L0gVxOu-lpBotsHN6CHvmdE3Vu2VwxUQA,79
36
+ labfreed/well_known_keys/gs1/gs1_ai_enum_sorted.py,sha256=D8hE6vm-GedS7W2uC52oYrvAKa4zM-7X11JeT_k23oM,1252
37
+ labfreed/well_known_keys/labfreed/well_known_keys.py,sha256=nqk66kHdSwJTJfMKlP-xQbBglS8F_NoWsGkfOVITFN0,331
38
+ labfreed/well_known_keys/unece/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
39
+ labfreed/well_known_keys/unece/__init__.py,sha256=MSP9lmjg9_D9iqG9Yq2_ajYfQSNS9wIT7FXA1c--59M,122
40
+ labfreed/well_known_keys/unece/unece_units.py,sha256=gNDQk6KGl-nGMf9Ycq_fQ8P2xxKITgLkcQWPd4H49gI,1630
41
+ labfreed-0.2.0b0.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
42
+ labfreed-0.2.0b0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
43
+ labfreed-0.2.0b0.dist-info/METADATA,sha256=yvB9hDNcYwlADZAAFLLj69mpSnpt5zH78rxxEybZYP4,17208
44
+ labfreed-0.2.0b0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.11.0
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,34 +0,0 @@
1
- import logging
2
- from pydantic import BaseModel
3
- from ..PAC_ID.data_model import Extension
4
- from .base36 import from_base36, to_base36
5
-
6
-
7
- class DisplayNames(Extension, BaseModel):
8
- display_names: list[str]
9
-
10
- @property
11
- def name(self)->str:
12
- return 'N'
13
-
14
- @property
15
- def type(self)->str:
16
- return 'N'
17
-
18
- @property
19
- def data(self)->str:
20
- return '/'.join([to_base36(dn) for dn in self.display_names])
21
-
22
- @staticmethod
23
- def from_spec_fields(name, type, data):
24
- if name != 'N':
25
- logging.warning(f'Name {name} was given, but this extension should only be used with name "N". Will ignore input')
26
-
27
- if type != 'N':
28
- logging.warning(f'Type {name} was given, but this extension should only be used with type "N". Will try to parse data as display names')
29
-
30
- display_names = [from_base36(b36) for b36 in data.split('/')]
31
-
32
- return DisplayNames(display_names=display_names)
33
-
34
-
@@ -1,109 +0,0 @@
1
- from abc import ABC
2
- from pydantic import Field
3
- from pydantic import BaseModel
4
-
5
- from ..PAC_ID.data_model import IDSegment, Category
6
-
7
- class CATBase(BaseModel, ABC):
8
- category_key:str
9
- additional_segments: list[IDSegment] = Field(default_factory=list)
10
-
11
- class Config:
12
- populate_by_name = True # this will allow field names, as well as aliases in validation
13
-
14
- def to_identifier_category(self, use_short_notation=False):
15
- '''Creates a Category with the correct segments.
16
- Segments are in order of the Pydantic model fields.
17
- Segment keys are omitted as long as the recommendation is followed.
18
- Additional segments are added at the end'''
19
- segments = []
20
- can_omit_keys = use_short_notation # keeps track of whether keys can still be omitted. That is the case when the segment recommendation is followed
21
- for field_name, field_info in self.model_fields.items():
22
- if field_name in ['category_key', 'additional_segments']:
23
- continue
24
- if value := getattr(self, field_name):
25
- if can_omit_keys:
26
- key = None
27
- else:
28
- key = field_info.alias
29
- segments.append(IDSegment(key= key, value= value) )
30
- else:
31
- can_omit_keys = False
32
- if self.additional_segments:
33
- segments.extend(self.additional_segments)
34
- return Category(key=self.category_key,
35
- segments=segments)
36
-
37
-
38
-
39
-
40
- class Material_Device(CATBase):
41
- category_key: str = Field(default='-MD', frozen=True)
42
- model_number: str = Field( alias='240', min_length=1)
43
- serial_number: str = Field( alias='21', min_length=1)
44
-
45
- class Material_Substance(CATBase):
46
- category_key: str = Field(default='-MS', frozen=True)
47
- product_number:str = Field( alias='240', min_length=1)
48
- batch_number:str|None = Field(default=None, alias='10')
49
- container_size:str|None = Field(default=None, alias='20')
50
- container_number:str|None = Field(default=None, alias='21')
51
- aliquot:str|None = Field(default=None, alias='250')
52
-
53
- class Material_Consumable(CATBase):
54
- category_key: str = Field(default='-MC', frozen=True)
55
- product_number:str = Field( alias='240', min_length=1)
56
- batch_number:str|None = Field(default=None, alias='10')
57
- packing_size:str|None = Field(default=None, alias='20')
58
- serial_number:str|None = Field(default=None, alias='21')
59
- aliquot:str|None = Field(default=None, alias='250')
60
-
61
- class Material_Misc(Material_Consumable):
62
- category_key: str = Field(default='-MM', frozen=True)
63
-
64
-
65
-
66
- class Data_Result(CATBase):
67
- category_key: str = Field(default='-DR', frozen=True)
68
- id:str = Field( alias='21', min_length=1)
69
-
70
- class Data_Method(CATBase):
71
- category_key: str = Field(default='-DM', frozen=True)
72
- id:str = Field( alias='21', min_length=1)
73
-
74
- class Data_Calibration(CATBase):
75
- category_key: str = Field(default='-DC', frozen=True)
76
- id:str = Field( alias='21', min_length=1)
77
-
78
- class Data_Progress(CATBase):
79
- category_key: str = Field(default='-DP', frozen=True)
80
- id:str = Field( alias='21', min_length=1)
81
-
82
- class Data_Static(CATBase):
83
- category_key: str = Field(default='-DS', frozen=True)
84
- id:str = Field( alias='21', min_length=1)
85
-
86
-
87
-
88
-
89
- mapping = {
90
- '-MD': Material_Device,
91
- '-MS': Material_Substance,
92
- '-MC': Material_Consumable,
93
- '-MM': Material_Misc,
94
- '-DM': Data_Method,
95
- '-DR': Data_Result,
96
- '-DC': Data_Calibration,
97
- '-DP': Data_Progress,
98
- '-DS': Data_Static
99
- }
100
-
101
- def CAT_from_category(category:Category) -> CATBase|None:
102
- raise NotImplementedError()
103
-
104
- def CAT_from_category_key(category_key) -> CATBase|None:
105
- return mapping.get(category_key)
106
-
107
-
108
- if __name__ == "__main__":
109
- pass