labfreed 0.0.9__py2.py3-none-any.whl → 0.0.10__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.
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from pydantic import BaseModel
3
- from ..PAC_ID.data_model import Extension
3
+ from labfreed.PAC_ID.extensions import Extension
4
4
  from labfreed.utilities.base36 import from_base36, to_base36
5
5
 
6
6
 
@@ -20,7 +20,7 @@ class DisplayNames(Extension, BaseModel):
20
20
  return '/'.join([to_base36(dn) for dn in self.display_names])
21
21
 
22
22
  @staticmethod
23
- def from_spec_fields(name, type, data):
23
+ def from_spec_fields(*, name, type, data):
24
24
  if name != 'N':
25
25
  logging.warning(f'Name {name} was given, but this extension should only be used with name "N". Will ignore input')
26
26
 
@@ -30,5 +30,8 @@ class DisplayNames(Extension, BaseModel):
30
30
  display_names = [from_base36(b36) for b36 in data.split('/')]
31
31
 
32
32
  return DisplayNames(display_names=display_names)
33
+
34
+ def __str__(self):
35
+ return 'Display names: '+ ';'.join(self.display_names)
33
36
 
34
37
 
@@ -0,0 +1,232 @@
1
+ # import re
2
+ # from typing import Optional
3
+ # from typing_extensions import Self
4
+ # from pydantic import Field, ValidationInfo, computed_field, conlist, model_validator, field_validator
5
+
6
+ # from abc import ABC, abstractproperty, abstractstaticmethod
7
+
8
+ # from labfreed.PAC_ID.data_model import PACID
9
+
10
+ # from ..utilities.well_known_keys import WellKnownKeys
11
+ # from labfreed.validation import BaseModelWithValidationMessages, ValidationMessage, hsegment_pattern, domain_name_pattern
12
+
13
+
14
+ # # class IDSegment(BaseModelWithValidationMessages):
15
+ # # key:str|None = None
16
+ # # value:str
17
+
18
+ # # @model_validator(mode="after")
19
+ # # def validate_segment(self):
20
+ # # key = self.key or ""
21
+ # # value = self.value
22
+
23
+ # # # MUST be a valid hsegment according to RFC 1738, but without * (see PAC-ID Extension)
24
+ # # # This means it must be true for both, key and value
25
+ # # if not_allowed_chars := set(re.sub(hsegment_pattern, '', key)):
26
+ # # self.add_validation_message(
27
+ # # source=f"id segment key {key}",
28
+ # # type="Error",
29
+ # # msg=f"{' '.join(not_allowed_chars)} must not be used.",
30
+ # # recommendation = "The segment key must be a valid hsegment",
31
+ # # highlight_pattern = key,
32
+ # # highlight_sub = not_allowed_chars
33
+ # # )
34
+
35
+ # # if not_allowed_chars := set(re.sub(hsegment_pattern, '', value)):
36
+ # # self.add_validation_message(
37
+ # # source=f"id segment key {value}",
38
+ # # type="Error",
39
+ # # msg=f"{' '.join(not_allowed_chars)} must not be used.",
40
+ # # recommendation = "The segment key must be a valid hsegment",
41
+ # # highlight_pattern = value,
42
+ # # highlight_sub = not_allowed_chars
43
+ # # )
44
+
45
+ # # # Segment key SHOULD be limited to A-Z, 0-9, and -+..
46
+ # # if not_recommended_chars := set(re.sub(r'[A-Z0-9-:+]', '', key)):
47
+ # # self.add_validation_message(
48
+ # # source=f"id segment key {key}",
49
+ # # type="Recommendation",
50
+ # # msg=f"{' '.join(not_recommended_chars)} should not be used.",
51
+ # # recommendation = "SHOULD be limited to A-Z, 0-9, and -+",
52
+ # # highlight_pattern = key,
53
+ # # highlight_sub = not_recommended_chars
54
+ # # )
55
+
56
+ # # # Segment key should be in Well know keys
57
+ # # if key and key not in [k.value for k in WellKnownKeys]:
58
+ # # self.add_validation_message(
59
+ # # source=f"id segment key {key}",
60
+ # # type="Recommendation",
61
+ # # msg=f"{key} is not a well known segment key.",
62
+ # # recommendation = "RECOMMENDED to be a well-known id segment key.",
63
+ # # highlight_pattern = key
64
+ # # )
65
+
66
+
67
+ # # # Segment value SHOULD be limited to A-Z, 0-9, and -+..
68
+ # # if not_recommended_chars := set(re.sub(r'[A-Z0-9-:+]', '', value)):
69
+ # # self.add_validation_message(
70
+ # # source=f"id segment value {value}",
71
+ # # type="Recommendation",
72
+ # # msg=f"Characters {' '.join(not_recommended_chars)} should not be used.",
73
+ # # recommendation = "SHOULD be limited to A-Z, 0-9, and -+",
74
+ # # highlight_pattern = value,
75
+ # # highlight_sub = not_recommended_chars
76
+ # # )
77
+
78
+ # # # Segment value SHOULD be limited to A-Z, 0-9, and :-+ for new designs.
79
+ # # # this means that ":" in key or value is problematic
80
+ # # if ':' in key:
81
+ # # self.add_validation_message(
82
+ # # source=f"id segment key {key}",
83
+ # # type="Recommendation",
84
+ # # msg=f"Character ':' should not be used in segment key, since this character is used to separate key and value this can lead to undefined behaviour.",
85
+ # # highlight_pattern = key
86
+ # # )
87
+ # # if ':' in value:
88
+ # # self.add_validation_message(
89
+ # # source=f"id segment value {value}",
90
+ # # type="Recommendation",
91
+ # # msg=f"Character ':' should not be used in segment value, since this character is used to separate key and value this can lead to undefined behaviour.",
92
+ # # highlight_pattern = value
93
+ # # )
94
+
95
+ # # return self
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ # class PAC_CAT(PACID):
104
+
105
+ # @computed_field
106
+ # @property
107
+ # def categories(self) -> list[Category]:
108
+ # categories = list()
109
+ # c = Category(segments=[])
110
+ # categories.append(c)
111
+ # for s in self.segments:
112
+ # # new category starts with "-"
113
+ # if s.value[0] == '-':
114
+ # cat_key = s.value
115
+ # c = Category(key=cat_key, segments=[])
116
+ # categories.append(c)
117
+ # else:
118
+ # c.segments.append(s)
119
+
120
+ # # the first category might have no segments. remove categories without segments
121
+ # if not categories[0].segments:
122
+ # categories = categories[1:]
123
+
124
+ # return categories
125
+
126
+ # @model_validator(mode='after')
127
+ # def check_keys_are_unique_in_each_category(self) -> Self:
128
+ # for c in self.categories:
129
+ # keys = [s.key for s in c.segments if s.key]
130
+ # duplicate_keys = [k for k in set(keys) if keys.count(k) > 1]
131
+ # if duplicate_keys:
132
+ # for k in duplicate_keys:
133
+ # self.add_validation_message(
134
+ # source=f"identifier {k}",
135
+ # type="Error",
136
+ # msg=f"Duplicate key {k} in category {c.key}",
137
+ # highlight_pattern = k
138
+ # )
139
+ # return self
140
+
141
+ # # @model_validator(mode='after')
142
+ # # def check_length(self) -> Self:
143
+ # # l = 0
144
+ # # for s in self.segments:
145
+ # # if s.key:
146
+ # # l += len(s.key)
147
+ # # l += 1 # for ":"
148
+ # # l += len(s.value)
149
+ # # l += len(self.segments) - 1 # account for "/" separating the segments
150
+
151
+ # # if l > 256:
152
+ # # self.add_validation_message(
153
+ # # source=f"identifier",
154
+ # # type="Error",
155
+ # # msg=f'Identifier is {l} characters long, Identifier must not exceed 256 characters.',
156
+ # # highlight_pattern = ""
157
+ # # )
158
+ # # return self
159
+
160
+ # @staticmethod
161
+ # def from_categories(categories:list[Category]) :
162
+ # segments = list()
163
+ # for c in categories:
164
+ # if c.key:
165
+ # segments.append(IDSegment(value=c.key))
166
+ # segments.extend(c.segments)
167
+ # return Identifier(segments=segments)
168
+
169
+
170
+
171
+
172
+
173
+ # # class PACID(BaseModelWithValidationMessages):
174
+ # # issuer:str
175
+ # # identifier: Identifier
176
+
177
+ # # @model_validator(mode="after")
178
+ # # def validate_issuer(self):
179
+ # # if not re.fullmatch(domain_name_pattern, self.issuer):
180
+ # # self.add_validation_message(
181
+ # # source="PAC-ID",
182
+ # # type="Error",
183
+ # # highlight_pattern=self.issuer,
184
+ # # msg=f"Issuer must be a valid domain name. "
185
+ # # )
186
+
187
+ # # # recommendation that A-Z, 0-9, -, and . should be used
188
+ # # if not_recommended_chars := set(re.sub(r'[A-Z0-9\.-]', '', self.issuer)):
189
+ # # self.add_validation_message(
190
+ # # source="PAC-ID",
191
+ # # type="Recommendation",
192
+ # # highlight_pattern=self.issuer,
193
+ # # highlight_sub=not_recommended_chars,
194
+ # # msg=f"Characters {' '.join(not_recommended_chars)} should not be used. Issuer SHOULD contain only the characters A-Z, 0-9, -, and . "
195
+ # # )
196
+ # # return self
197
+
198
+ # # def __str__(self):
199
+ # # id_segments = ''
200
+ # # for s in self.identifier.segments:
201
+ # # if s.key:
202
+ # # id_segments += f'/{s.key}:{s.value}'
203
+ # # else:
204
+ # # id_segments += f'/{s.value}'
205
+
206
+ # # out = f"HTTPS://PAC.{self.issuer}{id_segments}"
207
+ # # return out
208
+
209
+
210
+
211
+
212
+ # # class PACID_With_Extensions(BaseModelWithValidationMessages):
213
+ # # pac_id: PACID
214
+ # # extensions: list[Extension] = Field(default_factory=list)
215
+
216
+ # # def __str__(self):
217
+ # # out = str(self.pac_id)
218
+ # # out += '*'.join(str(e) for e in self.extensions)
219
+
220
+ # # def get_extension_of_type(self, type:str) -> list[Extension]:
221
+ # # return [e for e in self.extensions if e.type == type]
222
+
223
+ # # def get_extension(self, name:str) -> Extension|None:
224
+ # # out = [e for e in self.extensions if e.name == name]
225
+ # # if not out:
226
+ # # return None
227
+ # # return out[0]
228
+
229
+
230
+
231
+
232
+
@@ -1,25 +1,176 @@
1
+ from __future__ import annotations # optional in 3.11, but recommended for consistency
2
+
1
3
  from abc import ABC
2
- from pydantic import Field
3
- from pydantic import BaseModel
4
+ from typing import Self
5
+ from pydantic import Field, computed_field, model_validator
6
+
7
+ from labfreed.validation import BaseModelWithValidationMessages
8
+
9
+ from ..PAC_ID.data_model import PACID, IDSegment
4
10
 
5
- from ..PAC_ID.data_model import IDSegment, Category
6
11
 
7
- class CATBase(BaseModel, ABC):
8
- category_key:str
9
- additional_segments: list[IDSegment] = Field(default_factory=list)
10
12
 
11
- class Config:
12
- populate_by_name = True # this will allow field names, as well as aliases in validation
13
+ class PAC_CAT(PACID):
14
+ '''
15
+ Extends a PAC-ID with interpretation of the identifier as categories
16
+ '''
17
+ categories:list[Category] = Field(default_factory=list())
18
+
19
+ @property
20
+ def identifier(self) -> list[IDSegment]:
21
+ out = list()
22
+ for category in self.categories:
23
+ out.append(IDSegment(value=category.key))
24
+ out.extend(category.segments)
25
+ return out
26
+
27
+ def get_category(self, key):
28
+ tmp = [c for c in self.categories if c.key == key]
29
+ if not tmp:
30
+ return None
31
+ return tmp[0]
32
+
33
+
34
+ @classmethod
35
+ def from_pac_id(cls, pac_id:PACID):
36
+ d = pac_id.model_dump()
37
+ issuer = d.get('issuer')
38
+
39
+ category_segments = cls._split_into_categories(pac_id.identifier)
40
+ categories = list()
41
+ for c in category_segments:
42
+ categories.append(cls.cat_from_cat_segments(c))
43
+
44
+ return PAC_CAT(issuer=issuer, categories=categories, identifier=pac_id.identifier)
45
+
46
+
47
+ @classmethod
48
+ def cat_from_cat_segments(cls, segments:list[IDSegment]):
49
+ segments = segments.copy()
50
+ category_key = segments[0].value
51
+ segments.pop(0)
52
+
53
+ mapping = {
54
+ '-MD': Material_Device,
55
+ '-MS': Material_Substance,
56
+ '-MC': Material_Consumable,
57
+ '-MM': Material_Misc,
58
+ '-DM': Data_Method,
59
+ '-DR': Data_Result,
60
+ '-DC': Data_Calibration,
61
+ '-DP': Data_Progress,
62
+ '-DS': Data_Static
63
+ }
64
+ cat = mapping.get(category_key) or Category
65
+
66
+ # implicit segment keys
67
+ model_dict = {v.alias: None for k, v in cat.model_fields.items() if v.alias and k not in ['key','additional_segments']}
68
+ for k, seg in zip(model_dict.keys(), segments.copy()):
69
+ if seg.key:
70
+ break
71
+ model_dict[k] = seg.value
72
+ segments.pop(0)
73
+
74
+ # try to fill model keys if not already set
75
+ for s in segments:
76
+ if s.key in model_dict and not model_dict.get(s.key):
77
+ model_dict[s.key] = s.value
78
+ segments.remove(s)
79
+
80
+ model_dict['additional_segments'] = segments
81
+ model_dict['key'] = category_key
82
+ return cat(**model_dict)
83
+
84
+ @staticmethod
85
+ def _split_into_categories(segments:list[IDSegment]):
86
+ categories = list()
87
+ c_segments = list()
88
+ categories.append(c_segments)
89
+ for s in segments:
90
+ # new category starts with "-"
91
+ if s.value[0] == '-':
92
+ cat_key = s.value
93
+ c = [s]
94
+ categories.append(c)
95
+ else:
96
+ c.append(s)
97
+
98
+ # first cat can be empty > remove
99
+ categories = [c for c in categories if len(c) > 0]
100
+
101
+ return categories
102
+
103
+
104
+ # @computed_field
105
+ # @property
106
+ # def categories(self) -> list[Category]:
107
+ # categories = list()
108
+ # c = Category(segments=[])
109
+ # categories.append(c)
110
+ # for s in self.identifier:
111
+ # s:IDSegment = s
112
+ # # new category starts with "-"
113
+ # if s.value[0] == '-':
114
+ # cat_key = s.value
115
+ # c = Category(key=cat_key, segments=[])
116
+ # categories.append(c)
117
+ # else:
118
+ # c.segments.append(s)
119
+
120
+ # # the first category might have no segments. remove categories without segments
121
+ # if not categories[0].segments:
122
+ # categories = categories[1:]
123
+
124
+ # return categories
125
+
126
+ @model_validator(mode='after')
127
+ def check_keys_are_unique_in_each_category(self) -> Self:
128
+ for c in self.categories:
129
+ keys = [s.key for s in c.segments if s.key]
130
+ duplicate_keys = [k for k in set(keys) if keys.count(k) > 1]
131
+ if duplicate_keys:
132
+ for k in duplicate_keys:
133
+ self.add_validation_message(
134
+ source=f"identifier {k}",
135
+ type="Error",
136
+ msg=f"Duplicate key {k} in category {c.key}",
137
+ highlight_pattern = k
138
+ )
139
+ return self
140
+
141
+
142
+ # @classmethod
143
+ # def from_categories(cls, issuer:str, categories:list[Category]):
144
+ # return PAC_CAT(issuer=issuer, identifier=cls.identifier_from_categories(categories))
145
+
146
+
147
+ # @classmethod
148
+ # def identifier_from_categories(cls, categories:list[Category]) :
149
+ # segments = list()
150
+ # for c in categories:
151
+ # if c.key:
152
+ # segments.append(IDSegment(value=c.key))
153
+ # segments.extend(c.segments)
154
+ # return segments
13
155
 
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'''
156
+
157
+
158
+
159
+
160
+ class Category(BaseModelWithValidationMessages):
161
+ model_config = {
162
+ "populate_by_name": True
163
+ }
164
+ key:str
165
+ additional_segments: list[IDSegment] = Field(default_factory=list)
166
+
167
+ @computed_field
168
+ @property
169
+ def segments(self, use_short_notation=False) -> list[IDSegment]:
19
170
  segments = []
20
171
  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
172
  for field_name, field_info in self.model_fields.items():
22
- if field_name in ['category_key', 'additional_segments']:
173
+ if field_name in ['key', 'additional_segments']:
23
174
  continue
24
175
  if value := getattr(self, field_name):
25
176
  if can_omit_keys:
@@ -31,79 +182,188 @@ class CATBase(BaseModel, ABC):
31
182
  can_omit_keys = False
32
183
  if self.additional_segments:
33
184
  segments.extend(self.additional_segments)
34
- return Category(key=self.category_key,
35
- segments=segments)
185
+
186
+ return segments
187
+
188
+
189
+ @model_validator(mode='after')
190
+ def warn_unusual_category_key(self):
191
+ ''' this base class is instantiated only if the key is not a known category key'''
192
+ self.add_validation_message(
193
+ source=f"Category {self.key}",
194
+ type="Warning",
195
+ msg=f'Category key {self.key} is not a well known key. It is recommended to use well known keys only',
196
+ highlight_pattern = f"{self.key}"
197
+ )
198
+ return self
199
+
200
+
201
+ # def to_identifier_category(self, use_short_notation=False):
202
+ # '''Creates a Category with the correct segments.
203
+ # Segments are in order of the Pydantic model fields.
204
+ # Segment keys are omitted as long as the recommendation is followed.
205
+ # Additional segments are added at the end'''
206
+ # segments = []
207
+ # 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
208
+ # for field_name, field_info in self.model_fields.items():
209
+ # if field_name in ['category_key', 'additional_segments']:
210
+ # continue
211
+ # if value := getattr(self, field_name):
212
+ # if can_omit_keys:
213
+ # key = None
214
+ # else:
215
+ # key = field_info.alias
216
+ # segments.append(IDSegment(key= key, value= value) )
217
+ # else:
218
+ # can_omit_keys = False
219
+ # if self.additional_segments:
220
+ # segments.extend(self.additional_segments)
221
+ # return Category(key=self.key,
222
+ # segments=segments)
223
+
224
+
225
+
226
+ # def _apply_category_defaults(self, segments_in: list[IDSegment]):
227
+
228
+ # category_conventions = MappingProxyType(
229
+ # {
230
+ # '-MD': ['240', '21'],
231
+ # '-MS': ['240', '10', '20', '21', '250'],
232
+ # '-MC': ['240', '10', '20', '21', '250'],
233
+ # '-MM': ['240', '10', '20', '21', '250']
234
+ # }
235
+ # )
236
+
237
+ # segments = segments_in.copy()
238
+ # default_keys = None
239
+ # for s in segments:
240
+ # if not s.key and default_keys:
241
+ # s.key = default_keys.pop(0)
242
+ # else:
243
+ # default_keys = None
244
+
245
+ # # category starts: start with new defaults.
246
+ # if s.value in category_conventions.keys():
247
+ # default_keys = category_conventions.get(s.value).copy() #copy, so the entries can be popped when used
248
+ # return segments
36
249
 
37
250
 
38
251
 
39
252
 
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)
253
+ class Material_Device(Category):
254
+ key: str = Field(default='-MD', frozen=True)
255
+ model_number: str|None = Field( alias='240')
256
+ serial_number: str|None = Field( alias='21')
257
+
258
+ @model_validator(mode='after')
259
+ def validate_mandatory_fields(self):
260
+ if not self.model_number:
261
+ self.add_validation_message(
262
+ source=f"Category {self.key}",
263
+ type="Error",
264
+ msg=f'Category key {self.key} is missing mandatory field Model NUmber',
265
+ highlight_pattern = f"{self.key}"
266
+ )
267
+ if not self.serial_number:
268
+ self.add_validation_message(
269
+ source=f"Category {self.key}",
270
+ type="Error",
271
+ msg=f'Category key {self.key} is missing mandatory field Serial NUmber',
272
+ highlight_pattern = f"{self.key}"
273
+ )
44
274
 
45
- class Material_Substance(CATBase):
46
- category_key: str = Field(default='-MS', frozen=True)
47
- product_number:str = Field( alias='240', min_length=1)
275
+ class Material_Substance(Category):
276
+ key: str = Field(default='-MS', frozen=True)
277
+ product_number:str|None = Field( alias='240')
48
278
  batch_number:str|None = Field(default=None, alias='10')
49
279
  container_size:str|None = Field(default=None, alias='20')
50
280
  container_number:str|None = Field(default=None, alias='21')
51
281
  aliquot:str|None = Field(default=None, alias='250')
52
282
 
53
- class Material_Consumable(CATBase):
54
- category_key: str = Field(default='-MC', frozen=True)
55
- product_number:str = Field( alias='240', min_length=1)
283
+ @model_validator(mode='after')
284
+ def validate_mandatory_fields(self):
285
+ if not self.product_number:
286
+ self.add_validation_message(
287
+ source=f"Category {self.key}",
288
+ type="Error",
289
+ msg=f'Category key {self.key} is missing mandatory field Product NUmber',
290
+ highlight_pattern = f"{self.key}"
291
+ )
292
+
293
+ class Material_Consumable(Category):
294
+ key: str = Field(default='-MC', frozen=True)
295
+ product_number:str|None = Field( alias='240')
56
296
  batch_number:str|None = Field(default=None, alias='10')
57
297
  packing_size:str|None = Field(default=None, alias='20')
58
298
  serial_number:str|None = Field(default=None, alias='21')
59
299
  aliquot:str|None = Field(default=None, alias='250')
60
300
 
301
+ @model_validator(mode='after')
302
+ def validate_mandatory_fields(self):
303
+ if not self.product_number:
304
+ self.add_validation_message(
305
+ source=f"Category {self.key}",
306
+ type="Error",
307
+ msg=f"Category key {self.key} is missing mandatory field 'Product Number'",
308
+ highlight_pattern = f"{self.key}"
309
+ )
310
+
61
311
  class Material_Misc(Material_Consumable):
62
- category_key: str = Field(default='-MM', frozen=True)
312
+ key: str = Field(default='-MM', frozen=True)
313
+
314
+
63
315
 
64
316
 
317
+ class Data_Abstract(Category, ABC):
318
+ key: str
319
+ id:str|None = Field( alias='21')
320
+
321
+ @model_validator(mode='after')
322
+ def validate_mandatory_fields(self):
323
+ if not self.id:
324
+ self.add_validation_message(
325
+ source=f"Category {self.key}",
326
+ type="Error",
327
+ msg=f"Category key {self.key} is missing mandatory field 'ID'",
328
+ highlight_pattern = f"{self.key}"
329
+ )
65
330
 
66
- class Data_Result(CATBase):
67
- category_key: str = Field(default='-DR', frozen=True)
68
- id:str = Field( alias='21', min_length=1)
331
+ class Data_Result(Category):
332
+ key: str = Field(default='-DR', frozen=True)
69
333
 
70
- class Data_Method(CATBase):
71
- category_key: str = Field(default='-DM', frozen=True)
72
- id:str = Field( alias='21', min_length=1)
334
+ class Data_Method(Category):
335
+ key: str = Field(default='-DM', frozen=True)
73
336
 
74
- class Data_Calibration(CATBase):
75
- category_key: str = Field(default='-DC', frozen=True)
76
- id:str = Field( alias='21', min_length=1)
337
+ class Data_Calibration(Category):
338
+ key: str = Field(default='-DC', frozen=True)
77
339
 
78
- class Data_Progress(CATBase):
79
- category_key: str = Field(default='-DP', frozen=True)
80
- id:str = Field( alias='21', min_length=1)
340
+ class Data_Progress(Category):
341
+ key: str = Field(default='-DP', frozen=True)
81
342
 
82
- class Data_Static(CATBase):
83
- category_key: str = Field(default='-DS', frozen=True)
84
- id:str = Field( alias='21', min_length=1)
343
+ class Data_Static(Category):
344
+ key: str = Field(default='-DS', frozen=True)
85
345
 
86
346
 
87
347
 
88
348
 
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
- }
349
+ # mapping = {
350
+ # '-MD': Material_Device,
351
+ # '-MS': Material_Substance,
352
+ # '-MC': Material_Consumable,
353
+ # '-MM': Material_Misc,
354
+ # '-DM': Data_Method,
355
+ # '-DR': Data_Result,
356
+ # '-DC': Data_Calibration,
357
+ # '-DP': Data_Progress,
358
+ # '-DS': Data_Static
359
+ # }
100
360
 
101
- def CAT_from_category(category:Category) -> CATBase|None:
102
- raise NotImplementedError()
361
+ # def CAT_from_category(category:Category) -> Category|None:
362
+ # raise NotImplementedError()
103
363
 
104
- def CAT_from_category_key(category_key) -> CATBase|None:
105
- return mapping.get(category_key)
364
+ # def CAT_from_category_key(category_key) -> Category|None:
365
+ # return mapping.get(category_key)
106
366
 
107
367
 
108
- if __name__ == "__main__":
109
- pass
368
+ # if __name__ == "__main__":
369
+ # pass