labfreed 0.0.20__py2.py3-none-any.whl → 0.1.0__py2.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/IO/parse_pac.py CHANGED
@@ -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()
labfreed/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.0.20"
5
+ __version__ = "0.1.0"
labfreed/validation.py CHANGED
@@ -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):
@@ -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":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 0.0.20
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
@@ -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
@@ -69,7 +74,7 @@ pac_id.print_validation_messages(target='markdown')
69
74
  >>
70
75
  >> Recommendation in id segment value bal500
71
76
  >> HTTPS://PAC.METTORIUS.COM/-MD/🔸b🔸🔸a🔸🔸l🔸500/@1234
72
- >> Characters b l a should not be used.
77
+ >> Characters a b l should not be used.
73
78
  >>
74
79
  >> Recommendation in id segment value @1234
75
80
  >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/🔸@🔸1234
@@ -190,8 +195,9 @@ trex.print_validation_messages(target='markdown')
190
195
  >> ---------------------------------------
191
196
  >>
192
197
  >> Error in TREX table column Date
193
- >> 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:20250409T094048.268:T:FOO::1.1:20250409T094048.268:T:BAR::1.3:20250409T094048.268:F:BLUBB
194
- >> Column header key contains invalid characters: e,t,a
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
195
201
  ```
196
202
  ```python
197
203
  # there is an error. 'Date' uses lower case. Lets fix it
@@ -210,7 +216,34 @@ pac_str = pac_with_trex.serialize()
210
216
  print(pac_str)
211
217
  ```
212
218
  ```text
213
- >> 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:20250409T094048.268:T:FOO::1.1:20250409T094048.268:T:BAR::1.3:20250409T094048.268: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]
214
247
  ```
215
248
  <!-- END EXAMPLES -->
216
249
 
@@ -218,6 +251,9 @@ print(pac_str)
218
251
 
219
252
  ## Change Log
220
253
 
254
+ ### v0.1.0
255
+ - DRAFT Support for PAC-ID Resolver
256
+
221
257
  ### v0.0.20
222
258
  - bugfix in TREX table to dict conversion
223
259
  - markdown compatible validation printing
@@ -1,13 +1,16 @@
1
- labfreed/__init__.py,sha256=JJg9mHM5goSWphrIerAaoiUjcOEZ7AXqGJIlmFog-pA,88
2
- labfreed/validation.py,sha256=he9utRxQwks4ro94AVi8t5rU4jgRcA-6uz1XEmqoAnM,6359
1
+ labfreed/__init__.py,sha256=LebroXmoov8_KunUmdQn2n6f793Y9WSU58Q9C_6Dxz4,87
2
+ labfreed/validation.py,sha256=PW08_mVpp27Bju3MblACHXupAXbl60GjRaSGXw161pU,6442
3
3
  labfreed/DisplayNameExtension/DisplayNameExtension.py,sha256=l9JZY2eRS0V-H5h3-WXIHiiBJuljns-_e_t9Bp84_CU,1155
4
4
  labfreed/IO/generate_qr.py,sha256=wdZSf51Id03xSY8liK2RfB7WyGAw9O4s0VhZzrkAa-g,16680
5
- labfreed/IO/parse_pac.py,sha256=2c-HXkiQdUrGTL8zGb5CmO9l6ZrCb07rrTMMKdMi3_o,6253
5
+ labfreed/IO/parse_pac.py,sha256=fZKNWuVGnYZCY0k6xVB1JOmLN5g6D8RW5CIq6-6Y9KM,6288
6
6
  labfreed/PAC_CAT/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
7
- labfreed/PAC_CAT/data_model.py,sha256=dGwcQGLy1Dk6SFbs9utxKQKm_4ROZrXdv618APlQg7M,14308
7
+ labfreed/PAC_CAT/data_model.py,sha256=qPrpzooI5tmH9P5JxfHWn0Ruung66gJ9KojCu5lXVzY,14320
8
8
  labfreed/PAC_ID/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- labfreed/PAC_ID/data_model.py,sha256=g09qgC-TV6fjJw9VyDF6mTJ6co2i2RKZc0Z-BmiiUIQ,7483
9
+ labfreed/PAC_ID/data_model.py,sha256=vALf8thR4zq7WrVZaKnIiS8hGBJ7UuKoy2heOY97tOs,7481
10
10
  labfreed/PAC_ID/extensions.py,sha256=YKIE-aFf1jdL4sqCqUe3txjnP8-dA2zCJrT5lBSjvuE,1092
11
+ labfreed/PAC_ID_Resolver/cit.yaml,sha256=-UcP-vKwhwGmYZVkVOjPZWEwHPzxUDcTFZFVM2_zMF0,2017
12
+ labfreed/PAC_ID_Resolver/data_types.py,sha256=i9F4FzLdAUpcFIX9fg9bLFRqQRe0E2ptb17etdtsj_c,1609
13
+ labfreed/PAC_ID_Resolver/resolver.py,sha256=2EKpDEzOM8Ri-Gy5cKVE6aoHsVFRqZE9fd_llG4wrFI,8178
11
14
  labfreed/TREX/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
12
15
  labfreed/TREX/data_model.py,sha256=tGgjp76wbS1MSS1Ep842CZyintsbecTZrlapj8WwGH8,29704
13
16
  labfreed/TREX/parse.py,sha256=86962VEJpkrTcT436iFIB5dNed5WHABzpjxRjkA3PXo,2043
@@ -15,7 +18,7 @@ labfreed/TREX/unece_units.py,sha256=scPKdsPzY1neAdFOhA08_tRZaR-yplM8mBhIzzDqZBk,
15
18
  labfreed/utilities/base36.py,sha256=_yX8aQ1OwrK5tnJU1NUEzQSFGr9xAVnNvPObpNzCPYs,2895
16
19
  labfreed/utilities/utility_types.py,sha256=dM0qZgshF3cHJThVzia7UIAOdkNLKukAaaduLqKSaMY,2195
17
20
  labfreed/utilities/well_known_keys.py,sha256=nqk66kHdSwJTJfMKlP-xQbBglS8F_NoWsGkfOVITFN0,331
18
- labfreed-0.0.20.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
19
- labfreed-0.0.20.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
20
- labfreed-0.0.20.dist-info/METADATA,sha256=phvfg_T1RGixhz1rN27aqGk7xRlxLNs_yjj-Ts2Pc-k,6961
21
- labfreed-0.0.20.dist-info/RECORD,,
21
+ labfreed-0.1.0.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
22
+ labfreed-0.1.0.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
23
+ labfreed-0.1.0.dist-info/METADATA,sha256=bTILYvmhLnxvXo2HM9EBlwmOQttglU5Hc-Bk9dKKWcY,7625
24
+ labfreed-0.1.0.dist-info/RECORD,,