Skip to content

Commit f36d3a0

Browse files
committed
Added base classes for object types, vocabulary types, collection types, and property types
Moved definitions to datamodel
1 parent 742bda6 commit f36d3a0

File tree

8 files changed

+607
-178
lines changed

8 files changed

+607
-178
lines changed

bam_data_store/datamodel/__init__.py

Whitespace-only changes.
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
import re
2+
from enum import Enum
3+
from typing import Any, Optional
4+
5+
from pydantic import BaseModel, Field, field_validator, model_validator
6+
7+
8+
class DataType(str, Enum):
9+
BOOLEAN = 'BOOLEAN'
10+
CONTROLLEDVOCABULARY = 'CONTROLLEDVOCABULARY'
11+
DATE = 'DATE'
12+
HYPERLINK = 'HYPERLINK'
13+
INTEGER = 'INTEGER'
14+
MATERIAL = 'MATERIAL'
15+
MULTILINE_VARCHAR = 'MULTILINE_VARCHAR'
16+
OBJECT = 'OBJECT'
17+
REAL = 'REAL'
18+
TIMESTAMP = 'TIMESTAMP'
19+
VARCHAR = 'VARCHAR'
20+
XML = 'XML'
21+
22+
23+
class EntityDef(BaseModel):
24+
"""
25+
Abstract base class for all masterdata entity definitions. The entity definitions are immutable properties.
26+
This class provides a common interface (with common attributes like `version`, `code` and
27+
`description`.) for all entity definitions.
28+
"""
29+
30+
version: int = Field(
31+
...,
32+
description="""
33+
Version of the entity definition. This is an integer that is incremented each time the
34+
definition is changed.
35+
""",
36+
) # ? is this useful?
37+
38+
code: str = Field(
39+
...,
40+
description="""
41+
Code string identifying the entity with an openBIS inventory definition. Must be
42+
uppercase and separated by underscores, e.g. `'EXPERIMENTAL_STEP'`.
43+
""",
44+
)
45+
46+
description: str = Field(
47+
...,
48+
description="""
49+
Description of the entity. This is the human-readable text for the object and must be
50+
as complete and concise as possible. The German description can be added after the English
51+
description separated by a double slash (//), e.g. `'Chemical Substance//Chemische Substanz'`.
52+
""",
53+
)
54+
55+
# TODO check ontology_id, ontology_version, ontology_annotation_id, internal (found in the openBIS docu)
56+
57+
@field_validator('code')
58+
@classmethod
59+
def validate_code(cls, value: str) -> str:
60+
if not value or not re.match(r'^[A-Z_]+$', value):
61+
raise ValueError('`code` must be uppercase and separated by underscores')
62+
return value
63+
64+
65+
class BaseObjectTypeDef(EntityDef):
66+
"""
67+
Definition class used for the common fields for `CollectionTypeDef`, `ObjectTypeDef`, and `DataSetType`.
68+
It adds the fields of `validation_script`.
69+
"""
70+
71+
validation_script: Optional[str] = Field(
72+
default=None,
73+
description="""
74+
Script written in Jython used to validate the object type.
75+
""",
76+
) # ? is this truly used?
77+
78+
79+
class CollectionTypeDef(BaseObjectTypeDef):
80+
"""
81+
Definition class for a collection type. E.g.:
82+
83+
```python
84+
class DefaultExperiment(BaseModel):
85+
defs = CollectionTypeDef(
86+
version=1,
87+
code='DEFAULT_EXPERIMENT',
88+
description='',
89+
validation_script='DEFAULT_EXPERIMENT.date_range_validation',
90+
)
91+
```
92+
"""
93+
94+
pass
95+
96+
97+
class DataSetTypeDef(BaseObjectTypeDef):
98+
"""
99+
Definition class for a data set type. E.g.:
100+
101+
```python
102+
class RawData(BaseModel):
103+
defs = DataSetTypeDef(
104+
version=1,
105+
code='RAW_DATA',
106+
description='',
107+
)
108+
"""
109+
110+
# TODO check descriptions
111+
112+
main_dataset_pattern: Optional[str] = Field(
113+
default=None,
114+
description="""""",
115+
)
116+
117+
main_dataset_path: Optional[str] = Field(
118+
default=None,
119+
description="""""",
120+
)
121+
122+
123+
class ObjectTypeDef(BaseObjectTypeDef):
124+
"""
125+
Definition class for an object type. It adds the fields of `generated_code_prefix`, `auto_generated_codes`,
126+
and `validation_script` to the common attributes of an entity definition. E.g.:
127+
128+
```python
129+
class Instrument(BaseModel):
130+
defs = ObjectTypeDef(
131+
version=1,
132+
code='INSTRUMENT',
133+
description='
134+
Measuring Instrument//Messger\u00e4t
135+
',
136+
generated_code_prefix='INS',
137+
)
138+
```
139+
"""
140+
141+
generated_code_prefix: Optional[str] = Field(
142+
default=None,
143+
description="""
144+
A short prefix for the defined object type, e.g. 'CHEM'. If not specified, it is defined
145+
using the first 3 characters of `code`.
146+
""",
147+
)
148+
149+
auto_generated_codes: bool = Field(
150+
True,
151+
description="""
152+
Boolean used to generate codes using `generated_code_prefix` and a unique number. Set to
153+
True by default.
154+
""",
155+
)
156+
157+
@model_validator(mode='after')
158+
@classmethod
159+
def model_validator_after_init(cls, data: Any) -> Any:
160+
"""
161+
Validate the model after instantiation of the class.
162+
163+
Args:
164+
data (Any): The data containing the fields values to validate.
165+
166+
Returns:
167+
Any: The data with the validated fields.
168+
"""
169+
if not data.generated_code_prefix:
170+
data.generated_code_prefix = data.code[:3]
171+
return data
172+
173+
174+
class PropertyTypeDef(EntityDef):
175+
"""
176+
Definition class for a property type. It adds the fields of `property_label`, `data_type`,
177+
`vocabulary_code`, `metadata`, `dynamic_script`, and `multivalued` to the common attributes of
178+
an entity definition. E.g.:
179+
180+
```python
181+
class Alias(PropertyTypeDef):
182+
defs = PropertyTypeDef(
183+
version=1,
184+
code='ALIAS',
185+
description='
186+
e.g. abbreviation or nickname//z.B. Abkürzung oder Spitzname//z.B. Abkürzung oder Spitzname
187+
',
188+
data_type='VARCHAR',
189+
property_label='Alternative name',
190+
)
191+
```
192+
"""
193+
194+
property_label: str = Field(
195+
...,
196+
description="""
197+
Label that appears in the inventory view. This is the human-readable text for the property
198+
type definition, and it typically coincides with the `code`, e.g., `'Monitoring date'` for the
199+
`MONITORING_DATE` property type.
200+
""",
201+
)
202+
203+
data_type: DataType = Field(
204+
...,
205+
description="""
206+
The data type of the property, i.e., if it is an integer, float, string, etc. The allowed
207+
data types in openBIS are:
208+
- `BOOLEAN`
209+
- `CONTROLLEDVOCABULARY`
210+
- `DATE`
211+
- `HYPERLINK`
212+
- `INTEGER`
213+
- `MATERIAL`
214+
- `MULTILINE_VARCHAR`
215+
- `OBJECT`
216+
- `REAL`
217+
- `TIMESTAMP`
218+
- `VARCHAR`
219+
- `XML`
220+
221+
These are defined as an enumeration in the `DataType` class.
222+
223+
Read more in https://openbis.readthedocs.io/en/latest/uncategorized/register-master-data-via-the-admin-interface.html#data-types-available-in-openbis.
224+
""",
225+
)
226+
227+
vocabulary_code: Optional[str] = Field(
228+
default=None,
229+
description="""
230+
String identifying the controlled vocabulary used for the data type of the property. This is
231+
thus only relevant if `data_type == 'CONTROLLEDVOCABULARY'`.
232+
""",
233+
)
234+
235+
metadata: Optional[dict] = Field(
236+
default=None,
237+
description="""""",
238+
)
239+
240+
dynamic_script: Optional[str] = Field(
241+
default=None,
242+
description="""""",
243+
)
244+
245+
multivalued: Optional[str] = Field(
246+
default=None,
247+
description="""""",
248+
)
249+
250+
251+
class PropertyTypeAssignment(PropertyTypeDef):
252+
"""
253+
aaa
254+
"""
255+
256+
mandatory: bool = Field(
257+
...,
258+
description="""
259+
If `True`, the property is mandatory and has to be set during instantiation of the object type.
260+
If `False`, the property is optional.
261+
""",
262+
)
263+
264+
show_in_edit_views: bool = Field(
265+
...,
266+
description="""
267+
If `True`, the property is shown in the edit views of the ELN in the object type instantiation.
268+
If `False`, the property is hidden.
269+
""",
270+
)
271+
272+
section: str = Field(
273+
...,
274+
description="""
275+
Section to which the property type belongs to. E.g., `'General Information'`.
276+
""",
277+
)
278+
279+
unique: Optional[str] = Field(
280+
default=None,
281+
description="""""",
282+
)
283+
284+
internal_assignment: Optional[str] = Field(
285+
default=None,
286+
description="""""",
287+
)
288+
289+
290+
class VocabularyTypeDef(EntityDef):
291+
"""
292+
Definition class for a vocabulary type. E.g.:
293+
"""
294+
295+
url_template: Optional[str] = Field(
296+
default=None,
297+
description="""""",
298+
)
299+
300+
301+
class VocabularyTerm(VocabularyTypeDef):
302+
"""
303+
aaa
304+
"""
305+
306+
label: str = Field(
307+
...,
308+
description="""""",
309+
)
310+
311+
official: bool = Field(
312+
True,
313+
description="""""",
314+
)

0 commit comments

Comments
 (0)