logs-py 2.9.5__py3-none-any.whl → 3.0.0__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 (148) 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 +98 -93
  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 +276 -138
  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/FormatMethod.py +2 -2
  45. LOGS/Entities/FormattedTable/DatatypeFormattedTable.py +135 -0
  46. LOGS/Entities/FormattedTable/DatatypeFormattedTableCell.py +108 -0
  47. LOGS/Entities/FormattedTable/DatatypeFormattedTableSettings.py +11 -0
  48. LOGS/Entities/FormattedTable/__init__.py +9 -0
  49. LOGS/Entities/ILiterarTypedEntity.py +19 -0
  50. LOGS/Entities/Instrument.py +3 -3
  51. LOGS/Entities/Inventories.py +12 -0
  52. LOGS/Entities/Inventory.py +95 -0
  53. LOGS/Entities/InventoryMinimal.py +20 -0
  54. LOGS/Entities/InventoryRelations.py +23 -0
  55. LOGS/Entities/InventoryRequestParameter.py +53 -0
  56. LOGS/Entities/LabNotebook.py +37 -0
  57. LOGS/Entities/LabNotebookEntry.py +50 -27
  58. LOGS/Entities/LabNotebookEntryContent/BasicAttribute.py +15 -0
  59. LOGS/Entities/LabNotebookEntryContent/EntityAttribute.py +85 -0
  60. LOGS/Entities/LabNotebookEntryContent/EntryContentBlockquote.py +13 -0
  61. LOGS/Entities/LabNotebookEntryContent/EntryContentBulletList.py +17 -0
  62. LOGS/Entities/LabNotebookEntryContent/EntryContentCallout.py +40 -0
  63. LOGS/Entities/LabNotebookEntryContent/EntryContentContentPlaceholderNode.py +31 -0
  64. LOGS/Entities/LabNotebookEntryContent/EntryContentConverter.py +207 -0
  65. LOGS/Entities/LabNotebookEntryContent/EntryContentDocument.py +8 -0
  66. LOGS/Entities/LabNotebookEntryContent/EntryContentEntity.py +13 -0
  67. LOGS/Entities/LabNotebookEntryContent/EntryContentEntityMention.py +31 -0
  68. LOGS/Entities/LabNotebookEntryContent/EntryContentHeading.py +33 -0
  69. LOGS/Entities/LabNotebookEntryContent/EntryContentHorizontalRule.py +12 -0
  70. LOGS/Entities/LabNotebookEntryContent/EntryContentItem.py +37 -0
  71. LOGS/Entities/LabNotebookEntryContent/EntryContentListItem.py +49 -0
  72. LOGS/Entities/LabNotebookEntryContent/EntryContentOrderedList.py +31 -0
  73. LOGS/Entities/LabNotebookEntryContent/EntryContentParagraph.py +13 -0
  74. LOGS/Entities/LabNotebookEntryContent/EntryContentTable.py +17 -0
  75. LOGS/Entities/LabNotebookEntryContent/EntryContentTableCell.py +40 -0
  76. LOGS/Entities/LabNotebookEntryContent/EntryContentTableRow.py +8 -0
  77. LOGS/Entities/LabNotebookEntryContent/EntryContentTaskList.py +17 -0
  78. LOGS/Entities/LabNotebookEntryContent/EntryContentTaskListItem.py +31 -0
  79. LOGS/Entities/LabNotebookEntryContent/EntryContentText.py +33 -0
  80. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithAttribute.py +23 -0
  81. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithContent.py +38 -0
  82. LOGS/Entities/LabNotebookEntryContent/IEntryContentWithTextAttribute.py +16 -0
  83. LOGS/Entities/LabNotebookEntryContent/TextAttribute.py +46 -0
  84. LOGS/Entities/LabNotebookEntryContent/TextMarkAtributes.py +64 -0
  85. LOGS/Entities/LabNotebookEntryContent/TextMarkConverter.py +45 -0
  86. LOGS/Entities/LabNotebookEntryContent/TextMarks.py +71 -0
  87. LOGS/Entities/LabNotebookEntryContent/__init__.py +34 -0
  88. LOGS/Entities/LabNotebookEntryRequestParameter.py +2 -0
  89. LOGS/Entities/LabNotebookExperiment.py +52 -0
  90. LOGS/Entities/LabNotebookExperimentMinimal.py +8 -0
  91. LOGS/Entities/LabNotebookExperimentRequestParameter.py +49 -0
  92. LOGS/Entities/LabNotebookExperiments.py +16 -0
  93. LOGS/Entities/LabNotebookMinimal.py +19 -0
  94. LOGS/Entities/LabNotebookModels.py +14 -0
  95. LOGS/Entities/LabNotebookRequestParameter.py +43 -0
  96. LOGS/Entities/LabNotebooks.py +12 -0
  97. LOGS/Entities/Method.py +3 -3
  98. LOGS/Entities/ParserLog.py +4 -0
  99. LOGS/Entities/Person.py +2 -2
  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 +10 -6
  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 +127 -45
  120. LOGS/Interfaces/IHierarchyType.py +63 -0
  121. LOGS/Interfaces/IPermissionedEntity.py +29 -5
  122. LOGS/Interfaces/IProjectBased.py +1 -1
  123. LOGS/Interfaces/IRelatedEntity.py +3 -2
  124. LOGS/Interfaces/ITypedEntity.py +69 -12
  125. LOGS/Interfaces/IVersionedEntity.py +39 -0
  126. LOGS/LOGS.py +140 -48
  127. LOGS/LOGSConnection.py +52 -24
  128. LOGS/LOGSOptions.py +8 -0
  129. LOGS/Parameters/Color.py +92 -0
  130. LOGS/Parameters/ParameterBase.py +55 -0
  131. LOGS/Parameters/ParameterConverter.py +24 -0
  132. LOGS/Parameters/ParameterElement.py +99 -0
  133. LOGS/Parameters/ParameterList.py +52 -0
  134. LOGS/Parameters/ParameterTable.py +64 -0
  135. LOGS/Parameters/__init__.py +13 -0
  136. LOGS/__init__.py +1 -0
  137. {logs_py-2.9.5.dist-info → logs_py-3.0.0.dist-info}/METADATA +3 -2
  138. logs_py-3.0.0.dist-info/RECORD +263 -0
  139. {logs_py-2.9.5.dist-info → logs_py-3.0.0.dist-info}/WHEEL +1 -1
  140. LOGS/Entities/CustomFieldEnums.py +0 -25
  141. LOGS/Entities/DatasetType.py +0 -7
  142. LOGS/Entities/DatasetTypeMinimal.py +0 -8
  143. LOGS/Entities/SampleType.py +0 -34
  144. LOGS/Entities/SampleTypeMinimal.py +0 -8
  145. LOGS/Entities/SampleTypeRequestParameter.py +0 -8
  146. LOGS/Entities/SampleTypes.py +0 -12
  147. logs_py-2.9.5.dist-info/RECORD +0 -183
  148. {logs_py-2.9.5.dist-info → logs_py-3.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,22 @@
1
+ from typing import Optional
2
+
3
+ from LOGS.Entities.DatatrackNumericMatrix import DatatrackNumericMatrix
4
+ from LOGS.Entities.TrackData import TrackData
5
+
6
+
7
+ class TrackMatrixData(TrackData):
8
+ _matrix: Optional[DatatrackNumericMatrix] = None
9
+
10
+ def fetchFull(self):
11
+ if self.matrix:
12
+ self.matrix.fetchFull()
13
+
14
+ @property
15
+ def matrix(self) -> Optional[DatatrackNumericMatrix]:
16
+ return self._matrix
17
+
18
+ @matrix.setter
19
+ def matrix(self, value):
20
+ self._matrix = self.checkAndConvertNullable(
21
+ value, DatatrackNumericMatrix, "matrix"
22
+ )
@@ -0,0 +1,21 @@
1
+ from typing import Optional
2
+
3
+ from LOGS.Entities.Track import Track
4
+ from LOGS.Entities.TrackTableData import TrackTableData
5
+
6
+
7
+ class TrackTable(Track):
8
+ _datatracks: Optional[TrackTableData] = None
9
+
10
+ def _fetchData(self):
11
+ if self.datatracks:
12
+ if self.datatracks.table:
13
+ self.datatracks.table.fetchFull()
14
+
15
+ @property
16
+ def datatracks(self) -> Optional[TrackTableData]:
17
+ return self._datatracks
18
+
19
+ @datatracks.setter
20
+ def datatracks(self, value):
21
+ self._datatracks = self.checkAndConvertNullable(value, TrackTableData, "data")
@@ -0,0 +1,22 @@
1
+ from typing import Optional
2
+
3
+ from LOGS.Entities.DatatrackFormattedTable import DatatrackFormattedTable
4
+ from LOGS.Entities.TrackData import TrackData
5
+
6
+
7
+ class TrackTableData(TrackData):
8
+ _table: Optional[DatatrackFormattedTable] = None
9
+
10
+ def fetchFull(self):
11
+ if self.table:
12
+ self.table.fetchFull()
13
+
14
+ @property
15
+ def table(self) -> Optional[DatatrackFormattedTable]:
16
+ return self._table
17
+
18
+ @table.setter
19
+ def table(self, value):
20
+ self._table = self.checkAndConvertNullable(
21
+ value, DatatrackFormattedTable, "matrix"
22
+ )
LOGS/Entities/TrackXY.py CHANGED
@@ -10,8 +10,10 @@ class TrackXY(Track):
10
10
  def _fetchData(self):
11
11
  if self.datatracks:
12
12
  if self.datatracks.x:
13
+ self.datatracks.x.cacheDir = self.cacheDir
13
14
  self.datatracks.x.fetchFull()
14
15
  if self.datatracks.y:
16
+ self.datatracks.y.cacheDir = self.cacheDir
15
17
  self.datatracks.y.fetchFull()
16
18
 
17
19
  def __iter__(self):
@@ -33,4 +35,6 @@ class TrackXY(Track):
33
35
 
34
36
  @datatracks.setter
35
37
  def datatracks(self, value):
36
- self._datatracks = self.checkAndConvertNullable(value, TrackXYData, "data")
38
+ self._datatracks = self.checkAndConvertNullable(
39
+ value, TrackXYData, "datatracks"
40
+ )
@@ -47,5 +47,5 @@ class TrackXYComplex(Track):
47
47
  @datatracks.setter
48
48
  def datatracks(self, value):
49
49
  self._datatracks = self.checkAndConvertNullable(
50
- value, TrackXYComplexData, "data"
50
+ value, TrackXYComplexData, "datatracks"
51
51
  )
LOGS/Entities/__init__.py CHANGED
@@ -15,10 +15,14 @@ from .BridgeMinimal import *
15
15
  from .BridgeRequestParameter import *
16
16
  from .BridgeType import *
17
17
  from .CustomField import *
18
- from .CustomFieldEnums import *
18
+ from .CustomFieldModels import *
19
19
  from .CustomFieldRequestParameter import *
20
+ from .CustomFieldValue import *
20
21
  from .CustomSchema import *
21
22
  from .CustomSchemaSection import *
23
+ from .CustomType import *
24
+ from .CustomTypeMinimal import *
25
+ from .CustomTypeRequestParameter import *
22
26
  from .Dataset import *
23
27
  from .DatasetCreator import *
24
28
  from .DatasetInfo import *
@@ -28,14 +32,15 @@ from .DatasetMinimal import *
28
32
  from .DatasetRelations import *
29
33
  from .DatasetRequestParameter import *
30
34
  from .Datasets import *
31
- from .DatasetType import *
32
- from .DatasetTypeMinimal import *
33
35
  from .DatasetUploadParameter import *
34
36
  from .DataSource import *
35
37
  from .DataSourceMinimal import *
36
38
  from .DataSourceRequestParameter import *
37
39
  from .Datatrack import *
40
+ from .DatatrackFormattedTable import *
41
+ from .DatatrackImage import *
38
42
  from .DatatrackNumericArray import *
43
+ from .DatatrackNumericMatrix import *
39
44
  from .Document import *
40
45
  from .DocumentRelations import *
41
46
  from .DocumentRequestParameter import *
@@ -63,10 +68,23 @@ from .Instrument import *
63
68
  from .InstrumentMinimal import *
64
69
  from .InstrumentRequestParameter import *
65
70
  from .Instruments import *
71
+ from .Inventory import *
72
+ from .InventoryMinimal import *
73
+ from .InventoryRequestParameter import *
74
+ from .LabNotebook import *
66
75
  from .LabNotebookEntries import *
67
- from .LabNotebookEntry import *
76
+ from .LabNotebookEntryContent import *
68
77
  from .LabNotebookEntryMinimal import *
78
+ from .LabNotebookEntryRelations import *
69
79
  from .LabNotebookEntryRequestParameter import *
80
+ from .LabNotebookExperiment import *
81
+ from .LabNotebookExperimentMinimal import *
82
+ from .LabNotebookExperimentRequestParameter import *
83
+ from .LabNotebookExperiments import *
84
+ from .LabNotebookMinimal import *
85
+ from .LabNotebookModels import *
86
+ from .LabNotebookRequestParameter import *
87
+ from .LabNotebooks import *
70
88
  from .Method import *
71
89
  from .MethodMinimal import *
72
90
  from .MethodRequestParameter import *
@@ -94,11 +112,12 @@ from .SampleMinimal import *
94
112
  from .SampleRelations import *
95
113
  from .SampleRequestParameter import *
96
114
  from .Samples import *
97
- from .SampleType import *
98
- from .SampleTypeMinimal import *
99
- from .SampleTypeRequestParameter import *
100
115
  from .Track import *
101
116
  from .TrackData import *
117
+ from .TrackImage import *
118
+ from .TrackImageData import *
119
+ from .TrackMatrix import *
120
+ from .TrackMatrixData import *
102
121
  from .TrackSettings import *
103
122
  from .TrackXY import *
104
123
  from .TrackXYComplex import *
@@ -9,7 +9,9 @@ class ConnectedEntity(SerializeableContent):
9
9
  _connection: Optional[LOGSConnection]
10
10
  _endpoint: Optional[List[str]] = None
11
11
  _uiEndpoint: Optional[List[str]] = None
12
- _noSerialize = ["connection"]
12
+ _noSerialize = ["connection", "cachePath", "cacheId", "cacheDir"]
13
+ _cacheDir: Optional[str] = None
14
+ _cacheId: str = cast(str, None)
13
15
 
14
16
  def __init__(self, ref=None, connection: Optional[LOGSConnection] = None):
15
17
  self._connection = connection
@@ -24,6 +26,24 @@ class ConnectedEntity(SerializeableContent):
24
26
  raise EntityNotConnectedException(self)
25
27
  return self._connection
26
28
 
29
+ def _getConnectionData(self):
30
+ if not self._endpoint:
31
+ raise NotImplementedError(
32
+ "Endpoint missing for of entity type %a."
33
+ % (
34
+ type(self).__name__
35
+ if type(self).__name__ != ConnectedEntity.__name__
36
+ else "unknown"
37
+ )
38
+ )
39
+
40
+ return self._getConnection(), self._endpoint
41
+
42
+ def clearCache(self):
43
+ raise NotImplementedError(
44
+ "Clearing cache of %a class is not implemented." % type(self).__name__
45
+ )
46
+
27
47
  @property
28
48
  def connection(self) -> Optional[LOGSConnection]:
29
49
  return self._connection
@@ -43,3 +63,21 @@ class ConnectedEntity(SerializeableContent):
43
63
  @property
44
64
  def identifier(self):
45
65
  return "%s" % (type(self).__name__)
66
+
67
+ @property
68
+ def cacheDir(self) -> Optional[str]:
69
+ return self._cacheDir
70
+
71
+ @cacheDir.setter
72
+ def cacheDir(self, value):
73
+ self._cacheDir = self.checkAndConvertNullable(value, str, "cacheDir")
74
+
75
+ @property
76
+ def cacheId(self) -> str:
77
+ if self._cacheId is None:
78
+ if not hasattr(self, "id"):
79
+ setattr(self, "id", self.generateID())
80
+
81
+ return f"{type(self).__name__}_{str(getattr(self, 'id'))}"
82
+ else:
83
+ return self._cacheId
LOGS/Entity/Entity.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from typing import Any, Optional, cast
2
2
 
3
- from LOGS.Auxiliary import MinimalModelGenerator
3
+ from LOGS.Auxiliary import MinimalModelGenerator, Tools
4
4
  from LOGS.Auxiliary.Constants import Constants
5
5
  from LOGS.Auxiliary.Exceptions import (
6
6
  EntityDeletingException,
@@ -32,24 +32,15 @@ class Entity(ConnectedEntity):
32
32
  super().__init__(ref=ref, connection=connection)
33
33
 
34
34
  def _getConnectionData(self):
35
- if not self._endpoint:
36
- raise NotImplementedError(
37
- "Endpoint missing for of entity type %a."
38
- % (
39
- type(self).__name__
40
- if type(self).__name__ != Entity.__name__
41
- else "unknown"
42
- )
43
- )
35
+ (connection, endpoint) = super()._getConnectionData()
44
36
 
45
37
  if not self.id:
46
38
  raise EntityNotFoundException(self)
47
39
 
48
- return self._getConnection(), self._endpoint, self.id
40
+ return connection, endpoint, self.id
49
41
 
50
42
  def __str__(self):
51
- s = (" name:'%s'" % getattr(self, "name")) if hasattr(self, "name") else ""
52
- return "<%s id:%s%s>" % (type(self).__name__, str(self.id), s)
43
+ return Tools.ObjectToString(self)
53
44
 
54
45
  def getUIUrl(self) -> str:
55
46
  if not self._uiEndpoint:
@@ -188,7 +179,11 @@ class Entity(ConnectedEntity):
188
179
 
189
180
  @property
190
181
  def identifier(self):
191
- name = f"'{getattr(self, 'name')}'" if hasattr(self, "name") else None
182
+ name = (
183
+ f" '{getattr(self, 'name')}'"
184
+ if hasattr(self, "name") and getattr(self, "name")
185
+ else ""
186
+ )
192
187
  return "%s(id:%s)%s" % (
193
188
  type(self).__name__,
194
189
  str(self.id),
@@ -2,7 +2,6 @@ import inspect
2
2
  import json
3
3
  import math
4
4
  import random
5
- from copy import deepcopy
6
5
  from datetime import datetime
7
6
  from enum import Enum
8
7
  from typing import (
@@ -32,7 +31,12 @@ _T = TypeVar("_T")
32
31
  class SerializeableContent:
33
32
  _noSerialize: List[str] = []
34
33
  _typeMapper: Optional[Dict[str, Any]] = None
35
- _planeClass = False
34
+ _slack: Dict[str, Any] = {}
35
+
36
+ _planeClass: bool = False
37
+ _includeNone: bool = False
38
+ _debugPrintRef: bool = False
39
+ _includeSlack: bool = False
36
40
 
37
41
  def __init__(self, ref=None):
38
42
  if ref != None:
@@ -45,23 +49,25 @@ class SerializeableContent:
45
49
  self,
46
50
  ref,
47
51
  selfClass,
48
- fromInstance=None,
49
- fromDict=None,
50
- formatDict=None,
51
52
  convertOtherType: Optional[Tuple[type, Callable[[Any], Any]]] = None,
52
53
  ):
53
- # print("FromRef", selfClass.__name__, self._json_schema)
54
+ if self._debugPrintRef:
55
+ print("FromRef", selfClass.__name__, "\n", self._dictToJson(ref))
54
56
 
55
- # if not isinstance(ref, (selfClass, dict)) and convertOtherType:
56
- # ref = convertOtherType(ref)
57
57
  if convertOtherType and isinstance(ref, convertOtherType[0]):
58
58
  ref = convertOtherType[1](ref)
59
59
 
60
- if isinstance(ref, selfClass):
61
- if fromInstance:
62
- fromInstance(ref)
63
- else:
64
- self.fromInstance(ref)
60
+ serializableAncestors = tuple(
61
+ [
62
+ c
63
+ for c in inspect.getmro(selfClass)
64
+ if issubclass(c, SerializeableContent)
65
+ ]
66
+ )
67
+
68
+ # if isinstance(ref, selfClass):
69
+ if isinstance(ref, serializableAncestors):
70
+ self.fromInstance(ref)
65
71
  elif isinstance(ref, dict):
66
72
  if hasattr(self, "_typeMapper") and self._typeMapper:
67
73
  for k, t in self._typeMapper.items():
@@ -75,10 +81,7 @@ class SerializeableContent:
75
81
  elements=ref, fieldName=k, fieldType=t, allowNone=True
76
82
  )
77
83
 
78
- if fromDict:
79
- fromDict(ref)
80
- else:
81
- self.fromDict(ref, formatDict=formatDict)
84
+ self.fromDict(ref)
82
85
  else:
83
86
  types: List[type] = [dict, type(self)]
84
87
  if convertOtherType:
@@ -99,21 +102,73 @@ class SerializeableContent:
99
102
  attrList = self._getAttrList()
100
103
  for k in attrList:
101
104
  if hasattr(ref, k):
102
- setattr(self, k, getattr(ref, k))
105
+ try:
106
+ setattr(self, k, getattr(ref, k))
107
+ except AttributeError:
108
+ pass
103
109
 
104
- def fromDict(self, ref, formatDict=None) -> None:
105
- if formatDict:
106
- ref = deepcopy(ref)
107
- ref = formatDict(ref)
108
- if ref == None:
109
- ref = {}
110
+ def _getSlack(self, ignoreClasses: Optional[List[Type]] = None):
111
+ slack = {"class": type(self).__name__, "slack": {}}
112
+ if self._slack:
113
+ slack["slack"]["self"] = self._slack
114
+ attrList = self._getAttrList()
115
+ for k in attrList:
116
+ try:
117
+ if hasattr(self, k):
118
+ item = getattr(self, k)
119
+ if isinstance(item, list):
120
+ slacks = {}
121
+ for i, e in enumerate(item):
122
+ if ignoreClasses and any(
123
+ type(e) == c for c in ignoreClasses
124
+ ):
125
+ continue
126
+ if isinstance(e, SerializeableContent):
127
+ s = e._getSlack(ignoreClasses=ignoreClasses)
128
+ if s["slack"]:
129
+ slacks[f"{k}[{i}]"] = s
130
+ if slacks:
131
+ slack["slack"].update(slacks)
132
+
133
+ if isinstance(item, SerializeableContent):
134
+ if ignoreClasses and any(
135
+ type(item) == c for c in ignoreClasses
136
+ ):
137
+ continue
138
+ s = item._getSlack(ignoreClasses=ignoreClasses)
139
+ if s["slack"]:
140
+ slack["slack"][k] = s
141
+ except AttributeError:
142
+ pass
143
+
144
+ return slack
145
+
146
+ def _printSlackDict(self, slack: dict, prefix=""):
147
+ if not slack or "slack" not in slack or not slack["slack"]:
148
+ return
149
+
150
+ prefix += slack["class"] if prefix == "" else f"({slack['class']})"
151
+ if "self" in slack["slack"]:
152
+ print(f"{prefix}: '{slack['slack']['self']}'")
153
+ for k, v in slack["slack"].items():
154
+ if k == "self":
155
+ continue
156
+ self._printSlackDict(v, prefix + f".{k}")
110
157
 
111
- # if "type" in ref:
112
- # self.type = ref["type"]
158
+ def _printSlack(self, prefix="", ignoreClasses: Optional[List[Type]] = None):
159
+ self._printSlackDict(self._getSlack(ignoreClasses=ignoreClasses))
113
160
 
114
- # self.validateDict(ref)
161
+ def fromDict(self, ref) -> None:
115
162
  # print("ref", ref)
116
163
  # print("ref", type(self).__name__)
164
+ if not hasattr(self, "_noSerialize"):
165
+ self._noSerialize = []
166
+
167
+ mappedKey = {
168
+ k: False
169
+ for k, v in ref.items()
170
+ if v is not None and k not in self._noSerialize
171
+ }
117
172
 
118
173
  for k in dir(self):
119
174
  # print(
@@ -123,19 +178,27 @@ class SerializeableContent:
123
178
  # "->",
124
179
  # ref[k] if k in ref else "NULL",
125
180
  # )
126
- if k in ref and hasattr(self, k) and not callable(getattr(self, k)):
181
+
182
+ try:
183
+ hasAttr = hasattr(self, k)
184
+ except (
185
+ EntityIncompleteException
186
+ ): # while deserializing we want to ignore incomplete fields
187
+ hasAttr = False
188
+
189
+ if k in ref and hasAttr and not callable(getattr(self, k)):
127
190
  try:
128
191
  # print(" ", k, "->", ref[k])
129
192
  setattr(self, k, ref[k])
193
+ mappedKey[k] = True
130
194
  except AttributeError as e:
131
195
  # print(f"[{type(self).__name__}] ERROR:", k, "->", ref[k], e)
132
196
  pass
133
197
 
134
- # This is the old way to check if settable: checks if a private attr exists and sets this
135
- # setattr(self, k, [])
136
- # if hasattr(self, _k) and not callable(getattr(self, _k)) and k in ref:
137
- # print(k, "->", ref[k])
138
- # setattr(self, _k, ref[k])
198
+ self._slack = {k: ref[k] for k, v in mappedKey.items() if not v}
199
+
200
+ # if self._slack:
201
+ # print(type(self).__name__, "->", ", ".join(self._slack.keys()))
139
202
 
140
203
  @classmethod
141
204
  def toBaseclassString(cls, obj):
@@ -148,11 +211,13 @@ class SerializeableContent:
148
211
  def toString(self):
149
212
  return str(self)
150
213
 
151
- @classmethod
152
- def _serializeItem(cls, item):
214
+ def _serializeItem(self, item):
153
215
  # print("serialize", item, hasattr(item, "__dict__"))
154
216
  if hasattr(item, "toDict"):
155
- return item.toDict()
217
+ if self._includeSlack and hasattr(item, "_toDictWithSlack"):
218
+ return item._toDictWithSlack()
219
+ else:
220
+ return item.toDict()
156
221
  if isinstance(item, cast(Any, np.float32)):
157
222
  return item.item()
158
223
  elif hasattr(
@@ -199,6 +264,13 @@ class SerializeableContent:
199
264
 
200
265
  return result
201
266
 
267
+ def _toDictWithSlack(self):
268
+ tmp = self._includeSlack
269
+ self._includeSlack = True
270
+ result = self.toDict()
271
+ self._includeSlack = tmp
272
+ return result
273
+
202
274
  def toDict(self) -> Dict[str, Any]:
203
275
  # print("toDict", type(self).__name__)
204
276
  if not hasattr(self, "_noSerialize"):
@@ -233,9 +305,12 @@ class SerializeableContent:
233
305
  # d[k] = "2021-12-01T00:00:00.000Z"
234
306
  elif isinstance(a, Enum):
235
307
  d[k] = a.value
236
- elif a != None:
308
+ elif a != None or self._includeNone:
237
309
  d[k] = self._serializeItem(a)
238
310
 
311
+ if self._includeSlack:
312
+ d.update({k: v for k, v in self._slack.items() if k not in d})
313
+
239
314
  return d
240
315
 
241
316
  @classmethod
@@ -274,12 +349,16 @@ class SerializeableContent:
274
349
  self.toDict(), indent=indent, sort_keys=sort_keys, compact=compact
275
350
  )
276
351
 
277
- def printJson(self, validate=False):
278
- print(self.toJson(validate=validate))
352
+ def printJson(self, indent=2, sort_keys=True, compact=False, validate=False):
353
+ print(
354
+ self.toJson(
355
+ validate=validate, indent=indent, sort_keys=sort_keys, compact=compact
356
+ )
357
+ )
279
358
 
280
359
  @classmethod
281
360
  def truncString(cls, text: str, length: int = 30) -> str:
282
- return Tools.truncString(text=text, length=length)
361
+ return Tools.truncString(text=str(text), length=length)
283
362
 
284
363
  @staticmethod
285
364
  def delEntryFromDict(d: dict, entry: str):
@@ -515,11 +594,14 @@ class SerializeableContent:
515
594
  excludeCharacters.append("line feed")
516
595
  for k in text.keys():
517
596
  if k not in excludeKeys:
518
- text[k], messages = cls.replaceControlCharacters(
519
- text[k],
520
- excludeKeys=excludeKeys,
521
- excludeCharacters=excludeCharacters,
522
- mergeMessages=mergeMessages,
597
+ text[k], messages = cast(
598
+ Any,
599
+ cls.replaceControlCharacters(
600
+ text[k],
601
+ excludeKeys=excludeKeys,
602
+ excludeCharacters=excludeCharacters,
603
+ mergeMessages=mergeMessages,
604
+ ),
523
605
  )
524
606
  if messages:
525
607
  for m in messages:
@@ -0,0 +1,63 @@
1
+ from dataclasses import dataclass
2
+ from typing import TYPE_CHECKING, List, Optional
3
+
4
+ from LOGS.Auxiliary import Tools
5
+ from LOGS.Entity.EntityMinimalWithIntId import EntityMinimalWithIntId
6
+ from LOGS.Interfaces.IEntityInterface import IEntityInterface
7
+
8
+ if TYPE_CHECKING:
9
+ pass
10
+
11
+
12
+ @dataclass
13
+ class IHierarchyTypeRequest:
14
+ childrenOfParentIds: Optional[List[int]] = None
15
+ descendantsOfIds: Optional[List[int]] = None
16
+ isRoot: Optional[List[bool]] = None
17
+
18
+
19
+ class IHierarchyType(IEntityInterface):
20
+ _inventoryName: Optional[str]
21
+ _isHierarchyRoot: Optional[bool]
22
+ _rootHierarchy: Optional[EntityMinimalWithIntId]
23
+ _parentTypes: Optional[List[EntityMinimalWithIntId]]
24
+
25
+ @property
26
+ def inventoryName(self) -> Optional[str]:
27
+ return self._inventoryName
28
+
29
+ @inventoryName.setter
30
+ def inventoryName(self, value):
31
+ self._inventoryName = Tools.checkAndConvert(
32
+ value, str, "inventoryName", allowNone=True
33
+ )
34
+
35
+ @property
36
+ def isHierarchyRoot(self) -> Optional[bool]:
37
+ return self._isHierarchyRoot
38
+
39
+ @isHierarchyRoot.setter
40
+ def isHierarchyRoot(self, value):
41
+ self._isHierarchyRoot = Tools.checkAndConvert(
42
+ value, bool, "isHierarchyRoot", allowNone=True
43
+ )
44
+
45
+ @property
46
+ def rootHierarchy(self) -> Optional[EntityMinimalWithIntId]:
47
+ return self._rootHierarchy
48
+
49
+ @rootHierarchy.setter
50
+ def rootHierarchy(self, value):
51
+ self._rootHierarchy = Tools.checkAndConvert(
52
+ value, EntityMinimalWithIntId, "rootHierarchy", allowNone=True
53
+ )
54
+
55
+ @property
56
+ def parentTypes(self) -> Optional[List[EntityMinimalWithIntId]]:
57
+ return self._parentTypes
58
+
59
+ @parentTypes.setter
60
+ def parentTypes(self, value):
61
+ self._parentTypes = Tools.checkListAndConvert(
62
+ value, EntityMinimalWithIntId, "parentTypes", allowNone=True
63
+ )
@@ -1,7 +1,8 @@
1
1
  from dataclasses import dataclass
2
- from typing import TYPE_CHECKING, Optional
2
+ from typing import TYPE_CHECKING, Generic, Optional, Type, TypeVar, cast
3
3
 
4
4
  from LOGS.Auxiliary import Tools
5
+ from LOGS.Entity.SerializeableContent import SerializeableClass
5
6
  from LOGS.Interfaces.IEntityInterface import IEntityInterface
6
7
 
7
8
  if TYPE_CHECKING:
@@ -13,15 +14,38 @@ class IPermissionedEntityRequest:
13
14
  includePermissions: Optional[bool] = None
14
15
 
15
16
 
16
- class IPermissionedEntity(IEntityInterface):
17
- _permissions: Optional[dict[str, bool]] = None
17
+ class IPermissionModel:
18
+ edit: Optional[bool] = None
19
+
20
+
21
+ class GenericPermission(IPermissionModel, SerializeableClass):
22
+ edit: Optional[bool] = False
23
+
24
+
25
+ _PERMISSION = TypeVar("_PERMISSION", bound=IPermissionModel)
26
+
27
+
28
+ class IPermissionedEntity(Generic[_PERMISSION], IEntityInterface):
29
+ _permissionType: Optional[Type[_PERMISSION]] = None
30
+
31
+ _permissions: Optional[_PERMISSION] = None
18
32
 
19
33
  @property
20
- def permissions(self) -> Optional[dict[str, bool]]:
34
+ def permissions(self) -> Optional[_PERMISSION]:
21
35
  return self._permissions
22
36
 
23
37
  @permissions.setter
24
38
  def permissions(self, value):
39
+ if not self._permissionType:
40
+ raise NotImplementedError("Permission type must be set")
41
+
25
42
  self._permissions = Tools.checkAndConvert(
26
- value, dict, "permissions", allowNone=True
43
+ value,
44
+ cast(Type[_PERMISSION], self._permissionType),
45
+ "permissions",
46
+ allowNone=True,
27
47
  )
48
+
49
+
50
+ class GenericPermissionEntity(IPermissionedEntity[GenericPermission]):
51
+ _permissionType: Type[GenericPermission] = GenericPermission
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
10
10
 
11
11
  @dataclass
12
12
  class IProjectBasedRequest:
13
- projects: Optional[List[str]] = None
13
+ projectIds: Optional[List[int]] = None
14
14
 
15
15
 
16
16
  class IProjectBased(IEntityInterface):