logs-py 2.9.6__py3-none-any.whl → 3.0.1__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 logs-py might be problematic. Click here for more details.
- LOGS/Auxiliary/DateTimeConverter.py +11 -1
- LOGS/Auxiliary/Exceptions.py +40 -4
- LOGS/Auxiliary/LOGSErrorResponse.py +4 -1
- LOGS/Auxiliary/MinimalModelGenerator.py +88 -28
- LOGS/Auxiliary/Tools.py +11 -0
- LOGS/Converter/Conversion.py +248 -0
- LOGS/Converter/Converter.py +96 -0
- LOGS/Converter/ConverterParameter.py +88 -0
- LOGS/Converter/ExportParamters.py +89 -0
- LOGS/Converter/__init__.py +13 -0
- LOGS/Entities/Bridge.py +6 -3
- LOGS/Entities/CustomField.py +96 -91
- LOGS/Entities/CustomFieldModels.py +57 -0
- LOGS/Entities/CustomFieldRelations.py +10 -0
- LOGS/Entities/CustomFieldRequestParameter.py +43 -15
- LOGS/Entities/CustomFieldValue.py +88 -0
- LOGS/Entities/CustomFieldValueConverter.py +66 -0
- LOGS/Entities/CustomType.py +187 -0
- LOGS/Entities/CustomTypeEntityType.py +11 -0
- LOGS/Entities/CustomTypeMinimal.py +8 -0
- LOGS/Entities/CustomTypeRelations.py +59 -0
- LOGS/Entities/CustomTypeRequestParameter.py +61 -0
- LOGS/Entities/CustomTypeSection.py +39 -0
- LOGS/Entities/CustomTypes.py +12 -0
- LOGS/Entities/DataSource.py +28 -14
- LOGS/Entities/Dataset.py +274 -136
- LOGS/Entities/DatasetCreator.py +23 -72
- LOGS/Entities/DatasetInfo.py +23 -2
- LOGS/Entities/DatasetModels.py +31 -0
- LOGS/Entities/DatasetRequestParameter.py +45 -32
- LOGS/Entities/Datatrack.py +74 -30
- LOGS/Entities/DatatrackFormattedTable.py +25 -0
- LOGS/Entities/DatatrackGeneric.py +34 -0
- LOGS/Entities/DatatrackImage.py +25 -0
- LOGS/Entities/DatatrackNumericArray.py +9 -39
- LOGS/Entities/DatatrackNumericMatrix.py +86 -0
- LOGS/Entities/DocumentRequestParameter.py +2 -2
- LOGS/Entities/EntitiesRequestParameter.py +2 -2
- LOGS/Entities/Experiment.py +3 -3
- LOGS/Entities/FileExcludePattern.py +8 -0
- LOGS/Entities/FormatFormat.py +22 -1
- LOGS/Entities/FormatFormatRequestParameter.py +2 -1
- LOGS/Entities/FormatFormats.py +1 -1
- LOGS/Entities/FormattedTable/DatatypeFormattedTable.py +135 -0
- LOGS/Entities/FormattedTable/DatatypeFormattedTableCell.py +108 -0
- LOGS/Entities/FormattedTable/DatatypeFormattedTableSettings.py +11 -0
- LOGS/Entities/FormattedTable/__init__.py +9 -0
- LOGS/Entities/ILiterarTypedEntity.py +19 -0
- LOGS/Entities/Instrument.py +3 -3
- LOGS/Entities/Inventories.py +12 -0
- LOGS/Entities/Inventory.py +95 -0
- LOGS/Entities/InventoryMinimal.py +20 -0
- LOGS/Entities/InventoryRelations.py +23 -0
- LOGS/Entities/InventoryRequestParameter.py +53 -0
- LOGS/Entities/LabNotebook.py +37 -0
- LOGS/Entities/LabNotebookEntry.py +47 -24
- LOGS/Entities/LabNotebookEntryContent/BasicAttribute.py +15 -0
- LOGS/Entities/LabNotebookEntryContent/EntityAttribute.py +85 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentBlockquote.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentBulletList.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentCallout.py +40 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentContentPlaceholderNode.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentConverter.py +207 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentDocument.py +8 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentEntity.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentEntityMention.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentHeading.py +33 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentHorizontalRule.py +12 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentItem.py +37 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentListItem.py +49 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentOrderedList.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentParagraph.py +13 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTable.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTableCell.py +40 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTableRow.py +8 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTaskList.py +17 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentTaskListItem.py +31 -0
- LOGS/Entities/LabNotebookEntryContent/EntryContentText.py +33 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithAttribute.py +23 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithContent.py +38 -0
- LOGS/Entities/LabNotebookEntryContent/IEntryContentWithTextAttribute.py +16 -0
- LOGS/Entities/LabNotebookEntryContent/TextAttribute.py +46 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarkAtributes.py +64 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarkConverter.py +45 -0
- LOGS/Entities/LabNotebookEntryContent/TextMarks.py +71 -0
- LOGS/Entities/LabNotebookEntryContent/__init__.py +34 -0
- LOGS/Entities/LabNotebookEntryRequestParameter.py +2 -0
- LOGS/Entities/LabNotebookExperiment.py +52 -0
- LOGS/Entities/LabNotebookExperimentMinimal.py +8 -0
- LOGS/Entities/LabNotebookExperimentRequestParameter.py +49 -0
- LOGS/Entities/LabNotebookExperiments.py +16 -0
- LOGS/Entities/LabNotebookMinimal.py +19 -0
- LOGS/Entities/LabNotebookModels.py +14 -0
- LOGS/Entities/LabNotebookRequestParameter.py +43 -0
- LOGS/Entities/LabNotebooks.py +12 -0
- LOGS/Entities/Method.py +3 -3
- LOGS/Entities/ParserLog.py +4 -0
- LOGS/Entities/Person.py +2 -2
- LOGS/Entities/PersonRequestParameter.py +1 -0
- LOGS/Entities/Project.py +7 -7
- LOGS/Entities/{ProjectUserPermission.py → ProjectPersonPermission.py} +14 -4
- LOGS/Entities/Role.py +3 -3
- LOGS/Entities/RunState.py +1 -0
- LOGS/Entities/Sample.py +36 -57
- LOGS/Entities/SampleRequestParameter.py +30 -15
- LOGS/Entities/Track.py +8 -4
- LOGS/Entities/TrackData.py +11 -0
- LOGS/Entities/TrackImage.py +21 -0
- LOGS/Entities/TrackImageData.py +20 -0
- LOGS/Entities/TrackMatrix.py +28 -0
- LOGS/Entities/TrackMatrixData.py +22 -0
- LOGS/Entities/TrackTable.py +21 -0
- LOGS/Entities/TrackTableData.py +22 -0
- LOGS/Entities/TrackXY.py +5 -1
- LOGS/Entities/TrackXYComplex.py +1 -1
- LOGS/Entities/__init__.py +26 -7
- LOGS/Entity/ConnectedEntity.py +39 -1
- LOGS/Entity/Entity.py +9 -14
- LOGS/Entity/SerializeableContent.py +62 -5
- LOGS/Interfaces/IHierarchyType.py +63 -0
- LOGS/Interfaces/IPermissionedEntity.py +29 -5
- LOGS/Interfaces/IProjectBased.py +1 -1
- LOGS/Interfaces/ITypedEntity.py +69 -12
- LOGS/Interfaces/IVersionedEntity.py +39 -0
- LOGS/LOGS.py +137 -46
- LOGS/LOGSConnection.py +52 -24
- LOGS/LOGSOptions.py +8 -0
- LOGS/Parameters/Color.py +92 -0
- LOGS/Parameters/ParameterBase.py +55 -0
- LOGS/Parameters/ParameterConverter.py +24 -0
- LOGS/Parameters/ParameterElement.py +99 -0
- LOGS/Parameters/ParameterList.py +52 -0
- LOGS/Parameters/ParameterTable.py +64 -0
- LOGS/Parameters/__init__.py +13 -0
- LOGS/__init__.py +1 -0
- {logs_py-2.9.6.dist-info → logs_py-3.0.1.dist-info}/METADATA +2 -1
- logs_py-3.0.1.dist-info/RECORD +263 -0
- LOGS/Entities/CustomFieldEnums.py +0 -25
- LOGS/Entities/DatasetType.py +0 -7
- LOGS/Entities/DatasetTypeMinimal.py +0 -8
- LOGS/Entities/SampleType.py +0 -34
- LOGS/Entities/SampleTypeMinimal.py +0 -8
- LOGS/Entities/SampleTypeRequestParameter.py +0 -8
- LOGS/Entities/SampleTypes.py +0 -12
- logs_py-2.9.6.dist-info/RECORD +0 -183
- {logs_py-2.9.6.dist-info → logs_py-3.0.1.dist-info}/WHEEL +0 -0
- {logs_py-2.9.6.dist-info → logs_py-3.0.1.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
2
|
import re
|
|
3
|
+
import time
|
|
3
4
|
from typing import List, cast
|
|
4
5
|
|
|
6
|
+
import pytz
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
class DateTimeConverter:
|
|
7
10
|
# When adding pattern here put the pattern with most information on top
|
|
@@ -22,5 +25,12 @@ class DateTimeConverter:
|
|
|
22
25
|
dates.append(dt.datetime.strptime(entry, pattern))
|
|
23
26
|
except:
|
|
24
27
|
continue
|
|
28
|
+
if len(dates) < 1:
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
d = dates[0]
|
|
32
|
+
if d.tzinfo == pytz.UTC or d.tzinfo is None:
|
|
33
|
+
local_tz = pytz.timezone(time.tzname[0]) # Change to your local timezone
|
|
34
|
+
d = d.replace(tzinfo=pytz.utc).astimezone(local_tz)
|
|
25
35
|
|
|
26
|
-
return
|
|
36
|
+
return d
|
LOGS/Auxiliary/Exceptions.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, List, Optional, TypeVar, Union, cast
|
|
1
|
+
from typing import TYPE_CHECKING, Any, List, Optional, TypeVar, Union, cast
|
|
2
2
|
|
|
3
3
|
from LOGS.Auxiliary.Constants import Constants
|
|
4
4
|
from LOGS.Auxiliary.LOGSErrorResponse import LOGSErrorResponse
|
|
5
5
|
from LOGS.Auxiliary.Tools import Tools
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
|
+
from LOGS.Converter.Conversion import Conversion
|
|
8
9
|
from LOGS.Entity.ConnectedEntity import ConnectedEntity
|
|
9
10
|
from LOGS.Entity.Entity import Entity
|
|
10
11
|
|
|
@@ -46,7 +47,7 @@ class LOGSException(Exception):
|
|
|
46
47
|
|
|
47
48
|
def _fromResponse(self, response: LOGSErrorResponse):
|
|
48
49
|
self.title = response.title
|
|
49
|
-
self.details = response.
|
|
50
|
+
self.details = response.description
|
|
50
51
|
self.status = response.status
|
|
51
52
|
self.type = response.type
|
|
52
53
|
|
|
@@ -105,6 +106,7 @@ class EntityIncompleteException(LOGSException):
|
|
|
105
106
|
parameterName: Optional[str] = None,
|
|
106
107
|
functionName: Optional[str] = None,
|
|
107
108
|
responseError: Optional[LOGSErrorResponse] = None,
|
|
109
|
+
hasFetchFull: bool = True,
|
|
108
110
|
):
|
|
109
111
|
if not errors and responseError:
|
|
110
112
|
errors = responseError.errors
|
|
@@ -115,6 +117,7 @@ class EntityIncompleteException(LOGSException):
|
|
|
115
117
|
errors=errors,
|
|
116
118
|
functionName=functionName,
|
|
117
119
|
parameterName=parameterName,
|
|
120
|
+
hasFetchFull=hasFetchFull,
|
|
118
121
|
),
|
|
119
122
|
responseError=responseError,
|
|
120
123
|
)
|
|
@@ -125,14 +128,20 @@ class EntityIncompleteException(LOGSException):
|
|
|
125
128
|
errors: Optional[List[str]] = None,
|
|
126
129
|
parameterName: Optional[str] = None,
|
|
127
130
|
functionName: Optional[str] = None,
|
|
131
|
+
hasFetchFull: bool = True,
|
|
128
132
|
):
|
|
129
133
|
indent = " " * 2
|
|
130
134
|
message = ""
|
|
131
135
|
|
|
132
136
|
name = f" '{parameterName}' " if parameterName else " "
|
|
133
|
-
func =
|
|
137
|
+
func = []
|
|
138
|
+
if functionName:
|
|
139
|
+
func.append(f"'{functionName}'")
|
|
134
140
|
|
|
135
|
-
|
|
141
|
+
if hasFetchFull:
|
|
142
|
+
func.append(f"'fetchFull()'")
|
|
143
|
+
|
|
144
|
+
message = f"Additional field{name}of entity {entity.identifier} was not fetched for efficiency reasons. Use {' or '.join(func)} method to fetch this parameter"
|
|
136
145
|
|
|
137
146
|
indent *= 2
|
|
138
147
|
if errors:
|
|
@@ -297,3 +306,30 @@ class EntityNotConnectedException(NotConnectedException):
|
|
|
297
306
|
super().__init__("Entity %a is not connected." % (identifier))
|
|
298
307
|
else:
|
|
299
308
|
super().__init__("Entity is not connected.")
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class IllegalFieldValueException(LOGSException):
|
|
312
|
+
|
|
313
|
+
def __init__(
|
|
314
|
+
self,
|
|
315
|
+
entityType: Any,
|
|
316
|
+
fieldName: str,
|
|
317
|
+
value: Any,
|
|
318
|
+
errorMessage: Optional[str] = None,
|
|
319
|
+
):
|
|
320
|
+
if isinstance(entityType, object):
|
|
321
|
+
t = type(entityType).__name__
|
|
322
|
+
elif isinstance(entityType, type) and issubclass(entityType, Entity):
|
|
323
|
+
t = entityType.__name__
|
|
324
|
+
|
|
325
|
+
m = f"Illegal value for field '{t}.{fieldName} = {value}'"
|
|
326
|
+
if errorMessage:
|
|
327
|
+
m += ":" + errorMessage
|
|
328
|
+
super().__init__(m)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class UnfinishedConversionException(LOGSException):
|
|
332
|
+
def __init__(self, conversion: "Conversion"):
|
|
333
|
+
super().__init__(
|
|
334
|
+
f"Conversion for dataset {conversion.datasetId} from format '{conversion.datasetFormat}' to format '{conversion.exportFormat}' is not finished yet."
|
|
335
|
+
)
|
|
@@ -3,7 +3,7 @@ from typing import Any, List, Optional, cast
|
|
|
3
3
|
|
|
4
4
|
class LOGSErrorResponse:
|
|
5
5
|
title: Optional[str] = None
|
|
6
|
-
|
|
6
|
+
description: Optional[str] = None
|
|
7
7
|
status: Optional[int] = None
|
|
8
8
|
type: Optional[str] = None
|
|
9
9
|
|
|
@@ -27,6 +27,9 @@ class LOGSErrorResponse:
|
|
|
27
27
|
if "title" in ref:
|
|
28
28
|
errors.append(str(ref["title"]))
|
|
29
29
|
|
|
30
|
+
if "description" in ref:
|
|
31
|
+
errors.extend(str(ref["description"]).split("\n"))
|
|
32
|
+
|
|
30
33
|
if "error" in ref:
|
|
31
34
|
errors = [f"({str(ref['error'])})"]
|
|
32
35
|
|
|
@@ -11,40 +11,52 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
def _typeByTypename(fieldType):
|
|
13
13
|
switcher = {
|
|
14
|
-
"BridgeMinimal": BridgeMinimalFromDict,
|
|
15
14
|
"Bridge": BridgeMinimalFromDict,
|
|
16
|
-
"
|
|
15
|
+
"BridgeMinimal": BridgeMinimalFromDict,
|
|
16
|
+
"CustomType": CustomTypeMinimalFromDict,
|
|
17
|
+
"CustomTypeMinimal": CustomTypeMinimalFromDict,
|
|
17
18
|
"Dataset": DatasetMinimalFromDict,
|
|
18
|
-
"
|
|
19
|
+
"DatasetMinimal": DatasetMinimalFromDict,
|
|
19
20
|
"Equipment": EquipmentMinimalFromDict,
|
|
20
|
-
"
|
|
21
|
+
"EquipmentMinimal": EquipmentMinimalFromDict,
|
|
21
22
|
"Experiment": ExperimentMinimalFromDict,
|
|
22
|
-
"
|
|
23
|
+
"ExperimentMinimal": ExperimentMinimalFromDict,
|
|
24
|
+
"FormatFormat": FormatFormatMinimalFromDict,
|
|
25
|
+
"FormatFormatMinimal": FormatFormatMinimalFromDict,
|
|
26
|
+
"Format": FormatMinimalFromDict,
|
|
27
|
+
"FormatInstrument": FormatInstrumentMinimalFromDict,
|
|
28
|
+
"FormatInstrumentMinimal": FormatInstrumentMinimalFromDict,
|
|
29
|
+
"FormatMethod": FormatMethodMinimalFromDict,
|
|
30
|
+
"FormatMethodMinimal": FormatMethodMinimalFromDict,
|
|
31
|
+
"FormatMinimal": FormatMinimalFromDict,
|
|
32
|
+
"FormatVendor": FormatVendorMinimalFromDict,
|
|
33
|
+
"FormatVendorMinimal": FormatVendorMinimalFromDict,
|
|
34
|
+
"InstrumentFacility": InstrumentMinimalFromDict,
|
|
35
|
+
"InstrumentFacilityMinimal": InstrumentMinimalFromDict,
|
|
23
36
|
"Instrument": InstrumentMinimalFromDict,
|
|
24
|
-
"
|
|
37
|
+
"InstrumentMinimal": InstrumentMinimalFromDict,
|
|
38
|
+
"LabNotebook": LabNotebookMinimalFromDict,
|
|
39
|
+
"LabNotebookMinimal": LabNotebookMinimalFromDict,
|
|
40
|
+
"LabNotebookExperiment": LabNotebookExperimentMinimalFromDict,
|
|
41
|
+
"LabNotebookExperimentMinimal": LabNotebookExperimentMinimalFromDict,
|
|
42
|
+
"LabNotebookEntry": LabNotebookEntryMinimalFromDict,
|
|
43
|
+
"LabNotebookEntryMinimal": LabNotebookEntryMinimalFromDict,
|
|
25
44
|
"Method": MethodMinimalFromDict,
|
|
45
|
+
"MethodMinimal": MethodMinimalFromDict,
|
|
46
|
+
"OriginMinimal": OriginMinimalFromDict,
|
|
47
|
+
"Origin": OriginMinimalFromDict,
|
|
26
48
|
"PersonMinimal": PersonMinimalFromDict,
|
|
27
49
|
"Person": PersonMinimalFromDict,
|
|
28
50
|
"ProjectMinimal": ProjectMinimalFromDict,
|
|
29
51
|
"Project": ProjectMinimalFromDict,
|
|
30
52
|
"SampleMinimal": SampleMinimalFromDict,
|
|
31
53
|
"Sample": SampleMinimalFromDict,
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"Format": FormatMinimalFromDict,
|
|
39
|
-
"FormatMinimal": FormatMinimalFromDict,
|
|
40
|
-
"FormatVendor": FormatVendorMinimalFromDict,
|
|
41
|
-
"FormatVendorMinimal": FormatVendorMinimalFromDict,
|
|
42
|
-
"FormatMethod": FormatMethodMinimalFromDict,
|
|
43
|
-
"FormatMethodMinimal": FormatMethodMinimalFromDict,
|
|
44
|
-
"FormatInstrument": FormatInstrumentMinimalFromDict,
|
|
45
|
-
"FormatInstrumentMinimal": FormatInstrumentMinimalFromDict,
|
|
46
|
-
"FormatFormat": FormatFormatMinimalFromDict,
|
|
47
|
-
"FormatFormatMinimal": FormatFormatMinimalFromDict,
|
|
54
|
+
"InventoryMinimal": InventoryMinimalFromDict,
|
|
55
|
+
"Inventory": InventoryMinimalFromDict,
|
|
56
|
+
"CustomTypeMinimal": CustomTypeMinimalFromDict,
|
|
57
|
+
"CustomType": CustomTypeMinimalFromDict,
|
|
58
|
+
"CustomFieldMinimal": CustomFieldMinimalFromDict,
|
|
59
|
+
"CustomField": CustomFieldMinimalFromDict,
|
|
48
60
|
}
|
|
49
61
|
return switcher.get(fieldType, lambda ref: None)
|
|
50
62
|
|
|
@@ -157,6 +169,38 @@ def BridgeMinimalFromDict(
|
|
|
157
169
|
)
|
|
158
170
|
|
|
159
171
|
|
|
172
|
+
def CustomTypeMinimalFromDict(
|
|
173
|
+
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
174
|
+
fieldName: Optional[str] = None,
|
|
175
|
+
connection: Optional["LOGSConnection"] = None,
|
|
176
|
+
):
|
|
177
|
+
from LOGS.Entities.CustomTypeMinimal import CustomTypeMinimal
|
|
178
|
+
|
|
179
|
+
return _checkAndConvert(
|
|
180
|
+
ref,
|
|
181
|
+
CustomTypeMinimal,
|
|
182
|
+
fieldName=fieldName,
|
|
183
|
+
allowNone=True,
|
|
184
|
+
connection=connection,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def CustomFieldMinimalFromDict(
|
|
189
|
+
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
190
|
+
fieldName: Optional[str] = None,
|
|
191
|
+
connection: Optional["LOGSConnection"] = None,
|
|
192
|
+
):
|
|
193
|
+
from LOGS.Entities.CustomFieldMinimal import CustomFieldMinimal
|
|
194
|
+
|
|
195
|
+
return _checkAndConvert(
|
|
196
|
+
ref,
|
|
197
|
+
CustomFieldMinimal,
|
|
198
|
+
fieldName=fieldName,
|
|
199
|
+
allowNone=True,
|
|
200
|
+
connection=connection,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
160
204
|
def DatasetMinimalFromDict(
|
|
161
205
|
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
162
206
|
fieldName: Optional[str] = None,
|
|
@@ -265,32 +309,48 @@ def SampleMinimalFromDict(
|
|
|
265
309
|
)
|
|
266
310
|
|
|
267
311
|
|
|
268
|
-
def
|
|
312
|
+
def InventoryMinimalFromDict(
|
|
313
|
+
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
314
|
+
fieldName: Optional[str] = None,
|
|
315
|
+
connection: Optional["LOGSConnection"] = None,
|
|
316
|
+
):
|
|
317
|
+
from LOGS.Entities.InventoryMinimal import InventoryMinimal
|
|
318
|
+
|
|
319
|
+
return _checkAndConvert(
|
|
320
|
+
ref,
|
|
321
|
+
InventoryMinimal,
|
|
322
|
+
fieldName=fieldName,
|
|
323
|
+
allowNone=True,
|
|
324
|
+
connection=connection,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def LabNotebookMinimalFromDict(
|
|
269
329
|
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
270
330
|
fieldName: Optional[str] = None,
|
|
271
331
|
connection: Optional["LOGSConnection"] = None,
|
|
272
332
|
):
|
|
273
|
-
from LOGS.Entities.
|
|
333
|
+
from LOGS.Entities.LabNotebookMinimal import LabNotebookMinimal
|
|
274
334
|
|
|
275
335
|
return _checkAndConvert(
|
|
276
336
|
ref,
|
|
277
|
-
|
|
337
|
+
LabNotebookMinimal,
|
|
278
338
|
fieldName=fieldName,
|
|
279
339
|
allowNone=True,
|
|
280
340
|
connection=connection,
|
|
281
341
|
)
|
|
282
342
|
|
|
283
343
|
|
|
284
|
-
def
|
|
344
|
+
def LabNotebookExperimentMinimalFromDict(
|
|
285
345
|
ref: Optional[Union[dict, Constants.ID_TYPE]],
|
|
286
346
|
fieldName: Optional[str] = None,
|
|
287
347
|
connection: Optional["LOGSConnection"] = None,
|
|
288
348
|
):
|
|
289
|
-
from LOGS.Entities.
|
|
349
|
+
from LOGS.Entities.LabNotebookExperimentMinimal import LabNotebookExperimentMinimal
|
|
290
350
|
|
|
291
351
|
return _checkAndConvert(
|
|
292
352
|
ref,
|
|
293
|
-
|
|
353
|
+
LabNotebookExperimentMinimal,
|
|
294
354
|
fieldName=fieldName,
|
|
295
355
|
allowNone=True,
|
|
296
356
|
connection=connection,
|
LOGS/Auxiliary/Tools.py
CHANGED
|
@@ -51,6 +51,14 @@ class Tools:
|
|
|
51
51
|
messageStrMaxLength = 25
|
|
52
52
|
__byteUnits = ["", "K", "M", "G", "T", "P", "E", "Z"]
|
|
53
53
|
|
|
54
|
+
@classmethod
|
|
55
|
+
def ObjectToString(cls, obj: Any) -> str:
|
|
56
|
+
name = getattr(obj, "name") if hasattr(obj, "name") else None
|
|
57
|
+
id = getattr(obj, "id") if hasattr(obj, "id") else None
|
|
58
|
+
i = " id:'%s'" % id if id is not None else ""
|
|
59
|
+
n = " name:'%s'" % name if name is not None else ""
|
|
60
|
+
return "<%s%s%s>" % (type(obj).__name__, i, n)
|
|
61
|
+
|
|
54
62
|
@classmethod
|
|
55
63
|
def unbufferStdout(cls):
|
|
56
64
|
unbuffered = UnbufferedStdout()
|
|
@@ -181,6 +189,9 @@ class Tools:
|
|
|
181
189
|
return value
|
|
182
190
|
|
|
183
191
|
if issubclass(cast(Type[_T], fieldType), Enum):
|
|
192
|
+
if allowNone and value == None:
|
|
193
|
+
return cast(Any, None)
|
|
194
|
+
|
|
184
195
|
try:
|
|
185
196
|
enum = cast(Any, fieldType)
|
|
186
197
|
return enum(value)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from time import sleep, time
|
|
4
|
+
from typing import Any, Callable, Dict, List, Optional, cast
|
|
5
|
+
|
|
6
|
+
from LOGS.Auxiliary.Exceptions import (
|
|
7
|
+
EntityFetchingException,
|
|
8
|
+
LOGSException,
|
|
9
|
+
UnfinishedConversionException,
|
|
10
|
+
)
|
|
11
|
+
from LOGS.Auxiliary.Tools import Tools
|
|
12
|
+
from LOGS.Converter.ConverterParameter import ParameterType
|
|
13
|
+
from LOGS.Entities.ParserLog import ParserLog
|
|
14
|
+
from LOGS.Entity import Entity
|
|
15
|
+
from LOGS.Entity.ConnectedEntity import ConnectedEntity
|
|
16
|
+
from LOGS.Entity.SerializeableContent import SerializeableClass
|
|
17
|
+
from LOGS.LOGSConnection import ResponseTypes
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConversionState(Enum):
|
|
21
|
+
Successfull = "Successfull"
|
|
22
|
+
Failed = "Failed"
|
|
23
|
+
Waiting = "Waiting"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ConversionFile(SerializeableClass):
|
|
27
|
+
path: Optional[str] = None
|
|
28
|
+
size: Optional[int] = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DatasetConversionZipReadModel(SerializeableClass):
|
|
32
|
+
size: Optional[int] = None
|
|
33
|
+
id: Optional[str] = None
|
|
34
|
+
url: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ConverterParameterEntry(SerializeableClass):
|
|
38
|
+
id: Optional[str] = None
|
|
39
|
+
value: Optional[Any] = None
|
|
40
|
+
type: Optional[ParameterType] = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ConversionLogModel(ParserLog):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Conversion(ConnectedEntity):
|
|
48
|
+
_datasetId: Optional[int] = None
|
|
49
|
+
_datasetFormat: Optional[str] = None
|
|
50
|
+
_exportFormat: Optional[str] = None
|
|
51
|
+
_files: Optional[List[ConversionFile]] = None
|
|
52
|
+
_logs: Optional[List[ConversionLogModel]] = None
|
|
53
|
+
_output: Optional[str] = None
|
|
54
|
+
_state: Optional[ConversionState] = None
|
|
55
|
+
_zip: Optional[DatasetConversionZipReadModel] = None
|
|
56
|
+
_inputParameters: Optional[List[ConverterParameterEntry]] = None
|
|
57
|
+
|
|
58
|
+
_payload: Dict[str, Any] = {}
|
|
59
|
+
_parentEntity: Optional[Entity] = None
|
|
60
|
+
|
|
61
|
+
def download(
|
|
62
|
+
self,
|
|
63
|
+
directory: Optional[str] = None,
|
|
64
|
+
fileName: Optional[str] = None,
|
|
65
|
+
overwrite=False,
|
|
66
|
+
):
|
|
67
|
+
connection, _ = self._getConnectionData()
|
|
68
|
+
|
|
69
|
+
if self.state == ConversionState.Waiting:
|
|
70
|
+
raise UnfinishedConversionException(self)
|
|
71
|
+
|
|
72
|
+
if self.state == ConversionState.Failed:
|
|
73
|
+
raise LOGSException(
|
|
74
|
+
f"Conversion for dataset {self.datasetId} from format '{self.datasetFormat}' to format '{self.exportFormat}' failed. Check logs for more information."
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
self.zip is None
|
|
79
|
+
or self.zip.size is None
|
|
80
|
+
or self.zip.id is None
|
|
81
|
+
or self.zip.url is None
|
|
82
|
+
):
|
|
83
|
+
raise LOGSException(
|
|
84
|
+
f"Conversion for dataset {self.datasetId} from format '{self.datasetFormat}' to format '{self.exportFormat}' did not result in any data."
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if not directory:
|
|
88
|
+
directory = os.curdir
|
|
89
|
+
|
|
90
|
+
if not fileName:
|
|
91
|
+
fileName = f"dataset_{self.datasetId}_{self.zip.id}.zip"
|
|
92
|
+
|
|
93
|
+
path = os.path.join(directory, Tools.sanitizeFileName(fileName=fileName))
|
|
94
|
+
|
|
95
|
+
if overwrite:
|
|
96
|
+
if os.path.exists(path) and not os.path.isfile(path):
|
|
97
|
+
raise LOGSException("Path %a is not a file" % path)
|
|
98
|
+
else:
|
|
99
|
+
if os.path.exists(path):
|
|
100
|
+
raise LOGSException("File %a already exists" % path)
|
|
101
|
+
|
|
102
|
+
data, responseError = connection.getUrl(
|
|
103
|
+
self.zip.url, responseType=ResponseTypes.RAW
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if responseError:
|
|
107
|
+
raise LOGSException(
|
|
108
|
+
f"Could not fetch conversion result for dataset {self.datasetId} from format '{self.datasetFormat}' to format '{self.exportFormat}'.",
|
|
109
|
+
responseError=responseError,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
with open(path, mode="wb") as localfile:
|
|
113
|
+
localfile.write(cast(bytes, data))
|
|
114
|
+
|
|
115
|
+
return path
|
|
116
|
+
|
|
117
|
+
def _reloadOnWaiting(self, connection, endpoint):
|
|
118
|
+
if self.state != ConversionState.Waiting:
|
|
119
|
+
return
|
|
120
|
+
data, responseError = connection.postEndpoint(endpoint, data=self._payload)
|
|
121
|
+
if responseError:
|
|
122
|
+
raise EntityFetchingException(
|
|
123
|
+
entity=self._parentEntity, responseError=responseError
|
|
124
|
+
)
|
|
125
|
+
self.fromDict(data)
|
|
126
|
+
|
|
127
|
+
def awaitResult(self):
|
|
128
|
+
connection, endpoint = self._getConnectionData()
|
|
129
|
+
if self.state != ConversionState.Waiting:
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
while self.state == ConversionState.Waiting:
|
|
133
|
+
sleep(0.5)
|
|
134
|
+
# print("request...")
|
|
135
|
+
|
|
136
|
+
self._reloadOnWaiting(connection, endpoint)
|
|
137
|
+
|
|
138
|
+
# print("... done", self.state)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def awaitAllResults(
|
|
142
|
+
cls,
|
|
143
|
+
conversions: List["Conversion"],
|
|
144
|
+
timeout=600,
|
|
145
|
+
stateChangeHook: Optional[Callable[[int], None]] = None,
|
|
146
|
+
):
|
|
147
|
+
l = [c for c in conversions if c is not None]
|
|
148
|
+
|
|
149
|
+
connectionList = []
|
|
150
|
+
for i, c in enumerate(l):
|
|
151
|
+
connection, endpoint = c._getConnectionData()
|
|
152
|
+
connectionList.append((c, connection, endpoint))
|
|
153
|
+
|
|
154
|
+
count = sum(
|
|
155
|
+
[1 for c in connectionList if c[0].state != ConversionState.Waiting]
|
|
156
|
+
)
|
|
157
|
+
if stateChangeHook:
|
|
158
|
+
stateChangeHook(len(connectionList) - count)
|
|
159
|
+
|
|
160
|
+
start = time()
|
|
161
|
+
while count < len(connectionList) and time() - start < timeout:
|
|
162
|
+
oldCount = count
|
|
163
|
+
count = 0
|
|
164
|
+
for c in connectionList:
|
|
165
|
+
if c[0].state != ConversionState.Waiting:
|
|
166
|
+
count += 1
|
|
167
|
+
continue
|
|
168
|
+
c[0]._reloadOnWaiting(c[1], c[2])
|
|
169
|
+
if stateChangeHook and oldCount != count:
|
|
170
|
+
stateChangeHook(len(connectionList) - count)
|
|
171
|
+
# print(f"waiting for {len(connectionList) -count} jobs")
|
|
172
|
+
sleep(0.5)
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def datasetId(self) -> Optional[int]:
|
|
176
|
+
return self._datasetId
|
|
177
|
+
|
|
178
|
+
@datasetId.setter
|
|
179
|
+
def datasetId(self, value):
|
|
180
|
+
self._datasetId = self.checkAndConvertNullable(value, int, "datasetId")
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def datasetFormat(self) -> Optional[str]:
|
|
184
|
+
return self._datasetFormat
|
|
185
|
+
|
|
186
|
+
@datasetFormat.setter
|
|
187
|
+
def datasetFormat(self, value):
|
|
188
|
+
self._datasetFormat = self.checkAndConvertNullable(value, str, "datasetFormat")
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def exportFormat(self) -> Optional[str]:
|
|
192
|
+
return self._exportFormat
|
|
193
|
+
|
|
194
|
+
@exportFormat.setter
|
|
195
|
+
def exportFormat(self, value):
|
|
196
|
+
self._exportFormat = self.checkAndConvertNullable(value, str, "exportFormat")
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def files(self) -> Optional[List[ConversionFile]]:
|
|
200
|
+
return self._files
|
|
201
|
+
|
|
202
|
+
@files.setter
|
|
203
|
+
def files(self, value):
|
|
204
|
+
self._files = self.checkListAndConvertNullable(value, ConversionFile, "files")
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def logs(self) -> Optional[List[ConversionLogModel]]:
|
|
208
|
+
return self._logs
|
|
209
|
+
|
|
210
|
+
@logs.setter
|
|
211
|
+
def logs(self, value):
|
|
212
|
+
self._logs = self.checkListAndConvertNullable(value, ConversionLogModel, "logs")
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def output(self) -> Optional[str]:
|
|
216
|
+
return self._output
|
|
217
|
+
|
|
218
|
+
@output.setter
|
|
219
|
+
def output(self, value):
|
|
220
|
+
self._output = self.checkAndConvertNullable(value, str, "output")
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def state(self) -> Optional[ConversionState]:
|
|
224
|
+
return self._state
|
|
225
|
+
|
|
226
|
+
@state.setter
|
|
227
|
+
def state(self, value):
|
|
228
|
+
self._state = self.checkAndConvertNullable(value, ConversionState, "state")
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def zip(self) -> Optional[DatasetConversionZipReadModel]:
|
|
232
|
+
return self._zip
|
|
233
|
+
|
|
234
|
+
@zip.setter
|
|
235
|
+
def zip(self, value):
|
|
236
|
+
self._zip = self.checkAndConvertNullable(
|
|
237
|
+
value, DatasetConversionZipReadModel, "zip"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def inputParameters(self) -> Optional[List[ConverterParameterEntry]]:
|
|
242
|
+
return self._inputParameters
|
|
243
|
+
|
|
244
|
+
@inputParameters.setter
|
|
245
|
+
def inputParameters(self, value):
|
|
246
|
+
self._inputParameters = self.checkListAndConvertNullable(
|
|
247
|
+
value, ConverterParameterEntry, "inputParameters"
|
|
248
|
+
)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from LOGS.Auxiliary import Tools
|
|
4
|
+
from LOGS.Converter.ConverterParameter import IConverterParameter
|
|
5
|
+
from LOGS.Converter.ExportParamters import ExportParamters
|
|
6
|
+
from LOGS.Entity.SerializeableContent import SerializeableContent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Converter(SerializeableContent):
|
|
10
|
+
_formatId: Optional[str] = None
|
|
11
|
+
_exportId: Optional[str] = None
|
|
12
|
+
_version: Optional[str] = None
|
|
13
|
+
_name: Optional[str] = None
|
|
14
|
+
_id: Optional[str] = None
|
|
15
|
+
_parameters: Optional[List[IConverterParameter]] = None
|
|
16
|
+
|
|
17
|
+
def __init__(self, ref=None):
|
|
18
|
+
t = type(self)
|
|
19
|
+
|
|
20
|
+
self._noSerialize += [
|
|
21
|
+
t.parameters.fget.__name__, # type: ignore
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
super().__init__(ref)
|
|
25
|
+
|
|
26
|
+
def __str__(self):
|
|
27
|
+
return Tools.ObjectToString(self)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def formatId(self) -> Optional[str]:
|
|
31
|
+
return self._formatId
|
|
32
|
+
|
|
33
|
+
@formatId.setter
|
|
34
|
+
def formatId(self, value):
|
|
35
|
+
self._formatId = self.checkAndConvertNullable(value, str, "formatId")
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def exportId(self) -> Optional[str]:
|
|
39
|
+
return self._exportId
|
|
40
|
+
|
|
41
|
+
@exportId.setter
|
|
42
|
+
def exportId(self, value):
|
|
43
|
+
self._exportId = self.checkAndConvertNullable(value, str, "exportId")
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def version(self) -> Optional[str]:
|
|
47
|
+
return self._version
|
|
48
|
+
|
|
49
|
+
@version.setter
|
|
50
|
+
def version(self, value):
|
|
51
|
+
self._version = self.checkAndConvertNullable(value, str, "version")
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def name(self) -> Optional[str]:
|
|
55
|
+
return self._name
|
|
56
|
+
|
|
57
|
+
@name.setter
|
|
58
|
+
def name(self, value):
|
|
59
|
+
self._name = self.checkAndConvertNullable(value, str, "name")
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def id(self) -> Optional[str]:
|
|
63
|
+
return self._id
|
|
64
|
+
|
|
65
|
+
@id.setter
|
|
66
|
+
def id(self, value):
|
|
67
|
+
self._id = self.checkAndConvertNullable(value, str, "id")
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def requestParameter(self) -> Optional[ExportParamters]:
|
|
71
|
+
if self.parameters is None:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
p: Dict[str, Any] = {p.id: None for p in self.parameters if p.id}
|
|
75
|
+
p["_parentId"] = self.id
|
|
76
|
+
return ExportParamters(
|
|
77
|
+
ref=p,
|
|
78
|
+
types={
|
|
79
|
+
p.id: IConverterParameter.TypeMapper(p.type)
|
|
80
|
+
for p in self.parameters
|
|
81
|
+
if p.id
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def parameters(self) -> Optional[List[IConverterParameter]]:
|
|
87
|
+
return self._parameters
|
|
88
|
+
|
|
89
|
+
@parameters.setter
|
|
90
|
+
def parameters(self, value):
|
|
91
|
+
self._parameters = self.checkListAndConvertNullable(
|
|
92
|
+
value,
|
|
93
|
+
fieldType=IConverterParameter,
|
|
94
|
+
converter=IConverterParameter.GetParameterFromDict,
|
|
95
|
+
fieldName="parameters",
|
|
96
|
+
)
|