dccQuantities 2.0.0.dev1__tar.gz → 2.0.0.dev2__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.
- {dccquantities-2.0.0.dev1/src/dccQuantities.egg-info → dccquantities-2.0.0.dev2}/PKG-INFO +1 -1
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/pyproject.toml +1 -1
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/AbstractListType.py +2 -1
- dccquantities-2.0.0.dev2/src/AbstractQuantityTypeData.py +4 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/AbstractValueType.py +22 -6
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccName.py +1 -1
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccNoQuantity.py +9 -3
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccQuantityTable.py +5 -5
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccQuantityType.py +2 -5
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccRichContentType.py +1 -1
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/SiRealList.py +59 -10
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2/src/dccQuantities.egg-info}/PKG-INFO +1 -1
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/helpers.py +44 -33
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/parseUncertainties.py +5 -4
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_dccName.py +2 -2
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_parser.py +65 -52
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_serilizer.py +2 -2
- dccquantities-2.0.0.dev1/src/AbstractQuantityTypeData.py +0 -10
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/LICENSE +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/MANIFEST.in +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/README.md +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/setup.cfg +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccCharsXMLList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/DccFormulaType.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/SiComplexList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/SiHybrid.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/SiList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/__init__.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/SOURCES.txt +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/dependency_links.txt +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/requires.txt +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/top_level.txt +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantityParser.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/testHelpers.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_DccCharsXMLList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_DccNoQuantity.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_DccQuantityType.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_SiList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_SiRealList.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_SiRealList_parseData.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_SiRealList_toDict.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_generateExampleTableData.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_getAndProperties.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_helpers.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_quantityTypeCollector.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_surfaceFlatTableGeneration.py +0 -0
- {dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_tables.py +0 -0
|
@@ -10,7 +10,7 @@ class AbstractListType(AbstractQuantityTypeData):
|
|
|
10
10
|
def __init__(self, children: list[Union[AbstractListType,AbstractValueType]]) -> None:
|
|
11
11
|
super().__init__()
|
|
12
12
|
self.children = children
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
def toJsonDict(self):
|
|
15
15
|
result = defaultdict(list)
|
|
16
16
|
for child in self.children:
|
|
@@ -19,6 +19,7 @@ class AbstractListType(AbstractQuantityTypeData):
|
|
|
19
19
|
result[key].append(value)
|
|
20
20
|
return dict(result)
|
|
21
21
|
|
|
22
|
+
|
|
22
23
|
def flatten(self):
|
|
23
24
|
pass
|
|
24
25
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from dsiUnits import dsiUnit
|
|
3
|
+
from numpy.core.defchararray import endswith
|
|
3
4
|
|
|
4
5
|
from AbstractQuantityTypeData import AbstractQuantityTypeData
|
|
5
6
|
from typing import Union #for python 3.8/3.9 compatibility
|
|
@@ -59,7 +60,7 @@ class AbstractValueType(AbstractQuantityTypeData):
|
|
|
59
60
|
flattValues = vec_values(flattarray)[0]
|
|
60
61
|
flattUncs = vec_uncs(flattarray)[0]
|
|
61
62
|
# okay now we can create the json
|
|
62
|
-
suffix = "" if length ==1 else "XMLList"
|
|
63
|
+
suffix = "" if length ==1 and not self._originType.endswith('XMLList') else "XMLList"
|
|
63
64
|
resultjson = {"si:value"+suffix: flattValues,}
|
|
64
65
|
if flattUncs and self._uncInfo != None:
|
|
65
66
|
kfactor=self._uncInfo['coverageFactor']
|
|
@@ -72,18 +73,33 @@ class AbstractValueType(AbstractQuantityTypeData):
|
|
|
72
73
|
distribution=distribution[0]
|
|
73
74
|
if not np.all(kfactor==1.0):
|
|
74
75
|
# we should create expanded uncs now
|
|
76
|
+
|
|
77
|
+
if not "originalUnc" in self._uncInfo:
|
|
78
|
+
# we had no original uncer so wie calculate expanded unc
|
|
79
|
+
uncValues=(np.array(flattUncs) * kfactor).tolist()
|
|
80
|
+
if suffix=='':
|
|
81
|
+
try:
|
|
82
|
+
uncValues=uncValues[0]
|
|
83
|
+
except TypeError:
|
|
84
|
+
# if we cant suscribe it it must be int or float
|
|
85
|
+
pass
|
|
86
|
+
else:
|
|
87
|
+
uncValues=self._uncInfo["originalUnc"]
|
|
88
|
+
if suffix=='':
|
|
89
|
+
try:
|
|
90
|
+
uncValues=uncValues[0]
|
|
91
|
+
except TypeError:
|
|
92
|
+
# if we cant suscribe it it must be int or float
|
|
93
|
+
pass
|
|
94
|
+
|
|
75
95
|
resultjson["si:measurementUncertaintyUnivariate"+suffix] = {
|
|
76
96
|
"si:expandedMU"+suffix:{
|
|
97
|
+
"si:valueExpandedMU" + suffix:uncValues,
|
|
77
98
|
"si:coverageFactor"+suffix:kfactor,
|
|
78
99
|
"si:coverageProbability"+suffix:covP,
|
|
79
100
|
"si:distribution"+suffix:distribution
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
|
-
if not "originalUnc" in self._uncInfo:
|
|
83
|
-
# we had no original uncer so wie calculate expanded unc
|
|
84
|
-
resultjson["si:measurementUncertaintyUnivariate"+suffix]["si:valueExpandedMU" + suffix]= (np.array(flattUncs) * kfactor).tolist()
|
|
85
|
-
else:
|
|
86
|
-
resultjson["si:measurementUncertaintyUnivariate" + suffix]["si:valueExpandedMU" + suffix]=self._uncInfo["originalUnc"]
|
|
87
103
|
else:
|
|
88
104
|
resultjson["si:measurementUncertaintyUnivariate"+suffix] = {
|
|
89
105
|
"si:standardMU"+suffix:{
|
|
@@ -67,7 +67,7 @@ class DccName(dict):
|
|
|
67
67
|
else:
|
|
68
68
|
raise TypeError(f"Unsupported type {type(other)} for matching")
|
|
69
69
|
|
|
70
|
-
def
|
|
70
|
+
def to_json_dict(self):
|
|
71
71
|
return {'dcc:name':{'dcc:content': [{'@lang': key, '$': value} for key, value in dict(self).items()]}}
|
|
72
72
|
|
|
73
73
|
def merge_names(self, insertion: str, other: Union['DccName', str, float, int, None]):
|
|
@@ -11,7 +11,6 @@ from DccRichContentType import (
|
|
|
11
11
|
)
|
|
12
12
|
from DccName import DccName
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
class DccNoQuantity(AbstractQuantityTypeData):
|
|
16
15
|
def __init__(
|
|
17
16
|
self,
|
|
@@ -48,8 +47,9 @@ class DccNoQuantity(AbstractQuantityTypeData):
|
|
|
48
47
|
if len(paramStr) > 0:
|
|
49
48
|
paramStr = " (" + paramStr + ")"
|
|
50
49
|
return f"{str(self.data)}{paramStr}"
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
def toJsonDict(self) -> dict:
|
|
52
|
+
privateKeys=['_sorted']
|
|
53
53
|
keyMapping = {
|
|
54
54
|
'id': '@id',
|
|
55
55
|
'refId': '@refId',
|
|
@@ -68,9 +68,15 @@ class DccNoQuantity(AbstractQuantityTypeData):
|
|
|
68
68
|
elif key == 'data':
|
|
69
69
|
for key, value in self.data.items():
|
|
70
70
|
if value is not None:
|
|
71
|
-
|
|
71
|
+
if isinstance(value,list):
|
|
72
|
+
if len(value) >0: #skip empty lists
|
|
73
|
+
result[dataKeyMapping[key]] = []
|
|
74
|
+
for item in value:
|
|
75
|
+
result[dataKeyMapping[key]].append(item.toJSONDict())
|
|
72
76
|
if set(self.data.keys()) - set(dataKeyMapping.keys()):
|
|
73
77
|
pass # TODO: This should not happen, maybe add a warning?
|
|
78
|
+
elif key in privateKeys:
|
|
79
|
+
pass
|
|
74
80
|
else:
|
|
75
81
|
# Use the fallback handler for unexpected keys.
|
|
76
82
|
unexpected_key_serialization_handler(result, key, value, self.__class__.__name__)
|
|
@@ -459,7 +459,7 @@ class DccLongTable(DccQuantityTable):
|
|
|
459
459
|
FieldSpec(
|
|
460
460
|
name=None,
|
|
461
461
|
tag="dcc:name",
|
|
462
|
-
serializer=lambda s: s.name.
|
|
462
|
+
serializer=lambda s: s.name.to_json_dict()["dcc:name"] if s.name else None
|
|
463
463
|
),
|
|
464
464
|
|
|
465
465
|
# 2. description
|
|
@@ -606,7 +606,7 @@ class DccLongTable(DccQuantityTable):
|
|
|
606
606
|
all_quants = idxs + vals
|
|
607
607
|
|
|
608
608
|
return [
|
|
609
|
-
q.
|
|
609
|
+
q.to_json_dict()
|
|
610
610
|
for q in all_quants
|
|
611
611
|
]
|
|
612
612
|
|
|
@@ -637,7 +637,7 @@ class DccFlatTable(DccQuantityTable):
|
|
|
637
637
|
FieldSpec(
|
|
638
638
|
name=None,
|
|
639
639
|
tag="dcc:name",
|
|
640
|
-
serializer=lambda s: s.name.
|
|
640
|
+
serializer=lambda s: s.name.to_json_dict()["dcc:name"] if s.name else None
|
|
641
641
|
),
|
|
642
642
|
|
|
643
643
|
# 2. description
|
|
@@ -745,12 +745,12 @@ class DccFlatTable(DccQuantityTable):
|
|
|
745
745
|
"""
|
|
746
746
|
# helper to build one wrapper
|
|
747
747
|
def make_wrapper(title: dict, ref_type: list[str], quants: list):
|
|
748
|
-
wrapper = DccName(title).
|
|
748
|
+
wrapper = DccName(title).to_json_dict() # yields {'dcc:name': ...}
|
|
749
749
|
wrapper["@refType"] = ref_type
|
|
750
750
|
# each quant.toJsonDict() returns {'dcc:quantity': {...}}
|
|
751
751
|
# we pull out that inner dict
|
|
752
752
|
wrapper["dcc:quantity"] = [
|
|
753
|
-
q.
|
|
753
|
+
q.to_json_dict() for q in quants
|
|
754
754
|
]
|
|
755
755
|
return wrapper
|
|
756
756
|
|
|
@@ -28,7 +28,7 @@ class DccQuantityType(ExplicitSerializerMixin):
|
|
|
28
28
|
FieldSpec(
|
|
29
29
|
name=None,
|
|
30
30
|
tag="dcc:name",
|
|
31
|
-
serializer=lambda s: s.name.
|
|
31
|
+
serializer=lambda s: s.name.to_json_dict()["dcc:name"]
|
|
32
32
|
),
|
|
33
33
|
|
|
34
34
|
# 2. description (raw dict under 'dcc:description')
|
|
@@ -223,7 +223,4 @@ class DccQuantityType(ExplicitSerializerMixin):
|
|
|
223
223
|
"""
|
|
224
224
|
Wrap the ordered fields under the <dcc:quantity> root.
|
|
225
225
|
"""
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
# keep backwards‐compatibility if code calls toJsonDict()
|
|
229
|
-
toJsonDict = to_json_dict
|
|
226
|
+
return self.to_dict()
|
|
@@ -14,28 +14,47 @@ from parseUncertainties import parseUncertainties, uncertaintyKeys
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
from helpers import FieldSpec,ExplicitSerializerMixin
|
|
16
16
|
|
|
17
|
-
|
|
18
17
|
class SiRealList(ExplicitSerializerMixin,AbstractValueType):
|
|
19
|
-
# 1)
|
|
18
|
+
# 1) Specs for the single‐value form
|
|
20
19
|
__single_specs__ = [
|
|
21
|
-
#
|
|
20
|
+
# optional label first
|
|
22
21
|
FieldSpec("label", "si:label",
|
|
23
22
|
lambda s: s.label[0] if isinstance(s.label, list) else s.label),
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
|
|
24
|
+
# raw value
|
|
25
|
+
FieldSpec(None, "si:value", "serialize_value", merge=False),
|
|
26
|
+
|
|
27
|
+
# unit
|
|
26
28
|
FieldSpec("unit", "si:unit",
|
|
27
29
|
lambda s: str(s.unit[0])),
|
|
30
|
+
|
|
31
|
+
# timestamp
|
|
28
32
|
FieldSpec("dateTime", "si:dateTime",
|
|
29
33
|
lambda s: s.dateTime[0] if isinstance(s.dateTime, list) else s.dateTime),
|
|
34
|
+
|
|
35
|
+
# then any measurementUncertainty…
|
|
36
|
+
FieldSpec(None, "si:measurementUncertaintyUnivariate",
|
|
37
|
+
"serialize_unc", merge=True),
|
|
30
38
|
]
|
|
39
|
+
# For unkown reason the order of sireal and sireallist ist not consitent, WTF!
|
|
31
40
|
|
|
32
|
-
# 2)
|
|
41
|
+
# 2) Specs for the list‐value form
|
|
33
42
|
__list_specs__ = [
|
|
34
|
-
|
|
35
|
-
FieldSpec("
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
# optional label list
|
|
44
|
+
FieldSpec("label", "si:labelXMLList", lambda s: s.label),
|
|
45
|
+
|
|
46
|
+
# array of values
|
|
47
|
+
FieldSpec(None, "si:valueXMLList", "serialize_value", merge=False),
|
|
48
|
+
|
|
49
|
+
# list‐unit
|
|
50
|
+
FieldSpec("unit", "si:unitXMLList", lambda s: [str(u) for u in s.unit]),
|
|
38
51
|
|
|
52
|
+
# optional timestamp list
|
|
53
|
+
FieldSpec("dateTime", "si:dateTimeXMLList", lambda s: s.dateTime),
|
|
54
|
+
|
|
55
|
+
# then any list‐uncertainty
|
|
56
|
+
FieldSpec(None, "si:measurementUncertaintyUnivariateXMLList",
|
|
57
|
+
"serialize_unc", merge=True),
|
|
39
58
|
]
|
|
40
59
|
|
|
41
60
|
def __init__(
|
|
@@ -173,6 +192,36 @@ class SiRealList(ExplicitSerializerMixin,AbstractValueType):
|
|
|
173
192
|
# 3) Wrap under the correct root element
|
|
174
193
|
return {root: ordered}
|
|
175
194
|
|
|
195
|
+
# ————— helper methods for those specs —————
|
|
196
|
+
|
|
197
|
+
def serialize_value(self):
|
|
198
|
+
"""
|
|
199
|
+
Return just the flattened 'si:value' or 'si:valueXMLList' entry
|
|
200
|
+
from serilizeDataToJSON().
|
|
201
|
+
"""
|
|
202
|
+
if not hasattr(self,'_data'):
|
|
203
|
+
self._data = self.serilizeDataToJSON()
|
|
204
|
+
for key, val in self._data.items():
|
|
205
|
+
if key.startswith("si:value"):
|
|
206
|
+
return val
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
def serialize_unc(self):
|
|
210
|
+
"""
|
|
211
|
+
Return only the uncertainty sub-dict (everything *except* the 'si:value…'
|
|
212
|
+
keys) from serilizeDataToJSON(), so it merges in the correct position.
|
|
213
|
+
"""
|
|
214
|
+
# we dont need to copy since unc will allways call after the values ...
|
|
215
|
+
if not hasattr(self, '_data'):
|
|
216
|
+
self._data = self.serilizeDataToJSON()
|
|
217
|
+
for key in list(self._data.keys()):
|
|
218
|
+
if key.startswith("si:value"):
|
|
219
|
+
self._data.pop(key)
|
|
220
|
+
out=deepcopy(self._data)
|
|
221
|
+
del self._data
|
|
222
|
+
#we will delete '_data' since we don't need it anymore ... if we serialize again, we will create it again completely to prevent race conditions ...
|
|
223
|
+
return out
|
|
224
|
+
|
|
176
225
|
def __neg__(self):
|
|
177
226
|
new_data = [-item for item in self.data]
|
|
178
227
|
return SiRealList(
|
|
@@ -33,10 +33,15 @@ _REGEX_TYPE = type(re.compile(''))
|
|
|
33
33
|
class DCCJSONEncoder(json.JSONEncoder):
|
|
34
34
|
def default(self, obj):
|
|
35
35
|
# If the object has a callable toJSON method, use it.
|
|
36
|
+
if hasattr(obj, 'to_json_dict') and callable(obj.to_json_dict):
|
|
37
|
+
return obj.to_json_dict()
|
|
38
|
+
|
|
36
39
|
if hasattr(obj, 'toJSONDict') and callable(obj.toJSONDict):
|
|
37
40
|
return obj.toJSONDict()
|
|
41
|
+
|
|
38
42
|
elif hasattr(obj, 'toJSON') and callable(obj.toJSON):
|
|
39
43
|
return obj.toJSON()
|
|
44
|
+
|
|
40
45
|
elif isinstance(obj, dsiUnit):
|
|
41
46
|
return str(obj)
|
|
42
47
|
# 3a) explicit DateTime10
|
|
@@ -79,42 +84,48 @@ class ExplicitSerializerMixin:
|
|
|
79
84
|
"""
|
|
80
85
|
out = OrderedDict()
|
|
81
86
|
for spec in self.__serialize_fields__:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
try:
|
|
88
|
+
# Determine raw value
|
|
89
|
+
if spec.serializer is None:
|
|
90
|
+
val = getattr(self, spec.name, None)
|
|
91
|
+
elif isinstance(spec.serializer, tuple):
|
|
92
|
+
method, key = spec.serializer
|
|
93
|
+
temp = getattr(self, method)() if isinstance(method, str) else method(self)
|
|
94
|
+
val = temp.get(key) if isinstance(temp, dict) else None
|
|
95
|
+
elif isinstance(spec.serializer, str):
|
|
96
|
+
val = getattr(self, spec.serializer)()
|
|
97
|
+
else:
|
|
98
|
+
val = spec.serializer(self)
|
|
99
|
+
|
|
100
|
+
# Skip None or empty collections/arrays
|
|
101
|
+
if val is None:
|
|
102
|
+
continue
|
|
103
|
+
if isinstance(val, (list, tuple, dict, set)) and len(val) == 0:
|
|
104
|
+
continue
|
|
105
|
+
if isinstance(val, np.ndarray) and val.size == 0:
|
|
106
|
+
continue
|
|
107
|
+
|
|
108
|
+
# Merge dict or assign directly
|
|
109
|
+
if spec.merge:
|
|
110
|
+
if not isinstance(val, dict):
|
|
111
|
+
raise ValueError(f"Field {spec.name} expected to merge a dict, got {type(val)}")
|
|
112
|
+
for k, v in val.items():
|
|
113
|
+
if v in [None, [], {}, (), set()] or (isinstance(v, np.ndarray) and v.size == 0):
|
|
114
|
+
continue
|
|
115
|
+
out[k] = v
|
|
116
|
+
else:
|
|
117
|
+
out[spec.tag or spec.name] = val
|
|
93
118
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
119
|
+
except Exception as e:
|
|
120
|
+
# Silently skip common NoneType attribute access errors (e.g., s.name.to_json_dict())
|
|
121
|
+
if isinstance(e, AttributeError) and "'NoneType'" in str(e):
|
|
122
|
+
continue
|
|
123
|
+
warnings.warn(
|
|
124
|
+
f"Serialization of field {spec.name or spec.tag} failed in {self.__class__.__name__}: {e}",
|
|
125
|
+
RuntimeWarning
|
|
126
|
+
)
|
|
100
127
|
continue
|
|
101
128
|
|
|
102
|
-
# Merge dict or assign directly
|
|
103
|
-
if spec.merge:
|
|
104
|
-
if not isinstance(val, dict):
|
|
105
|
-
raise ValueError(f"Field {spec.name} expected to merge a dict, got {type(val)}")
|
|
106
|
-
for k, v in val.items():
|
|
107
|
-
# Also treat any empty collections in merged dict as skip
|
|
108
|
-
if v is None:
|
|
109
|
-
continue
|
|
110
|
-
if isinstance(v, (list, tuple, dict, set)) and len(v) == 0:
|
|
111
|
-
continue
|
|
112
|
-
if isinstance(v, np.ndarray) and v.size == 0:
|
|
113
|
-
continue
|
|
114
|
-
out[k] = v
|
|
115
|
-
else:
|
|
116
|
-
out[spec.tag or spec.name] = val
|
|
117
|
-
|
|
118
129
|
return out
|
|
119
130
|
|
|
120
131
|
def to_json_dict(self) -> dict:
|
|
@@ -51,6 +51,7 @@ def parseUncertainties(jsonDict: dict, data: list, relativeUncertainty: dict = N
|
|
|
51
51
|
|
|
52
52
|
def parseExpandedUnc(jsonDict: dict, data: list, relativeUncertainty: dict = None):
|
|
53
53
|
uncData = {}
|
|
54
|
+
#TODO we will lose keys if one of the predescending wasn't defined NEDS TO BE CHANGED ASAP
|
|
54
55
|
if "si:expandedUnc" in jsonDict.keys():
|
|
55
56
|
uncJsonData = jsonDict["si:expandedUnc"]
|
|
56
57
|
uncData["uncertainty"] = uncJsonData["si:uncertainty"]
|
|
@@ -73,13 +74,13 @@ def parseExpandedUnc(jsonDict: dict, data: list, relativeUncertainty: dict = Non
|
|
|
73
74
|
)
|
|
74
75
|
elif "si:measurementUncertaintyUnivariate" in jsonDict.keys():
|
|
75
76
|
try:
|
|
76
|
-
uncJsonData = jsonDict["si:measurementUncertaintyUnivariate"]
|
|
77
|
-
uncData["uncertainty"] = uncJsonData[
|
|
77
|
+
uncJsonData = jsonDict["si:measurementUncertaintyUnivariate"]['si:expandedMU']
|
|
78
|
+
uncData["uncertainty"] = uncJsonData['si:valueExpandedMU']
|
|
78
79
|
uncData["coverageFactor"] = uncJsonData["si:coverageFactor"]
|
|
79
80
|
uncData["coverageProbability"] = uncJsonData["si:coverageProbability"]
|
|
80
81
|
uncData["distribution"] = (
|
|
81
|
-
uncJsonData["si:
|
|
82
|
-
if "si:
|
|
82
|
+
uncJsonData["si:distribution"]
|
|
83
|
+
if "si:distribution" in uncJsonData.keys()
|
|
83
84
|
else ["normal"]
|
|
84
85
|
)
|
|
85
86
|
except Exception as e:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from DccName import DccName
|
|
3
3
|
|
|
4
|
-
def
|
|
4
|
+
def test_to_json_dict():
|
|
5
5
|
jsonDict = {'dcc:name':{'dcc:content': [{'@lang': 'en', '$': 'Room temperature during calibration'}, {'@lang': 'de', '$': 'Raumtemperatur währenden der Kalibration'}]}}
|
|
6
6
|
parsedDict = {'en': 'Room temperature during calibration', 'de': 'Raumtemperatur währenden der Kalibration'}
|
|
7
7
|
nameInstance = DccName(parsedDict)
|
|
8
|
-
generatedJsonDict = nameInstance.
|
|
8
|
+
generatedJsonDict = nameInstance.to_json_dict()
|
|
9
9
|
assert jsonDict == generatedJsonDict
|
|
10
10
|
|
|
11
11
|
def test_matches_with_subset_dict():
|
|
@@ -13,6 +13,71 @@ from helpers import replaceQuantitiesInDict,DCCJSONEncoder
|
|
|
13
13
|
from dccXMLJSONConv.dccConv import XMLToDict,DictToXML
|
|
14
14
|
from dccQuantityParser import parseItemFromJsonDict
|
|
15
15
|
from xmlschema import XMLSchemaValidationError
|
|
16
|
+
import copy
|
|
17
|
+
|
|
18
|
+
@pytest.mark.filterwarnings("ignore:Parsing a correctly marked non D-SI unit")
|
|
19
|
+
@pytest.mark.filterwarnings("ignore:The identifier .* does not match any D-SI units!")
|
|
20
|
+
def test_allFilesBackAndForthSer():
|
|
21
|
+
# load our list of known-invalid files
|
|
22
|
+
filePath = get_test_file(
|
|
23
|
+
"tests", "data", "private", "1_7calibrationanddccsampledata",
|
|
24
|
+
"AndereScheine", "grabbedFiles", "validation_results.json"
|
|
25
|
+
)
|
|
26
|
+
dirPath = get_test_file(
|
|
27
|
+
"tests", "data", "private", "1_7calibrationanddccsampledata",
|
|
28
|
+
"AndereScheine", "grabbedFiles")
|
|
29
|
+
with open(filePath, "r") as validationFile:
|
|
30
|
+
validationDict = json.load(validationFile)
|
|
31
|
+
invalidFileNames = [
|
|
32
|
+
"dcc-2019-75056_mod.xml",
|
|
33
|
+
"DCCTableXMLStub.xml",
|
|
34
|
+
"test_xmlDumpingSingleQuantNoUncer.xml",
|
|
35
|
+
"test_dccQuantTabXMLDumping.xml",
|
|
36
|
+
"CalSchein_20220708_8305_SN1842876.xml",
|
|
37
|
+
"dcc-vacuumlab-CDG.xml",
|
|
38
|
+
"acoustics_refTypeDefinition.xml"
|
|
39
|
+
]
|
|
40
|
+
# add any others flagged in the validation results
|
|
41
|
+
invalidFileNames += [
|
|
42
|
+
entry["Invalid File"] for entry in validationDict.values()
|
|
43
|
+
]
|
|
44
|
+
allowed_reason = "value doesn't match any pattern of ['3\\\\.3\\\\.0']"
|
|
45
|
+
# iterate every XML that isn't already known-bad
|
|
46
|
+
#TODO test all files and fix things like quants WO a name
|
|
47
|
+
for fileCount,xmlFile in enumerate(dirPath.rglob("*.xml")):
|
|
48
|
+
#for xmlFile in [get_test_file( "tests", "data", "private", "1_7calibrationanddccsampledata","sinCal","sin_acceleration_example_dcc","sin_acceleration_example_dcc_WithExampleConformatyStatment.xml")]:
|
|
49
|
+
if xmlFile.name in invalidFileNames:
|
|
50
|
+
continue
|
|
51
|
+
with open(xmlFile, "r") as f:
|
|
52
|
+
xml_text = f.read()
|
|
53
|
+
xmlDict, errors = XMLToDict(xml_text)
|
|
54
|
+
# update schema Version brutaly to 3.3.0
|
|
55
|
+
xmlDict['@xsi:schemaLocation']=r'https://ptb.de/dcc https://ptb.de/dcc/v3.3.0/dcc.xsd'
|
|
56
|
+
xmlDict['@schemaVersion'] = '3.3.0'
|
|
57
|
+
|
|
58
|
+
xmlDictcopy=copy.deepcopy(xmlDict)
|
|
59
|
+
|
|
60
|
+
serDict, quantList = replaceQuantitiesInDict(xmlDictcopy, parser=parseItemFromJsonDict,returnQuantityList=True)
|
|
61
|
+
assert len(quantList) > 0
|
|
62
|
+
json_text = json.dumps(serDict, cls=DCCJSONEncoder)
|
|
63
|
+
dictForConversion=json.loads(json_text)
|
|
64
|
+
xml_out, root_elem, errors = DictToXML(dictForConversion)
|
|
65
|
+
assert xml_out, f"No XML produced for {xmlFile.name}"
|
|
66
|
+
# Filter out the one allowed schema‐validation complaint
|
|
67
|
+
remaining = [
|
|
68
|
+
err for err in errors
|
|
69
|
+
if not (
|
|
70
|
+
isinstance(err, XMLSchemaValidationError)
|
|
71
|
+
and err.reason.startswith("value doesn't match any pattern of ")
|
|
72
|
+
)
|
|
73
|
+
]
|
|
74
|
+
# If anything unexpected remains, fail
|
|
75
|
+
assert not remaining, (
|
|
76
|
+
f"Unexpected validation errors in {xmlFile.name}:\n"
|
|
77
|
+
+ "\n".join(f" • {type(err).__name__}: {getattr(err, 'reason', err)}"
|
|
78
|
+
for err in remaining)
|
|
79
|
+
)
|
|
80
|
+
|
|
16
81
|
|
|
17
82
|
def test_parsedQuantValuesAndFunctions(): # Use the correct relative paths
|
|
18
83
|
try:
|
|
@@ -152,55 +217,3 @@ def test_allFiles():
|
|
|
152
217
|
except Exception as e:
|
|
153
218
|
raise e
|
|
154
219
|
|
|
155
|
-
@pytest.mark.filterwarnings("ignore:Parsing a correctly marked non D-SI unit")
|
|
156
|
-
@pytest.mark.filterwarnings("ignore:The identifier .* does not match any D-SI units!")
|
|
157
|
-
def test_allFilesBackAndForthSer():
|
|
158
|
-
# load our list of known-invalid files
|
|
159
|
-
filePath = get_test_file(
|
|
160
|
-
"tests", "data", "private", "1_7calibrationanddccsampledata",
|
|
161
|
-
"AndereScheine", "grabbedFiles", "validation_results.json"
|
|
162
|
-
)
|
|
163
|
-
dirPath = get_test_file(
|
|
164
|
-
"tests", "data", "private", "1_7calibrationanddccsampledata",
|
|
165
|
-
"AndereScheine", "grabbedFiles")
|
|
166
|
-
with open(filePath, "r") as validationFile:
|
|
167
|
-
validationDict = json.load(validationFile)
|
|
168
|
-
invalidFileNames = [
|
|
169
|
-
"dcc-2019-75056_mod.xml",
|
|
170
|
-
"DCCTableXMLStub.xml",
|
|
171
|
-
"test_xmlDumpingSingleQuantNoUncer.xml",
|
|
172
|
-
"test_dccQuantTabXMLDumping.xml",
|
|
173
|
-
"CalSchein_20220708_8305_SN1842876.xml",
|
|
174
|
-
"dcc-vacuumlab-CDG.xml",
|
|
175
|
-
"acoustics_refTypeDefinition.xml"
|
|
176
|
-
]
|
|
177
|
-
# add any others flagged in the validation results
|
|
178
|
-
invalidFileNames += [
|
|
179
|
-
entry["Invalid File"] for entry in validationDict.values()
|
|
180
|
-
]
|
|
181
|
-
allowed_reason = "value doesn't match any pattern of ['3\\\\.3\\\\.0']"
|
|
182
|
-
# iterate every XML that isn't already known-bad
|
|
183
|
-
for xmlFile in dirPath.rglob("*.xml"):
|
|
184
|
-
if xmlFile.name in invalidFileNames:
|
|
185
|
-
continue
|
|
186
|
-
with open(xmlFile, "r") as f:
|
|
187
|
-
xml_text = f.read()
|
|
188
|
-
xmlDict = XMLToDict(xml_text)
|
|
189
|
-
serDict, errors = replaceQuantitiesInDict(xmlDict, parser=parseItemFromJsonDict)
|
|
190
|
-
json_text = json.dumps(serDict, cls=DCCJSONEncoder)
|
|
191
|
-
xml_out, root_elem, errors = DictToXML(json.loads(json_text))
|
|
192
|
-
assert xml_out, f"No XML produced for {xmlFile.name}"
|
|
193
|
-
# Filter out the one allowed schema‐validation complaint
|
|
194
|
-
remaining = [
|
|
195
|
-
err for err in errors
|
|
196
|
-
if not (
|
|
197
|
-
isinstance(err, XMLSchemaValidationError)
|
|
198
|
-
and err.reason.startswith("value doesn't match any pattern of ")
|
|
199
|
-
)
|
|
200
|
-
]
|
|
201
|
-
# If anything unexpected remains, fail
|
|
202
|
-
assert not remaining, (
|
|
203
|
-
f"Unexpected validation errors in {xmlFile.name}:\n"
|
|
204
|
-
+ "\n".join(f" • {type(err).__name__}: {getattr(err, 'reason', err)}"
|
|
205
|
-
for err in remaining)
|
|
206
|
-
)
|
|
@@ -38,12 +38,12 @@ def test_basic():
|
|
|
38
38
|
warnings.warn(str(e))
|
|
39
39
|
serilizedData=[]
|
|
40
40
|
for q in dccQunats:
|
|
41
|
-
serilizedData.append(q.
|
|
41
|
+
serilizedData.append(q.to_json_dict())
|
|
42
42
|
# check if the first key is 'dcc:qunatity'
|
|
43
43
|
for i,serilized in enumerate(serilizedData):
|
|
44
44
|
try:
|
|
45
45
|
jsonSTR=json.dumps(serilized, cls=DCCJSONEncoder)
|
|
46
46
|
except TypeError as te:
|
|
47
47
|
raise te # to catch unimplemented cases
|
|
48
|
-
simplejsonDict=loads(jsonSTR)
|
|
48
|
+
simplejsonDict=loads(jsonSTR)
|
|
49
49
|
inputJSONDict=quantityDict[i][1]
|
|
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
|
{dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/requires.txt
RENAMED
|
File without changes
|
{dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/src/dccQuantities.egg-info/top_level.txt
RENAMED
|
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
|
{dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_generateExampleTableData.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dccquantities-2.0.0.dev1 → dccquantities-2.0.0.dev2}/tests/test_surfaceFlatTableGeneration.py
RENAMED
|
File without changes
|
|
File without changes
|