labfreed 0.2.6a5__py3-none-any.whl → 0.2.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of labfreed might be problematic. Click here for more details.

labfreed/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.2.6a5"
5
+ __version__ = "0.2.7"
6
6
 
7
7
  from labfreed.pac_id import * # noqa: F403
8
8
  from labfreed.pac_cat import * # noqa: F403
labfreed/pac_id/pac_id.py CHANGED
@@ -45,7 +45,7 @@ class PAC_ID(LabFREED_BaseModel):
45
45
  from labfreed.pac_id.url_parser import PAC_Parser
46
46
  return PAC_Parser.from_url(url, try_pac_cat=try_pac_cat, suppress_validation_errors=suppress_validation_errors, extension_interpreters=extension_interpreters)
47
47
 
48
- def to_url(self, use_short_notation=False, uppercase_only=False) -> str:
48
+ def to_url(self, use_short_notation:None|bool=None, uppercase_only=False) -> str:
49
49
  from labfreed.pac_id.url_serializer import PACID_Serializer
50
50
  return PACID_Serializer.to_url(self, use_short_notation=use_short_notation, uppercase_only=uppercase_only)
51
51
 
@@ -9,20 +9,23 @@ class PACID_Serializer():
9
9
  '''Represents a PAC-ID including it's extensions'''
10
10
 
11
11
  @classmethod
12
- def to_url(cls, pac:PAC_ID, use_short_notation=False, uppercase_only=False) -> str:
12
+ def to_url(cls, pac:PAC_ID, use_short_notation:bool|None=None, uppercase_only=False) -> str:
13
13
  """Serializes the PAC-ID including extensions.
14
14
 
15
15
  Args:
16
- use_short_notation (bool, optional): Uses shortening conventions for extensions and categories..
16
+ use_short_notation (bool|None, optional): None (default): Preserves the identifier as is. Extensions use short form
17
+ True: forces short notation for categories and extensions
18
+ False: forces long notation for categories and extensions
17
19
  uppercase_only (bool, optional): Forces all uppercase letters (results in smaller QR)..
18
20
 
19
21
  Returns:
20
22
  str: Something like this HTTPS://PAC.METTORIUS.COM/-MD/BAL500/1234*N$N/ABC*SUM$TREX/A$T.A:ABC
21
23
 
22
24
  """
23
- extensions_str = cls._serialize_extensions(pac.extensions, use_short_notation=use_short_notation)
24
-
25
25
  identifier_str = cls._serialize_identifier(pac, use_short_notation=use_short_notation)
26
+
27
+ use_short_notation_for_extensions = True if use_short_notation is None else use_short_notation
28
+ extensions_str = cls._serialize_extensions(pac.extensions, use_short_notation=use_short_notation_for_extensions)
26
29
  out = f"HTTPS://PAC.{pac.issuer}{identifier_str}{extensions_str}"
27
30
 
28
31
  if uppercase_only:
@@ -30,9 +33,10 @@ class PACID_Serializer():
30
33
  return out
31
34
 
32
35
  @classmethod
33
- def _serialize_identifier(cls, pac:PAC_ID|PAC_CAT, use_short_notation=True):
36
+ def _serialize_identifier(cls, pac:PAC_ID|PAC_CAT, use_short_notation:None|bool=None):
34
37
  ''' Serializes the PAC-ID'''
35
- if isinstance(pac, PAC_CAT):
38
+
39
+ if isinstance(pac, PAC_CAT) and use_short_notation is not None:
36
40
  for c in pac.categories:
37
41
  segments = [IDSegment(value=c.key)]
38
42
  if isinstance(c, PredefinedCategory):
@@ -91,7 +91,6 @@ class CIT_v1(LabFREED_BaseModel):
91
91
 
92
92
  cols = [c.strip() for c in line.split('\t')]
93
93
  if len(cols) < 5:
94
- logging.error(f'invalid line {line}')
95
94
  msg = ValidationMessage(
96
95
  level=ValidationMsgLevel.ERROR,
97
96
  source='CIT line',
@@ -102,7 +101,6 @@ class CIT_v1(LabFREED_BaseModel):
102
101
  errors.append(msg)
103
102
  continue
104
103
  if len(cols) > 5:
105
- logging.error(f'invalid line {line}')
106
104
  msg = ValidationMessage(
107
105
  level=ValidationMsgLevel.ERROR,
108
106
  source='CIT line',
@@ -123,7 +121,6 @@ class CIT_v1(LabFREED_BaseModel):
123
121
  )
124
122
  entries.append(entry)
125
123
  except ValueError:
126
- logging.error(f'invalid line {line}')
127
124
  msg = ValidationMessage(
128
125
  level=ValidationMsgLevel.ERROR,
129
126
  source='CIT line',
@@ -130,7 +130,12 @@ class CIT_v2(LabFREED_BaseModel):
130
130
 
131
131
  @classmethod
132
132
  def from_yaml(cls, yml:str) -> Self:
133
- return cls.model_validate(yml)
133
+ try:
134
+ d = yaml.safe_load(yml)
135
+ except yaml.YAMLError as e:
136
+ # not a valid yaml
137
+ raise ValueError("This is not a valid yaml") from e
138
+ return cls.model_validate(d)
134
139
 
135
140
  def __str__(self):
136
141
  yml = yaml.dump(self.model_dump() )
@@ -1,4 +1,6 @@
1
+ from functools import lru_cache
1
2
  import logging
3
+ import traceback
2
4
  from typing import Self
3
5
  import yaml
4
6
  from requests import get
@@ -24,8 +26,7 @@ def load_cit(path):
24
26
 
25
27
  def cit_from_str(s:str, origin:str='') -> CIT_v1|CIT_v2:
26
28
  try:
27
- cit_yml= yaml.safe_load(s)
28
- cit2 = CIT_v2.from_yaml(cit_yml)
29
+ cit2 = CIT_v2.from_yaml(s)
29
30
  cit_version = 'v2'
30
31
  except Exception:
31
32
  cit2 = None
@@ -38,6 +39,7 @@ def cit_from_str(s:str, origin:str='') -> CIT_v1|CIT_v2:
38
39
  cit = cit2 or cit1 or None
39
40
  return cit
40
41
 
42
+ @lru_cache
41
43
  def _get_issuer_cit(issuer:str):
42
44
  '''Gets the issuer's cit.'''
43
45
  url = 'HTTPS://PAC.' + issuer + '/coupling-information-table'
@@ -64,15 +66,16 @@ class PAC_ID_Resolver():
64
66
  self._cits = cits
65
67
 
66
68
 
67
- def resolve(self, pac_url:PAC_ID|str, check_service_status=True) -> list[ServiceGroup]:
69
+ def resolve(self, pac_url:PAC_ID|str, check_service_status=True, use_issuer_cit=True) -> list[ServiceGroup]:
68
70
  '''Resolve a PAC-ID'''
69
71
  if isinstance(pac_url, str):
70
72
  pac_id = PAC_CAT.from_url(pac_url)
71
73
  pac_id_catless = PAC_ID.from_url(pac_url, try_pac_cat=False)
72
74
 
73
75
  cits = self._cits.copy()
74
- if issuer_cit := _get_issuer_cit(pac_id.issuer):
75
- cits.append(issuer_cit)
76
+ if use_issuer_cit:
77
+ if issuer_cit := _get_issuer_cit(pac_id.issuer):
78
+ cits.append(issuer_cit)
76
79
 
77
80
  matches = []
78
81
  for cit in cits:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 0.2.6a5
3
+ Version: 0.2.7
4
4
  Summary: Python implementation of LabFREED building blocks
5
5
  Author-email: Reto Thürer <thuerer.r@buchi.com>
6
6
  Requires-Python: >=3.11
@@ -38,7 +38,7 @@ Provides-Extra: dev
38
38
  [![PyPI](https://img.shields.io/pypi/v/labfreed.svg)](https://pypi.org/project/labfreed/) ![Python Version](https://img.shields.io/pypi/pyversions/labfreed) [![Test Labfreed](https://github.com/retothuerer/LabFREED/actions/workflows/run-tests.yml/badge.svg)](https://github.com/retothuerer/LabFREED/actions/workflows/run-tests.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
39
39
 
40
40
 
41
- This is a Python implementation of [LabFREED](https://labfreed.wega-it.com) building blocks.
41
+ This is a Python implementation of [LabFREED](https://labfreed.org/) building blocks.
42
42
 
43
43
  ## Supported Building Blocks
44
44
  - PAC-ID
@@ -53,7 +53,7 @@ This is a Python implementation of [LabFREED](https://labfreed.wega-it.com) buil
53
53
  - base36 <> str conversions
54
54
  - PAC-ID Resolver
55
55
  - support for CIT v1
56
- - draft support for CIT v1 (improved version)
56
+ - draft support for CIT v2 (improved version)
57
57
  - combined use of multiple cit in any combination of version
58
58
  - Generation of QR codes (PAC-ID with extensions)
59
59
 
@@ -105,24 +105,24 @@ pac.print_validation_messages()
105
105
  >> Validation Results
106
106
  >> ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
107
107
  >> │ **RECOMMENDATION** in id segment value bal500 │
108
- >> │ Characters 'b','l','a' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
108
+ >> │ Characters 'a','l','b' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
109
109
  >> │ │
110
- >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:👉bal👈500/21:@1234
110
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/👉bal👈500/@1234
111
111
  >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
112
112
  >> │ **RECOMMENDATION** in id segment value @1234 │
113
113
  >> │ Characters '@' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
114
114
  >> │ │
115
- >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:👉@👈1234
115
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/bal500/👉@👈1234
116
116
  >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
117
117
  >> │ **RECOMMENDATION** in id segment value bal500 │
118
- >> │ Characters 'b','l','a' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
118
+ >> │ Characters 'a','l','b' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
119
119
  >> │ │
120
- >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:👉bal👈500/21:@1234
120
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/👉bal👈500/@1234
121
121
  >> ├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
122
122
  >> │ **RECOMMENDATION** in id segment value @1234 │
123
123
  >> │ Characters '@' should not be used., Characters SHOULD be limited to upper case letters (A-Z), numbers (0-9), '-' and '+' │
124
124
  >> │ │
125
- >> │ HTTPS://PAC.METTORIUS.COM/-MD/240:bal500/21:👉@👈1234
125
+ >> │ HTTPS://PAC.METTORIUS.COM/-MD/bal500/👉@👈1234
126
126
  >> └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
127
127
  ```
128
128
  ### Save as QR Code
@@ -152,8 +152,8 @@ if isinstance(pac, PAC_CAT):
152
152
  ```
153
153
  ```text
154
154
  >> Categories in
155
- >> HTTPS://PAC.METTORIUS.COM/-MD/240:
156
- >> bal500/21:@1234
155
+ >> HTTPS://PAC.METTORIUS.COM/-DR/XQ90
156
+ >> 8756/-MD/bal500/@1234
157
157
  >> ┌────────────────────┬───────────┐
158
158
  >> │ Main Category │ │
159
159
  >> │ key () │ -DR │
@@ -248,7 +248,7 @@ trex.print_validation_messages()
248
248
  >> Validation Results
249
249
  >> ┌────────────────────────────────────────────────────────────┐
250
250
  >> │ **ERROR** in TREX table column Date │
251
- >> │ Column header key contains invalid characters: 'e','a','t' │
251
+ >> │ Column header key contains invalid characters: 'a','t','e' │
252
252
  >> │ │
253
253
  >> │ STOP$T.D:20240505T1306 │
254
254
  >> │ +TEMP$KEL:10.15 │
@@ -256,9 +256,9 @@ trex.print_validation_messages()
256
256
  >> │ +COMMENT$T.A:FOO │
257
257
  >> │ +COMMENT2$T.T:12G3 │
258
258
  >> │ +TABLE$$DURATION$HUR:D👉ate👈$T.D:OK$T.B:COMMENT$T.A:: │
259
- >> │ 1:20250430T100239.279:T:FOO:: │
260
- >> │ 1.1:20250430T100239.280:T:BAR:: │
261
- >> │ 1.3:20250430T100239.280:F:BLUBB │
259
+ >> │ 1:20250513T080159.146:T:FOO:: │
260
+ >> │ 1.1:20250513T080159.146:T:BAR:: │
261
+ >> │ 1.3:20250513T080159.146:F:BLUBB │
262
262
  >> └────────────────────────────────────────────────────────────┘
263
263
  ```
264
264
  #### Combine PAC-ID and TREX and serialize
@@ -270,7 +270,7 @@ pac_str = pac.to_url()
270
270
  print(pac_str)
271
271
  ```
272
272
  ```text
273
- >> 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:12G3+TABLE$$DURATION$HUR:Date$T.D:OK$T.B:COMMENT$T.A::1:20250430T100239.279:T:FOO::1.1:20250430T100239.280:T:BAR::1.3:20250430T100239.280:F:BLUBB
273
+ >> 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:12G3+TABLE$$DURATION$HUR:Date$T.D:OK$T.B:COMMENT$T.A::1:20250513T080159.146:T:FOO::1.1:20250513T080159.146:T:BAR::1.3:20250513T080159.146:F:BLUBB
274
274
  ```
275
275
  ## PAC-ID Resolver
276
276
 
@@ -306,12 +306,12 @@ for sg in service_groups:
306
306
  >> ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
307
307
  >> │ CAS Search │ https://pubchem.ncbi.nlm.nih.gov/#query=7732-18-5 │ ACTIVE │
308
308
  >> └──────────────┴───────────────────────────────────────────────────┴───────────┘
309
- >> Services from origin 'MY_COMPANY
310
- >> ┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
311
- >> ┃ Service Name ┃ URL ┃ Reachable ┃
312
- >> ┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
313
- >> │ Chemical Management │ https://chem-manager.com/METTORIUS.COM/-MS/240:X3511/CAS:7732-18-5 │ INACTIVE │
314
- >> └─────────────────────┴────────────────────────────────────────────────────────────────────┴───────────┘
309
+ >> Services from origin 'MY_COMPANY
310
+ >> ┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
311
+ >> ┃ Service Name ┃ URL ┃ Reachable ┃
312
+ >> ┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
313
+ >> │ Chemical Management │ https://chem-manager.com/METTORIUS.COM/-MS/X3511/CAS:7732-18-5 │ INACTIVE │
314
+ >> └─────────────────────┴────────────────────────────────────────────────────────────────┴───────────┘
315
315
  >> Services from origin 'METTORIUS.COM
316
316
  >> ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
317
317
  >> ┃ Service Name ┃ URL ┃ Reachable ┃
@@ -327,6 +327,13 @@ for sg in service_groups:
327
327
 
328
328
  <!-- BEGIN CHANGELOG -->
329
329
  ## Change Log
330
+ ### v0.2.7
331
+ - Improved README. No functional changes
332
+
333
+ ### v0.2.6
334
+ - PAC_ID.to_url() preserves the identifier as is by default but allows to force short or long notation.
335
+ - PAC-ID Resolver does not try to resolve PAC-CAT with CIT v1.
336
+
330
337
  ### v0.2.5
331
338
  - resolvers checks service states by default
332
339
  - improvements and bugfixes in conversion from python types to TREX
@@ -1,4 +1,4 @@
1
- labfreed/__init__.py,sha256=HM--oq6iUUbtBQn6g2KfzcilwUaipYei_vdBhlM_itM,338
1
+ labfreed/__init__.py,sha256=cdoNTE10KG03M6MTCkgCbySTOajvy8HehAEgYvLJKmY,336
2
2
  labfreed/labfreed_infrastructure.py,sha256=EPDSCaGxWakAoPpHyc6ltf-pOuKyS5829lj_EG6wa74,10072
3
3
  labfreed/pac_cat/__init__.py,sha256=KNPtQzBD1XVohvG_ucOs7RJj-oi6biUTGB1k-T2o6pk,568
4
4
  labfreed/pac_cat/category_base.py,sha256=lFQNiTUukyhWdaSCAI7CZxLtj6kNtnBCE4UsePwsGqE,1801
@@ -7,14 +7,14 @@ labfreed/pac_cat/predefined_categories.py,sha256=5wnMCj-CrACV2W4lH13w7qynWIwi506
7
7
  labfreed/pac_id/__init__.py,sha256=NGMbzkwQ4txKeT5pxdIZordwHO8J3_q84jzPanjKoHg,675
8
8
  labfreed/pac_id/extension.py,sha256=zuHI8e51otPbpO1r1xDFh32uXTT8L5pCJn74B-aOUpI,1112
9
9
  labfreed/pac_id/id_segment.py,sha256=r5JU1SJuRXhZJJxy5T3xjrb598wIDTLpivSJhIUAzjQ,4526
10
- labfreed/pac_id/pac_id.py,sha256=IWXYlKFjQKB_9U5bINWC5_Lb5pcVbuleocvGs79A28w,5300
10
+ labfreed/pac_id/pac_id.py,sha256=PyOa5y2IVLEcmj7ZkFuURC1lrP3BU0Yj8pzAllhtatw,5309
11
11
  labfreed/pac_id/url_parser.py,sha256=TAQHxFf7Li8GA517mfOivmnJAJgh782oaSDzmOOkyTE,5942
12
- labfreed/pac_id/url_serializer.py,sha256=3D5pwcAP4ZrCQ22BRtxIwqWrFtZuY9913hCLPJNeyPI,2845
12
+ labfreed/pac_id/url_serializer.py,sha256=BgGoU_8W0Lvo153cXH8gX1k8H-FJtGizsEzjRaaEMcg,3270
13
13
  labfreed/pac_id_resolver/__init__.py,sha256=RNBlrDOSR42gmSNH9wJVhK_xwEX45cvTKVgWW2bjh7Q,113
14
14
  labfreed/pac_id_resolver/cit_common.py,sha256=xEkSSumj_IYgnXn3yKvoTBbgExnIfPY7E-RHU-7pcX8,2905
15
- labfreed/pac_id_resolver/cit_v1.py,sha256=1dx0zqJfzFOE4kP8_i8EJSLhvjVovc_i9Bazb53B0fU,9548
16
- labfreed/pac_id_resolver/cit_v2.py,sha256=I4Eri6r61O_BFFwCIyHZzwCQCVQJ7Rj9TW8MIOb2Rwg,11944
17
- labfreed/pac_id_resolver/resolver.py,sha256=SQlATlaUsmS6EZlEMyBQsp00ixpN3r-3V5pMXcvHYCw,2739
15
+ labfreed/pac_id_resolver/cit_v1.py,sha256=W7UCO0Gm0w09FSo_USFB1-V2tl3iErDxoe2OHh4fkvc,9383
16
+ labfreed/pac_id_resolver/cit_v2.py,sha256=wM1wf8UWbepatWNgkJ3l0l-HNJHqsqqPMql5k8fkVso,12127
17
+ labfreed/pac_id_resolver/resolver.py,sha256=UfSxRwTTjSgL4VoHfsQiaGTj3tt8dTDDd2wVcbr2Xvc,2817
18
18
  labfreed/pac_id_resolver/services.py,sha256=TPoH6YlSwa0hmawHpOiMwIpBAinhoRhMSoexop0YscI,2462
19
19
  labfreed/qr/__init__.py,sha256=fdKwP6W2Js--yMbBUdn-g_2uq2VqPpfQJeDLHsMDO-Y,61
20
20
  labfreed/qr/generate_qr.py,sha256=mSt-U872O3ReHB_UdS-MzYu0wRgdlKcAOEfTxg5CLRk,16616
@@ -39,7 +39,7 @@ labfreed/well_known_keys/labfreed/well_known_keys.py,sha256=nqk66kHdSwJTJfMKlP-x
39
39
  labfreed/well_known_keys/unece/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
40
40
  labfreed/well_known_keys/unece/__init__.py,sha256=MSP9lmjg9_D9iqG9Yq2_ajYfQSNS9wIT7FXA1c--59M,122
41
41
  labfreed/well_known_keys/unece/unece_units.py,sha256=gNDQk6KGl-nGMf9Ycq_fQ8P2xxKITgLkcQWPd4H49gI,1630
42
- labfreed-0.2.6a5.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
43
- labfreed-0.2.6a5.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
44
- labfreed-0.2.6a5.dist-info/METADATA,sha256=Vdc6vdvGls5bzknFaZmD7OCMz0yM0FNzd0M6UrFbRoM,18616
45
- labfreed-0.2.6a5.dist-info/RECORD,,
42
+ labfreed-0.2.7.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
43
+ labfreed-0.2.7.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
44
+ labfreed-0.2.7.dist-info/METADATA,sha256=LgChVG_EYO1fXu-FLEfydV_mZvDgmylj3-hxnREkE9g,18795
45
+ labfreed-0.2.7.dist-info/RECORD,,