labfreed 0.0.19__tar.gz → 0.1.0__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.
Files changed (43) hide show
  1. {labfreed-0.0.19 → labfreed-0.1.0}/PKG-INFO +69 -15
  2. {labfreed-0.0.19 → labfreed-0.1.0}/README.md +68 -15
  3. labfreed-0.1.0/cit_mine.yaml +22 -0
  4. {labfreed-0.0.19 → labfreed-0.1.0}/examples.py +32 -7
  5. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/IO/parse_pac.py +1 -1
  6. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/PAC_CAT/data_model.py +2 -2
  7. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/PAC_ID/data_model.py +1 -1
  8. labfreed-0.1.0/labfreed/PAC_ID_Resolver/cit.yaml +92 -0
  9. labfreed-0.1.0/labfreed/PAC_ID_Resolver/data_types.py +59 -0
  10. labfreed-0.1.0/labfreed/PAC_ID_Resolver/resolver.py +221 -0
  11. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/TREX/data_model.py +2 -2
  12. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/__init__.py +1 -1
  13. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/validation.py +13 -3
  14. {labfreed-0.0.19 → labfreed-0.1.0}/main.py +21 -1
  15. labfreed-0.0.19/labfreed/IO/generate_label.py +0 -81
  16. {labfreed-0.0.19 → labfreed-0.1.0}/.vscode/launch.json +0 -0
  17. {labfreed-0.0.19 → labfreed-0.1.0}/.vscode/settings.json +0 -0
  18. {labfreed-0.0.19 → labfreed-0.1.0}/LICENSE +0 -0
  19. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/DisplayNameExtension/DisplayNameExtension.py +0 -0
  20. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/IO/generate_qr.py +0 -0
  21. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/PAC_CAT/__init__.py +0 -0
  22. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/PAC_ID/__init__.py +0 -0
  23. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/PAC_ID/extensions.py +0 -0
  24. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/TREX/UneceUnits.json +0 -0
  25. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/TREX/parse.py +0 -0
  26. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/TREX/unece_units.py +0 -0
  27. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/utilities/base36.py +0 -0
  28. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/utilities/utility_types.py +0 -0
  29. {labfreed-0.0.19 → labfreed-0.1.0}/labfreed/utilities/well_known_keys.py +0 -0
  30. {labfreed-0.0.19 → labfreed-0.1.0}/publish.ps1 +0 -0
  31. {labfreed-0.0.19 → labfreed-0.1.0}/publish.sh +0 -0
  32. {labfreed-0.0.19 → labfreed-0.1.0}/publish_commands +0 -0
  33. {labfreed-0.0.19 → labfreed-0.1.0}/pyproject.toml +0 -0
  34. {labfreed-0.0.19 → labfreed-0.1.0}/pytest.ini +0 -0
  35. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_(de)_serialization_incl_extension/test__parse.py +0 -0
  36. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_(de)_serialization_incl_extension/test__serialize.py +0 -0
  37. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_PAC_CAT/test_PAC_CAT_parse.py +0 -0
  38. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_PAC_CAT/test_PAC_CAT_serialize.py +0 -0
  39. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_PAC_ID/test_PAC_ID_serialize.py +0 -0
  40. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_PAC_ID/test_pac_id_parse.py +0 -0
  41. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_TREX/test_TREX_parse.py +0 -0
  42. {labfreed-0.0.19 → labfreed-0.1.0}/tests/test_TREX/test_TREX_serialize.py +0 -0
  43. {labfreed-0.0.19 → labfreed-0.1.0}/update_readme.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 0.0.19
3
+ Version: 0.1.0
4
4
  Summary: Python implementation of LabFREED building blocks
5
5
  Author-email: Reto Thürer <thuerer.r@buchi.com>
6
6
  Description-Content-Type: text/markdown
@@ -19,7 +19,7 @@ Requires-Dist: typer>=0.15.2
19
19
  [![Tests](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml/badge.svg)](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml)
20
20
  -->
21
21
 
22
- This is a Python implementation of [LabFREED](www.labfreed.wega-it.com) building blocks.
22
+ This is a Python implementation of [LabFREED](https://labfreed.wega-it.com) building blocks.
23
23
 
24
24
  ## Supported Building Blocks
25
25
  - PAC-ID
@@ -38,11 +38,16 @@ pip install labfreed
38
38
  ## Usage Examples
39
39
  > ⚠️ **Note:** These examples are building on each other. Imports and parsing are not repeated in each example.
40
40
  <!-- BEGIN EXAMPLES -->
41
+ ```python
42
+ # import built ins
43
+ import os
44
+ ```
41
45
  ### Parse a simple PAC-ID
42
46
 
43
47
  ```python
44
48
  from labfreed.IO.parse_pac import PAC_Parser
45
49
 
50
+
46
51
  # Parse the PAC-ID
47
52
  pac_str = 'HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234'
48
53
  pac_id = PAC_Parser().parse(pac_str).pac_id
@@ -60,7 +65,7 @@ Note that the PAC-ID -- while valid -- uses characters which are not recommended
60
65
  There is a nice function to highlight problems
61
66
 
62
67
  ```python
63
- pac_id.print_validation_messages()
68
+ pac_id.print_validation_messages(target='markdown')
64
69
  ```
65
70
  ```text
66
71
  >> =======================================
@@ -68,15 +73,15 @@ pac_id.print_validation_messages()
68
73
  >> ---------------------------------------
69
74
  >>
70
75
  >> Recommendation in id segment value bal500
71
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
72
- >> Characters l a b should not be used.
76
+ >> HTTPS://PAC.METTORIUS.COM/-MD/🔸b🔸🔸a🔸🔸l🔸500/@1234
77
+ >> Characters a b l should not be used.
73
78
  >>
74
79
  >> Recommendation in id segment value @1234
75
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
80
+ >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/🔸@🔸1234
76
81
  >> Characters @ should not be used.
77
82
  >>
78
83
  >> Warning in Category -MD
79
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
84
+ >> HTTPS://PAC.METTORIUS.COM/🔸-MD🔸/bal500/@1234
80
85
  >> Category key -MD is not a well known key. It is recommended to use well known keys only
81
86
  ```
82
87
  ### Save as QR Code
@@ -144,12 +149,12 @@ print(f'WEIGHT = {v}')
144
149
  from labfreed.PAC_ID.data_model import PACID, IDSegment
145
150
  from labfreed.utilities.well_known_keys import WellKnownKeys
146
151
 
147
- pac_id = PACID(issuer='METTORIUS:COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
152
+ pac_id = PACID(issuer='METTORIUS.COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
148
153
  pac_str = pac_id.serialize()
149
154
  print(pac_str)
150
155
  ```
151
156
  ```text
152
- >> HTTPS://PAC.METTORIUS:COM/21:1234
157
+ >> HTTPS://PAC.METTORIUS.COM/21:1234
153
158
  ```
154
159
  #### Create a TREX
155
160
  TREX can conveniently be created from a python dictionary.
@@ -174,7 +179,7 @@ trex.update(
174
179
  )
175
180
 
176
181
  # Create a table
177
- table = DataTable(['DURATION', 'DATE', 'OK', 'COMMENT'])
182
+ table = DataTable(['DURATION', 'Date', 'OK', 'COMMENT'])
178
183
  table.append([Quantity(value=1, unit=Unit(symbol='h', name='hour')), datetime.now(), True, 'FOO'])
179
184
  table.append([ 1.1, datetime.now(), True, 'BAR'])
180
185
  table.append([ 1.3, datetime.now(), False, 'BLUBB'])
@@ -182,11 +187,24 @@ table.append([ 1.3, datetime.no
182
187
  trex.update({'TABLE': table})
183
188
 
184
189
  # Validation also works the same way for TREX
185
- if trex.get_nested_validation_messages():
186
- trex.print_validation_messages()
187
-
188
- # Side Note: The TREX can be turned back into a dict
190
+ trex.print_validation_messages(target='markdown')
191
+ ```
192
+ ```text
193
+ >> =======================================
194
+ >> Validation Results
195
+ >> ---------------------------------------
196
+ >>
197
+ >> Error in TREX table column Date
198
+ >> DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:D🔸a🔸🔸t🔸🔸e🔸$T.D:OK$T.B:COMMENT$T.A::1:20250410T094130.847:T:FOO::1.1:20250410T094130.847:T:BAR::1.3
199
+ >> :20250410T094130.847:F:BLUBB
200
+ >> Column header key contains invalid characters: t,a,e
201
+ ```
202
+ ```python
203
+ # there is an error. 'Date' uses lower case. Lets fix it
189
204
  d = trex.dict()
205
+ d['TABLE'].col_names[1] = 'DATE'
206
+ trex = TREX(name_='DEMO')
207
+ trex.update(d)
190
208
  ```
191
209
  #### Combine PAC-ID and TREX and serialize
192
210
 
@@ -198,7 +216,34 @@ pac_str = pac_with_trex.serialize()
198
216
  print(pac_str)
199
217
  ```
200
218
  ```text
201
- >> HTTPS://PAC.METTORIUS:COM/21:1234*DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:DATE$T.D:OK$T.B:COMMENT$T.A::1:20250409T082814.766:T:FOO::1.1:20250409T082814.766:T:BAR::1.3:20250409T082814.766:F:BLUBB
219
+ >> HTTPS://PAC.METTORIUS.COM/21:1234*DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:DATE$T.D:OK$T.B:COMMENT$T.A::1:20250410T094130.847:T:FOO::1.1:20250410T094130.847:T:BAR::1.3:20250410T094130.847:F:BLUBB
220
+ ```
221
+ ## PAC-ID Resolver
222
+
223
+ ```python
224
+ from labfreed.PAC_ID_Resolver.resolver import PAC_ID_Resolver, load_cit
225
+ # Get a CIT
226
+ dir = os.path.dirname(__file__)
227
+ p = os.path.join(dir, 'cit_mine.yaml')
228
+ cit = load_cit(p)
229
+
230
+ # validate the CIT
231
+ cit.is_valid()
232
+ cit.print_validation_messages()
233
+ ```
234
+ ```text
235
+ >> [Error during execution: name '__file__' is not defined]
236
+ ```
237
+ ```python
238
+ # resolve a pac id
239
+ service_groups = PAC_ID_Resolver(cits=[cit]).resolve(pac_with_trex)
240
+ for sg in service_groups:
241
+ sg.print()
242
+
243
+ 5
244
+ ```
245
+ ```text
246
+ >> [Error during execution: name 'cit' is not defined]
202
247
  ```
203
248
  <!-- END EXAMPLES -->
204
249
 
@@ -206,7 +251,16 @@ print(pac_str)
206
251
 
207
252
  ## Change Log
208
253
 
254
+ ### v0.1.0
255
+ - DRAFT Support for PAC-ID Resolver
256
+
257
+ ### v0.0.20
258
+ - bugfix in TREX table to dict conversion
259
+ - markdown compatible validation printing
260
+
209
261
  ### v0.0.19
210
262
  - supports PAC-ID, PAC-CAT, TREX and DisplayName
211
263
  - QR generation
212
264
  - ok-ish test coverage
265
+
266
+
@@ -6,7 +6,7 @@
6
6
  [![Tests](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml/badge.svg)](https://github.com/retothuerer/LabFREED/actions/workflows/ci.yml)
7
7
  -->
8
8
 
9
- This is a Python implementation of [LabFREED](www.labfreed.wega-it.com) building blocks.
9
+ This is a Python implementation of [LabFREED](https://labfreed.wega-it.com) building blocks.
10
10
 
11
11
  ## Supported Building Blocks
12
12
  - PAC-ID
@@ -25,11 +25,16 @@ pip install labfreed
25
25
  ## Usage Examples
26
26
  > ⚠️ **Note:** These examples are building on each other. Imports and parsing are not repeated in each example.
27
27
  <!-- BEGIN EXAMPLES -->
28
+ ```python
29
+ # import built ins
30
+ import os
31
+ ```
28
32
  ### Parse a simple PAC-ID
29
33
 
30
34
  ```python
31
35
  from labfreed.IO.parse_pac import PAC_Parser
32
36
 
37
+
33
38
  # Parse the PAC-ID
34
39
  pac_str = 'HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234'
35
40
  pac_id = PAC_Parser().parse(pac_str).pac_id
@@ -47,7 +52,7 @@ Note that the PAC-ID -- while valid -- uses characters which are not recommended
47
52
  There is a nice function to highlight problems
48
53
 
49
54
  ```python
50
- pac_id.print_validation_messages()
55
+ pac_id.print_validation_messages(target='markdown')
51
56
  ```
52
57
  ```text
53
58
  >> =======================================
@@ -55,15 +60,15 @@ pac_id.print_validation_messages()
55
60
  >> ---------------------------------------
56
61
  >>
57
62
  >> Recommendation in id segment value bal500
58
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
59
- >> Characters l a b should not be used.
63
+ >> HTTPS://PAC.METTORIUS.COM/-MD/🔸b🔸🔸a🔸🔸l🔸500/@1234
64
+ >> Characters a b l should not be used.
60
65
  >>
61
66
  >> Recommendation in id segment value @1234
62
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
67
+ >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/🔸@🔸1234
63
68
  >> Characters @ should not be used.
64
69
  >>
65
70
  >> Warning in Category -MD
66
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
71
+ >> HTTPS://PAC.METTORIUS.COM/🔸-MD🔸/bal500/@1234
67
72
  >> Category key -MD is not a well known key. It is recommended to use well known keys only
68
73
  ```
69
74
  ### Save as QR Code
@@ -131,12 +136,12 @@ print(f'WEIGHT = {v}')
131
136
  from labfreed.PAC_ID.data_model import PACID, IDSegment
132
137
  from labfreed.utilities.well_known_keys import WellKnownKeys
133
138
 
134
- pac_id = PACID(issuer='METTORIUS:COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
139
+ pac_id = PACID(issuer='METTORIUS.COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
135
140
  pac_str = pac_id.serialize()
136
141
  print(pac_str)
137
142
  ```
138
143
  ```text
139
- >> HTTPS://PAC.METTORIUS:COM/21:1234
144
+ >> HTTPS://PAC.METTORIUS.COM/21:1234
140
145
  ```
141
146
  #### Create a TREX
142
147
  TREX can conveniently be created from a python dictionary.
@@ -161,7 +166,7 @@ trex.update(
161
166
  )
162
167
 
163
168
  # Create a table
164
- table = DataTable(['DURATION', 'DATE', 'OK', 'COMMENT'])
169
+ table = DataTable(['DURATION', 'Date', 'OK', 'COMMENT'])
165
170
  table.append([Quantity(value=1, unit=Unit(symbol='h', name='hour')), datetime.now(), True, 'FOO'])
166
171
  table.append([ 1.1, datetime.now(), True, 'BAR'])
167
172
  table.append([ 1.3, datetime.now(), False, 'BLUBB'])
@@ -169,11 +174,24 @@ table.append([ 1.3, datetime.no
169
174
  trex.update({'TABLE': table})
170
175
 
171
176
  # Validation also works the same way for TREX
172
- if trex.get_nested_validation_messages():
173
- trex.print_validation_messages()
174
-
175
- # Side Note: The TREX can be turned back into a dict
177
+ trex.print_validation_messages(target='markdown')
178
+ ```
179
+ ```text
180
+ >> =======================================
181
+ >> Validation Results
182
+ >> ---------------------------------------
183
+ >>
184
+ >> Error in TREX table column Date
185
+ >> DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:D🔸a🔸🔸t🔸🔸e🔸$T.D:OK$T.B:COMMENT$T.A::1:20250410T094130.847:T:FOO::1.1:20250410T094130.847:T:BAR::1.3
186
+ >> :20250410T094130.847:F:BLUBB
187
+ >> Column header key contains invalid characters: t,a,e
188
+ ```
189
+ ```python
190
+ # there is an error. 'Date' uses lower case. Lets fix it
176
191
  d = trex.dict()
192
+ d['TABLE'].col_names[1] = 'DATE'
193
+ trex = TREX(name_='DEMO')
194
+ trex.update(d)
177
195
  ```
178
196
  #### Combine PAC-ID and TREX and serialize
179
197
 
@@ -185,7 +203,34 @@ pac_str = pac_with_trex.serialize()
185
203
  print(pac_str)
186
204
  ```
187
205
  ```text
188
- >> HTTPS://PAC.METTORIUS:COM/21:1234*DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:DATE$T.D:OK$T.B:COMMENT$T.A::1:20250409T082814.766:T:FOO::1.1:20250409T082814.766:T:BAR::1.3:20250409T082814.766:F:BLUBB
206
+ >> HTTPS://PAC.METTORIUS.COM/21:1234*DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:DATE$T.D:OK$T.B:COMMENT$T.A::1:20250410T094130.847:T:FOO::1.1:20250410T094130.847:T:BAR::1.3:20250410T094130.847:F:BLUBB
207
+ ```
208
+ ## PAC-ID Resolver
209
+
210
+ ```python
211
+ from labfreed.PAC_ID_Resolver.resolver import PAC_ID_Resolver, load_cit
212
+ # Get a CIT
213
+ dir = os.path.dirname(__file__)
214
+ p = os.path.join(dir, 'cit_mine.yaml')
215
+ cit = load_cit(p)
216
+
217
+ # validate the CIT
218
+ cit.is_valid()
219
+ cit.print_validation_messages()
220
+ ```
221
+ ```text
222
+ >> [Error during execution: name '__file__' is not defined]
223
+ ```
224
+ ```python
225
+ # resolve a pac id
226
+ service_groups = PAC_ID_Resolver(cits=[cit]).resolve(pac_with_trex)
227
+ for sg in service_groups:
228
+ sg.print()
229
+
230
+ 5
231
+ ```
232
+ ```text
233
+ >> [Error during execution: name 'cit' is not defined]
189
234
  ```
190
235
  <!-- END EXAMPLES -->
191
236
 
@@ -193,7 +238,15 @@ print(pac_str)
193
238
 
194
239
  ## Change Log
195
240
 
241
+ ### v0.1.0
242
+ - DRAFT Support for PAC-ID Resolver
243
+
244
+ ### v0.0.20
245
+ - bugfix in TREX table to dict conversion
246
+ - markdown compatible validation printing
247
+
196
248
  ### v0.0.19
197
249
  - supports PAC-ID, PAC-CAT, TREX and DisplayName
198
250
  - QR generation
199
- - ok-ish test coverage
251
+ - ok-ish test coverage
252
+
@@ -0,0 +1,22 @@
1
+ origin: MINE
2
+
3
+ cit:
4
+ # Test
5
+ - if:
6
+ entries:
7
+ - service_type: userhandover-generic
8
+ service_name: AAAAAAAAAAAAAAAAAAhhhhhh
9
+ application_intents:
10
+ - foo
11
+ template_url: https://AAAAAAAAAAAA.{$.pac.issuer}.com/{$.pac.identifier[1].value}
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
@@ -1,8 +1,11 @@
1
+ # import built ins
2
+ import os
1
3
  '''
2
4
  ### Parse a simple PAC-ID
3
5
  '''
4
6
  from labfreed.IO.parse_pac import PAC_Parser
5
7
 
8
+
6
9
  # Parse the PAC-ID
7
10
  pac_str = 'HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234'
8
11
  pac_id = PAC_Parser().parse(pac_str).pac_id
@@ -17,7 +20,7 @@ print(f'PAC-ID is valid: {is_valid}')
17
20
  Note that the PAC-ID -- while valid -- uses characters which are not recommended (results in larger QR code).
18
21
  There is a nice function to highlight problems
19
22
  '''
20
- pac_id.print_validation_messages()
23
+ pac_id.print_validation_messages(target='markdown')
21
24
 
22
25
  '''
23
26
  ### Save as QR Code
@@ -65,7 +68,7 @@ print(f'WEIGHT = {v}')
65
68
  from labfreed.PAC_ID.data_model import PACID, IDSegment
66
69
  from labfreed.utilities.well_known_keys import WellKnownKeys
67
70
 
68
- pac_id = PACID(issuer='METTORIUS:COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
71
+ pac_id = PACID(issuer='METTORIUS.COM', identifier=[IDSegment(key=WellKnownKeys.SERIAL, value='1234')])
69
72
  pac_str = pac_id.serialize()
70
73
  print(pac_str)
71
74
 
@@ -93,7 +96,7 @@ trex.update(
93
96
  )
94
97
 
95
98
  # Create a table
96
- table = DataTable(['DURATION', 'DATE', 'OK', 'COMMENT'])
99
+ table = DataTable(['DURATION', 'Date', 'OK', 'COMMENT'])
97
100
  table.append([Quantity(value=1, unit=Unit(symbol='h', name='hour')), datetime.now(), True, 'FOO'])
98
101
  table.append([ 1.1, datetime.now(), True, 'BAR'])
99
102
  table.append([ 1.3, datetime.now(), False, 'BLUBB'])
@@ -101,11 +104,13 @@ table.append([ 1.3, datetime.no
101
104
  trex.update({'TABLE': table})
102
105
 
103
106
  # Validation also works the same way for TREX
104
- if trex.get_nested_validation_messages():
105
- trex.print_validation_messages()
106
-
107
- # Side Note: The TREX can be turned back into a dict
107
+ trex.print_validation_messages(target='markdown')
108
+ ''''''
109
+ # there is an error. 'Date' uses lower case. Lets fix it
108
110
  d = trex.dict()
111
+ d['TABLE'].col_names[1] = 'DATE'
112
+ trex = TREX(name_='DEMO')
113
+ trex.update(d)
109
114
 
110
115
  '''
111
116
  #### Combine PAC-ID and TREX and serialize
@@ -120,3 +125,23 @@ print(pac_str)
120
125
 
121
126
 
122
127
 
128
+ '''
129
+ ## PAC-ID Resolver
130
+ '''
131
+ from labfreed.PAC_ID_Resolver.resolver import PAC_ID_Resolver, load_cit
132
+ # Get a CIT
133
+ dir = os.path.dirname(__file__)
134
+ p = os.path.join(dir, 'cit_mine.yaml')
135
+ cit = load_cit(p)
136
+
137
+ # validate the CIT
138
+ cit.is_valid()
139
+ cit.print_validation_messages()
140
+
141
+ ''''''
142
+ # resolve a pac id
143
+ service_groups = PAC_ID_Resolver(cits=[cit]).resolve(pac_with_trex)
144
+ for sg in service_groups:
145
+ sg.print()
146
+
147
+ 5
@@ -19,7 +19,7 @@ from ..validation import ValidationMessage, LabFREEDValidationError
19
19
 
20
20
 
21
21
  class PACID_With_Extensions(BaseModelWithValidationMessages):
22
- pac_id: PACID
22
+ pac_id: PACID = Field(serialization_alias='pac')
23
23
  extensions: list[Extension] = Field(default_factory=list)
24
24
 
25
25
  def __str__(self):
@@ -14,7 +14,7 @@ class PAC_CAT(PACID):
14
14
  '''
15
15
  Extends a PAC-ID with interpretation of the identifier as categories
16
16
  '''
17
- categories:list[Category] = Field(default_factory=list())
17
+ categories:list[Category] = Field(default_factory=list)
18
18
 
19
19
  @property
20
20
  def identifier(self) -> list[IDSegment]:
@@ -175,7 +175,7 @@ class Category(BaseModelWithValidationMessages):
175
175
  "populate_by_name": True
176
176
  }
177
177
  key:str
178
- additional_segments: list[IDSegment] = Field(default_factory=list)
178
+ additional_segments: list[IDSegment] = Field(default_factory=list, exclude=True)
179
179
 
180
180
  @computed_field
181
181
  @property
@@ -96,7 +96,7 @@ class IDSegment(BaseModelWithValidationMessages):
96
96
 
97
97
  class PACID(BaseModelWithValidationMessages):
98
98
  issuer:str
99
- identifier: conlist(IDSegment, min_length=1) = Field(..., default_factory=list()) # type: ignore # exclude=True prevents this from being serialized by Pydantic
99
+ identifier: conlist(IDSegment, min_length=1) = Field(..., default_factory=list) # type: ignore # exclude=True prevents this from being serialized by Pydantic
100
100
 
101
101
 
102
102
  @model_validator(mode='after')
@@ -0,0 +1,92 @@
1
+ origin: PAC.METTORIUS.COM
2
+
3
+ macros:
4
+ shop: &shop
5
+ service_type: userhandover-generic
6
+ service_name: Shop
7
+ application_intents:
8
+ - showdevicemanual-apinilabs
9
+ template_url: https://mettorius.com/shop/an={$.pac.identifier.categories[1].segments['240'].value}
10
+
11
+ manual: &manual
12
+ service_type: userhandover-generic
13
+ service_name: Manual
14
+ application_intents:
15
+ - showdevicemanual-apinilabs
16
+ template_url: https://mettorius.com/om/an={$..*['240'].value}
17
+
18
+ CoA: &coa
19
+ service_type: userhandover-generic
20
+ service_name: CoA
21
+ application_intents:
22
+ - showCoA-apinilabs
23
+ template_url: https://mettorius.com/downloads/an={$..*['240'].value}
24
+
25
+ dummy: &dummy
26
+ service_type: userhandover-generic
27
+ application_intents:
28
+ - dummy
29
+ template_url: https://mettorius.com/om/an={$..*['240'].value}
30
+
31
+
32
+ cit:
33
+ # Test
34
+ - if: mettorius.com == $.pac.issuer
35
+ entries:
36
+ - <<: *shop
37
+ - <<: *manual
38
+
39
+ # Instruments
40
+ - if: mettorius.com == $.pac.issuer AND $.pac.id.categories['-MD']
41
+ entries:
42
+ - <<: *shop
43
+ - <<: *manual
44
+
45
+
46
+ # Consumables
47
+ - if: mettorius.com == $.pac.issuer AND $.pac.id.categories['-MC']
48
+ entries:
49
+ - <<: *shop
50
+ - <<: *manual
51
+ - <<: *coa
52
+
53
+
54
+
55
+ # Showcase for logic
56
+ ##############################
57
+
58
+ # multiline string
59
+ - if: "($.pac.issuer == mettorius.com)
60
+ AND $.pac.id.categories['-MD']"
61
+ entries:
62
+ - <<: *dummy
63
+ service_name: multiline applicable_if
64
+
65
+ # folded string
66
+ - if: |
67
+ ($.pac.issuer == mettorius.com)
68
+ AND $.pac.id.categories['-MD']
69
+ entries:
70
+ - <<: *dummy
71
+ service_name: folded applicable_if
72
+
73
+ # multiline string
74
+ - if: |
75
+ NOT NOT ($.pac.issuer == mettorius.com)
76
+ AND $.pac.id.categories['-MD']
77
+ entries:
78
+ - <<: *dummy
79
+ service_name: multiline applicable_if
80
+
81
+ - if: NOT ($.pac.issuer != METTORIUS.COM)
82
+ entries:
83
+ - <<: *dummy
84
+ service_name: _3
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
@@ -0,0 +1,59 @@
1
+ from pydantic import BaseModel, Field, field_validator
2
+ from rich import print
3
+ from rich.table import Table
4
+
5
+ from labfreed.validation import BaseModelWithValidationMessages
6
+
7
+
8
+ class CITEntry(BaseModelWithValidationMessages):
9
+ service_name: str
10
+ application_intents:list[str]
11
+ service_type:str
12
+ template_url:str
13
+
14
+
15
+ class CITBlock(BaseModelWithValidationMessages):
16
+ applicable_if: str = Field(default='True', alias='if')
17
+ entries: list[CITEntry]
18
+
19
+ @field_validator('applicable_if', mode='before')
20
+ @classmethod
21
+ def convert_if(cls, v):
22
+ return v if v is not None else 'True'
23
+
24
+
25
+ class CIT(BaseModelWithValidationMessages):
26
+ origin: str = ''
27
+ macros:dict = Field(default_factory=dict)
28
+ cit: list[CITBlock] = Field(default_factory=list)
29
+
30
+
31
+
32
+
33
+ class Service(BaseModelWithValidationMessages):
34
+ service_name: str
35
+ application_intents:list[str]
36
+ service_type:str
37
+ url:str
38
+
39
+
40
+ class CITEvaluated(BaseModelWithValidationMessages):
41
+ origin: str = ""
42
+ services: list[Service] = Field(default_factory=list)
43
+
44
+ def __str__(self):
45
+ out = [f'CIT (origin {self.origin})']
46
+ for s in self.services:
47
+ out.append(f'{s.service_name}\t\t\t{s.url}')
48
+ return '\n'.join(out)
49
+
50
+ def print(self):
51
+ table = Table(title=f"Services from origin '{self.origin}")
52
+
53
+ table.add_column("Service Name")
54
+ table.add_column("URL")
55
+
56
+ for s in self.services:
57
+ table.add_row(s.service_name, s.url)
58
+
59
+ print(table)
@@ -0,0 +1,221 @@
1
+ import os
2
+ import re
3
+ import yaml
4
+ import json
5
+ import jsonpath_ng.ext as jsonpath
6
+
7
+
8
+ from labfreed.IO.parse_pac import PAC_Parser, PACID_With_Extensions
9
+ from labfreed.PAC_ID_Resolver.data_types import CIT, CITEntry, CITEvaluated, Service
10
+
11
+ from labfreed.PAC_ID_Resolver.non_needed.query_tools import JSONPathTools
12
+
13
+
14
+ def load_cit(path):
15
+ with open(path, 'r') as f:
16
+ cit = yaml.safe_load(f)
17
+ cit = CIT.model_validate(cit)
18
+ return cit
19
+
20
+
21
+ class PAC_ID_Resolver():
22
+ def __init__(self, cits:list[CIT]=None):
23
+ if not cits:
24
+ cits = []
25
+ self.cits = cits
26
+
27
+ # load the default cit
28
+ dir = os.path.dirname(__file__)
29
+ fn ='cit.yaml'
30
+ p = os.path.join(dir, fn)
31
+ with open(p, 'r') as f:
32
+ cit = yaml.safe_load(f)
33
+ cit = CIT.model_validate(cit)
34
+ self.cits.append(cit)
35
+
36
+
37
+ def resolve(self, pac_id:PACID_With_Extensions|str):
38
+ if isinstance(pac_id, str):
39
+ pac_id = PAC_Parser().parse(pac_id)
40
+
41
+ pac_id_json = pac_id.model_dump(by_alias=True)
42
+
43
+
44
+ # dir = os.path.dirname(__file__)
45
+ # p = os.path.join(dir, 'pac-id.json')
46
+ # with open(p , 'r') as f:
47
+ # _json = f.read()
48
+ # pac_id_json = json.loads(_json)
49
+
50
+ matches = [self._evaluate_against_cit(pac_id_json, cit) for cit in self.cits]
51
+ return matches
52
+
53
+
54
+ def _evaluate_against_cit(self, pac_id_json, cit:CIT):
55
+ cit_evaluated = CITEvaluated(origin=cit.origin)
56
+ for block in cit.cit:
57
+ _, is_applicable = self._evaluate_applicable_if(pac_id_json, block.applicable_if)
58
+ if not is_applicable:
59
+ continue
60
+
61
+ for e in block.entries:
62
+ url = self.eval_url_template(pac_id_json, e.template_url)
63
+ cit_evaluated.services.append(Service(
64
+ service_name=e.service_name,
65
+ application_intents=e.application_intents,
66
+ service_type=e.service_type,
67
+ url = url
68
+ )
69
+ )
70
+ return cit_evaluated
71
+
72
+
73
+ def _evaluate_applicable_if(self, pac_id_json:str, expression) -> tuple[str, bool]:
74
+ expression = self._apply_convenience_substitutions(expression)
75
+
76
+ tokens = self._tokenize_jsonpath_expression(expression)
77
+ expression_for_eval = self._expression_from_tokens(pac_id_json, tokens)
78
+ applicable = eval(expression_for_eval, {}, {})
79
+
80
+ return expression_for_eval, applicable
81
+
82
+
83
+ def _apply_convenience_substitutions(self, query):
84
+ ''' applies a few substitutions, which enable abbreviated syntax.'''
85
+
86
+ # allow access to array elements by key
87
+ q_mod = re.sub(r"\[('.+?')\]", r"[?(@.key == \1)]", query )
88
+
89
+ # allow shorter path
90
+ # substitutions = [
91
+ # (r'(?<=^)id', 'pac.id'),
92
+ # (r'(?<=^)cat', 'pac.id.cat'),
93
+ # (r'(?<=\.)id(?=\.)', 'identifier'),
94
+ # (r'(?<=\.)cat$', 'categories'),
95
+ # (r'(?<=\.)cat(?=\[)', 'categories'),
96
+ # (r'(?<=\.)seg$', 'segments'),
97
+ # (r'(?<=\.)seg(?=\[)', 'segments'),
98
+ # (r'(?<=^)isu', 'pac.isu'),
99
+ # (r'(?<=\.)isu', 'issuer'),
100
+ # (r'(?<=^)ext', 'pac.ext'),
101
+ # (r'(?<=\.)ext(?=$)', 'extensions'),
102
+ # (r'(?<=\.)ext(?=\[)', 'extensions'),
103
+ # ]
104
+ # for sub in substitutions:
105
+ # q_mod = re.sub(sub[0], sub[1], q_mod)
106
+
107
+ return q_mod
108
+
109
+
110
+ def _tokenize_jsonpath_expression(self, expr: str):
111
+ token_pattern = re.compile(
112
+ r"""
113
+ (?P<LPAREN>\() |
114
+ (?P<RPAREN>\)) |
115
+ (?P<LOGIC>\bAND\b|\bOR\b|\bNOT\b) |
116
+ (?P<OPERATOR>==|!=|<=|>=|<|>) |
117
+ (?P<JSONPATH>
118
+ \$ # starts with $
119
+ (?:
120
+ [^\s\[\]()]+ # path segments, dots, etc.
121
+ |
122
+ \[ # open bracket
123
+ (?: # non-capturing group
124
+ [^\[\]]+ # anything but brackets
125
+ |
126
+ \[[^\[\]]*\] # nested brackets (1 level)
127
+ )*
128
+ \]
129
+ )+ # one or more bracket/segment blocks
130
+ ) |
131
+ (?P<LITERAL>
132
+ [A-Za-z_][\w\.\-]*[A-Za-z0-9] # domain-like literals
133
+ )
134
+ """,
135
+ re.VERBOSE
136
+ )
137
+
138
+ tokens = []
139
+ pos = 0
140
+ while pos < len(expr):
141
+ match = token_pattern.match(expr, pos)
142
+ if match:
143
+ group_type = match.lastgroup
144
+ value = match.group().strip()
145
+ tokens.append((value, group_type))
146
+ pos = match.end()
147
+ elif expr[pos].isspace():
148
+ pos += 1 # skip whitespace
149
+ else:
150
+ raise SyntaxError(f"Unexpected character at position {pos}: {expr[pos]}")
151
+
152
+ return tokens
153
+
154
+
155
+ def _expression_from_tokens(self, pac_id_json:str, tokens: tuple[str, str]):
156
+ out = []
157
+ for i in range(len(tokens)):
158
+ prev_token = tokens[i-1] if i > 0 else (None, None)
159
+ curr_token = tokens[i]
160
+ next_token = tokens[i+1] if i < len(tokens)-1 else (None, None)
161
+ if curr_token[1] == 'JSONPATH':
162
+ res = self._evaluate_jsonpath(pac_id_json, curr_token[0])
163
+
164
+ if prev_token[1] == 'OPERATOR' or next_token[1] == 'OPERATOR':
165
+ # if token is part of comparison return the value of the node
166
+ if len(res) == 0:
167
+ out.append('""')
168
+ else:
169
+ out.append(f'"{res[0].upper()}"')
170
+ else:
171
+ # if token is not part of comparison evaluate to boolean
172
+ if len(res) == 0:
173
+ out.append(False)
174
+ else:
175
+ out.append(True)
176
+
177
+ elif curr_token[1] == 'LOGIC':
178
+ out.append(curr_token[0].lower())
179
+
180
+ elif curr_token[1] == 'LITERAL':
181
+ t = curr_token[0]
182
+ if t[0] != '"':
183
+ t = '"' + t
184
+ if t[-1] != '"':
185
+ t = t + '"'
186
+ out.append(t.upper())
187
+ else:
188
+ out.append(curr_token[0])
189
+
190
+ s = ' '.join([str(e) for e in out])
191
+ return s
192
+
193
+
194
+
195
+
196
+ def eval_url_template(self, pac_id_json, url_template):
197
+ url = url_template
198
+ placeholders = re.findall(r'\{(.+?)\}', url_template)
199
+ for placeholder in placeholders:
200
+ expanded_placeholder = self._apply_convenience_substitutions(placeholder)
201
+ res = self._evaluate_jsonpath(pac_id_json, expanded_placeholder) or ['']
202
+ url = url.replace(f'{{{placeholder}}}', str(res[0]))
203
+ # res = self.substitute_jsonpath_expressions(expanded_placeholder, Patterns.jsonpath.value, as_bool=False)
204
+ # url = url.replace(f'{{{placeholder}}}', res)
205
+ return url
206
+
207
+
208
+
209
+
210
+ def _evaluate_jsonpath(self, pac_id_json, jp_query):
211
+ jsonpath_expr = jsonpath.parse(jp_query)
212
+ matches = [match.value for match in jsonpath_expr.find(pac_id_json)]
213
+ return matches
214
+
215
+
216
+
217
+
218
+
219
+ if __name__ == '__main__':
220
+ r = PAC_ID_Resolver()
221
+ r.resolve()
@@ -436,7 +436,7 @@ class TREX_Table(TREX_Segment):
436
436
  self.add_validation_message(
437
437
  source=f"Table {self.key}",
438
438
  type="Error",
439
- msg=f"Size mismatch: Table header contains {self.col_names} keys, while most rows have {most_common_len}",
439
+ msg=f"Size mismatch: Table header contains {self.column_names} keys, while most rows have {most_common_len}",
440
440
  highlight_pattern = self.key
441
441
  )
442
442
  expected_row_len = most_common_len
@@ -527,7 +527,7 @@ class TREX_Table(TREX_Segment):
527
527
  r.append(Quantity(value=e.value, unit=unit))
528
528
  else:
529
529
  r.append(e.value_to_python_type())
530
- table.append(r)
530
+ table.append(r)
531
531
  return table
532
532
 
533
533
 
@@ -2,4 +2,4 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.0.19"
5
+ __version__ = "0.1.0"
@@ -15,7 +15,7 @@ class ValidationMessage(BaseModel):
15
15
  problem_msg:str
16
16
  recommendation_msg: str = ""
17
17
  highlight:str = "" #this can be used to highlight problematic parts
18
- highlight_sub:list[str] = Field(default_factory=list())
18
+ highlight_sub:list[str] = Field(default_factory=list)
19
19
 
20
20
  @property
21
21
  def emphazised_highlight(self):
@@ -113,7 +113,7 @@ class BaseModelWithValidationMessages(BaseModel):
113
113
  return filter_warnings(self.get_nested_validation_messages())
114
114
 
115
115
 
116
- def print_validation_messages(self, str_to_highlight_in=None):
116
+ def print_validation_messages(self, str_to_highlight_in=None, target='console'):
117
117
  if not str_to_highlight_in:
118
118
  str_to_highlight_in = str(self)
119
119
  msgs = self.get_nested_validation_messages()
@@ -124,6 +124,10 @@ class BaseModelWithValidationMessages(BaseModel):
124
124
  ]
125
125
  )
126
126
  )
127
+
128
+ if not msgs:
129
+ print('All clear!')
130
+ return
127
131
 
128
132
  for m in msgs:
129
133
  if m.type.casefold() == "error":
@@ -133,7 +137,13 @@ class BaseModelWithValidationMessages(BaseModel):
133
137
 
134
138
  text = Text.from_markup(f'\n [bold {color}]{m.type} [/bold {color}] in \t {m.source}' )
135
139
  print(text)
136
- formatted_highlight = m.emphazised_highlight.replace('emph', f'bold {color}')
140
+ match target:
141
+ case 'markdown':
142
+ formatted_highlight = m.emphazised_highlight.replace('emph', f'🔸').replace('[/', '').replace('[', '').replace(']', '')
143
+ case 'console':
144
+ formatted_highlight = m.emphazised_highlight.replace('emph', f'bold {color}')
145
+ case 'html':
146
+ formatted_highlight = m.emphazised_highlight.replace('emph', f'b').replace('[', '<').replace(']', '>')
137
147
  fmtd = str_to_highlight_in.replace(m.highlight, formatted_highlight)
138
148
  fmtd = Text.from_markup(fmtd)
139
149
  print(fmtd)
@@ -1,5 +1,10 @@
1
1
 
2
2
  from datetime import datetime
3
+ import os
4
+
5
+ import yaml
6
+ from labfreed.IO.parse_pac import PAC_Parser
7
+ from labfreed.PAC_ID_Resolver.resolver import PAC_ID_Resolver, load_cit
3
8
  from labfreed.TREX.data_model import TREX
4
9
  from labfreed.TREX.parse import TREX_Parser
5
10
  from labfreed.DisplayNameExtension.DisplayNameExtension import DisplayNames
@@ -9,10 +14,25 @@ from labfreed.PAC_CAT.data_model import *
9
14
  from labfreed.utilities.base36 import base36
10
15
  from labfreed.utilities.utility_types import DataTable, Quantity, Unit
11
16
 
12
- from labfreed.QR_Generator.generate_qr import save_qr_with_markers
17
+ from labfreed.IO.generate_qr import save_qr_with_markers
13
18
 
14
19
  if __name__ == "__main__":
15
20
 
21
+ pac = PAC_Parser().parse('HTTPS://PAC.METTORIUS.COM/-DR/MADFGAI/-MD/ABCG/ACG/PC:1234')
22
+
23
+ dir = os.path.dirname(__file__)
24
+ p = os.path.join(dir, 'cit_internal.yaml')
25
+ cit = load_cit(p)
26
+
27
+ services = PAC_ID_Resolver(cits=[cit]).resolve(pac)
28
+
29
+
30
+ cat = PAC_CAT.from_pac_id(pac.pac_id)
31
+ cat.identifier
32
+ jsn = cat.model_dump_json(indent=2)
33
+ print(jsn)
34
+
35
+
16
36
 
17
37
  save_qr_with_markers('HTTPS://PAC.METTORIUS.COM/-MD/ABCG/ACG')
18
38
 
@@ -1,81 +0,0 @@
1
- import os
2
-
3
- from .generate_qr import generate_qr_with_markers_svg
4
-
5
- from labfreed.PAC_ID.data_model import PACID
6
- from labfreed.DisplayNameExtension.DisplayNameExtension import DisplayNames
7
- from labfreed.IO.parse_pac import PACID_With_Extensions
8
-
9
-
10
-
11
-
12
-
13
- def generate_label_200_100(pac_url, pac:PACID_With_Extensions):
14
- title, infos = get_label_fields(pac)
15
- pac_svg = generate_qr_with_markers_svg(pac_url, height=60, width=100, border=0)
16
- label = _generate_label(pac_svg, 200, 100, title, infos)
17
- return label
18
-
19
- def generate_label_credit_card_size(pac_url, pac:PACID_With_Extensions):
20
- title, infos = get_label_fields(pac)
21
- pac_svg = generate_qr_with_markers_svg(pac_url, height=100, width=200, border=0)
22
- label = _generate_label(pac_svg, 240, 150, title, infos)
23
- return label
24
-
25
-
26
- def _generate_label(qr_svg, width, height, title=None, infos=[]):
27
- if not qr_svg:
28
- raise ValueError("no valid qr given")
29
- env = Environment(
30
- loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates")),
31
- autoescape=select_autoescape()
32
- )
33
- template = env.get_template("pac_label.jinja.svg")
34
- svg = template.render(width=width, height= height, pac_qr=qr_svg, title=title, info1=infos[0], info2=infos[1], info3=infos[2])
35
-
36
- return svg
37
-
38
-
39
-
40
- def get_label_fields(pac:PACID_With_Extensions) -> tuple[str, list[tuple[str, str]]]:
41
- '''
42
- returns a list of exactly length 3. Containing either info tuples (key value) or None
43
- '''
44
- if dn_extension := next((e for e in pac.extensions if isinstance(e, DisplayNames)), None): #find extension of type DisplayName
45
- title = dn_extension.display_names[0]
46
- else:
47
- title = ""
48
-
49
- infos = []
50
- cat = pac.pac_id.identifier.categories[0]
51
- for s in cat.segments:
52
- lbl = pretty_print_segment_label(cat.key, s.key)
53
- infos.append((lbl, s.value))
54
-
55
- while len(infos) < 3:
56
- infos.append(None)
57
-
58
- if len(infos) > 3:
59
- infos = infos[0:3]
60
-
61
- return title,infos
62
-
63
-
64
- def pretty_print_segment_label(category:str, segment_key:str):
65
- if not segment_key:
66
- return 'no key'
67
-
68
- cat = CAT_from_category_key(category)
69
- if cat:
70
- alias_to_field = {v.alias: k for k, v in cat.model_fields.items() if v.alias}
71
- segment_label = alias_to_field.get(segment_key, segment_key)
72
- segment_label = segment_label.replace('_', ' ').title()
73
-
74
- segment_label = segment_label.replace('Id', 'ID')
75
-
76
- else:
77
- segment_label = segment_key
78
-
79
- return segment_label
80
-
81
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes