valarray 0.4__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.
- valarray/__init__.py +6 -0
- valarray/core/__init__.py +27 -0
- valarray/core/array.py +121 -0
- valarray/core/array_type_adapter.py +109 -0
- valarray/core/axes_and_fields.py +127 -0
- valarray/core/comparisons.py +71 -0
- valarray/core/errors_exceptions/__init__.py +41 -0
- valarray/core/errors_exceptions/error_list.py +87 -0
- valarray/core/errors_exceptions/exceptions.py +75 -0
- valarray/core/errors_exceptions/generic.py +57 -0
- valarray/core/errors_exceptions/validation_errors/__init__.py +0 -0
- valarray/core/errors_exceptions/validation_errors/array_creation.py +14 -0
- valarray/core/errors_exceptions/validation_errors/axes.py +68 -0
- valarray/core/errors_exceptions/validation_errors/base.py +26 -0
- valarray/core/errors_exceptions/validation_errors/dtype.py +60 -0
- valarray/core/errors_exceptions/validation_errors/values.py +99 -0
- valarray/core/types/__init__.py +24 -0
- valarray/core/types/generics.py +40 -0
- valarray/core/types/other.py +23 -0
- valarray/core/utils.py +89 -0
- valarray/core/validation_functions/__init__.py +20 -0
- valarray/core/validation_functions/array.py +62 -0
- valarray/core/validation_functions/array_values.py +47 -0
- valarray/core/validation_functions/dtype.py +44 -0
- valarray/core/validation_functions/field_values/__init__.py +0 -0
- valarray/core/validation_functions/field_values/core.py +106 -0
- valarray/core/validation_functions/field_values/types_and_data_structures.py +90 -0
- valarray/core/validation_functions/field_values/utils.py +143 -0
- valarray/core/validation_functions/shape.py +67 -0
- valarray/core/validation_functions/utils.py +24 -0
- valarray/core/validators/__init__.py +13 -0
- valarray/core/validators/base.py +72 -0
- valarray/core/validators/value_comparisons.py +107 -0
- valarray/numpy/__init__.py +24 -0
- valarray/numpy/array.py +63 -0
- valarray/numpy/array_type_adapter.py +133 -0
- valarray/numpy/axes_and_fields.py +83 -0
- valarray/numpy/comparisons.py +135 -0
- valarray/numpy/errors_exceptions.py +172 -0
- valarray/numpy/types.py +32 -0
- valarray/numpy/validation_functions.py +170 -0
- valarray/numpy/validators.py +35 -0
- valarray-0.4.dist-info/METADATA +698 -0
- valarray-0.4.dist-info/RECORD +45 -0
- valarray-0.4.dist-info/WHEEL +4 -0
valarray/numpy/array.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from types import EllipsisType
|
|
2
|
+
from typing import Any, Generic
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import numpy.typing as npt
|
|
6
|
+
|
|
7
|
+
from valarray.core import ValidatedArray
|
|
8
|
+
from valarray.core.validators import Validator
|
|
9
|
+
|
|
10
|
+
from .array_type_adapter import NumpyArrayTypeAdapter
|
|
11
|
+
from .axes_and_fields import AxesTuple
|
|
12
|
+
from .types import AdvancedIndex, NumpyDTypeT
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ValidatedNumpyArray(
|
|
16
|
+
ValidatedArray[npt.NDArray[Any], npt.DTypeLike, np.dtype, AdvancedIndex, object],
|
|
17
|
+
Generic[NumpyDTypeT],
|
|
18
|
+
):
|
|
19
|
+
"""Base validated numpy array.
|
|
20
|
+
|
|
21
|
+
To implement a validated array, inherit from this class and set the following class variables:
|
|
22
|
+
- `dtype` - expected data type specification (such as `float`,`"float64"`, `np.float64`).
|
|
23
|
+
If not specified, do not validate data type.
|
|
24
|
+
For full list of accepted values, see:
|
|
25
|
+
https://numpy.org/doc/stable/reference/arrays.dtypes.html#specifying-and-constructing-data-types
|
|
26
|
+
- `schema` - expected shape specification (of type `valarray.numpy.axes_and_fields.AxesTuple`).
|
|
27
|
+
If not specified, do not validate shape.
|
|
28
|
+
- `lt`/`le`/`ge`/`gt`/`eq` - basic array value constraints -> less (or equal) than, greater (or equal) than, equal to
|
|
29
|
+
- `validators` - optional list of validators applied to the whole array.
|
|
30
|
+
|
|
31
|
+
You should also specify generic type variables:
|
|
32
|
+
- `NumpyDTypeT` - data type hint for array accessed through `array`/`a_` property.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
class ExampleArray(ValidatedNumpyArray):
|
|
36
|
+
dtype = np.float32
|
|
37
|
+
|
|
38
|
+
class ExampleArray2(ValidatedNumpyArray):
|
|
39
|
+
dtype = "float32"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
(introduced ***v0.1***, last_modified ***v0.3***)
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
schema: AxesTuple[NumpyDTypeT] | EllipsisType = ...
|
|
46
|
+
validators: tuple[
|
|
47
|
+
Validator[npt.NDArray[NumpyDTypeT], AdvancedIndex],
|
|
48
|
+
...,
|
|
49
|
+
] = ()
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def ata(self) -> NumpyArrayTypeAdapter:
|
|
53
|
+
return NumpyArrayTypeAdapter()
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def array(self) -> npt.NDArray[NumpyDTypeT]:
|
|
57
|
+
"""Access underlying `np.array`
|
|
58
|
+
|
|
59
|
+
(introduced ***v0.1***)
|
|
60
|
+
"""
|
|
61
|
+
return self._array
|
|
62
|
+
|
|
63
|
+
a_ = array
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import numpy.typing as npt
|
|
5
|
+
|
|
6
|
+
from valarray.core import ArrayTypeAdapter
|
|
7
|
+
from valarray.core.axes_and_fields import FieldNameAndIdx
|
|
8
|
+
|
|
9
|
+
from .comparisons import NumpyComparisons
|
|
10
|
+
from .errors_exceptions import NumpyErrors
|
|
11
|
+
from .types import AdvancedIndex
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class NumpyArrayTypeAdapter(
|
|
15
|
+
ArrayTypeAdapter[
|
|
16
|
+
npt.NDArray[Any],
|
|
17
|
+
npt.DTypeLike,
|
|
18
|
+
np.dtype[Any],
|
|
19
|
+
AdvancedIndex,
|
|
20
|
+
Any,
|
|
21
|
+
]
|
|
22
|
+
):
|
|
23
|
+
"""Adapter for numpy arrays.
|
|
24
|
+
|
|
25
|
+
(introduced ***v0.1***, last_modified ***v0.3***)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def errors(self):
|
|
30
|
+
return NumpyErrors()
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def array_type(self):
|
|
34
|
+
"""(introduced ***v0.1***)"""
|
|
35
|
+
return np.ndarray
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def comparisons(self) -> NumpyComparisons:
|
|
39
|
+
"""(introduced ***v0.3***)"""
|
|
40
|
+
return NumpyComparisons()
|
|
41
|
+
|
|
42
|
+
def change_dtype(self, arr, dtypelike):
|
|
43
|
+
"""(introduced ***v0.1***)"""
|
|
44
|
+
return arr.astype(dtypelike)
|
|
45
|
+
|
|
46
|
+
def create_array(self, obj, dtypelike):
|
|
47
|
+
"""(introduced ***v0.1***)"""
|
|
48
|
+
if dtypelike == ...:
|
|
49
|
+
arr = np.asarray(obj, None)
|
|
50
|
+
else:
|
|
51
|
+
arr = np.array(obj, dtypelike)
|
|
52
|
+
|
|
53
|
+
return arr
|
|
54
|
+
|
|
55
|
+
def is_array_empty(self, arr) -> bool:
|
|
56
|
+
"""(introduced ***v0.2.2***)"""
|
|
57
|
+
return arr.size < 1
|
|
58
|
+
|
|
59
|
+
def create_empty_array(self, ax_sizes, dtypelike):
|
|
60
|
+
"""(introduced ***v0.1.1***)"""
|
|
61
|
+
dt = None if dtypelike == ... else dtypelike
|
|
62
|
+
|
|
63
|
+
# Replace first and all unknown sizes with 0
|
|
64
|
+
# (3,2, None, 1) => (0,2,0,1)
|
|
65
|
+
shape = [0 if s is None else s for s in ax_sizes]
|
|
66
|
+
if len(shape) > 0:
|
|
67
|
+
shape[0] = 0
|
|
68
|
+
|
|
69
|
+
return np.empty(shape, dt)
|
|
70
|
+
|
|
71
|
+
def dtype_from_dtypelike(self, dtypelike):
|
|
72
|
+
"""(introduced ***v0.1***)"""
|
|
73
|
+
return np.dtype(dtypelike)
|
|
74
|
+
|
|
75
|
+
def dtypes_equal(self, actual_dtype, expected_dtype) -> bool:
|
|
76
|
+
"""(introduced ***v0.1***)"""
|
|
77
|
+
return actual_dtype == expected_dtype
|
|
78
|
+
|
|
79
|
+
def get_values(self, arr, indices):
|
|
80
|
+
"""Returns array values from indices defined by a boolean array
|
|
81
|
+
or a tuple of integer arrays.
|
|
82
|
+
|
|
83
|
+
(introduced ***v0.3***)"""
|
|
84
|
+
if indices is None:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
vals = arr[indices].tolist()
|
|
89
|
+
except IndexError:
|
|
90
|
+
# TODO: add logger and warning
|
|
91
|
+
vals = None
|
|
92
|
+
|
|
93
|
+
return vals
|
|
94
|
+
|
|
95
|
+
def select_subset(self, arr, ax, fields):
|
|
96
|
+
selection = []
|
|
97
|
+
for ax_i in range(len(arr.shape)):
|
|
98
|
+
if ax_i == ax.idx:
|
|
99
|
+
s = tuple(f.idx for f in fields)
|
|
100
|
+
else:
|
|
101
|
+
s = slice(None, None)
|
|
102
|
+
|
|
103
|
+
selection.append(s)
|
|
104
|
+
|
|
105
|
+
return arr[*selection]
|
|
106
|
+
|
|
107
|
+
def get_values_from_subset(
|
|
108
|
+
self,
|
|
109
|
+
arr,
|
|
110
|
+
indices,
|
|
111
|
+
ax,
|
|
112
|
+
fields,
|
|
113
|
+
):
|
|
114
|
+
if indices is None:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
dic: dict[FieldNameAndIdx, list[Any]] = {}
|
|
118
|
+
|
|
119
|
+
indices_tuple = indices if isinstance(indices, tuple) else np.where(indices)
|
|
120
|
+
|
|
121
|
+
val_arr = arr[indices_tuple]
|
|
122
|
+
|
|
123
|
+
field_idx_arr = indices_tuple[ax.idx]
|
|
124
|
+
|
|
125
|
+
for i, f in enumerate(fields):
|
|
126
|
+
vals = val_arr[field_idx_arr == i]
|
|
127
|
+
|
|
128
|
+
if len(vals) < 1:
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
dic[f] = vals.tolist()
|
|
132
|
+
|
|
133
|
+
return dic
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
*import* `AxesTuple` **TypeAlias** - defines axes of schema
|
|
3
|
+
|
|
4
|
+
*import* `FieldsTuple` **TypeAlias** - defines fields of schema axis
|
|
5
|
+
|
|
6
|
+
*import* `Field` **valarray.core.Field** - defines constraints on field
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Generic, TypeAlias
|
|
11
|
+
|
|
12
|
+
import numpy.typing as npt
|
|
13
|
+
|
|
14
|
+
import valarray.core
|
|
15
|
+
from valarray.numpy.types import AdvancedIndex, NumpyDTypeT
|
|
16
|
+
|
|
17
|
+
# NOTE: Need to specialize Field, FieldsTuple and AxesTuple,
|
|
18
|
+
# because Field with no set validators is not specialized with respect to array type (ArrayT).
|
|
19
|
+
# (Essentially trying to assign:
|
|
20
|
+
# Field[ArrayP, Any, Any] -> Field[npt.NDArray[Any], AdvancedIndex, object])
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Field(
|
|
25
|
+
valarray.core.Field[npt.NDArray[NumpyDTypeT], AdvancedIndex, object],
|
|
26
|
+
Generic[NumpyDTypeT],
|
|
27
|
+
):
|
|
28
|
+
"""Field of an array axis.
|
|
29
|
+
|
|
30
|
+
Arguments:
|
|
31
|
+
name (Optional[str]): Optional descriptive name of field. Defaults to `None`.
|
|
32
|
+
validators (tuple[Validator[npt.NDArray[NumpyDTypeT], AdvancedIndex], ...]):
|
|
33
|
+
optional list of validators applied to field values
|
|
34
|
+
lt (Optional[Any]):
|
|
35
|
+
Optional constraint -> field values less than. Defaults to None.
|
|
36
|
+
le (Optional[Any]):
|
|
37
|
+
Optional constraint -> field values less or equal than. Defaults to None.
|
|
38
|
+
ge (Optional[Any]):
|
|
39
|
+
Optional constraint -> field values greater than. Defaults to None.
|
|
40
|
+
gt (Optional[Any]):
|
|
41
|
+
Optional constraint -> field values greater or equal than. Defaults to None.
|
|
42
|
+
eq (Optional[Any]):
|
|
43
|
+
Optional constraint -> field values equal to. Defaults to None.
|
|
44
|
+
|
|
45
|
+
(introduced ***v0.4***)
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
```
|
|
49
|
+
from typing import Any
|
|
50
|
+
|
|
51
|
+
from valarray.numpy import Field, NumpyValidator
|
|
52
|
+
|
|
53
|
+
class ExampleNumpyValidator(NumpyValidator[Any]):
|
|
54
|
+
def validate(self, arr):
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
f1 = Field("example_named_field", ge=0)
|
|
58
|
+
f2 = Field(gt=10, validators=(ExampleNumpyValidator(),))
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
FieldsTuple: TypeAlias = tuple[str | Field[NumpyDTypeT], ...]
|
|
65
|
+
"""Tuple of numpy array fields.
|
|
66
|
+
|
|
67
|
+
(introduced ***v0.4***)
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
AxesTuple: TypeAlias = tuple[str | int | FieldsTuple[NumpyDTypeT], ...]
|
|
71
|
+
"""Tuple of numpy array axes. Can be either name, size or a tuple of fields.
|
|
72
|
+
```
|
|
73
|
+
import valarray.numpy
|
|
74
|
+
|
|
75
|
+
axes = (
|
|
76
|
+
16,
|
|
77
|
+
"items",
|
|
78
|
+
("x", "y", "length", valarray.numpy.Field()),
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
(introduced ***v0.4***)
|
|
83
|
+
"""
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import numpy.typing as npt
|
|
5
|
+
|
|
6
|
+
from valarray.core import Comparisons
|
|
7
|
+
from valarray.numpy.types import AdvancedIndex
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NumpyComparisons(Comparisons[npt.NDArray, AdvancedIndex, Any]):
|
|
11
|
+
"""(introduced ***v0.3***)"""
|
|
12
|
+
|
|
13
|
+
def where_not_lt(self, arr, value):
|
|
14
|
+
"""Returns indices of values which are ***not* less than** value.
|
|
15
|
+
|
|
16
|
+
Indices are tuple of integer arrays of length equal to number of array axes
|
|
17
|
+
|
|
18
|
+
-> `(np.array([idx0_axis0, idx1_axis0, ...]), np.array([idx0_axis1, idx1_axis1, ...]), ...)`
|
|
19
|
+
|
|
20
|
+
### Example:
|
|
21
|
+
``` # *not* less than 0
|
|
22
|
+
arr = np.array(
|
|
23
|
+
[
|
|
24
|
+
[-1 ,0],
|
|
25
|
+
[0, 1],
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
(introduced ***v0.3***)
|
|
32
|
+
"""
|
|
33
|
+
return np.where(~(arr < value))
|
|
34
|
+
|
|
35
|
+
def where_not_le(self, arr, value):
|
|
36
|
+
"""Returns indices of values which are ***not* less than or equal** value.
|
|
37
|
+
|
|
38
|
+
Indices are tuple of integer arrays of length equal to number of array axes
|
|
39
|
+
|
|
40
|
+
-> `(np.array([idx0_axis0, idx1_axis0, ...]), np.array([idx0_axis1, idx1_axis1, ...]), ...)`
|
|
41
|
+
|
|
42
|
+
### Example:
|
|
43
|
+
``` # *not* less than or equal 0
|
|
44
|
+
arr = np.array(
|
|
45
|
+
[
|
|
46
|
+
[-1 ,0],
|
|
47
|
+
[0, 1],
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
(introduced ***v0.3***)
|
|
54
|
+
"""
|
|
55
|
+
return np.where(~(arr <= value))
|
|
56
|
+
|
|
57
|
+
def where_not_ge(self, arr, value):
|
|
58
|
+
"""Returns indices of values which are ***not* greater than or equal** value.
|
|
59
|
+
|
|
60
|
+
Indices are tuple of integer arrays of length equal to number of array axes
|
|
61
|
+
|
|
62
|
+
-> `(np.array([idx0_axis0, idx1_axis0, ...]), np.array([idx0_axis1, idx1_axis1, ...]), ...)`
|
|
63
|
+
|
|
64
|
+
### Example:
|
|
65
|
+
``` # *not* greater than or equal 0
|
|
66
|
+
arr = np.array(
|
|
67
|
+
[
|
|
68
|
+
[-1 ,0],
|
|
69
|
+
[0, 1],
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
(introduced ***v0.3***)
|
|
76
|
+
"""
|
|
77
|
+
return np.where(~(arr >= value))
|
|
78
|
+
|
|
79
|
+
def where_not_gt(self, arr, value):
|
|
80
|
+
"""Returns indices of values which are ***not* greater than** value.
|
|
81
|
+
|
|
82
|
+
Indices are tuple of integer arrays of length equal to number of array axes
|
|
83
|
+
|
|
84
|
+
-> `(np.array([idx0_axis0, idx1_axis0, ...]), np.array([idx0_axis1, idx1_axis1, ...]), ...)`
|
|
85
|
+
|
|
86
|
+
### Example:
|
|
87
|
+
``` # *not* greater than 0
|
|
88
|
+
arr = np.array(
|
|
89
|
+
[
|
|
90
|
+
[-1 ,0],
|
|
91
|
+
[0, 1],
|
|
92
|
+
]
|
|
93
|
+
)
|
|
94
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
(introduced ***v0.3***)
|
|
98
|
+
"""
|
|
99
|
+
return np.where(~(arr > value))
|
|
100
|
+
|
|
101
|
+
def where_not_eq(self, arr, value):
|
|
102
|
+
"""Returns indices of values which are ***not* equal** value.
|
|
103
|
+
|
|
104
|
+
Indices are tuple of integer arrays of length equal to number of array axes
|
|
105
|
+
|
|
106
|
+
-> `(np.array([idx0_axis0, idx1_axis0, ...]), np.array([idx0_axis1, idx1_axis1, ...]), ...)`
|
|
107
|
+
|
|
108
|
+
### Example:
|
|
109
|
+
``` # *not* equal 0
|
|
110
|
+
arr = np.array(
|
|
111
|
+
[
|
|
112
|
+
[-1 ,0],
|
|
113
|
+
[0, 1],
|
|
114
|
+
]
|
|
115
|
+
)
|
|
116
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
(introduced ***v0.3***)
|
|
120
|
+
"""
|
|
121
|
+
return np.where(~(arr == value))
|
|
122
|
+
|
|
123
|
+
def n_indices(self, indices):
|
|
124
|
+
"""Counts the number of indices.
|
|
125
|
+
|
|
126
|
+
(introduced ***v0.3***)
|
|
127
|
+
"""
|
|
128
|
+
if isinstance(indices, np.ndarray) and indices.dtype == np.bool_:
|
|
129
|
+
n = int(indices.sum())
|
|
130
|
+
elif len(indices) == 0:
|
|
131
|
+
n = 0
|
|
132
|
+
else:
|
|
133
|
+
n = len(indices[0])
|
|
134
|
+
|
|
135
|
+
return n
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
*import* `NumpyIncorrectDTypeError` **ValidationError**
|
|
3
|
+
|
|
4
|
+
*import* `NumpyCannotCoerceDTypeError` **ValidationError**
|
|
5
|
+
|
|
6
|
+
*import* `NumpyInvalidArrayValuesError` **ValidationError**
|
|
7
|
+
|
|
8
|
+
*import* `NumpyErrors` **dataclass**
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any, Self
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import numpy.typing as npt
|
|
16
|
+
|
|
17
|
+
from valarray.core.errors_exceptions import (
|
|
18
|
+
CannotCoerceDTypeError,
|
|
19
|
+
GenericErrors,
|
|
20
|
+
IncorrectDTypeError,
|
|
21
|
+
InvalidArrayValuesError,
|
|
22
|
+
InvalidFieldValuesError,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from .types import AdvancedIndex
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NumpyIncorrectDTypeError(IncorrectDTypeError[npt.DTypeLike, np.dtype]):
|
|
29
|
+
"""***Validation error:*** Array has the wrong data type.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
actual_dtype (np.dtype): Data type of the actual array.
|
|
33
|
+
expected_dtype (np.dtype): Expected data type.
|
|
34
|
+
expected_dtypelike (npt.DTypeLike):
|
|
35
|
+
Expected data type specification (`numpy.typing.DTypeLike`)
|
|
36
|
+
from `ValidatedArray.dtype`.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
```
|
|
40
|
+
err = NumpyIncorrectDTypeError(
|
|
41
|
+
np.dtype(np.float32), np.dtype(np.float64), np.float64
|
|
42
|
+
)
|
|
43
|
+
print(err.msg)
|
|
44
|
+
>>> "Incorrect DType: 'float32', expected 'float64'."
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
(introduced ***v0.2.4***)
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class NumpyCannotCoerceDTypeError(CannotCoerceDTypeError[npt.DTypeLike, np.dtype]):
|
|
52
|
+
"""***Validation error:*** Array type adapter is not able to convert an existing array
|
|
53
|
+
to specified data type when creating an instance of ValidatedArray.
|
|
54
|
+
|
|
55
|
+
Attributes:
|
|
56
|
+
actual_dtype (np.dtype): Data type of array passed to `ValidatedArray.__init__`.
|
|
57
|
+
target_dtype (np.dtype): Data type to convert to (as a data type object).
|
|
58
|
+
target_dtypelike (npt.DTypeLike):
|
|
59
|
+
Expected data type specification (`numpy.typing.DTypeLike`) from `ValidatedArray.dtype`.
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
```
|
|
63
|
+
err = NumpyCannotCoerceDTypeError(np.dtype("<U1"), np.dtype(int), int)
|
|
64
|
+
print(err.msg)
|
|
65
|
+
>>> "Cannot coerce data type from: '<U1' to 'int64'."
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
(introduced ***v0.2.4***)
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class NumpyInvalidArrayValuesError(
|
|
73
|
+
InvalidArrayValuesError[npt.NDArray[Any], AdvancedIndex]
|
|
74
|
+
):
|
|
75
|
+
"""***ValidationError:*** Array has wrong values.
|
|
76
|
+
|
|
77
|
+
Attributes:
|
|
78
|
+
validator: (Validator[npt.NDArray[Any], AdvancedIndex]):
|
|
79
|
+
Validator applied to the whole array.
|
|
80
|
+
invalid_values (Optional[list[Any]]):
|
|
81
|
+
Values causing the validation to fail. Defaults to None.
|
|
82
|
+
invalid_indices (Optional[AdvancedIndex]): Indices of invalid values.
|
|
83
|
+
result_msg (Optional[str]): Optional message returned by validator.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
```
|
|
87
|
+
err = NumpyInvalidArrayValuesError(
|
|
88
|
+
validator=ExampleValidator("bool"),
|
|
89
|
+
invalid_values=[1],
|
|
90
|
+
invalid_indices=np.array([[1, 1, 0], [1, 0, 1]], dtype=np.bool_),
|
|
91
|
+
)
|
|
92
|
+
print(err.msg)
|
|
93
|
+
>>> Invalid Array Values (ExampleValidator):
|
|
94
|
+
[1]
|
|
95
|
+
|
|
96
|
+
err = NumpyInvalidArrayValuesError(
|
|
97
|
+
validator=ExampleValidator("tuple"),
|
|
98
|
+
invalid_values=[1],
|
|
99
|
+
invalid_indices=(np.array([0, 1]), np.array([2, 1])),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
print(err.msg)
|
|
103
|
+
>>> Invalid Array Values (ExampleValidator):
|
|
104
|
+
[1]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
(introduced ***v0.3***, last_modified ***v0.4***)"""
|
|
108
|
+
|
|
109
|
+
def __eq__(self, other: Self):
|
|
110
|
+
other_vars = vars(other)
|
|
111
|
+
|
|
112
|
+
for k, v in vars(self).items():
|
|
113
|
+
other_v = other_vars.get(k)
|
|
114
|
+
|
|
115
|
+
# NOTE: stack, because field can be a tuple of arrays.
|
|
116
|
+
# pyright complains, but numpy can actually stack `None's`
|
|
117
|
+
stacked_v = np.stack([v])
|
|
118
|
+
stacked_other_v = np.stack(
|
|
119
|
+
[other_v] # pyright: ignore[reportArgumentType,reportCallIssue]]
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if not np.all(stacked_v == stacked_other_v):
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class NumpyInvalidFieldValuesError(
|
|
129
|
+
InvalidFieldValuesError[npt.NDArray[Any], AdvancedIndex]
|
|
130
|
+
):
|
|
131
|
+
"""***ValidationError:*** Field or fields have wrong values.
|
|
132
|
+
|
|
133
|
+
Attributes:
|
|
134
|
+
validator: (Validator[npt.NDArray[Any], AdvancedIndex]):
|
|
135
|
+
Validator applied to array field(s).
|
|
136
|
+
invalid_values (Optional[InvalidFieldValues]):
|
|
137
|
+
Values causing the validation to fail, organized by axis and field. Defaults to None.
|
|
138
|
+
|
|
139
|
+
Examples:
|
|
140
|
+
```
|
|
141
|
+
err = NumpyInvalidFieldValuesError(
|
|
142
|
+
validator=IsEvenValidator("bool"),
|
|
143
|
+
invalid_values={
|
|
144
|
+
AxisNameAndIdx(1, "example_axis"): {
|
|
145
|
+
FieldNameAndIdx(0, "example_field"): [1]
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
print(err.msg)
|
|
150
|
+
>>> Invalid Field Values (IsEvenValidator):
|
|
151
|
+
Axis < 1 >: 'example_axis'
|
|
152
|
+
Field < 0 >: 'example_field': [1]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
(introduced ***v0.4***)
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class NumpyErrors(
|
|
161
|
+
GenericErrors[npt.NDArray[Any], npt.DTypeLike, np.dtype, AdvancedIndex]
|
|
162
|
+
):
|
|
163
|
+
"""(introduced ***v0.2.4***, last_modified ***v0.4***)"""
|
|
164
|
+
|
|
165
|
+
incorrect_dtype: type[NumpyIncorrectDTypeError] = NumpyIncorrectDTypeError
|
|
166
|
+
cannot_coerce_dtype: type[NumpyCannotCoerceDTypeError] = NumpyCannotCoerceDTypeError
|
|
167
|
+
invalid_array_values: type[NumpyInvalidArrayValuesError] = (
|
|
168
|
+
NumpyInvalidArrayValuesError
|
|
169
|
+
)
|
|
170
|
+
invalid_field_values: type[NumpyInvalidFieldValuesError] = (
|
|
171
|
+
NumpyInvalidFieldValuesError
|
|
172
|
+
)
|
valarray/numpy/types.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
*import* `NumpyDTypeT` **TypeVar**
|
|
3
|
+
|
|
4
|
+
*import* `AdvancedIndex` **type**
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TypeVar
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
11
|
+
|
|
12
|
+
NumpyDTypeT = TypeVar("NumpyDTypeT", bound=np.generic)
|
|
13
|
+
|
|
14
|
+
type AdvancedIndex = npt.NDArray[np.bool_] | tuple[npt.NDArray[np.integer], ...]
|
|
15
|
+
"""Advanced numpy index using:
|
|
16
|
+
- a boolean array
|
|
17
|
+
- tuple of integer arrays (length == nuber of array axes)
|
|
18
|
+
|
|
19
|
+
### Examples:
|
|
20
|
+
```
|
|
21
|
+
indices = np.array(
|
|
22
|
+
[
|
|
23
|
+
[False, False, False],
|
|
24
|
+
[True, False, False],
|
|
25
|
+
[False, False, True],
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
|
|
30
|
+
```
|
|
31
|
+
(introduced ***v0.3***)
|
|
32
|
+
"""
|