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.

Files changed (147) hide show
  1. LOGS/Auxiliary/DateTimeConverter.py +11 -1
  2. LOGS/Auxiliary/Exceptions.py +40 -4
  3. LOGS/Auxiliary/LOGSErrorResponse.py +4 -1
  4. LOGS/Auxiliary/MinimalModelGenerator.py +88 -28
  5. LOGS/Auxiliary/Tools.py +11 -0
  6. LOGS/Converter/Conversion.py +248 -0
  7. LOGS/Converter/Converter.py +96 -0
  8. LOGS/Converter/ConverterParameter.py +88 -0
  9. LOGS/Converter/ExportParamters.py +89 -0
  10. LOGS/Converter/__init__.py +13 -0
  11. LOGS/Entities/Bridge.py +6 -3
  12. LOGS/Entities/CustomField.py +96 -91
  13. LOGS/Entities/CustomFieldModels.py +57 -0
  14. LOGS/Entities/CustomFieldRelations.py +10 -0
  15. LOGS/Entities/CustomFieldRequestParameter.py +43 -15
  16. LOGS/Entities/CustomFieldValue.py +88 -0
  17. LOGS/Entities/CustomFieldValueConverter.py +66 -0
  18. LOGS/Entities/CustomType.py +187 -0
  19. LOGS/Entities/CustomTypeEntityType.py +11 -0
  20. LOGS/Entities/CustomTypeMinimal.py +8 -0
  21. LOGS/Entities/CustomTypeRelations.py +59 -0
  22. LOGS/Entities/CustomTypeRequestParameter.py +61 -0
  23. LOGS/Entities/CustomTypeSection.py +39 -0
  24. LOGS/Entities/CustomTypes.py +12 -0
  25. LOGS/Entities/DataSource.py +28 -14
  26. LOGS/Entities/Dataset.py +274 -136
  27. LOGS/Entities/DatasetCreator.py +23 -72
  28. LOGS/Entities/DatasetInfo.py +23 -2
  29. LOGS/Entities/DatasetModels.py +31 -0
  30. LOGS/Entities/DatasetRequestParameter.py +45 -32
  31. LOGS/Entities/Datatrack.py +74 -30
  32. LOGS/Entities/DatatrackFormattedTable.py +25 -0
  33. LOGS/Entities/DatatrackGeneric.py +34 -0
  34. LOGS/Entities/DatatrackImage.py +25 -0
  35. LOGS/Entities/DatatrackNumericArray.py +9 -39
  36. LOGS/Entities/DatatrackNumericMatrix.py +86 -0
  37. LOGS/Entities/DocumentRequestParameter.py +2 -2
  38. LOGS/Entities/EntitiesRequestParameter.py +2 -2
  39. LOGS/Entities/Experiment.py +3 -3
  40. LOGS/Entities/FileExcludePattern.py +8 -0
  41. LOGS/Entities/FormatFormat.py +22 -1
  42. LOGS/Entities/FormatFormatRequestParameter.py +2 -1
  43. LOGS/Entities/FormatFormats.py +1 -1
  44. LOGS/Entities/FormattedTable/DatatypeFormattedTable.py +135 -0
  45. LOGS/Entities/FormattedTable/DatatypeFormattedTableCell.py +108 -0
  46. LOGS/Entities/FormattedTable/DatatypeFormattedTableSettings.py +11 -0
  47. LOGS/Entities/FormattedTable/__init__.py +9 -0
  48. LOGS/Entities/ILiterarTypedEntity.py +19 -0
  49. LOGS/Entities/Instrument.py +3 -3
  50. LOGS/Entities/Inventories.py +12 -0
  51. LOGS/Entities/Inventory.py +95 -0
  52. LOGS/Entities/InventoryMinimal.py +20 -0
  53. LOGS/Entities/InventoryRelations.py +23 -0
  54. LOGS/Entities/InventoryRequestParameter.py +53 -0
  55. LOGS/Entities/LabNotebook.py +37 -0
  56. LOGS/Entities/LabNotebookEntry.py +47 -24
  57. LOGS/Entities/LabNotebookEntryContent/BasicAttribute.py +15 -0
  58. LOGS/Entities/LabNotebookEntryContent/EntityAttribute.py +85 -0
  59. LOGS/Entities/LabNotebookEntryContent/EntryContentBlockquote.py +13 -0
  60. LOGS/Entities/LabNotebookEntryContent/EntryContentBulletList.py +17 -0
  61. LOGS/Entities/LabNotebookEntryContent/EntryContentCallout.py +40 -0
  62. LOGS/Entities/LabNotebookEntryContent/EntryContentContentPlaceholderNode.py +31 -0
  63. LOGS/Entities/LabNotebookEntryContent/EntryContentConverter.py +207 -0
  64. LOGS/Entities/LabNotebookEntryContent/EntryContentDocument.py +8 -0
  65. LOGS/Entities/LabNotebookEntryContent/EntryContentEntity.py +13 -0
  66. LOGS/Entities/LabNotebookEntryContent/EntryContentEntityMention.py +31 -0
  67. LOGS/Entities/LabNotebookEntryContent/EntryContentHeading.py +33 -0
  68. LOGS/Entities/LabNotebookEntryContent/EntryContentHorizontalRule.py +12 -0
  69. LOGS/Entities/LabNotebookEntryContent/EntryContentItem.py +37 -0
  70. LOGS/Entities/LabNotebookEntryContent/EntryContentListItem.py +49 -0
  71. LOGS/Entities/LabNotebookEntryContent/EntryContentOrderedList.py +31 -0
  72. LOGS/Entities/LabNotebookEntryContent/EntryContentParagraph.py +13 -0
  73. LOGS/Entities/LabNotebookEntryContent/EntryContentTable.py +17 -0
  74. LOGS/Entities/LabNotebookEntryContent/EntryContentTableCell.py +40 -0
  75. LOGS/Entities/LabNotebookEntryContent/EntryContentTableRow.py +8 -0
  76. LOGS/Entities/LabNotebookEntryContent/EntryContentTaskList.py +17 -0
  77. LOGS/Entities/LabNotebookEntryContent/EntryContentTaskListItem.py +31 -0
  78. LOGS/Entities/LabNotebookEntryContent/EntryContentText.py +33 -0
  79. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithAttribute.py +23 -0
  80. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithContent.py +38 -0
  81. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithTextAttribute.py +16 -0
  82. LOGS/Entities/LabNotebookEntryContent/TextAttribute.py +46 -0
  83. LOGS/Entities/LabNotebookEntryContent/TextMarkAtributes.py +64 -0
  84. LOGS/Entities/LabNotebookEntryContent/TextMarkConverter.py +45 -0
  85. LOGS/Entities/LabNotebookEntryContent/TextMarks.py +71 -0
  86. LOGS/Entities/LabNotebookEntryContent/__init__.py +34 -0
  87. LOGS/Entities/LabNotebookEntryRequestParameter.py +2 -0
  88. LOGS/Entities/LabNotebookExperiment.py +52 -0
  89. LOGS/Entities/LabNotebookExperimentMinimal.py +8 -0
  90. LOGS/Entities/LabNotebookExperimentRequestParameter.py +49 -0
  91. LOGS/Entities/LabNotebookExperiments.py +16 -0
  92. LOGS/Entities/LabNotebookMinimal.py +19 -0
  93. LOGS/Entities/LabNotebookModels.py +14 -0
  94. LOGS/Entities/LabNotebookRequestParameter.py +43 -0
  95. LOGS/Entities/LabNotebooks.py +12 -0
  96. LOGS/Entities/Method.py +3 -3
  97. LOGS/Entities/ParserLog.py +4 -0
  98. LOGS/Entities/Person.py +2 -2
  99. LOGS/Entities/PersonRequestParameter.py +1 -0
  100. LOGS/Entities/Project.py +7 -7
  101. LOGS/Entities/{ProjectUserPermission.py → ProjectPersonPermission.py} +14 -4
  102. LOGS/Entities/Role.py +3 -3
  103. LOGS/Entities/RunState.py +1 -0
  104. LOGS/Entities/Sample.py +36 -57
  105. LOGS/Entities/SampleRequestParameter.py +30 -15
  106. LOGS/Entities/Track.py +8 -4
  107. LOGS/Entities/TrackData.py +11 -0
  108. LOGS/Entities/TrackImage.py +21 -0
  109. LOGS/Entities/TrackImageData.py +20 -0
  110. LOGS/Entities/TrackMatrix.py +28 -0
  111. LOGS/Entities/TrackMatrixData.py +22 -0
  112. LOGS/Entities/TrackTable.py +21 -0
  113. LOGS/Entities/TrackTableData.py +22 -0
  114. LOGS/Entities/TrackXY.py +5 -1
  115. LOGS/Entities/TrackXYComplex.py +1 -1
  116. LOGS/Entities/__init__.py +26 -7
  117. LOGS/Entity/ConnectedEntity.py +39 -1
  118. LOGS/Entity/Entity.py +9 -14
  119. LOGS/Entity/SerializeableContent.py +62 -5
  120. LOGS/Interfaces/IHierarchyType.py +63 -0
  121. LOGS/Interfaces/IPermissionedEntity.py +29 -5
  122. LOGS/Interfaces/IProjectBased.py +1 -1
  123. LOGS/Interfaces/ITypedEntity.py +69 -12
  124. LOGS/Interfaces/IVersionedEntity.py +39 -0
  125. LOGS/LOGS.py +137 -46
  126. LOGS/LOGSConnection.py +52 -24
  127. LOGS/LOGSOptions.py +8 -0
  128. LOGS/Parameters/Color.py +92 -0
  129. LOGS/Parameters/ParameterBase.py +55 -0
  130. LOGS/Parameters/ParameterConverter.py +24 -0
  131. LOGS/Parameters/ParameterElement.py +99 -0
  132. LOGS/Parameters/ParameterList.py +52 -0
  133. LOGS/Parameters/ParameterTable.py +64 -0
  134. LOGS/Parameters/__init__.py +13 -0
  135. LOGS/__init__.py +1 -0
  136. {logs_py-2.9.6.dist-info → logs_py-3.0.1.dist-info}/METADATA +2 -1
  137. logs_py-3.0.1.dist-info/RECORD +263 -0
  138. LOGS/Entities/CustomFieldEnums.py +0 -25
  139. LOGS/Entities/DatasetType.py +0 -7
  140. LOGS/Entities/DatasetTypeMinimal.py +0 -8
  141. LOGS/Entities/SampleType.py +0 -34
  142. LOGS/Entities/SampleTypeMinimal.py +0 -8
  143. LOGS/Entities/SampleTypeRequestParameter.py +0 -8
  144. LOGS/Entities/SampleTypes.py +0 -12
  145. logs_py-2.9.6.dist-info/RECORD +0 -183
  146. {logs_py-2.9.6.dist-info → logs_py-3.0.1.dist-info}/WHEEL +0 -0
  147. {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 dates[0] if len(dates) > 0 else None
36
+ return d
@@ -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.details
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 = f" '{functionName}' or all complete fetch " if functionName else " "
137
+ func = []
138
+ if functionName:
139
+ func.append(f"'{functionName}'")
134
140
 
135
- message = f"Additional field{name}of entity was not fetched for efficiency reasons. Use{func}'fetchFull()' method to fetch this parameter"
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
- details: Optional[str] = None
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
- "DatasetMinimal": DatasetMinimalFromDict,
15
+ "BridgeMinimal": BridgeMinimalFromDict,
16
+ "CustomType": CustomTypeMinimalFromDict,
17
+ "CustomTypeMinimal": CustomTypeMinimalFromDict,
17
18
  "Dataset": DatasetMinimalFromDict,
18
- "EquipmentMinimal": EquipmentMinimalFromDict,
19
+ "DatasetMinimal": DatasetMinimalFromDict,
19
20
  "Equipment": EquipmentMinimalFromDict,
20
- "ExperimentMinimal": ExperimentMinimalFromDict,
21
+ "EquipmentMinimal": EquipmentMinimalFromDict,
21
22
  "Experiment": ExperimentMinimalFromDict,
22
- "InstrumentMinimal": InstrumentMinimalFromDict,
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
- "MethodMinimal": MethodMinimalFromDict,
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
- "LabNotebookEntry": LabNotebookEntryMinimalFromDict,
33
- "LabNotebookEntryMinimal": LabNotebookEntryMinimalFromDict,
34
- "Origin": OriginMinimalFromDict,
35
- "OriginMinimal": OriginMinimalFromDict,
36
- "InstrumentFacility": InstrumentMinimalFromDict,
37
- "InstrumentFacilityMinimal": InstrumentMinimalFromDict,
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 DatasetTypeMinimalFromDict(
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.DatasetTypeMinimal import DatasetTypeMinimal
333
+ from LOGS.Entities.LabNotebookMinimal import LabNotebookMinimal
274
334
 
275
335
  return _checkAndConvert(
276
336
  ref,
277
- DatasetTypeMinimal,
337
+ LabNotebookMinimal,
278
338
  fieldName=fieldName,
279
339
  allowNone=True,
280
340
  connection=connection,
281
341
  )
282
342
 
283
343
 
284
- def SampleTypeMinimalFromDict(
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.SampleTypeMinimal import SampleTypeMinimal
349
+ from LOGS.Entities.LabNotebookExperimentMinimal import LabNotebookExperimentMinimal
290
350
 
291
351
  return _checkAndConvert(
292
352
  ref,
293
- SampleTypeMinimal,
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
+ )