sdata 0.22.5__tar.gz → 0.23.0__tar.gz
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-0.22.5/sdata.egg-info → sdata-0.23.0}/PKG-INFO +1 -1
- {sdata-0.22.5 → sdata-0.23.0}/sdata/__init__.py +1 -1
- {sdata-0.22.5 → sdata-0.23.0}/sdata/data.py +38 -12
- {sdata-0.22.5 → sdata-0.23.0}/sdata/image.py +72 -16
- {sdata-0.22.5 → sdata-0.23.0}/sdata/metadata.py +48 -11
- {sdata-0.22.5 → sdata-0.23.0}/sdata/suuid.py +30 -3
- {sdata-0.22.5 → sdata-0.23.0/sdata.egg-info}/PKG-INFO +1 -1
- {sdata-0.22.5 → sdata-0.23.0}/LICENSE-MIT +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/MANIFEST.in +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/README.md +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/blob.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/default.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/dictionary.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/mapping.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/merge.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/attrdict/mixins.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_common.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_dump.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_exceptions.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_exif.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_insert.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_load.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_remove.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_transplant.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/_webp.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/piexif/helper.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/collections/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/collections/rangebucketmap.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/collections/rangemap.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/collections/rangeset.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/range/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/range/cut.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/ranger/range/range.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/semver.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/simple_graph_db/LICENSE +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/simple_graph_db/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/simple_graph_db/database.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/simple_graph_db/schema.sql +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sobol_seq.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sortedcontainers/LICENSE +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sortedcontainers/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sortedcontainers/sorteddict.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sortedcontainers/sortedlist.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sortedcontainers/sortedset.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/sqlitedict.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/timeflake/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/timeflake/flake.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/contrib/timeflake/utils.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/doe.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/experiments/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/experiments/ks2.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/experiments/lapshear.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/experiments/material.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/db.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/hdf.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/isomme.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/pgp.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/pud.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/simple_signature.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/iolib/vault.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/timestamp.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/tools.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata/workbook.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata.egg-info/SOURCES.txt +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata.egg-info/dependency_links.txt +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata.egg-info/requires.txt +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/sdata.egg-info/top_level.txt +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/setup.cfg +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/setup.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/iolib/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/iolib/pud/__init__.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/iolib/pud/test_pud.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/iolib/test_hdf.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_attribute.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_blob.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_data.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_image.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_io.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_ks2.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_metadata.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_sqlite.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_suuid.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_table.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_testprogram.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_timeflake.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_timestamp.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_tools.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_vault.py +0 -0
- {sdata-0.22.5 → sdata-0.23.0}/tests/test_workbook.py +0 -0
|
@@ -52,6 +52,7 @@ class Data(object):
|
|
|
52
52
|
|
|
53
53
|
SDATA_VERSION = "!sdata_version"
|
|
54
54
|
SDATA_NAME = "!sdata_name"
|
|
55
|
+
SDATA_SNAME = "!sdata_sname"
|
|
55
56
|
SDATA_UUID = "!sdata_uuid"
|
|
56
57
|
SDATA_SUUID = "!sdata_suuid"
|
|
57
58
|
SDATA_CTIME = "!sdata_ctime"
|
|
@@ -59,9 +60,10 @@ class Data(object):
|
|
|
59
60
|
SDATA_PARENT = "!sdata_parent"
|
|
60
61
|
SDATA_CLASS = "!sdata_class"
|
|
61
62
|
SDATA_PROJECT = "!sdata_project"
|
|
63
|
+
SDATA_URL = "!sdata_url"
|
|
62
64
|
|
|
63
65
|
SDATA_ATTRIBUTES = [SDATA_VERSION, SDATA_NAME, SDATA_UUID, SDATA_SUUID, SDATA_CLASS, SDATA_PARENT, SDATA_PROJECT,
|
|
64
|
-
SDATA_CTIME, SDATA_MTIME]
|
|
66
|
+
SDATA_CTIME, SDATA_MTIME, SDATA_URL]
|
|
65
67
|
|
|
66
68
|
def __init__(self, **kwargs):
|
|
67
69
|
"""create Data object
|
|
@@ -94,12 +96,14 @@ class Data(object):
|
|
|
94
96
|
# set default sdata attributes
|
|
95
97
|
self.metadata.add(self.SDATA_VERSION, __version__, dtype="str", description="sdata package version")
|
|
96
98
|
self.metadata.add(self.SDATA_NAME, "N.N.", dtype="str", description="name of the data object")
|
|
99
|
+
self.metadata.add(self.SDATA_SNAME, "", dtype="str", description="sname of the data object")
|
|
97
100
|
self.metadata.add(self.SDATA_UUID, "", dtype="str", description="Universally Unique Identifier")
|
|
98
101
|
self.metadata.add(self.SDATA_SUUID, "", dtype="str", description="Super Universally Unique Identifier")
|
|
99
102
|
self.metadata.add(self.SDATA_PARENT, "", dtype="str", description="uuid of the parent sdata object")
|
|
100
103
|
self.metadata.add(self.SDATA_CLASS, self.__class__.__name__, dtype="str", description="sdata class")
|
|
101
104
|
self.metadata.add(self.SDATA_CTIME, now_utc_str(), dtype="str", description="creation date")
|
|
102
105
|
self.metadata.add(self.SDATA_MTIME, now_utc_str(), dtype="str", description="modification date")
|
|
106
|
+
self.metadata.add(self.SDATA_URL, "", dtype="str", description="url of the data object")
|
|
103
107
|
|
|
104
108
|
metadata = kwargs.get("metadata")
|
|
105
109
|
if metadata is not None:
|
|
@@ -150,10 +154,19 @@ class Data(object):
|
|
|
150
154
|
# logger.info("uuid new")
|
|
151
155
|
self._set_uuid(uuid.uuid4())
|
|
152
156
|
|
|
153
|
-
|
|
157
|
+
if "suuid" not in kwargs:
|
|
158
|
+
self.gen_suuid()
|
|
159
|
+
else:
|
|
160
|
+
suuid = sdata.SUUID.from_suuid_str(kwargs.get("suuid"))
|
|
161
|
+
self.suuid = kwargs.get("suuid")
|
|
162
|
+
self.sname = suuid.sname
|
|
163
|
+
|
|
164
|
+
if "sname" in kwargs:
|
|
165
|
+
self.sname = kwargs.get("sname")
|
|
154
166
|
|
|
155
167
|
def gen_suuid(self):
|
|
156
168
|
self.suuid = sdata.SUUID(self.__class__.__name__, self.name, huuid=self.uuid).idstr
|
|
169
|
+
self.sname = sdata.SUUID(self.__class__.__name__, self.name, huuid=self.uuid).sname
|
|
157
170
|
|
|
158
171
|
def gen_uuid_from_state(self):
|
|
159
172
|
"""generate the same uuid for the same data
|
|
@@ -330,6 +343,15 @@ class Data(object):
|
|
|
330
343
|
|
|
331
344
|
suuid = property(fget=_get_suuid, fset=_set_suuid, doc="suuid of the object")
|
|
332
345
|
|
|
346
|
+
|
|
347
|
+
def _get_sname(self):
|
|
348
|
+
return self.metadata.get(self.SDATA_SNAME).value
|
|
349
|
+
|
|
350
|
+
def _set_sname(self, value):
|
|
351
|
+
self.metadata.set_attr(self.SDATA_SNAME, value)
|
|
352
|
+
|
|
353
|
+
sname = property(fget=_get_sname, fset=_set_sname, doc="sname of the object")
|
|
354
|
+
|
|
333
355
|
def _get_uuid(self):
|
|
334
356
|
return self.metadata.get(self.SDATA_UUID).value
|
|
335
357
|
# return self._uuid
|
|
@@ -969,7 +991,6 @@ class Data(object):
|
|
|
969
991
|
exportlines.append(self.metadata.to_csv_header(prefix="#;", sep=";", filepath=None))
|
|
970
992
|
if self.df is not None:
|
|
971
993
|
exportlines.append(self.df.to_csv(sep=";"))
|
|
972
|
-
|
|
973
994
|
exportstr = "".join(exportlines)
|
|
974
995
|
|
|
975
996
|
if filepath is None:
|
|
@@ -988,16 +1009,21 @@ class Data(object):
|
|
|
988
1009
|
:return: sdata.Data
|
|
989
1010
|
"""
|
|
990
1011
|
data = cls()
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1012
|
+
df = None
|
|
1013
|
+
try:
|
|
1014
|
+
if filepath:
|
|
1015
|
+
df = pd.read_csv(filepath, sep=";", comment="#", index_col=0)
|
|
1016
|
+
sio = open(filepath, "r")
|
|
1017
|
+
elif s is not None:
|
|
1018
|
+
sio = StringIO(s)
|
|
1019
|
+
pd.read_csv(sio, sep=";", comment="#")
|
|
1020
|
+
sio.seek(0)
|
|
1021
|
+
else:
|
|
1022
|
+
logger.error("data.from_csv: no csv data available")
|
|
1023
|
+
except Exception as exp:
|
|
1024
|
+
logging.error(f"{exp}")
|
|
1000
1025
|
raise
|
|
1026
|
+
return
|
|
1001
1027
|
|
|
1002
1028
|
attritute_list = []
|
|
1003
1029
|
for line in sio:
|
|
@@ -7,6 +7,7 @@ from sdata.timestamp import TimeStamp
|
|
|
7
7
|
from sdata.data import Data
|
|
8
8
|
from sdata.suuid import SUUID
|
|
9
9
|
from sdata.metadata import Metadata, Attribute
|
|
10
|
+
import sdata.contrib
|
|
10
11
|
import sdata.contrib.piexif
|
|
11
12
|
import sdata.contrib.piexif.helper
|
|
12
13
|
import json
|
|
@@ -25,11 +26,22 @@ class Image(Data):
|
|
|
25
26
|
highly experimental"""
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
def __init__(self, **kwargs):
|
|
29
|
+
def __init__(self, url, **kwargs):
|
|
29
30
|
"""Image Object"""
|
|
31
|
+
|
|
32
|
+
# url = kwargs.get("url", "")
|
|
33
|
+
load = kwargs.get("load", False)
|
|
34
|
+
try:
|
|
35
|
+
name = os.path.basename(url)
|
|
36
|
+
except Exception as exp:
|
|
37
|
+
name = None
|
|
38
|
+
if "name" not in kwargs:
|
|
39
|
+
kwargs["name"] = name
|
|
30
40
|
Data.__init__(self, **kwargs)
|
|
31
|
-
self.url =
|
|
41
|
+
self.url = url
|
|
32
42
|
self.img = None
|
|
43
|
+
if load is True:
|
|
44
|
+
self.load()
|
|
33
45
|
|
|
34
46
|
@classmethod
|
|
35
47
|
def _from_filepath(cls, filepath, **kwargs):
|
|
@@ -38,7 +50,10 @@ class Image(Data):
|
|
|
38
50
|
"""
|
|
39
51
|
project = kwargs.get("project")
|
|
40
52
|
suuid = SUUID.from_file(cls.__class__.__name__, filepath, ns_name=project)
|
|
41
|
-
|
|
53
|
+
kwargs["uuid"] = suuid.huuid
|
|
54
|
+
kwargs["url"] = filepath
|
|
55
|
+
|
|
56
|
+
data = cls(name=os.path.basename(filepath), **kwargs)
|
|
42
57
|
return data
|
|
43
58
|
|
|
44
59
|
@classmethod
|
|
@@ -47,13 +62,21 @@ class Image(Data):
|
|
|
47
62
|
|
|
48
63
|
"""
|
|
49
64
|
project = kwargs.get("project")
|
|
50
|
-
|
|
65
|
+
class_name = "Image" #cls.__class__.__name__
|
|
66
|
+
suuid = SUUID.from_file(class_name, filepath, ns_name=project)
|
|
67
|
+
kwargs["sname"] = suuid.sname
|
|
68
|
+
kwargs["uuid"] = suuid.huuid
|
|
69
|
+
kwargs["suuid"] = suuid.idstr
|
|
70
|
+
kwargs["url"] = filepath
|
|
71
|
+
name = os.path.basename(filepath)
|
|
72
|
+
|
|
73
|
+
|
|
51
74
|
if filepath.lower().endswith(".png"):
|
|
52
75
|
data = cls.from_png(filepath, **kwargs)
|
|
53
76
|
elif filepath.lower().endswith(".jpg"):
|
|
54
77
|
data = cls.from_jpg(filepath, **kwargs)
|
|
55
78
|
else:
|
|
56
|
-
data = cls(name=
|
|
79
|
+
data = cls(name=name, **kwargs)
|
|
57
80
|
return data
|
|
58
81
|
|
|
59
82
|
def get_sha3_256(self, filepath):
|
|
@@ -78,6 +101,15 @@ class Image(Data):
|
|
|
78
101
|
self.img = PIL.Image.open(self.url)
|
|
79
102
|
return self.img
|
|
80
103
|
|
|
104
|
+
def to_numpy(self):
|
|
105
|
+
"""returns a NumPy array created from the color channels of the given Image object
|
|
106
|
+
|
|
107
|
+
array([[[192, 190, 187],
|
|
108
|
+
[193, 190, 187],
|
|
109
|
+
[193, 190, 185],
|
|
110
|
+
"""
|
|
111
|
+
return np.array(self.img)
|
|
112
|
+
|
|
81
113
|
@classmethod
|
|
82
114
|
def from_png(cls, filepath, **kwargs):
|
|
83
115
|
"""load png image and metadata
|
|
@@ -93,12 +125,28 @@ class Image(Data):
|
|
|
93
125
|
data.metadata = data.metadata.from_json(d)
|
|
94
126
|
return data
|
|
95
127
|
|
|
128
|
+
@staticmethod
|
|
129
|
+
def _get_metadata(filepath, **kwargs):
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
if filepath.lower().endswith(".png"):
|
|
134
|
+
d = Image._get_png_metadata(filepath, **kwargs)
|
|
135
|
+
elif filepath.lower().endswith(".jpg"):
|
|
136
|
+
d = Image._get_png_metadata(filepath, **kwargs)
|
|
137
|
+
else:
|
|
138
|
+
d = {}
|
|
139
|
+
return d
|
|
140
|
+
|
|
96
141
|
@staticmethod
|
|
97
142
|
def _get_png_metadata(filepath, **kwargs):
|
|
98
143
|
"""load metadata json dict from img.info
|
|
99
144
|
"""
|
|
100
145
|
img = PIL.Image.open(filepath)
|
|
101
|
-
|
|
146
|
+
try:
|
|
147
|
+
d = json.loads(img.info.get("sdata"))
|
|
148
|
+
except Exception as exp:
|
|
149
|
+
d = {}
|
|
102
150
|
return d
|
|
103
151
|
|
|
104
152
|
@classmethod
|
|
@@ -111,9 +159,12 @@ class Image(Data):
|
|
|
111
159
|
return
|
|
112
160
|
data = cls._from_filepath(filepath, **kwargs)
|
|
113
161
|
# data.load()
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
162
|
+
try:
|
|
163
|
+
d = cls._get_jpg_metadata(filepath)
|
|
164
|
+
if d is not None:
|
|
165
|
+
data.metadata = data.metadata.from_json(d)
|
|
166
|
+
except Exception as exp:
|
|
167
|
+
logging.debug(exp)
|
|
117
168
|
return data
|
|
118
169
|
|
|
119
170
|
@staticmethod
|
|
@@ -130,7 +181,7 @@ class Image(Data):
|
|
|
130
181
|
d = json.loads(json_string)
|
|
131
182
|
return d
|
|
132
183
|
|
|
133
|
-
def
|
|
184
|
+
def saveas(self, filepath, rename=True, random=True, **kwargs):
|
|
134
185
|
"""save image
|
|
135
186
|
|
|
136
187
|
"""
|
|
@@ -138,17 +189,22 @@ class Image(Data):
|
|
|
138
189
|
if rename is True:
|
|
139
190
|
basename = os.path.basename(filepath)
|
|
140
191
|
other.rename(basename, random=random)
|
|
192
|
+
other.update_mtime()
|
|
193
|
+
other.save(filepath)
|
|
194
|
+
return other
|
|
141
195
|
|
|
142
|
-
|
|
143
|
-
other.load()
|
|
196
|
+
def save(self, filepath, **kwargs):
|
|
144
197
|
|
|
145
|
-
if
|
|
146
|
-
|
|
198
|
+
if self.img is None:
|
|
199
|
+
self.load()
|
|
200
|
+
|
|
201
|
+
if filepath.endswith(".png"):
|
|
202
|
+
self._save_png(filepath)
|
|
147
203
|
elif filepath.lower().endswith(".jpg"):
|
|
148
|
-
|
|
204
|
+
self._save_jpg(filepath)
|
|
149
205
|
else:
|
|
150
206
|
logging.warning(f"metadata not supported for {filepath}")
|
|
151
|
-
|
|
207
|
+
self.img.save(filepath)
|
|
152
208
|
|
|
153
209
|
def _save_png(self, filepath):
|
|
154
210
|
"""save png with metadata
|
|
@@ -56,6 +56,7 @@ class Attribute(object):
|
|
|
56
56
|
"""Attribute class"""
|
|
57
57
|
|
|
58
58
|
DTYPES = {'float': float, 'int': int, 'str': str, 'timestamp': TimeStamp, "bool": bool}
|
|
59
|
+
DTYPES_INV = {v: k for k, v in DTYPES.items()}
|
|
59
60
|
|
|
60
61
|
def __init__(self, name, value, **kwargs):
|
|
61
62
|
"""Attribute
|
|
@@ -158,6 +159,8 @@ s
|
|
|
158
159
|
"""
|
|
159
160
|
if value is None:
|
|
160
161
|
return None
|
|
162
|
+
if value in self.DTYPES_INV.keys():
|
|
163
|
+
value = self.DTYPES_INV.get(value, "str")
|
|
161
164
|
elif "float" in value:
|
|
162
165
|
value = "float"
|
|
163
166
|
elif "int" in value:
|
|
@@ -259,7 +262,7 @@ class Metadata(object):
|
|
|
259
262
|
* type (int, str, float, bool, timestamp)
|
|
260
263
|
"""
|
|
261
264
|
|
|
262
|
-
ATTRIBUTEKEYS = ["name", "value", "
|
|
265
|
+
ATTRIBUTEKEYS = ["name", "value", "unit", "dtype", "description", "label", "required"]
|
|
263
266
|
|
|
264
267
|
def __init__(self, **kwargs):
|
|
265
268
|
"""Metadata class
|
|
@@ -307,7 +310,7 @@ class Metadata(object):
|
|
|
307
310
|
attr = name # name is the Attribute!
|
|
308
311
|
else:
|
|
309
312
|
attr = self.get_attr(prefix + name) or Attribute(name, value, **kwargs)
|
|
310
|
-
for key in ["
|
|
313
|
+
for key in ["unit", "dtype", "description", "label", "required"]:
|
|
311
314
|
if key in kwargs:
|
|
312
315
|
if key in kwargs:
|
|
313
316
|
# print("!!!", attr, key, kwargs.get(key))
|
|
@@ -355,16 +358,21 @@ class Metadata(object):
|
|
|
355
358
|
pass
|
|
356
359
|
return str(value), "str"
|
|
357
360
|
|
|
358
|
-
def update_from_dict(self, d):
|
|
361
|
+
def update_from_dict(self, d, guess_dtype=True):
|
|
359
362
|
"""set attributes from dict
|
|
360
363
|
|
|
361
364
|
:param d: dict
|
|
362
365
|
:return:
|
|
363
366
|
"""
|
|
364
367
|
for k, v in d.items():
|
|
365
|
-
|
|
368
|
+
if guess_dtype is False:
|
|
369
|
+
value = v
|
|
370
|
+
dtype = None
|
|
371
|
+
else:
|
|
372
|
+
value, dtype = self.guess_dtype_from_value(v)
|
|
366
373
|
if dtype in ["float", "int", "bool"]:
|
|
367
|
-
v = {"name":k, "value":value
|
|
374
|
+
v = {"name":k, "value":value}
|
|
375
|
+
# v = {"name":k, "value":value, "dtype":dtype, "unit":"", "description":"", "label":"", "required":False}
|
|
368
376
|
elif isinstance(v, (str,)):
|
|
369
377
|
v = {"name":k, "value":v, "dtype":"str", "unit":"", "description":"", "label":"", "required":False}
|
|
370
378
|
elif hasattr(v, "keys"):
|
|
@@ -375,7 +383,8 @@ class Metadata(object):
|
|
|
375
383
|
"label":v.get("label", ""), "required":v.get("required", False)}
|
|
376
384
|
else:
|
|
377
385
|
v, dtype = self.guess_dtype_from_value(v)
|
|
378
|
-
v = {"name":k, "value":v, "dtype":dtype, "unit":"", "description":"", "label":"", "required":False}
|
|
386
|
+
# v = {"name":k, "value":v, "dtype":dtype, "unit":"", "description":"", "label":"", "required":False}
|
|
387
|
+
v = {"name":k, "value":v, "dtype":dtype}
|
|
379
388
|
self.set_attr(**v)
|
|
380
389
|
|
|
381
390
|
@classmethod
|
|
@@ -449,6 +458,9 @@ class Metadata(object):
|
|
|
449
458
|
@classmethod
|
|
450
459
|
def from_dataframe(cls, df):
|
|
451
460
|
"""create metadata from dataframe"""
|
|
461
|
+
df.unit.fillna("", inplace=True)
|
|
462
|
+
df.label.fillna("", inplace=True)
|
|
463
|
+
df.description.fillna("", inplace=True)
|
|
452
464
|
d = df.to_dict(orient='index')
|
|
453
465
|
metadata = cls.from_dict(d)
|
|
454
466
|
return metadata
|
|
@@ -533,17 +545,17 @@ class Metadata(object):
|
|
|
533
545
|
def from_list(cls, mlist):
|
|
534
546
|
"""create metadata from a list of Attribute values
|
|
535
547
|
|
|
536
|
-
[['force_x', 1.2, '
|
|
537
|
-
['force_y', 3.1, '
|
|
548
|
+
[['force_x', 1.2, 'kN', 'float', 'force in x-direction'],
|
|
549
|
+
['force_y', 3.1, 'N', 'float', 'force in y-direction', 'label', True]]
|
|
538
550
|
"""
|
|
539
551
|
metadata = cls()
|
|
540
552
|
for alist in mlist:
|
|
541
553
|
if len(alist) < 2:
|
|
542
554
|
logger.error("Metadata.from_list skip {}".format(alist))
|
|
543
555
|
else:
|
|
544
|
-
alist.extend(["", "", "", ""])
|
|
545
|
-
#["name", "value", "
|
|
546
|
-
metadata.add(alist[0], alist[1],
|
|
556
|
+
alist.extend(["", "", "", "", ""])
|
|
557
|
+
#["name", "value", "unit", "dtype", "description", "label", "required"]
|
|
558
|
+
metadata.add(alist[0], alist[1], unit=alist[2], dtype=alist[3], description=alist[4],
|
|
547
559
|
label=alist[5], required=alist[6])
|
|
548
560
|
return metadata
|
|
549
561
|
|
|
@@ -618,6 +630,31 @@ class Metadata(object):
|
|
|
618
630
|
def __getitem__(self, name):
|
|
619
631
|
return self.get(name)
|
|
620
632
|
|
|
633
|
+
def __setitem__(self, name, value):
|
|
634
|
+
"""update value in Attribute or create new Attribute"""
|
|
635
|
+
attr = self.get(name)
|
|
636
|
+
|
|
637
|
+
if attr is None:
|
|
638
|
+
attr = Attribute(name=name, value=value, dtype=type(value).__name__)
|
|
639
|
+
self._attributes[attr.name] = attr
|
|
640
|
+
else:
|
|
641
|
+
dtype = attr.guess_dtype(value)
|
|
642
|
+
attr.dtype = dtype
|
|
643
|
+
attr.value = dtype(value)
|
|
644
|
+
|
|
645
|
+
def __contains__(self, item):
|
|
646
|
+
return item in self.attributes.keys()
|
|
647
|
+
|
|
648
|
+
def pop(self, item):
|
|
649
|
+
try:
|
|
650
|
+
return self._attributes.pop(item)
|
|
651
|
+
except KeyError as exp:
|
|
652
|
+
return None
|
|
653
|
+
|
|
654
|
+
def __iter__(self):
|
|
655
|
+
for x in self.attributes.items():
|
|
656
|
+
yield x
|
|
657
|
+
|
|
621
658
|
@property
|
|
622
659
|
def sha3_256(self):
|
|
623
660
|
"""Return a new SHA3 hash object with a hashbit length of 32 bytes.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import uuid
|
|
2
2
|
import base64
|
|
3
3
|
import hashlib
|
|
4
|
+
import os
|
|
4
5
|
|
|
5
6
|
"""
|
|
6
7
|
SUUID
|
|
@@ -54,7 +55,14 @@ class SUUID:
|
|
|
54
55
|
if name is None:
|
|
55
56
|
name = ""
|
|
56
57
|
|
|
57
|
-
self.name = name
|
|
58
|
+
self.name = self._clean_name(name)
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _clean_name(name):
|
|
62
|
+
rs = ["|", ";"]
|
|
63
|
+
for r in rs:
|
|
64
|
+
name = name.replace(r, "")
|
|
65
|
+
return name
|
|
58
66
|
|
|
59
67
|
def __str__(self):
|
|
60
68
|
return f"({self.class_name}|{self.name}|{self.huuid})"
|
|
@@ -88,6 +96,11 @@ class SUUID:
|
|
|
88
96
|
s = "".join([self.huuid, self.class_name + "|" + self.name])
|
|
89
97
|
return base64.b64encode(s.encode())
|
|
90
98
|
|
|
99
|
+
@property
|
|
100
|
+
def sname(self):
|
|
101
|
+
s = "|".join([self.class_name, self.name, self.huuid])
|
|
102
|
+
return s
|
|
103
|
+
|
|
91
104
|
@property
|
|
92
105
|
def suuid(self):
|
|
93
106
|
s = "".join([self.huuid, self.class_name + "|" + self.name])
|
|
@@ -149,6 +162,7 @@ class SUUID:
|
|
|
149
162
|
:param ns_string: e.g. projectname "MyProject"
|
|
150
163
|
:return: suuid
|
|
151
164
|
"""
|
|
165
|
+
name = cls._clean_name(name)
|
|
152
166
|
uid = cls.get_uuid_from_name(name=name, ns_name=ns_name)
|
|
153
167
|
suuid = cls(class_name=class_name, name=name, huuid=uid.hex)
|
|
154
168
|
return suuid
|
|
@@ -167,6 +181,7 @@ class SUUID:
|
|
|
167
181
|
:param ns_string: e.g. projectname "MyProject"
|
|
168
182
|
:return: suuid
|
|
169
183
|
"""
|
|
184
|
+
name = cls._clean_name(name)
|
|
170
185
|
suuid = cls.from_name(class_name, name=name, ns_name=ns_name)
|
|
171
186
|
return suuid.id
|
|
172
187
|
|
|
@@ -188,7 +203,9 @@ class SUUID:
|
|
|
188
203
|
sh = hashlib.sha3_256()
|
|
189
204
|
with open(filepath, "rb") as fh:
|
|
190
205
|
sh.update(fh.read())
|
|
206
|
+
basename = os.path.basename(filepath)
|
|
191
207
|
suuid = cls.from_name(class_name=class_name, name=sh.hexdigest(), ns_name=ns_name)
|
|
208
|
+
suuid.name = basename
|
|
192
209
|
return suuid
|
|
193
210
|
|
|
194
211
|
@classmethod
|
|
@@ -210,7 +227,7 @@ class SUUID:
|
|
|
210
227
|
@classmethod
|
|
211
228
|
def from_suuid_bytes(cls, bytestring):
|
|
212
229
|
"""
|
|
213
|
-
:param bytestring:
|
|
230
|
+
:param bytestring: 'MTNhNjMxMWNjZDFlNDFiOGI2MzJhNGY0ZTIzMjdiNTFQYXJ0fG15dGVzdG5hbWUwMQ=='
|
|
214
231
|
"""
|
|
215
232
|
id_string = base64.b64decode(bytestring).decode()
|
|
216
233
|
return cls.from_idstr(id_string)
|
|
@@ -218,13 +235,23 @@ class SUUID:
|
|
|
218
235
|
@classmethod
|
|
219
236
|
def from_suuid_str(cls, string):
|
|
220
237
|
"""
|
|
221
|
-
:param string: '
|
|
238
|
+
:param string: 'MTNhNjMxMWNjZDFlNDFiOGI2MzJhNGY0ZTIzMjdiNTFQYXJ0fG15dGVzdG5hbWUwMQ=='
|
|
222
239
|
|
|
223
240
|
"""
|
|
224
241
|
|
|
225
242
|
id_string = base64.b64decode(string.encode()).decode()
|
|
226
243
|
return cls.from_idstr(id_string)
|
|
227
244
|
|
|
245
|
+
|
|
246
|
+
@classmethod
|
|
247
|
+
def from_suuid_sname(cls, s):
|
|
248
|
+
"""
|
|
249
|
+
:param string: 'Part|mytestname01|22a476e75a68486a92764eb830395923'
|
|
250
|
+
|
|
251
|
+
"""
|
|
252
|
+
class_name, name, huuid = s.split("|")
|
|
253
|
+
return cls(class_name=class_name, name=name, huuid=huuid)
|
|
254
|
+
|
|
228
255
|
@classmethod
|
|
229
256
|
def from_idstr(cls, id_string):
|
|
230
257
|
try:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|