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.
Files changed (45) hide show
  1. valarray/__init__.py +6 -0
  2. valarray/core/__init__.py +27 -0
  3. valarray/core/array.py +121 -0
  4. valarray/core/array_type_adapter.py +109 -0
  5. valarray/core/axes_and_fields.py +127 -0
  6. valarray/core/comparisons.py +71 -0
  7. valarray/core/errors_exceptions/__init__.py +41 -0
  8. valarray/core/errors_exceptions/error_list.py +87 -0
  9. valarray/core/errors_exceptions/exceptions.py +75 -0
  10. valarray/core/errors_exceptions/generic.py +57 -0
  11. valarray/core/errors_exceptions/validation_errors/__init__.py +0 -0
  12. valarray/core/errors_exceptions/validation_errors/array_creation.py +14 -0
  13. valarray/core/errors_exceptions/validation_errors/axes.py +68 -0
  14. valarray/core/errors_exceptions/validation_errors/base.py +26 -0
  15. valarray/core/errors_exceptions/validation_errors/dtype.py +60 -0
  16. valarray/core/errors_exceptions/validation_errors/values.py +99 -0
  17. valarray/core/types/__init__.py +24 -0
  18. valarray/core/types/generics.py +40 -0
  19. valarray/core/types/other.py +23 -0
  20. valarray/core/utils.py +89 -0
  21. valarray/core/validation_functions/__init__.py +20 -0
  22. valarray/core/validation_functions/array.py +62 -0
  23. valarray/core/validation_functions/array_values.py +47 -0
  24. valarray/core/validation_functions/dtype.py +44 -0
  25. valarray/core/validation_functions/field_values/__init__.py +0 -0
  26. valarray/core/validation_functions/field_values/core.py +106 -0
  27. valarray/core/validation_functions/field_values/types_and_data_structures.py +90 -0
  28. valarray/core/validation_functions/field_values/utils.py +143 -0
  29. valarray/core/validation_functions/shape.py +67 -0
  30. valarray/core/validation_functions/utils.py +24 -0
  31. valarray/core/validators/__init__.py +13 -0
  32. valarray/core/validators/base.py +72 -0
  33. valarray/core/validators/value_comparisons.py +107 -0
  34. valarray/numpy/__init__.py +24 -0
  35. valarray/numpy/array.py +63 -0
  36. valarray/numpy/array_type_adapter.py +133 -0
  37. valarray/numpy/axes_and_fields.py +83 -0
  38. valarray/numpy/comparisons.py +135 -0
  39. valarray/numpy/errors_exceptions.py +172 -0
  40. valarray/numpy/types.py +32 -0
  41. valarray/numpy/validation_functions.py +170 -0
  42. valarray/numpy/validators.py +35 -0
  43. valarray-0.4.dist-info/METADATA +698 -0
  44. valarray-0.4.dist-info/RECORD +45 -0
  45. valarray-0.4.dist-info/WHEEL +4 -0
valarray/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """
2
+ `.core` ***module*** - Core classes, functions
3
+ on which concrete implemetations for specific array types are based upon.
4
+
5
+ `.numpy` ***module*** - Validating numpy arrays.
6
+ """
@@ -0,0 +1,27 @@
1
+ """
2
+ *import* `ValidatedArray` **ABC**
3
+
4
+ *import* `ArrayTypeAdapter` **ABC**
5
+
6
+ *import* `Comparisons` **ABC**
7
+
8
+ *import* `Field` **dataclass**
9
+
10
+ `.validation_functions` ***module***
11
+
12
+ `.validators` ***module***
13
+
14
+ `.errors_exceptions` ***module***
15
+
16
+ `.types` ***module***
17
+
18
+ `.axes_and_fields` ***module***
19
+
20
+ `.utils` ***module***
21
+ """
22
+
23
+ # pyright: reportUnusedImport=false
24
+ from .array import ValidatedArray
25
+ from .array_type_adapter import ArrayTypeAdapter
26
+ from .axes_and_fields import Field
27
+ from .comparisons import Comparisons
valarray/core/array.py ADDED
@@ -0,0 +1,121 @@
1
+ from abc import ABC, abstractmethod
2
+ from types import EllipsisType
3
+ from typing import Any, Final, Generic, Optional, Self
4
+
5
+ from valarray.core.axes_and_fields import AxesTuple
6
+
7
+ from .array_type_adapter import ArrayTypeAdapter
8
+ from .axes_and_fields import AxesTuple
9
+ from .errors_exceptions import ValidationException
10
+ from .types import ArrayIndicesT, ArrayT, ComparableValueT, DTypeLikeT, DTypeT
11
+ from .utils import constraints_to_validators, setup_array
12
+ from .validation_functions import validate_array
13
+ from .validators.base import Validator
14
+
15
+
16
+ class ValidatedArray(
17
+ ABC, Generic[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT, ComparableValueT]
18
+ ):
19
+ """Abstract base class for Validated Array implementations.
20
+ Subclasses need to implement:
21
+
22
+ **abstract property**
23
+ - `ata` -> returns a subclass of `ArrayTypeAdapter`
24
+
25
+ You should also specify generic type variables:
26
+ - `ArrayT` - type of array object
27
+ - `DTypeLikeT` - data type specification
28
+ - `DTypeT` - data type object
29
+ - `ArrayIndexT` - object(s) that can select values from array using `__getitem__` method.
30
+ - `ComparableValueT` - type of object an array can be compared with.
31
+
32
+ (introduced ***v0.1***, last_modified ***v0.3***)
33
+ """
34
+
35
+ dtype: DTypeLikeT | EllipsisType = ...
36
+ schema: AxesTuple[ArrayT, ArrayIndicesT, ComparableValueT] | EllipsisType = ...
37
+ validators: tuple[Validator[ArrayT, ArrayIndicesT], ...] = ()
38
+
39
+ lt: Optional[ComparableValueT] = None
40
+ le: Optional[ComparableValueT] = None
41
+ ge: Optional[ComparableValueT] = None
42
+ gt: Optional[ComparableValueT] = None
43
+ eq: Optional[ComparableValueT] = None
44
+
45
+ @property
46
+ @abstractmethod
47
+ def ata(
48
+ self,
49
+ ) -> ArrayTypeAdapter[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT, ComparableValueT]:
50
+ """Interface for operations that have different implementations for each array type."""
51
+
52
+ def __init__(self, obj: Any, validate=True, coerce_dtype=False) -> None:
53
+ self.is_validated = False
54
+
55
+ self._array: Final[ArrayT] = setup_array(
56
+ obj,
57
+ self.dtype,
58
+ coerce_dtype,
59
+ self.schema,
60
+ self.ata,
61
+ self.__class__.__name__,
62
+ ) # [!] CreateArrayException, CoerceDTypeException
63
+
64
+ if validate:
65
+ self.validate_array()
66
+
67
+ @classmethod
68
+ def wrap(cls, array: ArrayT) -> Self:
69
+ """Creates `ValidatedArray` without validation.
70
+
71
+ (introduced ***v0.1***, last_modified ***v0.1.1***)
72
+ """
73
+ return cls(array, validate=False)
74
+
75
+ @classmethod
76
+ def validate(cls, array: ArrayT) -> Self:
77
+ """Creates `ValidatedArray` by validating an existing array.
78
+
79
+ (introduced ***v0.1***, last_modified ***v0.1.1***)
80
+ """
81
+ return cls(array, validate=True)
82
+
83
+ @classmethod
84
+ def empty(cls) -> Self:
85
+ """Creates empty `ValidatedArray` by validating an existing array.
86
+
87
+ (introduced ***v0.1.1***)
88
+ """
89
+ return cls(None)
90
+
91
+ def validate_array(self):
92
+ """Validate array if it isn't already validated.
93
+
94
+ (introduced ***v0.1***, last_modified ***v.0.4***)"""
95
+ if self.is_validated:
96
+ return
97
+
98
+ # TODO: do not validate dtype if not necessary
99
+
100
+ validators = constraints_to_validators(
101
+ self.lt, self.le, self.ge, self.gt, self.eq, self.ata.comparisons
102
+ ) + list(self.validators)
103
+
104
+ errs = validate_array(
105
+ self._array, self.dtype, self.schema, validators, self.ata
106
+ )
107
+
108
+ if errs:
109
+ raise ValidationException(self.__class__.__name__, errs)
110
+
111
+ self.is_validated = True
112
+
113
+ def __repr__(self) -> str:
114
+ """(introduced ***v0.1***, last_modified ***v0.2.2***)"""
115
+ cls_name = self.__class__.__name__
116
+
117
+ if self.ata.is_array_empty((self._array)):
118
+ rep = f"{cls_name}.empty()"
119
+ else:
120
+ rep = f"{cls_name}({repr(self._array)})"
121
+ return rep
@@ -0,0 +1,109 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import Sequence
3
+ from types import EllipsisType
4
+ from typing import Any, Generic, Optional
5
+
6
+ from .axes_and_fields import AxisNameAndIdx, FieldNameAndIdx
7
+ from .comparisons import Comparisons
8
+ from .errors_exceptions import GenericErrors
9
+ from .types import ArrayT, AxSizes, ComparableValueT, DTypeLikeT, DTypeT
10
+ from .types.generics import ArrayIndicesT
11
+
12
+
13
+ class ArrayTypeAdapter(
14
+ ABC, Generic[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT, ComparableValueT]
15
+ ):
16
+ """Generic base array type adapter.
17
+
18
+ Type variables:
19
+ - `ArrayT` - type of array object
20
+ - `DTypeLikeT` - data type specification
21
+ - `DTypeT` - data type object
22
+ - `ArrayIndexT` - object(s) that can select values from array using `__getitem__` method.
23
+ - `ComparableValueT` - value array can be compared with
24
+ using `<`, `<=`, `==`, `=>`, `>` operators
25
+
26
+ Subclasses need to implement:
27
+ **abstract property**
28
+ - `errors` -
29
+ Subtypes of generic `ValidationError` classes.
30
+ - `array_type` -
31
+ Array type (to be used in `isinstance(obj, adapter.array_type)` check)
32
+ - `comparisons` -
33
+ Subtype of generic `Comparisons` class.
34
+
35
+ **abstract method**
36
+ - `create_array` -
37
+ Create an array object from data with specified dtype(like).
38
+ - `create_empty_array` -
39
+ Create an empty array object with specified dtype(like).
40
+ - `is_array_empty` -
41
+ Check if array is empty.
42
+ - `change_dtype` -
43
+ Change array data type.
44
+ - `dtype_from_dtypelike` -
45
+ Create dtype object from dtypelike.
46
+ - `dtypes_equal` -
47
+ Check if dtypes are equal
48
+ - `get_values` -
49
+ Get a list of values from array
50
+
51
+ (`dtypes_equal` and `get_values` are neccessary because `__eq__` and `__getitem__`
52
+ methods respectively can have different parameter names)
53
+
54
+ (introduced ***v0.1***, last_modified ***v0.4***)
55
+ """
56
+
57
+ @property
58
+ @abstractmethod
59
+ def errors(self) -> GenericErrors[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT]: ...
60
+
61
+ @property
62
+ @abstractmethod
63
+ def array_type(self) -> type[ArrayT]: ...
64
+
65
+ @property
66
+ @abstractmethod
67
+ def comparisons(self) -> Comparisons[ArrayT, ArrayIndicesT, ComparableValueT]:
68
+ """Methods used by `ComparisonValidator`"""
69
+
70
+ @abstractmethod
71
+ def change_dtype(self, arr: ArrayT, dtypelike: DTypeLikeT) -> ArrayT: ...
72
+
73
+ @abstractmethod
74
+ def create_array(
75
+ self, obj: Any, dtypelike: DTypeLikeT | EllipsisType
76
+ ) -> ArrayT: ...
77
+
78
+ @abstractmethod
79
+ def is_array_empty(self, arr: ArrayT) -> bool: ...
80
+
81
+ @abstractmethod
82
+ def create_empty_array(
83
+ self, ax_sizes: AxSizes, dtypelike: DTypeLikeT | EllipsisType
84
+ ) -> ArrayT: ...
85
+
86
+ @abstractmethod
87
+ def dtype_from_dtypelike(self, dtypelike: DTypeLikeT) -> DTypeT: ...
88
+
89
+ @abstractmethod
90
+ def dtypes_equal(self, actual_dtype: DTypeT, expected_dtype: DTypeT) -> bool: ...
91
+
92
+ @abstractmethod
93
+ def get_values(
94
+ self, arr: ArrayT, indices: Optional[ArrayIndicesT]
95
+ ) -> Optional[list[Any]]: ...
96
+
97
+ @abstractmethod
98
+ def select_subset(
99
+ self, arr: ArrayT, ax: AxisNameAndIdx, fields: Sequence[FieldNameAndIdx]
100
+ ) -> ArrayT: ...
101
+
102
+ @abstractmethod
103
+ def get_values_from_subset(
104
+ self,
105
+ arr: ArrayT,
106
+ indices: Optional[ArrayIndicesT],
107
+ ax: AxisNameAndIdx,
108
+ fields: Sequence[FieldNameAndIdx],
109
+ ) -> Optional[dict[FieldNameAndIdx, Any]]: ...
@@ -0,0 +1,127 @@
1
+ """
2
+ *import* `AxesTuple` **TypeAlias** - defines axes of schema
3
+
4
+ *import* `FieldsTuple` **TypeAlias** - defines fields of schema axis
5
+
6
+ *import* `Field` **dataclass** - defines constraints on field
7
+ """
8
+
9
+ from dataclasses import dataclass
10
+ from typing import ClassVar, Generic, Optional, TypeAlias
11
+
12
+ from valarray.core.validators import Validator
13
+
14
+ from .types.generics import ArrayIndicesT, ArrayT, ComparableValueT
15
+
16
+
17
+ @dataclass
18
+ class Field(Generic[ArrayT, ArrayIndicesT, ComparableValueT]):
19
+ """Field of an array axis.
20
+
21
+ Arguments:
22
+ name (Optional[str]): Optional descriptive name of field. Defaults to `None`.
23
+ validators (tuple[Validator[ArrayT, ArrayIndicesT], ...]):
24
+ optional list of validators applied to field values
25
+ lt (Optional[ComparableValueT]):
26
+ Optional constraint -> field values less than. Defaults to None.
27
+ le (Optional[ComparableValueT]):
28
+ Optional constraint -> field values less or equal than. Defaults to None.
29
+ ge (Optional[ComparableValueT]):
30
+ Optional constraint -> field values greater than. Defaults to None.
31
+ gt (Optional[ComparableValueT]):
32
+ Optional constraint -> field values greater or equal than. Defaults to None.
33
+ eq (Optional[ComparableValueT]):
34
+ Optional constraint -> field values equal to. Defaults to None.
35
+
36
+ (introduced ***v0.4***)
37
+ """
38
+
39
+ name: Optional[str] = None
40
+ validators: tuple[Validator[ArrayT, ArrayIndicesT], ...] = ()
41
+
42
+ lt: Optional[ComparableValueT] = None
43
+ le: Optional[ComparableValueT] = None
44
+ ge: Optional[ComparableValueT] = None
45
+ gt: Optional[ComparableValueT] = None
46
+ eq: Optional[ComparableValueT] = None
47
+
48
+
49
+ @dataclass(unsafe_hash=True)
50
+ class _NameAndIdx:
51
+ _specifier: ClassVar[str] = "Field/Axis"
52
+ idx: int
53
+ name: Optional[str] = None
54
+
55
+ def __str__(self) -> str:
56
+ name_str = f": '{self.name}'" if self.name is not None else ""
57
+ return f"{self._specifier} < {self.idx} >{name_str}"
58
+
59
+
60
+ @dataclass(unsafe_hash=True)
61
+ class AxisNameAndIdx(_NameAndIdx):
62
+ """Name and index of axis.
63
+
64
+ Example:
65
+ ```
66
+ a_named = AxisNameAndIdx(name="example_axis", idx=3)
67
+ a = AxisNameAndIdx(idx=3)
68
+
69
+ print(a_named)
70
+ >>> Axis < 3 >: 'example_axis'
71
+
72
+ print(a)
73
+ >>> Axis < 3 >
74
+ ```
75
+
76
+ (introduced ***v0.4***)
77
+ """
78
+
79
+ _specifier: ClassVar[str] = "Axis"
80
+
81
+
82
+ @dataclass(unsafe_hash=True)
83
+ class FieldNameAndIdx(_NameAndIdx):
84
+ """Name and index of field.
85
+
86
+ Example:
87
+ ```
88
+ f_named = FieldNameAndIdx(name="example_field", idx=3)
89
+ f = FieldNameAndIdx(idx=3)
90
+
91
+ print(f_named)
92
+ >>> Field < 3 >: 'example_field'
93
+
94
+ print(f)
95
+ >>> Field < 3 >
96
+ ```
97
+
98
+ (introduced ***v0.4***)
99
+ """
100
+
101
+ _specifier: ClassVar[str] = "Field"
102
+
103
+
104
+ FieldsTuple: TypeAlias = tuple[
105
+ str | Field[ArrayT, ArrayIndicesT, ComparableValueT], ...
106
+ ]
107
+ """Tuple of array fields.
108
+
109
+ (introduced ***v0.1.1***, last_modified ***v0.4***)
110
+ """
111
+
112
+ AxesTuple: TypeAlias = tuple[
113
+ str | int | FieldsTuple[ArrayT, ArrayIndicesT, ComparableValueT], ...
114
+ ]
115
+ """Tuple of array axes. Can be either name, size or a tuple of fields.
116
+ ```
117
+ import valarray.core
118
+
119
+ axes = (
120
+ 16,
121
+ 'items',
122
+ ('x','y', valarray.core.Field()),
123
+ )
124
+ ```
125
+
126
+ (introduced ***v0.1.1***, last_modified ***v0.4***)
127
+ """
@@ -0,0 +1,71 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Generic
3
+
4
+ from valarray.core.types import ArrayIndicesT, ArrayT, ComparableValueT
5
+
6
+
7
+ class Comparisons(ABC, Generic[ArrayT, ArrayIndicesT, ComparableValueT]):
8
+ """Generic comparison functions.
9
+
10
+ Type variables:
11
+ - `ArrayT` - type of array object
12
+ - `ArrayIndexT` - object(s) that can select values from array using `__getitem__` method.
13
+ - `ComparableValueT` - value array can be compared with
14
+ using `<`, `<=`, `==`, `=>`, `>` operators
15
+
16
+ Subclasses need to implement:
17
+ **abstract method**
18
+ - `where_not_lt` -
19
+ Returns indices of values which are not less than value.
20
+ - `where_not_le` -
21
+ Returns indices of values which are not less than or equal value.
22
+ - `where_not_ge` -
23
+ Returns indices of values which are not greater than or equal value.
24
+ - `where_not_gt` -
25
+ Returns indices of values which are not greater than value.
26
+ - `where_not_eq` -
27
+ Returns indices of values which are not equal value.
28
+ - `n_indices` -
29
+ Returns number of indices.
30
+
31
+
32
+ (introduced ***v0.3***, last_modified ***v0.4***)
33
+ """
34
+
35
+ @abstractmethod
36
+ def where_not_lt(self, arr: ArrayT, value: ComparableValueT) -> ArrayIndicesT:
37
+ """(introduced ***v0.3***)"""
38
+
39
+ @abstractmethod
40
+ def where_not_le(self, arr: ArrayT, value: ComparableValueT) -> ArrayIndicesT:
41
+ """(introduced ***v0.3***)"""
42
+
43
+ @abstractmethod
44
+ def where_not_ge(self, arr: ArrayT, value: ComparableValueT) -> ArrayIndicesT:
45
+ """(introduced ***v0.3***)"""
46
+
47
+ @abstractmethod
48
+ def where_not_gt(self, arr: ArrayT, value: ComparableValueT) -> ArrayIndicesT:
49
+ """(introduced ***v0.3***)"""
50
+
51
+ @abstractmethod
52
+ def where_not_eq(self, arr: ArrayT, value: ComparableValueT) -> ArrayIndicesT:
53
+ """(introduced ***v0.3***)"""
54
+
55
+ @abstractmethod
56
+ def n_indices(self, indices: ArrayIndicesT) -> int:
57
+ """(introduced ***v0.3***)"""
58
+
59
+ def __hash__(self) -> int:
60
+ # HACK: For ComparisonValidator to be hashable, *Comparisons must be hashable.
61
+ # Because all instances of each type of *Comparisons class are the same
62
+ # I just convert class name into integer and use it as a hash
63
+ # using: https://stackoverflow.com/questions/61848516/convert-whole-ascii-string-into-a-int
64
+ cls_name = self.__class__.__name__
65
+ return int.from_bytes(cls_name.encode("utf-8"), byteorder="big", signed=False)
66
+
67
+ def __eq__(self, other: Any) -> bool:
68
+ try:
69
+ return hash(self) == hash(other)
70
+ except TypeError:
71
+ return False
@@ -0,0 +1,41 @@
1
+ """
2
+ # Errors
3
+ *import* `ValidationError` **ABC**
4
+
5
+ *import* `CannotCreateArrayError` **ValidationError**
6
+
7
+ *import* `IncorrectDTypeError` **ValidationError**
8
+
9
+ *import* `CannotCoerceDTypeError` **ValidationError**
10
+
11
+ *import* `IncorrectAxNumberError` **ValidationError**
12
+
13
+ *import* `IncorrectAxSizesError` **ValidationError**
14
+
15
+ *import* `InvalidArrayValuesError` **ValidationError**
16
+
17
+ *import* `InvalidFieldValuesError` **ValidationError**
18
+
19
+
20
+ # Exceptions
21
+ *import* `ValidationException` **Exception**
22
+
23
+ *import* `CreateArrayException` **Exception**
24
+
25
+ *import* `CoerceDTypeException` **Exception**
26
+
27
+ # Other
28
+ *import* `ValidationErrorList` **UserList**
29
+
30
+ *import* `GenericErrors` **dataclass**
31
+ """
32
+
33
+ # pyright: reportUnusedImport=false
34
+ from .error_list import ValidationErrorList
35
+ from .exceptions import CoerceDTypeException, CreateArrayException, ValidationException
36
+ from .generic import GenericErrors
37
+ from .validation_errors.array_creation import CannotCreateArrayError
38
+ from .validation_errors.axes import IncorrectAxNumberError, IncorrectAxSizesError
39
+ from .validation_errors.base import ValidationError
40
+ from .validation_errors.dtype import CannotCoerceDTypeError, IncorrectDTypeError
41
+ from .validation_errors.values import InvalidArrayValuesError, InvalidFieldValuesError
@@ -0,0 +1,87 @@
1
+ from __future__ import annotations
2
+
3
+ from collections import UserList
4
+ from typing import Generic, Sequence, overload
5
+
6
+ from .validation_errors.base import SelectedValidationErrorT, ValidationErrorT
7
+
8
+ _ErrorTypes = (
9
+ type[SelectedValidationErrorT] | tuple[type[SelectedValidationErrorT], ...]
10
+ )
11
+ """Error type or a tuple of error types.
12
+ For example `IncorrectAxSizesError` or `(IncorrectAxSizesError, IncorrectDTypeError)`"""
13
+
14
+
15
+ class ValidationErrorList(UserList[ValidationErrorT], Generic[ValidationErrorT]):
16
+ """List of `ValidationError` objects.
17
+
18
+ Compared to built-in list, implements two methods:
19
+ - `raise_`/`raise_on_errors` - raises `ValidationException` if not empty.
20
+ - `__getitem__` - in addition to indexing by integer or slice can be filtered by type
21
+ or tuple of types of `ValidationError`
22
+
23
+ ### Examples:
24
+ ```
25
+ errs = ValidationErrorList(
26
+ [IncorrectAxSizesError(...), IncorrectDTypeError(...), InvalidFieldValuesError(...)]
27
+ )
28
+
29
+ err = errs[0]
30
+ >>> IncorrectAxSizesError(...)
31
+
32
+ sliced_errs = errs[:2]
33
+ >>> [IncorrectAxSizesError(...), IncorrectDTypeError(...)]
34
+
35
+ filtered_errs_type = errs[IncorrectAxSizesError]
36
+ >>> [IncorrectAxSizesError(...)]
37
+
38
+ filtered_errs_tuple = errs[(IncorrectAxSizesError, InvalidFieldValuesError)]
39
+ >>> [IncorrectAxSizesError(...), InvalidFieldValuesError(...)]
40
+ ```
41
+ """
42
+
43
+ def __init__(self, errs: Sequence[ValidationErrorT]):
44
+ super().__init__(errs)
45
+
46
+ def raise_(self):
47
+ """Raises `ValidationException` if there are errors."""
48
+ # NOTE: scoped import to prevent circular import
49
+ # ValidationException -> ValidationErrorList -> ValidationException
50
+ from .exceptions import ValidationException
51
+
52
+ if self.data:
53
+ raise ValidationException(None, ValidationErrorList(self.data))
54
+
55
+ raise_on_errors = raise_
56
+
57
+ @overload
58
+ def __getitem__(self, i: int) -> ValidationErrorT: ...
59
+
60
+ @overload
61
+ def __getitem__(self, i: slice) -> ValidationErrorList[ValidationErrorT]: ...
62
+
63
+ @overload
64
+ def __getitem__(
65
+ self,
66
+ i: _ErrorTypes[SelectedValidationErrorT],
67
+ ) -> ValidationErrorList[SelectedValidationErrorT]: ...
68
+
69
+ def __getitem__(
70
+ self,
71
+ i: int | slice | _ErrorTypes[SelectedValidationErrorT],
72
+ ) -> (
73
+ ValidationErrorList[SelectedValidationErrorT]
74
+ | ValidationErrorList[ValidationErrorT]
75
+ | ValidationErrorT
76
+ ):
77
+ if isinstance(i, (type, tuple)):
78
+ filtered_errs: list[SelectedValidationErrorT] = [
79
+ err for err in self.data if isinstance(err, i)
80
+ ] # pyright: ignore[reportAssignmentType] | I don't know why pyright complains
81
+ items = ValidationErrorList(filtered_errs)
82
+ elif isinstance(i, slice):
83
+ items = type(self)(self.data[i])
84
+ else:
85
+ items = self.data[i]
86
+
87
+ return items
@@ -0,0 +1,75 @@
1
+ from typing import Generic, Optional
2
+
3
+ from .error_list import ValidationErrorList
4
+ from .validation_errors.array_creation import CannotCreateArrayError
5
+ from .validation_errors.base import ValidationErrorT
6
+ from .validation_errors.dtype import CannotCoerceDTypeError
7
+
8
+
9
+ # TODO: ugh, typing issues, pls fix ->
10
+ # except ValidationException as exc:
11
+ # exc.errs -> 'Unknown'
12
+ class ValidationException(ValueError, Generic[ValidationErrorT]):
13
+ """Exception caused by failed array validation.
14
+
15
+ Attributes:
16
+ cls_name (Optional[str]):
17
+ Optional name of ValidatedArray subclass that caused this exception.
18
+ errs (ValidationErrorList[ValidationError):
19
+ List of validation errors responsible.
20
+
21
+ (introduced ***v0.1***, last_modified ***v0.4***)
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ cls_name: Optional[str],
27
+ errs: ValidationErrorList[ValidationErrorT],
28
+ *args: object,
29
+ ) -> None:
30
+
31
+ super().__init__(*args)
32
+
33
+ self.cls_name = cls_name
34
+ self.errs = errs
35
+ """List of validation errors."""
36
+
37
+ def __str__(self) -> str:
38
+ prefix = f"'{self.cls_name}' " if self.cls_name is not None else ""
39
+ err_msgs = "\n".join([e.msg for e in self.errs])
40
+ return f"{prefix}validation failed:\n" + err_msgs
41
+
42
+
43
+ class CreateArrayException(ValidationException):
44
+ """Special case of `ValidationException`
45
+ on failure to create a validated array from generic data.
46
+
47
+ Attributes:
48
+ cls_name (str):
49
+ Name of ValidatedArray subclass that caused this exception.
50
+ errs (ValidationErrorList[CannotCreateArrayError]): List containing error responsible.
51
+
52
+ (introduced ***v0.1***, last_modified ***v0.4***)
53
+ """
54
+
55
+ def __init__(self, cls_name: str) -> None:
56
+ super().__init__(
57
+ cls_name=cls_name, errs=ValidationErrorList([CannotCreateArrayError()])
58
+ )
59
+
60
+
61
+ class CoerceDTypeException(ValidationException):
62
+ """Special case of `ValidationException`
63
+ on failure to coerce the data type of an existing array.
64
+
65
+ Attributes:
66
+ cls_name (str):
67
+ Name of ValidatedArray subclass that caused this exception.
68
+ errs (ValidationErrorList[CannotCoerceDTypeError]):
69
+ List containing error with actual and target data type information.
70
+
71
+ (introduced ***v0.1***, last_modified ***v0.4***)
72
+ """
73
+
74
+ def __init__(self, cls_name: str, err: CannotCoerceDTypeError) -> None:
75
+ super().__init__(cls_name=cls_name, errs=ValidationErrorList([err]))