pyetp 0.0.39__py3-none-any.whl → 0.0.43__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.
- pyetp/__init__.py +10 -2
- pyetp/_version.py +34 -0
- pyetp/client.py +561 -620
- pyetp/config.py +9 -10
- pyetp/{resqml_objects/__init__.py → resqml_objects.py} +82 -72
- pyetp/types.py +130 -93
- pyetp/uri.py +28 -16
- pyetp/utils_arrays.py +224 -98
- pyetp/utils_xml.py +44 -678
- pyetp-0.0.43.dist-info/METADATA +88 -0
- pyetp-0.0.43.dist-info/RECORD +21 -0
- {pyetp-0.0.39.dist-info → pyetp-0.0.43.dist-info}/WHEEL +2 -1
- pyetp-0.0.43.dist-info/top_level.txt +2 -0
- resqml_objects/__init__.py +7 -0
- resqml_objects/epc_readers.py +114 -0
- resqml_objects/parsers.py +12 -0
- resqml_objects/serializers.py +10 -0
- resqml_objects/v201/__init__.py +1847 -0
- {pyetp/resqml_objects → resqml_objects/v201}/generated.py +2244 -2185
- resqml_objects/v201/utils.py +46 -0
- pyetp/utils.py +0 -15
- pyetp-0.0.39.dist-info/METADATA +0 -56
- pyetp-0.0.39.dist-info/RECORD +0 -14
- {pyetp-0.0.39.dist-info → pyetp-0.0.43.dist-info/licenses}/LICENSE.md +0 -0
pyetp/uri.py
CHANGED
|
@@ -4,8 +4,8 @@ from uuid import UUID
|
|
|
4
4
|
from etpproto.uri import DataObjectURI as _DataObjectURI
|
|
5
5
|
from etpproto.uri import DataspaceUri as _DataspaceURI
|
|
6
6
|
from pydantic import BaseConfig
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
import resqml_objects.v201 as ro
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class _Mixin:
|
|
@@ -21,7 +21,10 @@ class _Mixin:
|
|
|
21
21
|
|
|
22
22
|
@classmethod
|
|
23
23
|
def __modify_schema__(cls, field_schema):
|
|
24
|
-
field_schema.update(
|
|
24
|
+
field_schema.update(
|
|
25
|
+
type="url",
|
|
26
|
+
example="eml:///dataspace('my/space')/resqml20.ObjectName(5fe90ad4-6d34-4f73-a72d-992b26f8442e)",
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
@classmethod
|
|
27
30
|
def __get_validators__(cls):
|
|
@@ -38,7 +41,6 @@ class _Mixin:
|
|
|
38
41
|
|
|
39
42
|
|
|
40
43
|
class DataspaceURI(_DataspaceURI, _Mixin):
|
|
41
|
-
|
|
42
44
|
@classmethod
|
|
43
45
|
def from_name(cls, name: str):
|
|
44
46
|
return cls(f"eml:///dataspace('{name}')")
|
|
@@ -50,36 +52,46 @@ class DataspaceURI(_DataspaceURI, _Mixin):
|
|
|
50
52
|
if isinstance(v, DataObjectURI):
|
|
51
53
|
return cls.from_name(v.dataspace)
|
|
52
54
|
if isinstance(v, str):
|
|
53
|
-
if v.startswith(
|
|
54
|
-
return
|
|
55
|
+
if v.startswith("eml://"):
|
|
56
|
+
return (
|
|
57
|
+
cls(v)
|
|
58
|
+
if v.endswith("')")
|
|
59
|
+
else cls.from_name(DataObjectURI(v).dataspace)
|
|
60
|
+
)
|
|
55
61
|
else:
|
|
56
62
|
return cls.from_name(v)
|
|
57
63
|
raise TypeError(f"Type {type(v)} not supported dataspace uri")
|
|
58
64
|
|
|
59
65
|
|
|
60
66
|
class DataObjectURI(_DataObjectURI, _Mixin):
|
|
61
|
-
|
|
62
67
|
@classmethod
|
|
63
|
-
def from_parts(
|
|
68
|
+
def from_parts(
|
|
69
|
+
cls,
|
|
70
|
+
duri: Union[DataspaceURI, str],
|
|
71
|
+
domain_and_version: str,
|
|
72
|
+
obj_type: str,
|
|
73
|
+
uuid: Union[UUID, str],
|
|
74
|
+
):
|
|
64
75
|
duri = DataspaceURI.from_any(duri)
|
|
65
76
|
return cls(f"{duri}/{domain_and_version}.{obj_type}({uuid})")
|
|
66
77
|
|
|
67
78
|
@classmethod
|
|
68
|
-
def from_obj(cls, dataspace: Union[DataspaceURI
|
|
69
|
-
|
|
79
|
+
def from_obj(cls, dataspace: Union[DataspaceURI, str], obj: ro.AbstractObject):
|
|
70
80
|
objname = obj.__class__.__name__
|
|
71
|
-
if getattr(obj,
|
|
72
|
-
namespace: str = getattr(obj.Meta,
|
|
81
|
+
if getattr(obj, "Meta", None):
|
|
82
|
+
namespace: str = getattr(obj.Meta, "namespace", None) or getattr(
|
|
83
|
+
obj.Meta, "target_namespace"
|
|
84
|
+
)
|
|
73
85
|
namespace = namespace.lower()
|
|
74
86
|
# TODO: we can rather look at citation.format - which could be used for xmlformat ? - however to be backward capatiable we check namespaces instead
|
|
75
|
-
if namespace.endswith(
|
|
87
|
+
if namespace.endswith("resqmlv2"):
|
|
76
88
|
domain = "resqml20"
|
|
77
|
-
elif namespace.endswith(
|
|
89
|
+
elif namespace.endswith("data/commonv2"):
|
|
78
90
|
domain = "eml20"
|
|
79
91
|
else:
|
|
80
92
|
raise TypeError(f"Could not parse domain from namespace ({namespace})")
|
|
81
93
|
else:
|
|
82
|
-
domain = "eml20" # fallback to eml20 for backwards compatibility.
|
|
94
|
+
domain = "eml20" # fallback to eml20 for backwards compatibility.
|
|
83
95
|
|
|
84
96
|
return cls.from_parts(dataspace, domain, objname, obj.uuid)
|
|
85
97
|
|
|
@@ -87,5 +99,5 @@ class DataObjectURI(_DataObjectURI, _Mixin):
|
|
|
87
99
|
BaseConfig.json_encoders = {
|
|
88
100
|
DataspaceURI: lambda v: str(v),
|
|
89
101
|
DataObjectURI: lambda v: str(v),
|
|
90
|
-
**BaseConfig.json_encoders
|
|
102
|
+
**BaseConfig.json_encoders,
|
|
91
103
|
}
|
pyetp/utils_arrays.py
CHANGED
|
@@ -1,134 +1,260 @@
|
|
|
1
|
-
|
|
2
1
|
import typing as T
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
5
|
-
|
|
6
|
-
from
|
|
4
|
+
import numpy.typing as npt
|
|
5
|
+
from etptypes.energistics.etp.v12.datatypes.any_array import AnyArray
|
|
6
|
+
from etptypes.energistics.etp.v12.datatypes.any_array_type import AnyArrayType
|
|
7
|
+
from etptypes.energistics.etp.v12.datatypes.any_logical_array_type import (
|
|
8
|
+
AnyLogicalArrayType,
|
|
9
|
+
)
|
|
10
|
+
from etptypes.energistics.etp.v12.datatypes.array_of_boolean import ArrayOfBoolean
|
|
11
|
+
from etptypes.energistics.etp.v12.datatypes.array_of_double import ArrayOfDouble
|
|
12
|
+
from etptypes.energistics.etp.v12.datatypes.array_of_float import ArrayOfFloat
|
|
13
|
+
from etptypes.energistics.etp.v12.datatypes.array_of_int import ArrayOfInt
|
|
14
|
+
from etptypes.energistics.etp.v12.datatypes.array_of_long import ArrayOfLong
|
|
15
|
+
from etptypes.energistics.etp.v12.datatypes.data_array_types.data_array import (
|
|
16
|
+
DataArray,
|
|
17
|
+
)
|
|
18
|
+
from etptypes.energistics.etp.v12.datatypes.data_array_types.data_array_metadata import (
|
|
19
|
+
DataArrayMetadata,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
SUPPORTED_ARRAY_TYPES: T.TypeAlias = (
|
|
23
|
+
ArrayOfFloat | ArrayOfBoolean | ArrayOfInt | ArrayOfLong | ArrayOfDouble
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# See section 13.2.2.1 for the allowed mapping between logical array types and
|
|
28
|
+
# transport array types.
|
|
29
|
+
# NOTE: Currently the logical-array-mapping does not work on the
|
|
30
|
+
# open-etp-server. We write the relevant logical array type, but we only get
|
|
31
|
+
# AnyLogicalArrayType.ARRAY_OF_BOOLEAN in return from the server.
|
|
32
|
+
_ANY_LOGICAL_ARRAY_TYPE_MAP: dict[npt.DTypeLike, AnyLogicalArrayType] = {
|
|
33
|
+
np.dtype(np.bool_): AnyLogicalArrayType.ARRAY_OF_BOOLEAN,
|
|
34
|
+
np.dtype(np.int8): AnyLogicalArrayType.ARRAY_OF_INT8,
|
|
35
|
+
np.dtype(np.uint8): AnyLogicalArrayType.ARRAY_OF_UINT8,
|
|
36
|
+
np.dtype("<i2"): AnyLogicalArrayType.ARRAY_OF_INT16_LE,
|
|
37
|
+
np.dtype("<i4"): AnyLogicalArrayType.ARRAY_OF_INT32_LE,
|
|
38
|
+
np.dtype("<i8"): AnyLogicalArrayType.ARRAY_OF_INT64_LE,
|
|
39
|
+
np.dtype("<u2"): AnyLogicalArrayType.ARRAY_OF_UINT16_LE,
|
|
40
|
+
np.dtype("<u4"): AnyLogicalArrayType.ARRAY_OF_UINT32_LE,
|
|
41
|
+
np.dtype("<u8"): AnyLogicalArrayType.ARRAY_OF_UINT64_LE,
|
|
42
|
+
np.dtype("<f4"): AnyLogicalArrayType.ARRAY_OF_FLOAT32_LE,
|
|
43
|
+
np.dtype("<f8"): AnyLogicalArrayType.ARRAY_OF_DOUBLE64_LE,
|
|
44
|
+
np.dtype(">i2"): AnyLogicalArrayType.ARRAY_OF_INT16_BE,
|
|
45
|
+
np.dtype(">i4"): AnyLogicalArrayType.ARRAY_OF_INT32_BE,
|
|
46
|
+
np.dtype(">i8"): AnyLogicalArrayType.ARRAY_OF_INT64_BE,
|
|
47
|
+
np.dtype(">u2"): AnyLogicalArrayType.ARRAY_OF_UINT16_BE,
|
|
48
|
+
np.dtype(">u4"): AnyLogicalArrayType.ARRAY_OF_UINT32_BE,
|
|
49
|
+
np.dtype(">u8"): AnyLogicalArrayType.ARRAY_OF_UINT64_BE,
|
|
50
|
+
np.dtype(">f4"): AnyLogicalArrayType.ARRAY_OF_FLOAT32_BE,
|
|
51
|
+
np.dtype(">f8"): AnyLogicalArrayType.ARRAY_OF_DOUBLE64_BE,
|
|
52
|
+
}
|
|
7
53
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
54
|
+
_INV_ANY_LOGICAL_ARRAY_TYPE_MAP: dict[AnyLogicalArrayType, npt.DTypeLike] = {
|
|
55
|
+
v: k for k, v in _ANY_LOGICAL_ARRAY_TYPE_MAP.items()
|
|
56
|
+
}
|
|
11
57
|
|
|
12
|
-
SUPPORED_ARRAY_TYPES = T.Union[ArrayOfFloat, ArrayOfBoolean, ArrayOfInt, ArrayOfLong, ArrayOfDouble]
|
|
13
58
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
59
|
+
# TODO: This map should be used once the logical-array-type is supported in the
|
|
60
|
+
# open-etp-server.
|
|
61
|
+
# _ANY_ARRAY_TYPE_MAP: dict[npt.DTypeLike, AnyArrayType] = {
|
|
62
|
+
# np.dtype(np.bool_): AnyArrayType.ARRAY_OF_BOOLEAN,
|
|
63
|
+
# np.dtype(np.int8): AnyArrayType.BYTES,
|
|
64
|
+
# np.dtype(np.uint8): AnyArrayType.BYTES,
|
|
65
|
+
# np.dtype("<i2"): AnyArrayType.BYTES,
|
|
66
|
+
# np.dtype("<i4"): AnyArrayType.BYTES,
|
|
67
|
+
# np.dtype("<i8"): AnyArrayType.BYTES,
|
|
68
|
+
# np.dtype("<u2"): AnyArrayType.BYTES,
|
|
69
|
+
# np.dtype("<u4"): AnyArrayType.BYTES,
|
|
70
|
+
# np.dtype("<u8"): AnyArrayType.BYTES,
|
|
71
|
+
# np.dtype("<f4"): AnyArrayType.ARRAY_OF_FLOAT,
|
|
72
|
+
# np.dtype("<f8"): AnyArrayType.ARRAY_OF_DOUBLE,
|
|
73
|
+
# np.dtype(">i2"): AnyArrayType.BYTES,
|
|
74
|
+
# np.dtype(">i4"): AnyArrayType.BYTES,
|
|
75
|
+
# np.dtype(">i8"): AnyArrayType.BYTES,
|
|
76
|
+
# np.dtype(">u2"): AnyArrayType.BYTES,
|
|
77
|
+
# np.dtype(">u4"): AnyArrayType.BYTES,
|
|
78
|
+
# np.dtype(">u8"): AnyArrayType.BYTES,
|
|
79
|
+
# np.dtype(">f4"): AnyArrayType.BYTES,
|
|
80
|
+
# np.dtype(">f8"): AnyArrayType.BYTES,
|
|
81
|
+
# }
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# This AnyArrayType-map is used until the logical-array-type is properly
|
|
85
|
+
# implemented for the open-etp-server. In this case we
|
|
86
|
+
_ANY_ARRAY_TYPE_MAP: dict[npt.DTypeLike, AnyArrayType] = {
|
|
87
|
+
np.dtype(np.bool_): AnyArrayType.ARRAY_OF_BOOLEAN,
|
|
88
|
+
np.dtype(np.int8): AnyArrayType.BYTES,
|
|
89
|
+
np.dtype("<i4"): AnyArrayType.ARRAY_OF_INT,
|
|
90
|
+
np.dtype("<i8"): AnyArrayType.ARRAY_OF_LONG,
|
|
91
|
+
np.dtype("<f4"): AnyArrayType.ARRAY_OF_FLOAT,
|
|
92
|
+
np.dtype("<f8"): AnyArrayType.ARRAY_OF_DOUBLE,
|
|
93
|
+
}
|
|
94
|
+
valid_dtypes = list(_ANY_ARRAY_TYPE_MAP)
|
|
95
|
+
|
|
96
|
+
_INV_ANY_ARRAY_TYPE_MAP: dict[AnyArrayType, npt.DTypeLike] = {
|
|
97
|
+
AnyArrayType.ARRAY_OF_BOOLEAN: np.dtype(np.bool_),
|
|
98
|
+
# The BYTES-arrays are converted to the proper dtype using the logical
|
|
99
|
+
# array type. We can therefore interpret the bytes as np.int8, before we
|
|
100
|
+
# combine the byte strings to the proper type.
|
|
101
|
+
AnyArrayType.BYTES: np.dtype(np.int8),
|
|
102
|
+
AnyArrayType.ARRAY_OF_INT: np.dtype("<i4"),
|
|
103
|
+
AnyArrayType.ARRAY_OF_LONG: np.dtype("<i8"),
|
|
104
|
+
AnyArrayType.ARRAY_OF_FLOAT: np.dtype("<f4"),
|
|
105
|
+
AnyArrayType.ARRAY_OF_DOUBLE: np.dtype("<f8"),
|
|
20
106
|
}
|
|
21
107
|
|
|
22
|
-
|
|
108
|
+
|
|
109
|
+
_ANY_ARRAY_MAP: dict[AnyArrayType, SUPPORTED_ARRAY_TYPES] = {
|
|
23
110
|
AnyArrayType.ARRAY_OF_FLOAT: ArrayOfFloat,
|
|
24
111
|
AnyArrayType.ARRAY_OF_DOUBLE: ArrayOfDouble,
|
|
25
112
|
AnyArrayType.ARRAY_OF_INT: ArrayOfInt,
|
|
26
113
|
AnyArrayType.ARRAY_OF_LONG: ArrayOfLong,
|
|
27
|
-
AnyArrayType.ARRAY_OF_BOOLEAN: ArrayOfBoolean
|
|
114
|
+
AnyArrayType.ARRAY_OF_BOOLEAN: ArrayOfBoolean,
|
|
115
|
+
AnyArrayType.BYTES: bytes,
|
|
28
116
|
}
|
|
29
117
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
118
|
+
_INV_ANY_ARRAY_MAP: dict[SUPPORTED_ARRAY_TYPES, AnyArrayType] = {
|
|
119
|
+
v: k for k, v in _ANY_ARRAY_MAP.items()
|
|
120
|
+
}
|
|
33
121
|
|
|
34
122
|
|
|
35
|
-
def
|
|
123
|
+
def check_if_array_is_valid_dtype(array: npt.NDArray[T.Any]) -> bool:
|
|
124
|
+
return array.dtype in valid_dtypes
|
|
36
125
|
|
|
37
|
-
arraytype = [item[0] for item in _ARRAY_MAP_TYPES.items() if item[1] == dtype]
|
|
38
|
-
if not len(arraytype):
|
|
39
|
-
raise TypeError(f"Not {type(dtype)} supported")
|
|
40
126
|
|
|
41
|
-
|
|
127
|
+
def get_valid_dtype_cast(array: npt.NDArray[T.Any]) -> npt.DTypeLike:
|
|
128
|
+
if check_if_array_is_valid_dtype(array):
|
|
129
|
+
return array.dtype
|
|
42
130
|
|
|
131
|
+
if array.dtype == np.dtype(np.uint8):
|
|
132
|
+
return np.dtype(np.int8)
|
|
133
|
+
elif array.dtype == np.dtype("<u2"):
|
|
134
|
+
return np.dtype("<i2")
|
|
135
|
+
elif array.dtype == np.dtype(">u2"):
|
|
136
|
+
return np.dtype("<i2")
|
|
137
|
+
elif array.dtype == np.dtype("<u4"):
|
|
138
|
+
return np.dtype("<i4")
|
|
139
|
+
elif array.dtype == np.dtype(">u4"):
|
|
140
|
+
return np.dtype("<i4")
|
|
141
|
+
elif array.dtype == np.dtype("<u8"):
|
|
142
|
+
return np.dtype("<i8")
|
|
143
|
+
elif array.dtype == np.dtype(">u8"):
|
|
144
|
+
return np.dtype("<i8")
|
|
43
145
|
|
|
44
|
-
|
|
45
|
-
return _ARRAY_MAP[get_transport(dtype)]
|
|
146
|
+
raise TypeError(f"Dtype {array.dtype} does not have a valid cast")
|
|
46
147
|
|
|
47
148
|
|
|
48
|
-
def
|
|
49
|
-
|
|
149
|
+
def get_logical_array_type(dtype: npt.DTypeLike) -> AnyLogicalArrayType:
|
|
150
|
+
logical_array_type = _ANY_LOGICAL_ARRAY_TYPE_MAP.get(dtype)
|
|
50
151
|
|
|
51
|
-
if
|
|
52
|
-
|
|
152
|
+
if logical_array_type is not None:
|
|
153
|
+
return logical_array_type
|
|
53
154
|
|
|
54
|
-
|
|
155
|
+
# Here we might be taking a chance by not caring about the endianess of the
|
|
156
|
+
# string.
|
|
157
|
+
if dtype.type == np.str_:
|
|
158
|
+
return AnyLogicalArrayType.ARRAY_OF_STRING
|
|
55
159
|
|
|
160
|
+
# We ignore the AnyLogicalArrayType.ARRAY_OF_CUSTOM for now.
|
|
161
|
+
raise KeyError(f"Data type {dtype} is not a valid ETP v1.2 logical array type")
|
|
56
162
|
|
|
57
|
-
def get_nbytes(md: DataArrayMetadata):
|
|
58
|
-
dtype = get_dtype(md.transport_array_type)
|
|
59
|
-
return int(np.prod(np.array(md.dimensions)) * dtype.itemsize)
|
|
60
163
|
|
|
164
|
+
def get_transport_array_type(dtype: npt.DTypeLike) -> AnyArrayType:
|
|
165
|
+
transport_array_type = _ANY_ARRAY_TYPE_MAP.get(dtype)
|
|
61
166
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return np.asarray(
|
|
65
|
-
data_array.data.item.values, # type: ignore
|
|
66
|
-
dtype=get_dtype(data_array.data)
|
|
67
|
-
).reshape(dims)
|
|
167
|
+
if transport_array_type is not None:
|
|
168
|
+
return transport_array_type
|
|
68
169
|
|
|
170
|
+
# Here we might be taking a chance by not caring about the endianess of the
|
|
171
|
+
# string.
|
|
172
|
+
if dtype.type == np.str_:
|
|
173
|
+
return AnyArrayType.ARRAY_OF_STRING
|
|
69
174
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
dimensions=data.shape, # type: ignore
|
|
74
|
-
data=AnyArray(item=cls(values=data.flatten().tolist()))
|
|
175
|
+
raise KeyError(
|
|
176
|
+
f"Data type {dtype} does not have a valid map to an ETP v1.2 transport array "
|
|
177
|
+
f"type. Valid types are: {list(_ANY_ARRAY_TYPE_MAP)}"
|
|
75
178
|
)
|
|
76
179
|
|
|
77
180
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
ncol=grid_x.shape[0],
|
|
108
|
-
nrow=grid_x.shape[1],
|
|
109
|
-
xori=min_x,
|
|
110
|
-
yori=min_y,
|
|
111
|
-
xinc=xinc,
|
|
112
|
-
yinc=yinc,
|
|
113
|
-
rotation=0.0,
|
|
114
|
-
values=zz,
|
|
181
|
+
def get_logical_and_transport_array_types(
|
|
182
|
+
dtype: npt.DTypeLike,
|
|
183
|
+
) -> tuple[AnyLogicalArrayType, AnyArrayType]:
|
|
184
|
+
# See section 13.2.2.1 in the ETP v1.2 specification for the allowed
|
|
185
|
+
# mappings between the logical and transport types.
|
|
186
|
+
# Using this function ensures that the combination of the logical and
|
|
187
|
+
# transport array types are valid (it is set up in valid combinations in
|
|
188
|
+
# the mapping dictionaries at the top).
|
|
189
|
+
|
|
190
|
+
return get_logical_array_type(dtype), get_transport_array_type(dtype)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_etp_data_array_from_numpy(data: npt.NDArray) -> DataArray:
|
|
194
|
+
transport_array_type = get_transport_array_type(data.dtype)
|
|
195
|
+
cls = _ANY_ARRAY_MAP[transport_array_type]
|
|
196
|
+
|
|
197
|
+
if cls is bytes:
|
|
198
|
+
# In the current implementation we only support 1-byte sized dtype's
|
|
199
|
+
# when using "bytes". In the future, with logical array types, this can
|
|
200
|
+
# cover multiple dtypes, but then the dimensions must be adjusted.
|
|
201
|
+
itemsize = data.dtype.itemsize
|
|
202
|
+
item = np.ravel(data).tobytes()
|
|
203
|
+
dimensions = list(data.shape)
|
|
204
|
+
dimensions[-1] = dimensions[-1] * itemsize
|
|
205
|
+
|
|
206
|
+
return DataArray(dimensions=dimensions, data=AnyArray(item=item))
|
|
207
|
+
|
|
208
|
+
return DataArray(
|
|
209
|
+
dimensions=data.shape, data=AnyArray(item=cls(values=np.ravel(data).tolist()))
|
|
115
210
|
)
|
|
116
211
|
|
|
117
212
|
|
|
118
|
-
def
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
213
|
+
def get_transport_array_size(metadata: DataArrayMetadata) -> int:
|
|
214
|
+
dtype = _INV_ANY_ARRAY_TYPE_MAP[metadata.transport_array_type]
|
|
215
|
+
return int(np.prod(metadata.dimensions) * dtype.itemsize)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def get_dtype_from_any_array_class(cls: AnyArray) -> npt.DTypeLike:
|
|
219
|
+
if cls is bytes:
|
|
220
|
+
return np.dtype(np.int8)
|
|
221
|
+
elif cls is ArrayOfBoolean:
|
|
222
|
+
return np.dtype(np.bool_)
|
|
223
|
+
elif cls is ArrayOfInt:
|
|
224
|
+
return np.dtype("<i4")
|
|
225
|
+
elif cls is ArrayOfLong:
|
|
226
|
+
return np.dtype("<i8")
|
|
227
|
+
elif cls is ArrayOfFloat:
|
|
228
|
+
return np.dtype("<f4")
|
|
229
|
+
elif cls is ArrayOfDouble:
|
|
230
|
+
return np.dtype("<f8")
|
|
231
|
+
# TODO: Update NumPy to >= 2.0, and import the ArrayOfString-class
|
|
232
|
+
# elif cls == ArrayOfString:
|
|
233
|
+
# return np.StringDType()
|
|
234
|
+
|
|
235
|
+
raise TypeError(f"Class {cls} is not a valid array class")
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def get_dtype_from_any_array_type(_type: T.Union[AnyArrayType | str]) -> npt.DTypeLike:
|
|
239
|
+
enum_name = AnyArrayType(_type)
|
|
240
|
+
return _INV_ANY_ARRAY_TYPE_MAP[enum_name]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def get_numpy_array_from_etp_data_array(
|
|
244
|
+
data_array: DataArray,
|
|
245
|
+
) -> npt.NDArray[
|
|
246
|
+
# The types used here do not tell which endianess is used for the returned
|
|
247
|
+
# arrays, but until we can use np.dtype("<f4")-like syntax (Python > 3.10),
|
|
248
|
+
# this will do.
|
|
249
|
+
np.int8 | np.bool_ | np.int32 | np.int64 | np.float32 | np.float64
|
|
250
|
+
]:
|
|
251
|
+
dtype = get_dtype_from_any_array_class(type(data_array.data.item))
|
|
252
|
+
|
|
253
|
+
if type(data_array.data.item) is bytes:
|
|
254
|
+
return np.array(np.frombuffer(data_array.data.item, dtype=dtype)).reshape(
|
|
255
|
+
data_array.dimensions
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return np.array(data_array.data.item.values, dtype=dtype).reshape(
|
|
259
|
+
data_array.dimensions
|
|
260
|
+
)
|