sdata 1.5.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.
- sdata/__init__.py +140 -0
- sdata/base.py +684 -0
- sdata/contrib/__init__.py +0 -0
- sdata/contrib/piexif/__init__.py +12 -0
- sdata/contrib/piexif/_common.py +94 -0
- sdata/contrib/piexif/_dump.py +346 -0
- sdata/contrib/piexif/_exceptions.py +2 -0
- sdata/contrib/piexif/_exif.py +638 -0
- sdata/contrib/piexif/_insert.py +60 -0
- sdata/contrib/piexif/_load.py +270 -0
- sdata/contrib/piexif/_remove.py +56 -0
- sdata/contrib/piexif/_transplant.py +45 -0
- sdata/contrib/piexif/_webp.py +240 -0
- sdata/contrib/piexif/helper.py +66 -0
- sdata/contrib/ranger/__init__.py +8 -0
- sdata/contrib/ranger/collections/__init__.py +0 -0
- sdata/contrib/ranger/collections/rangebucketmap.py +346 -0
- sdata/contrib/ranger/collections/rangemap.py +396 -0
- sdata/contrib/ranger/collections/rangeset.py +483 -0
- sdata/contrib/ranger/range/__init__.py +0 -0
- sdata/contrib/ranger/range/cut.py +285 -0
- sdata/contrib/ranger/range/range.py +644 -0
- sdata/contrib/sobol_seq.py +394 -0
- sdata/contrib/sortedcontainers/LICENSE +13 -0
- sdata/contrib/sortedcontainers/__init__.py +74 -0
- sdata/contrib/sortedcontainers/sorteddict.py +789 -0
- sdata/contrib/sortedcontainers/sortedlist.py +2646 -0
- sdata/contrib/sortedcontainers/sortedset.py +733 -0
- sdata/contrib/sqlitedict.py +598 -0
- sdata/contrib/timeflake/__init__.py +40 -0
- sdata/contrib/timeflake/flake.py +69 -0
- sdata/contrib/timeflake/utils.py +47 -0
- sdata/deprecated/__init__.py +10 -0
- sdata/deprecated/data.py +1503 -0
- sdata/did/__init__.py +129 -0
- sdata/did/_http.py +67 -0
- sdata/did/base58btc.py +49 -0
- sdata/did/did_github.py +152 -0
- sdata/did/did_peer4.py +155 -0
- sdata/did/did_web.py +222 -0
- sdata/did/diddoc.py +75 -0
- sdata/did/ed25519.py +225 -0
- sdata/did/eddsa.py +107 -0
- sdata/did/errors.py +40 -0
- sdata/did/issue_vc.py +193 -0
- sdata/did/jose.py +126 -0
- sdata/did/keys.py +104 -0
- sdata/did/utils_didkey.py +161 -0
- sdata/did/verify_vp.py +158 -0
- sdata/doe.py +101 -0
- sdata/dtypes.py +510 -0
- sdata/experiments/__init__.py +331 -0
- sdata/experiments/blob0.py +131 -0
- sdata/experiments/file.py +42 -0
- sdata/experiments/filegroup.py +144 -0
- sdata/experiments/image_old.py +313 -0
- sdata/experiments/ks2.py +15 -0
- sdata/experiments/lapshear.py +8 -0
- sdata/experiments/material.py +7 -0
- sdata/experiments/parameters_deprecated.py +394 -0
- sdata/experiments/workbook.py +226 -0
- sdata/format.py +125 -0
- sdata/imagemeta.py +533 -0
- sdata/interactive.py +118 -0
- sdata/iolib/__init__.py +51 -0
- sdata/iolib/hashtree.py +264 -0
- sdata/iolib/json1sqlitestore.py +554 -0
- sdata/iolib/jsonsqlitestore.py +704 -0
- sdata/iolib/pud.py +242 -0
- sdata/iolib/reader.py +262 -0
- sdata/iolib/writer.py +419 -0
- sdata/metadata.py +882 -0
- sdata/parameter.py +414 -0
- sdata/schema.py +273 -0
- sdata/sclass/__init__.py +111 -0
- sdata/sclass/bfo_classes.py +362 -0
- sdata/sclass/blob.py +362 -0
- sdata/sclass/content.py +87 -0
- sdata/sclass/dataframe.py +1251 -0
- sdata/sclass/dataframegroup.py +187 -0
- sdata/sclass/dependency_graph.py +85 -0
- sdata/sclass/filereference.py +124 -0
- sdata/sclass/image.py +218 -0
- sdata/sclass/lazy_namespace.py +155 -0
- sdata/sclass/process.py +383 -0
- sdata/sclass/process_graph.py +221 -0
- sdata/sclass/zipfile.py +135 -0
- sdata/semantic.py +346 -0
- sdata/suuid.py +136 -0
- sdata/timestamp.py +336 -0
- sdata/tools.py +14 -0
- sdata/units.py +602 -0
- sdata/vocab.py +149 -0
- sdata-1.5.0.dist-info/METADATA +264 -0
- sdata-1.5.0.dist-info/RECORD +98 -0
- sdata-1.5.0.dist-info/WHEEL +5 -0
- sdata-1.5.0.dist-info/licenses/LICENSE-MIT +21 -0
- sdata-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# -*-coding: utf-8-*-
|
|
2
|
+
import logging
|
|
3
|
+
logger = logging.getLogger("sdata")
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
from sdata import Data
|
|
7
|
+
from sdata.deprecated.data import Sdata_Uuid_Exeption
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
# import sdata.experiments.ks2
|
|
11
|
+
# import sdata.experiments.lapshear
|
|
12
|
+
# import sdata.experiments.material
|
|
13
|
+
#
|
|
14
|
+
# # ["name", "default_value", "dtype", "unit", "description", "required"]
|
|
15
|
+
# part_default_attributes = [
|
|
16
|
+
# ["part_id", None, "str", "-", "Part ID", True],
|
|
17
|
+
# ]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestProgram(Data):
|
|
21
|
+
"""A sdata Testprogram
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
# Trotz "Test"-Präfix keine pytest-Testklasse (gilt via Vererbung auch für
|
|
25
|
+
# TestSeries/Test) -> unterdrückt PytestCollectionWarning.
|
|
26
|
+
__test__ = False
|
|
27
|
+
|
|
28
|
+
ATTRIBUTES = [
|
|
29
|
+
['material_name', '', 'str', '-', 'Der Name des Materials.', '', False],
|
|
30
|
+
['material_norm_name', '', 'str', '-', 'Der normative Name des Materials.', '', False],
|
|
31
|
+
['material_number_norm', '', 'str', '-', 'Die normative Nummer des Materials.', '', False],
|
|
32
|
+
['material_manifacturer', '', 'str', '-', 'Die Hersteller des Materials.', '', False],
|
|
33
|
+
['material_grade', '', 'str', '-', 'Der Zustand des Materials.', '', False],
|
|
34
|
+
['material_coating', '', 'str', '-', 'Die Beschichtung des Materials.', '', False],
|
|
35
|
+
['material_density', '', 'float', 'g/cm^3', 'Die Dichte des Materials.', '', False],
|
|
36
|
+
['material_production_date', '', 'str', '-', 'Das Produktionsdatum des Materials.', '', False],
|
|
37
|
+
['responsible_person', '', 'str', '-', 'Verantwortlicher des Testprogramms.', '', False],
|
|
38
|
+
['responsible_person_phone', '', 'str', '-', 'Telefonnummer des Verantwortlichen vom Testprogramms.', '', False],
|
|
39
|
+
['responsible_person_email', '', 'str', '-', 'Emailadressen des Verantwortlichen vom Testprogramms.', '', False],
|
|
40
|
+
['responsible_person_organisation', '', 'str', '-', 'Organisation des Verantwortlichen vom Testprogramms.', '', False],
|
|
41
|
+
['notes', '', 'str', '-', 'Notizen zum Testprogramm.', '', False],
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
def __init__(self, **kwargs):
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
:param kwargs:
|
|
48
|
+
"""
|
|
49
|
+
Data.__init__(self, **kwargs)
|
|
50
|
+
self.metadata.add(name=self.SDATA_CLASS, value=self.__class__.__name__, dtype="str")
|
|
51
|
+
|
|
52
|
+
# if kwargs.get("uuid_testprogram") is not None:
|
|
53
|
+
# try:
|
|
54
|
+
# self.uuid_testprogram = kwargs.get("uuid_testprogram") # store given uuid str or generate a new uuid
|
|
55
|
+
# except Sdata_Uuid_Exeption as exp:
|
|
56
|
+
# if self.auto_correct is True:
|
|
57
|
+
# logger.warning("got invald uuid -> generate a new uuid")
|
|
58
|
+
# self.uuid_testprogram = uuid.uuid4().hex
|
|
59
|
+
# else:
|
|
60
|
+
# raise
|
|
61
|
+
|
|
62
|
+
self.name_testprogram = self.name
|
|
63
|
+
self.uuid_testprogram = self.uuid
|
|
64
|
+
|
|
65
|
+
if kwargs.get("name_testprogram") is not None:
|
|
66
|
+
self._set_name(kwargs.get("name_testprogram"))
|
|
67
|
+
if kwargs.get("uuid_testprogram") is not None:
|
|
68
|
+
self._set_uuid(kwargs.get("uuid_testprogram"))
|
|
69
|
+
|
|
70
|
+
for attrlist in self.ATTRIBUTES:
|
|
71
|
+
self.metadata.set_attr(attrlist[0], attrlist[1],
|
|
72
|
+
dtype=attrlist[2],
|
|
73
|
+
unit=attrlist[3],
|
|
74
|
+
description=attrlist[4],
|
|
75
|
+
label=attrlist[5],
|
|
76
|
+
required=attrlist[6])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def gen_testseries(self, **kwargs):
|
|
80
|
+
"""generate TestSeries instance
|
|
81
|
+
|
|
82
|
+
:param kwargs:
|
|
83
|
+
:return: TestSeries()
|
|
84
|
+
"""
|
|
85
|
+
class_name = kwargs.get("class_name", TestSeries)
|
|
86
|
+
if "class_name" in kwargs:
|
|
87
|
+
kwargs.pop("class_name")
|
|
88
|
+
|
|
89
|
+
ts = class_name(**kwargs)
|
|
90
|
+
ts.project = self.project
|
|
91
|
+
ts.name_testprogram = self.name_testprogram
|
|
92
|
+
ts.uuid_testprogram = self.uuid_testprogram
|
|
93
|
+
ts.metadata.add(self.SDATA_PARENT, self.uuid)
|
|
94
|
+
return ts
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def longname(self):
|
|
98
|
+
return "|".join([self.name_testprogram])
|
|
99
|
+
|
|
100
|
+
class TestSeries(TestProgram):
|
|
101
|
+
"""A sdata TestSeries
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
SDATA_TESTPROGRAM_NAME = "!sdata_testprogram_name"
|
|
106
|
+
SDATA_TESTPROGRAM_UUID = "!sdata_testprogram_uuid"
|
|
107
|
+
|
|
108
|
+
SDATA_TESTTYPE = "!sdata_testtype"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def __init__(self, **kwargs):
|
|
113
|
+
"""Test Series
|
|
114
|
+
|
|
115
|
+
:param kwargs:
|
|
116
|
+
"""
|
|
117
|
+
TestProgram.__init__(self, **kwargs)
|
|
118
|
+
|
|
119
|
+
self.metadata.add(name=self.SDATA_CLASS, value=self.__class__.__name__, dtype="str")
|
|
120
|
+
self.metadata.add(name=self.SDATA_TESTPROGRAM_NAME, value="N.N.", dtype="str", description="name of the testprogram")
|
|
121
|
+
self.metadata.add(name=self.SDATA_TESTPROGRAM_UUID, value="", dtype="str", description="uuid of the testprogram")
|
|
122
|
+
self.metadata.add(name=self.SDATA_TESTTYPE, value="", dtype="str", description="test type")
|
|
123
|
+
|
|
124
|
+
# if kwargs.get("name_testprogram") is not None:
|
|
125
|
+
# self.name_testprogram = kwargs.get("name_testprogram")
|
|
126
|
+
#
|
|
127
|
+
# if kwargs.get("uuid_testseries") is not None:
|
|
128
|
+
# try:
|
|
129
|
+
# self.uuid_testseries = kwargs.get("uuid_testseries") # store given uuid str or generate a new uuid
|
|
130
|
+
# except Sdata_Uuid_Exeption as exp:
|
|
131
|
+
# if self.auto_correct is True:
|
|
132
|
+
# logger.warning("got invald uuid -> generate a new uuid")
|
|
133
|
+
# self.uuid_testseries = uuid.uuid4().hex
|
|
134
|
+
# else:
|
|
135
|
+
# raise
|
|
136
|
+
|
|
137
|
+
self.uuid_testseries = self.uuid
|
|
138
|
+
self.name_testseries = self.name
|
|
139
|
+
|
|
140
|
+
# if kwargs.get("name") is not None:
|
|
141
|
+
# self._set_name(kwargs.get("name"))
|
|
142
|
+
# if kwargs.get("uuid") is not None:
|
|
143
|
+
# self._set_uuid(kwargs.get("uuid"))
|
|
144
|
+
|
|
145
|
+
# if kwargs.get("name_testseries") is not None:
|
|
146
|
+
# self.name_testseries = kwargs.get("name_testseries")
|
|
147
|
+
|
|
148
|
+
if kwargs.get("testtype") is not None:
|
|
149
|
+
self._set_testtype(kwargs.get("testtype"))
|
|
150
|
+
if kwargs.get("name_testseries") is not None:
|
|
151
|
+
self._set_name(kwargs.get("name_testseries"))
|
|
152
|
+
if kwargs.get("uuid_testseries") is not None:
|
|
153
|
+
self._set_uuid(kwargs.get("uuid_testseries"))
|
|
154
|
+
if kwargs.get("name") is not None:
|
|
155
|
+
self._set_name(kwargs.get("name"))
|
|
156
|
+
if kwargs.get("uuid") is not None:
|
|
157
|
+
self._set_uuid(kwargs.get("uuid"))
|
|
158
|
+
if kwargs.get("name_testprogram") is not None:
|
|
159
|
+
self._set_name_testprogram(kwargs.get("name_testprogram"))
|
|
160
|
+
if kwargs.get("uuid_testprogram") is not None:
|
|
161
|
+
self._set_uuid_testprogram(kwargs.get("uuid_testprogram"))
|
|
162
|
+
|
|
163
|
+
uuid_testseries = property(fget=TestProgram._get_uuid, fset=TestProgram._set_uuid, doc="uuid of the testseries")
|
|
164
|
+
name_testseries = property(fget=TestProgram._get_name, fset=TestProgram._set_name, doc="name of the testseries")
|
|
165
|
+
|
|
166
|
+
def _get_uuid_testprogram(self):
|
|
167
|
+
return self.metadata.get(self.SDATA_TESTPROGRAM_UUID).value
|
|
168
|
+
# return self._uuid
|
|
169
|
+
|
|
170
|
+
def _set_uuid_testprogram(self, value):
|
|
171
|
+
if isinstance(value, str):
|
|
172
|
+
try:
|
|
173
|
+
uuid.UUID(value)
|
|
174
|
+
self.metadata.set_attr(self.SDATA_TESTPROGRAM_UUID, uuid.UUID(value).hex)
|
|
175
|
+
except ValueError as exp:
|
|
176
|
+
logger.warning("data.uuid: %s" % exp)
|
|
177
|
+
raise Sdata_Uuid_Exeption("got invalid uuid str '{}'".format(str(value)))
|
|
178
|
+
elif isinstance(value, uuid.UUID):
|
|
179
|
+
self.metadata.set_attr(self.SDATA_TESTPROGRAM_UUID, value.hex)
|
|
180
|
+
else:
|
|
181
|
+
logger.error("Data.uuid: invalid uuid '{}'".format(value))
|
|
182
|
+
raise Exception("Data.uuid: invalid uuid '{}'".format(value))
|
|
183
|
+
|
|
184
|
+
uuid_testprogram = property(fget=_get_uuid_testprogram, fset=_set_uuid_testprogram, doc="uuid of the testprogram")
|
|
185
|
+
|
|
186
|
+
def _get_name_testprogram(self):
|
|
187
|
+
# return self._name
|
|
188
|
+
return self.metadata.get(self.SDATA_TESTPROGRAM_NAME).value
|
|
189
|
+
|
|
190
|
+
def _set_name_testprogram(self, value):
|
|
191
|
+
if isinstance(value, str):
|
|
192
|
+
try:
|
|
193
|
+
self.metadata.set_attr(self.SDATA_TESTPROGRAM_NAME, str(value)[:256])
|
|
194
|
+
except ValueError as exp:
|
|
195
|
+
logger.warning("data.name_testprogram: %s" % exp)
|
|
196
|
+
else:
|
|
197
|
+
# self._name = str(value)[:256]
|
|
198
|
+
self.metadata.set_attr(self.SDATA_TESTPROGRAM_NAME, str(value)[:256])
|
|
199
|
+
|
|
200
|
+
name_testprogram = property(fget=_get_name_testprogram, fset=_set_name_testprogram, doc="name of the testprogram")
|
|
201
|
+
|
|
202
|
+
def _get_testtype(self):
|
|
203
|
+
return self.metadata.get(self.SDATA_TESTTYPE).value
|
|
204
|
+
|
|
205
|
+
def _set_testtype(self, value):
|
|
206
|
+
if isinstance(value, str):
|
|
207
|
+
try:
|
|
208
|
+
self.metadata.set_attr(self.SDATA_TESTTYPE, str(value)[:256])
|
|
209
|
+
except ValueError as exp:
|
|
210
|
+
logger.warning("data.testtype: %s" % exp)
|
|
211
|
+
else:
|
|
212
|
+
self.metadata.set_attr(self.SDATA_TESTTYPE, str(value)[:256])
|
|
213
|
+
|
|
214
|
+
testtype = property(fget=_get_testtype, fset=_set_testtype, doc="testtype of the testseries")
|
|
215
|
+
|
|
216
|
+
def gen_test(self, **kwargs):
|
|
217
|
+
"""generate Test instance
|
|
218
|
+
|
|
219
|
+
:param kwargs:
|
|
220
|
+
:return: Test()
|
|
221
|
+
"""
|
|
222
|
+
class_name = kwargs.get("class_name", Test)
|
|
223
|
+
if "class_name" in kwargs:
|
|
224
|
+
kwargs.pop("class_name")
|
|
225
|
+
|
|
226
|
+
t = class_name(**kwargs)
|
|
227
|
+
t.name_testprogram = self.name_testprogram
|
|
228
|
+
t.uuid_testprogram = self.uuid_testprogram
|
|
229
|
+
t.name_testseries = self.name_testseries
|
|
230
|
+
t.uuid_testseries = self.uuid_testseries
|
|
231
|
+
t.project = self.project
|
|
232
|
+
t.testtype = self.testtype
|
|
233
|
+
t.metadata.add(self.SDATA_PARENT, self.uuid)
|
|
234
|
+
|
|
235
|
+
return t
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def longname(self):
|
|
239
|
+
return "|".join([self.name_testprogram, self.name])
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class Test(TestSeries):
|
|
243
|
+
"""A sdata Test
|
|
244
|
+
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
SDATA_TESTSERIES_NAME = "!sdata_testseries_name"
|
|
248
|
+
SDATA_TESTSERIES_UUID = "!sdata_testseries_uuid"
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def __init__(self, **kwargs):
|
|
252
|
+
"""Test
|
|
253
|
+
|
|
254
|
+
:param kwargs:
|
|
255
|
+
"""
|
|
256
|
+
TestSeries.__init__(self, **kwargs)
|
|
257
|
+
self.metadata.add(name=self.SDATA_TESTSERIES_NAME, value="N.N.", dtype="str", description="name of the testseries")
|
|
258
|
+
self.metadata.add(name=self.SDATA_TESTSERIES_UUID, value="", dtype="str", description="uuid of the testseries")
|
|
259
|
+
|
|
260
|
+
if kwargs.get("name") is not None:
|
|
261
|
+
self._set_name(kwargs.get("name"))
|
|
262
|
+
else:
|
|
263
|
+
self._set_name("N.N.")
|
|
264
|
+
if kwargs.get("testtype") is not None:
|
|
265
|
+
# print("testtype", kwargs.get("testtype"), self._set_testtype)
|
|
266
|
+
self._set_testtype(kwargs.get("testtype"))
|
|
267
|
+
if kwargs.get("name_testseries") is not None:
|
|
268
|
+
self._set_name_testseries(kwargs.get("name_testseries"))
|
|
269
|
+
if kwargs.get("uuid_testseries") is not None:
|
|
270
|
+
self._set_uuid_testseries(kwargs.get("uuid_testseries"))
|
|
271
|
+
if kwargs.get("name_testprogram") is not None:
|
|
272
|
+
self._set_name_testprogram(kwargs.get("name_testprogram"))
|
|
273
|
+
if kwargs.get("uuid_testprogram") is not None:
|
|
274
|
+
# print("uuid_testprogram", kwargs.get("uuid_testprogram"), self._set_uuid_testprogram)
|
|
275
|
+
self._set_uuid_testprogram(kwargs.get("uuid_testprogram"))
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _get_uuid_testseries(self):
|
|
279
|
+
return self.metadata.get(self.SDATA_TESTSERIES_UUID).value
|
|
280
|
+
|
|
281
|
+
def _set_uuid_testseries(self, value):
|
|
282
|
+
if isinstance(value, str):
|
|
283
|
+
try:
|
|
284
|
+
uuid.UUID(value)
|
|
285
|
+
self.metadata.set_attr(self.SDATA_TESTSERIES_UUID, uuid.UUID(value).hex)
|
|
286
|
+
except ValueError as exp:
|
|
287
|
+
logger.warning("data.uuid: %s" % exp)
|
|
288
|
+
raise Sdata_Uuid_Exeption("got invalid uuid str '{}'".format(str(value)))
|
|
289
|
+
elif isinstance(value, uuid.UUID):
|
|
290
|
+
self.metadata.set_attr(self.SDATA_TESTSERIES_UUID, value.hex)
|
|
291
|
+
else:
|
|
292
|
+
logger.error("Data.uuid: invalid uuid '{}'".format(value))
|
|
293
|
+
raise Exception("Data.uuid: invalid uuid '{}'".format(value))
|
|
294
|
+
|
|
295
|
+
uuid_testseries = property(fget=_get_uuid_testseries, fset=_set_uuid_testseries, doc="uuid of the testseries")
|
|
296
|
+
|
|
297
|
+
def _get_name_testseries(self):
|
|
298
|
+
return self.metadata.get(self.SDATA_TESTSERIES_NAME).value
|
|
299
|
+
|
|
300
|
+
def _set_name_testseries(self, value):
|
|
301
|
+
if isinstance(value, str):
|
|
302
|
+
try:
|
|
303
|
+
self.metadata.set_attr(self.SDATA_TESTSERIES_NAME, str(value)[:256])
|
|
304
|
+
except ValueError as exp:
|
|
305
|
+
logger.warning("data.name_testseries: %s" % exp)
|
|
306
|
+
else:
|
|
307
|
+
self.metadata.set_attr(self.SDATA_TESTSERIES_NAME, str(value)[:256])
|
|
308
|
+
|
|
309
|
+
name_testseries = property(fget=_get_name_testseries, fset=_set_name_testseries, doc="name of the testseries")
|
|
310
|
+
|
|
311
|
+
def _get_testtype(self):
|
|
312
|
+
return self.metadata.get(self.SDATA_TESTTYPE).value
|
|
313
|
+
|
|
314
|
+
def _set_testtype(self, value):
|
|
315
|
+
if isinstance(value, str):
|
|
316
|
+
try:
|
|
317
|
+
self.metadata.set_attr(self.SDATA_TESTTYPE, str(value)[:256])
|
|
318
|
+
except ValueError as exp:
|
|
319
|
+
logger.warning("data.testtype: %s" % exp)
|
|
320
|
+
else:
|
|
321
|
+
self.metadata.set_attr(self.SDATA_TESTTYPE, str(value)[:256])
|
|
322
|
+
|
|
323
|
+
testtype = property(fget=_get_testtype, fset=_set_testtype, doc="testtype of the testseries")
|
|
324
|
+
|
|
325
|
+
@property
|
|
326
|
+
def longname(self):
|
|
327
|
+
return "|".join([self.name_testprogram, self.name_testseries, self.name])
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
__all__ = []
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# -*-coding: utf-8-*-
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import collections
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
from sdata.timestamp import TimeStamp
|
|
8
|
+
from sdata.base import Base
|
|
9
|
+
from sdata.metadata import Metadata, Attribute
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import hashlib
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Blob(Base):
|
|
16
|
+
"""Binary Large Object as reference
|
|
17
|
+
|
|
18
|
+
.. warning::
|
|
19
|
+
|
|
20
|
+
highly experimental"""
|
|
21
|
+
|
|
22
|
+
VAULT_TYPES = ["filesystem", "hdf5", "db", "www"]
|
|
23
|
+
|
|
24
|
+
def __init__(self, **kwargs):
|
|
25
|
+
"""Binary Large Object
|
|
26
|
+
|
|
27
|
+
:param name:
|
|
28
|
+
:param url:
|
|
29
|
+
:param filetype:
|
|
30
|
+
:param vault:
|
|
31
|
+
:param kwargs:
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
super().__init__(**kwargs)
|
|
35
|
+
self.metadata.add("blob_name", kwargs.get("name", ""))
|
|
36
|
+
self.metadata.add("blob_type", "unknown")
|
|
37
|
+
self.url = kwargs.get("url", "")
|
|
38
|
+
self.metadata.add("blob_sha1", self.sha1)
|
|
39
|
+
self.metadata.add("blob_md5", self.md5)
|
|
40
|
+
self.metadata.add("vault", kwargs.get("vault", ""))
|
|
41
|
+
self.metadata.add("blob_filetype", kwargs.get("filetype", "unknown"))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_url(self):
|
|
45
|
+
# return self._name
|
|
46
|
+
return self.metadata.get("blob_url").value
|
|
47
|
+
|
|
48
|
+
def _set_url(self, value):
|
|
49
|
+
if isinstance(value, str):
|
|
50
|
+
try:
|
|
51
|
+
self.metadata.set_attr("blob_url", str(value)[:256])
|
|
52
|
+
except ValueError as exp:
|
|
53
|
+
logging.warning("blob.url: %s" % exp)
|
|
54
|
+
else:
|
|
55
|
+
# self._name = str(value)[:256]
|
|
56
|
+
self.metadata.set_attr("blob_url", str(value)[:256])
|
|
57
|
+
|
|
58
|
+
url = property(fget=_get_url, fset=_set_url, doc="url of the blob")
|
|
59
|
+
|
|
60
|
+
def exists(self, vault="filesystem"):
|
|
61
|
+
"""Test whether a object under the blob.url exists.
|
|
62
|
+
|
|
63
|
+
:param vault:
|
|
64
|
+
:return:
|
|
65
|
+
"""
|
|
66
|
+
if vault == "filesystem":
|
|
67
|
+
if os.path.exists(self.url):
|
|
68
|
+
return True
|
|
69
|
+
else:
|
|
70
|
+
return False
|
|
71
|
+
else:
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def sha1(self):
|
|
76
|
+
"""calculate the sha1 hash of the blob
|
|
77
|
+
|
|
78
|
+
:return: sha1
|
|
79
|
+
"""
|
|
80
|
+
hash = hashlib.sha1()
|
|
81
|
+
if self.url and os.path.exists(self.url):
|
|
82
|
+
with open(self.url, "rb") as fh:
|
|
83
|
+
self.update_hash(fh, hash)
|
|
84
|
+
return hash.hexdigest()
|
|
85
|
+
else:
|
|
86
|
+
logging.error("can't open external url '{}'".format(str(self.url)))
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def md5(self):
|
|
90
|
+
"""calculate the md5 hash of the blob
|
|
91
|
+
|
|
92
|
+
:return: sha1
|
|
93
|
+
"""
|
|
94
|
+
hash = hashlib.md5()
|
|
95
|
+
if self.url and os.path.exists(self.url):
|
|
96
|
+
with open(self.url, "rb") as fh:
|
|
97
|
+
self.update_hash(fh, hash)
|
|
98
|
+
return hash.hexdigest()
|
|
99
|
+
else:
|
|
100
|
+
logging.error("can't open external url '{}'".format(str(self.url)))
|
|
101
|
+
|
|
102
|
+
def update_hash(self, fh, hashobject, buffer_size = 65536):
|
|
103
|
+
"""A hash represents the object used to calculate a checksum of a
|
|
104
|
+
string of information.
|
|
105
|
+
|
|
106
|
+
.. code-block:: python
|
|
107
|
+
|
|
108
|
+
hashobject = hashlib.md5()
|
|
109
|
+
df = pd.DataFrame([1,2,3])
|
|
110
|
+
url = "/tmp/blob.csv"
|
|
111
|
+
df.to_csv(url)
|
|
112
|
+
blob = sdata.Blob(url=url)
|
|
113
|
+
fh = open(url, "rb")
|
|
114
|
+
blob.update_hash(fh, hashobject)
|
|
115
|
+
hashobject.hexdigest()
|
|
116
|
+
|
|
117
|
+
:param fh: file handle
|
|
118
|
+
:param hashobject: hash object, e.g. hashlib.sha1()
|
|
119
|
+
:param buffer_size: buffer size (default buffer_size=65536)
|
|
120
|
+
:return: hashobject
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
with fh as f:
|
|
125
|
+
while True:
|
|
126
|
+
data = f.read(buffer_size)
|
|
127
|
+
if not data:
|
|
128
|
+
break
|
|
129
|
+
hash.update(data)
|
|
130
|
+
return hash
|
|
131
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from sdata import SUUID, Base
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
class File(Base):
|
|
5
|
+
def __init__(self, **kwargs):
|
|
6
|
+
super().__init__(**kwargs)
|
|
7
|
+
|
|
8
|
+
def exists(self, path):
|
|
9
|
+
filepath = os.path.join(path, self.name)
|
|
10
|
+
return os.path.exists(path)
|
|
11
|
+
|
|
12
|
+
class Directory(Base):
|
|
13
|
+
def __init__(self, **kwargs):
|
|
14
|
+
super().__init__(**kwargs)
|
|
15
|
+
self.path = kwargs.get("path", os.getcwd())
|
|
16
|
+
self.files = {}
|
|
17
|
+
|
|
18
|
+
def register_files(self, path):
|
|
19
|
+
self.path = path
|
|
20
|
+
for f in os.listdir(self.path):
|
|
21
|
+
self.add(File(name=f))
|
|
22
|
+
|
|
23
|
+
def add(self, f):
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
self.files[f.name] = f
|
|
28
|
+
|
|
29
|
+
def ls(self):
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
return list(self.files.keys())
|
|
34
|
+
|
|
35
|
+
if __name__ == '__main__':
|
|
36
|
+
f = File(name="a.txt")
|
|
37
|
+
print(f)
|
|
38
|
+
|
|
39
|
+
d = Directory(name="/folder")
|
|
40
|
+
d.add(f)
|
|
41
|
+
print(d.ls())
|
|
42
|
+
print(d)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
from sdata.base import Base
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
class FileGroup(Base):
|
|
7
|
+
"""
|
|
8
|
+
A derived class from Base that manages a group of files.
|
|
9
|
+
Stores file metadata in self.data['files'] as a dictionary where:
|
|
10
|
+
- Keys are unique file identifiers (e.g., filenames or custom keys).
|
|
11
|
+
- Values are dictionaries containing 'name', 'url' (relative or absolute path),
|
|
12
|
+
'filetype' (e.g., 'pdf', 'txt'), and 'reference' (e.g., file content as bytes,
|
|
13
|
+
or a file handle, or any other reference to the file data).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initialize FileGroup.
|
|
19
|
+
|
|
20
|
+
:param kwargs: Keyword arguments passed to Base.__init__.
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(**kwargs)
|
|
23
|
+
# Initialize the files dictionary if not already present in data
|
|
24
|
+
if 'files' not in self.data:
|
|
25
|
+
self.data['files'] = {}
|
|
26
|
+
|
|
27
|
+
def add_file(
|
|
28
|
+
self,
|
|
29
|
+
key: str,
|
|
30
|
+
name: str,
|
|
31
|
+
url: str,
|
|
32
|
+
filetype: str,
|
|
33
|
+
reference: Any,
|
|
34
|
+
overwrite: bool = False
|
|
35
|
+
) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Add a file's metadata to the group.
|
|
38
|
+
|
|
39
|
+
:param key: Unique key for the file (e.g., filename or custom identifier).
|
|
40
|
+
:param name: The name of the file.
|
|
41
|
+
:param url: Relative or absolute path to the file.
|
|
42
|
+
:param filetype: The type of the file (e.g., 'pdf', 'csv', 'jpg').
|
|
43
|
+
:param reference: Reference to the file, e.g., bytes content, file object, or other data.
|
|
44
|
+
:param overwrite: If True, overwrite existing entry with the same key.
|
|
45
|
+
:raises ValueError: If key already exists and overwrite is False.
|
|
46
|
+
"""
|
|
47
|
+
if key in self.data['files'] and not overwrite:
|
|
48
|
+
raise ValueError(f"File with key '{key}' already exists. Set overwrite=True to replace.")
|
|
49
|
+
|
|
50
|
+
self.data['files'][key] = {
|
|
51
|
+
'name': name,
|
|
52
|
+
'url': url,
|
|
53
|
+
'filetype': filetype,
|
|
54
|
+
'reference': reference
|
|
55
|
+
}
|
|
56
|
+
logger.debug(f"Added file '{key}' to {self.sname}")
|
|
57
|
+
|
|
58
|
+
def get_file(self, key: str) -> Optional[Dict[str, Any]]:
|
|
59
|
+
"""
|
|
60
|
+
Retrieve a file's metadata by key.
|
|
61
|
+
|
|
62
|
+
:param key: The unique key for the file.
|
|
63
|
+
:return: Dictionary with file metadata if found, else None.
|
|
64
|
+
"""
|
|
65
|
+
return self.data['files'].get(key)
|
|
66
|
+
|
|
67
|
+
def remove_file(self, key: str) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Remove a file from the group by key.
|
|
70
|
+
|
|
71
|
+
:param key: The unique key for the file.
|
|
72
|
+
:raises KeyError: If the key does not exist.
|
|
73
|
+
"""
|
|
74
|
+
if key not in self.data['files']:
|
|
75
|
+
raise KeyError(f"File with key '{key}' not found.")
|
|
76
|
+
del self.data['files'][key]
|
|
77
|
+
logger.debug(f"Removed file '{key}' from {self.sname}")
|
|
78
|
+
|
|
79
|
+
def list_files(self) -> List[str]:
|
|
80
|
+
"""
|
|
81
|
+
List all file keys in the group.
|
|
82
|
+
|
|
83
|
+
:return: List of file keys.
|
|
84
|
+
"""
|
|
85
|
+
return list(self.data['files'].keys())
|
|
86
|
+
|
|
87
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
88
|
+
"""
|
|
89
|
+
Extend Base.to_dict to include the files in data.
|
|
90
|
+
Note: If 'reference' contains non-serializable objects (e.g., file handles),
|
|
91
|
+
they may need custom handling for serialization.
|
|
92
|
+
"""
|
|
93
|
+
return super().to_dict()
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def from_dict(cls, d: Dict[str, Any]) -> 'FileGroup':
|
|
97
|
+
"""
|
|
98
|
+
Create a FileGroup instance from a dictionary.
|
|
99
|
+
Assumes 'data' contains 'files' if previously serialized.
|
|
100
|
+
"""
|
|
101
|
+
instance = super().from_dict(d)
|
|
102
|
+
# Ensure 'files' is initialized if missing
|
|
103
|
+
if 'files' not in instance.data:
|
|
104
|
+
instance.data['files'] = {}
|
|
105
|
+
return instance
|
|
106
|
+
|
|
107
|
+
if __name__ == '__main__':
|
|
108
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
109
|
+
|
|
110
|
+
# Erstelle eine FileGroup-Instanz (z.B. für ein Projekt "Dokumentensammlung")
|
|
111
|
+
group = FileGroup(name="Dokumentensammlung", description="Eine Sammlung von PDF- und Text-Dateien.")
|
|
112
|
+
|
|
113
|
+
# Füge Dateien hinzu (hier mit Beispieldaten; 'reference' könnte z.B. Bytes oder ein File-Objekt sein)
|
|
114
|
+
group.add_file(
|
|
115
|
+
key="doc1",
|
|
116
|
+
name="Bericht.pdf",
|
|
117
|
+
url="/pfad/zum/bericht.pdf", # Relativ- oder Absolutpfad
|
|
118
|
+
filetype="pdf",
|
|
119
|
+
reference=b"Beispiel-Inhalt als Bytes" # Hier Bytes als Platzhalter; könnte auch ein File-Handle sein
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
group.add_file(
|
|
123
|
+
key="doc2",
|
|
124
|
+
name="Notizen.txt",
|
|
125
|
+
url="C:\\Dokumente\\notizen.txt", # Absolutpfad-Beispiel
|
|
126
|
+
filetype="txt",
|
|
127
|
+
reference="Text-Inhalt als String" # String als Referenz
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Versuche, eine Datei zu überschreiben (mit overwrite=True)
|
|
131
|
+
group.add_file(
|
|
132
|
+
key="doc1",
|
|
133
|
+
name="Aktualisierter_Bericht.pdf",
|
|
134
|
+
url="/neuer/pfad/zum/bericht.pdf",
|
|
135
|
+
filetype="pdf",
|
|
136
|
+
reference=b"Neuer Inhalt",
|
|
137
|
+
overwrite=True
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Liste alle Datei-Keys auf
|
|
141
|
+
print("Verfügbare Dateien:", group.list_files()) # Ausgabe: ['doc1', 'doc2']
|
|
142
|
+
|
|
143
|
+
# Hole Metadaten einer spezifischen Datei
|
|
144
|
+
file_info = group.get_file("doc1")
|