valarray 0.4.1__tar.gz → 0.4.2__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.
Files changed (106) hide show
  1. {valarray-0.4.1 → valarray-0.4.2}/PKG-INFO +44 -40
  2. {valarray-0.4.1 → valarray-0.4.2}/README.md +43 -39
  3. {valarray-0.4.1 → valarray-0.4.2}/pyproject.toml +1 -1
  4. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/errors_exceptions.py +5 -3
  5. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_validators.py +0 -3
  6. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/field_values/test_val_field_values_utils.py +5 -0
  7. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/test_val_array_values.py +4 -3
  8. {valarray-0.4.1 → valarray-0.4.2}/tests/test_imports.py +3 -0
  9. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/array.py +7 -3
  10. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/array_type_adapter/adapter.py +3 -1
  11. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/array_type_adapter/errors.py +16 -4
  12. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/axes_and_fields.py +6 -4
  13. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/exceptions.py +4 -7
  14. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/values.py +14 -8
  15. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/array.py +26 -7
  16. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/array_values.py +11 -10
  17. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/field_values/core.py +13 -7
  18. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/field_values/types_and_data_structures.py +5 -8
  19. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/field_values/utils.py +2 -2
  20. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validators/__init__.py +11 -0
  21. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validators/base.py +10 -1
  22. valarray-0.4.2/valarray/core/validators/types.py +29 -0
  23. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/array.py +2 -5
  24. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/array_type_adapter/errors.py +1 -1
  25. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/errors_exceptions.py +2 -2
  26. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/validation_functions.py +11 -6
  27. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/validators.py +18 -2
  28. {valarray-0.4.1 → valarray-0.4.2}/.coveragerc +0 -0
  29. {valarray-0.4.1 → valarray-0.4.2}/.gitignore +0 -0
  30. {valarray-0.4.1 → valarray-0.4.2}/assets/images/valarray_logo.svg +0 -0
  31. {valarray-0.4.1 → valarray-0.4.2}/docs/dependency_graphs/core.mmd +0 -0
  32. {valarray-0.4.1 → valarray-0.4.2}/docs/dependency_graphs/core_validation_errors.mmd +0 -0
  33. {valarray-0.4.1 → valarray-0.4.2}/docs/dependency_graphs/core_validation_functions.mmd +0 -0
  34. {valarray-0.4.1 → valarray-0.4.2}/docs/dependency_graphs/numpy.mmd +0 -0
  35. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue1_problem.py +0 -0
  36. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue1_solution.py +0 -0
  37. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue2_problem.py +0 -0
  38. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue2_solution.py +0 -0
  39. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue_3_problem.py +0 -0
  40. {valarray-0.4.1 → valarray-0.4.2}/docs/example_code/introduction/issue_3_solution.py +0 -0
  41. {valarray-0.4.1 → valarray-0.4.2}/requirements.txt +0 -0
  42. {valarray-0.4.1 → valarray-0.4.2}/requirements_dev.txt +0 -0
  43. {valarray-0.4.1 → valarray-0.4.2}/requirements_dev_optional.txt +0 -0
  44. {valarray-0.4.1 → valarray-0.4.2}/test_data/core/string_utils.py +0 -0
  45. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/__init__.py +0 -0
  46. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/array_and_dtype.py +0 -0
  47. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/array_type_adapter.py +0 -0
  48. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/comparisons.py +0 -0
  49. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/validated_array.py +0 -0
  50. {valarray-0.4.1 → valarray-0.4.2}/tests/core/classes_for_testing/validators.py +0 -0
  51. {valarray-0.4.1 → valarray-0.4.2}/tests/core/errors_exceptions/test_axes_errors.py +0 -0
  52. {valarray-0.4.1 → valarray-0.4.2}/tests/core/errors_exceptions/test_dtype_errors.py +0 -0
  53. {valarray-0.4.1 → valarray-0.4.2}/tests/core/errors_exceptions/test_error_list.py +0 -0
  54. {valarray-0.4.1 → valarray-0.4.2}/tests/core/errors_exceptions/test_exceptions.py +0 -0
  55. {valarray-0.4.1 → valarray-0.4.2}/tests/core/errors_exceptions/test_values_errors.py +0 -0
  56. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_array.py +0 -0
  57. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_axes_and_fields.py +0 -0
  58. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_data_structures.py +0 -0
  59. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_misc.py +0 -0
  60. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_string_utils.py +0 -0
  61. {valarray-0.4.1 → valarray-0.4.2}/tests/core/test_utils.py +0 -0
  62. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/field_values/test_ax_and_field_strings.py +0 -0
  63. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/field_values/test_val_field_values_core.py +0 -0
  64. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/test_val_array.py +0 -0
  65. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/test_val_dtype.py +0 -0
  66. {valarray-0.4.1 → valarray-0.4.2}/tests/core/validation_functions/test_val_shape.py +0 -0
  67. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/common.py +0 -0
  68. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/test_adapter.py +0 -0
  69. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/test_numpy_array.py +0 -0
  70. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/test_numpy_comparisons.py +0 -0
  71. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/test_numpy_errors_and_exceptions.py +0 -0
  72. {valarray-0.4.1 → valarray-0.4.2}/tests/numpy/test_validation.py +0 -0
  73. {valarray-0.4.1 → valarray-0.4.2}/valarray/__init__.py +0 -0
  74. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/__init__.py +0 -0
  75. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/array_type_adapter/__init__.py +0 -0
  76. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/array_type_adapter/comparisons.py +0 -0
  77. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/data_structures.py +0 -0
  78. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/__init__.py +0 -0
  79. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/error_list.py +0 -0
  80. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/__init__.py +0 -0
  81. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/array_creation.py +0 -0
  82. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/axes.py +0 -0
  83. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/base.py +0 -0
  84. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/errors_exceptions/validation_errors/dtype.py +0 -0
  85. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/string_utils/__init__.py +0 -0
  86. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/string_utils/array.py +0 -0
  87. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/string_utils/field.py +0 -0
  88. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/string_utils/general.py +0 -0
  89. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/string_utils/headings.py +0 -0
  90. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/types/__init__.py +0 -0
  91. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/types/generics.py +0 -0
  92. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/types/other.py +0 -0
  93. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/utils.py +0 -0
  94. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/__init__.py +0 -0
  95. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/dtype.py +0 -0
  96. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/field_values/__init__.py +0 -0
  97. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/shape.py +0 -0
  98. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validation_functions/utils.py +0 -0
  99. {valarray-0.4.1 → valarray-0.4.2}/valarray/core/validators/value_comparisons.py +0 -0
  100. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/__init__.py +0 -0
  101. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/array_type_adapter/__init__.py +0 -0
  102. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/array_type_adapter/adapter.py +0 -0
  103. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/array_type_adapter/comparisons.py +0 -0
  104. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/axes_and_fields.py +0 -0
  105. {valarray-0.4.1 → valarray-0.4.2}/valarray/numpy/types.py +0 -0
  106. {valarray-0.4.1 → valarray-0.4.2}/valarray/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valarray
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Library for validating numpy arrays.
5
5
  Project-URL: Homepage, https://codeberg.org/jfranek/valarray
6
6
  Author-email: "J. Franek" <franek.j27@email.cz>
@@ -14,7 +14,7 @@ Requires-Python: >=3.7
14
14
  Requires-Dist: numpy>=2
15
15
  Description-Content-Type: text/markdown
16
16
 
17
- ![](assets/images/valarray_logo.svg)
17
+ ![valarray logo](https://codeberg.org/jfranek/valarray/raw/branch/main/assets/images/valarray_logo.svg)
18
18
 
19
19
  In short, library for validating numpy arrays that also helps with static analysis and documentation. In long, see [Library rationale](#library-rationale).
20
20
 
@@ -55,8 +55,10 @@ except ValidationException as v_exc:
55
55
  >>> [-2.0, -6.0]
56
56
  ```
57
57
 
58
- # Table of contents
59
- - [Table of contents](#table-of-contents)
58
+ <!-- NOTE: Headings that are used as relative links (so most of them) must have id tag defined
59
+ (see https://github.com/pypa/readme_renderer/issues/169#issuecomment-808577486) otherwise links do not work on pypi.-->
60
+
61
+ # Table of contents <!-- omit from toc -->
60
62
  - [Library rationale](#library-rationale)
61
63
  - [1) Invalid values causing unintended behaviour](#1-invalid-values-causing-unintended-behaviour)
62
64
  - [Problem](#problem)
@@ -86,15 +88,16 @@ except ValidationException as v_exc:
86
88
  - [Settings](#settings)
87
89
  - [Caveats](#caveats)
88
90
  - [Changelog](#changelog)
91
+ - [0.4.2](#042)
89
92
  - [0.4.1](#041)
90
93
  - [0.4](#04)
91
94
  - [Breaking changes](#breaking-changes)
92
95
 
93
- # Library rationale
96
+ # Library rationale<a id="library-rationale"></a>
94
97
  This library aims to help with 3 issues encountered when working with numpy arrays:
95
98
 
96
- ## 1) Invalid values causing unintended behaviour
97
- ### Problem
99
+ ## 1) Invalid values causing unintended behaviour<a id="1-invalid-values-causing-unintended-behaviour"></a>
100
+ ### Problem<a id="problem"></a>
98
101
  Invalid values can cause crashes, or worse, cause silent failures.
99
102
 
100
103
  For example the following code fails silently when attempting to cut patches from image using bounding boxes with invalid coordinates.
@@ -128,7 +131,7 @@ for patch in patches:
128
131
  >>> (50, 200, 3)
129
132
  ```
130
133
 
131
- ### Solution
134
+ ### Solution<a id="solution"></a>
132
135
  Validate boxes array first. If errors are encountered, print descriptive error message(s).
133
136
 
134
137
  ```python
@@ -182,8 +185,8 @@ except ValidationException as exc:
182
185
  >>> Field < 0 >: [-10]
183
186
  ```
184
187
 
185
- ## 2) Limited support for static analysis
186
- ### Problem
188
+ ## 2) Limited support for static analysis<a id="2-limited-support-for-static-analysis"></a>
189
+ ### Problem<a id="problem-1"></a>
187
190
  Support for static analysis is limited. Tools can only check whether the datatype is correct, but not shape, values or what those values actually represent.
188
191
 
189
192
  For example, the function to crop patches needs the boxes to be defined by `xmin, ymin, xmax, ymax` but doesn't throw an error if input boxes are defined by `x_center, y_center, width, height` and static analysis tools cannot detect this error using bulit-in numpy types.
@@ -227,7 +230,7 @@ for patch in patches_inv:
227
230
  >>> (0, 200, 3)
228
231
  ```
229
232
 
230
- ### Solution
233
+ ### Solution<a id="solution-1"></a>
231
234
  `ValidatedNumpyArray` subclasses can represent these two types of boxes arrays, and can be used instead of bare numpy arrays in function/method signatures and such.
232
235
  ```python
233
236
  import numpy as np
@@ -294,8 +297,8 @@ for patch in patches_inv:
294
297
  print(patch.shape)
295
298
  ```
296
299
 
297
- ## 3) Need for explicit documentation
298
- ### Problem
300
+ ## 3) Need for explicit documentation<a id="3-need-for-explicit-documentation"></a>
301
+ ### Problem<a id="problem-2"></a>
299
302
  Using built-in numpy types provides only documentation for data types. Shape, values, constraints and what the array represents need to be explicitly documented either in comments or docstrings.
300
303
 
301
304
  If this type of array is used in multiple places / functions, this can cause duplicated documentation.
@@ -324,7 +327,7 @@ def cut_patches(
324
327
  return patches
325
328
  ```
326
329
 
327
- ### Solution
330
+ ### Solution<a id="solution-2"></a>
328
331
  Defining data type, schema and constraints on a `ValidatedNumpyArray` subclass already implicitly documents them.
329
332
 
330
333
  This can be complemented by adding additional (or summary) documentation in the class docstring.
@@ -372,8 +375,8 @@ def cut_patches(
372
375
  ```
373
376
 
374
377
 
375
- # Validated Array
376
- ## Defining a validated array
378
+ # Validated Array<a id="validated-array"></a>
379
+ ## Defining a validated array<a id="defining-a-validated-array"></a>
377
380
  Subclass `ValidatedNumpyArray` and define:
378
381
  - `dtype` - expected data type specification (such as `float`, `"float64"`, `np.float64`).
379
382
  If not specified, data type is not validated.
@@ -382,7 +385,7 @@ Subclass `ValidatedNumpyArray` and define:
382
385
  - `schema` - expected shape specification (of type `valarray.numpy.axes_and_fields.AxesTuple`). For details, see [Array Schema](#array-schema).
383
386
  If not specified, shape is not validated (and no field validators are applied).
384
387
  - `lt`/`le`/`ge`/`gt`/`eq` - basic array value constraints -> less (or equal) than, greater (or equal) than, equal to
385
- - `validators` - optional list of validators applied to the whole array. For details, see [Validators](##validators).
388
+ - `validators` - optional validator or a tuple of validators applied to the whole array. For details, see [Validators](##validators).
386
389
 
387
390
  ```python
388
391
  import numpy as np
@@ -393,7 +396,7 @@ class ExampleValidatedNumpyArray(ValidatedNumpyArray):
393
396
  schema = ('batch_size', 3, 5)
394
397
  ```
395
398
 
396
- ## Creating a validated array instance
399
+ ## Creating a validated array instance<a id="creating-a-validated-array-instance"></a>
397
400
  There are 4 ways to create a validated array instance:
398
401
  - validate an existing array
399
402
  ```python
@@ -436,7 +439,7 @@ v_arr = ExampleValidatedNumpyArray(np.array([1,2],dtype=np.float32), coerce_dtyp
436
439
  v_arr = ExampleValidatedNumpyArray(np.array([1,2],dtype=np.float32), coerce_dtype=True, validate=False)
437
440
  ```
438
441
 
439
- ## Accessing array values
442
+ ## Accessing array values<a id="accessing-array-values"></a>
440
443
  You can access the underlying array using the `.array`/`.a_` property:
441
444
  ```python
442
445
  arr = v_arr.array
@@ -459,7 +462,7 @@ class SpecifiedDataTypeArray(ValidatedNumpyArray[np.float32]): ...
459
462
  arr = SpecifiedDataTypeArray(...).array # np.typing.NDArray[np.float32]
460
463
  ```
461
464
 
462
- # Validation functions
465
+ # Validation functions<a id="validation-functions"></a>
463
466
  Array validation is designed to be modular and composable and validation functions can be used on they own if only runtime validation is required.
464
467
  Each validation function returns a list of errors, from which a `ValidationException` can be raised. For details see [Catching exceptions](#catching-exceptions).
465
468
  ```python
@@ -498,7 +501,7 @@ and a "composite" validation function:
498
501
  - *returns* `NumpyInvalidArrayValuesError`/`NumpyInvalidFieldValuesError` or no errors.
499
502
 
500
503
 
501
- # Array schema
504
+ # Array schema<a id="array-schema"></a>
502
505
  Schema defines expected axes, and for each axis its' fields and optionally constraints on the field values.
503
506
 
504
507
  Axes can be defined with:
@@ -519,11 +522,11 @@ schema = (
519
522
  ("field_a", Field())
520
523
  )
521
524
  ```
522
- ## Field
525
+ ## Field<a id="field"></a>
523
526
  Defines (optional) name and value constrints for array field. More specifically:
524
527
  - `name` - descriptive name used in error messages (if missing, field index is used instead)
525
528
  - `lt`/`le`/`ge`/`gt`/`eq` - basic array value constraints -> less (or equal) than, greater (or equal) than, equal to
526
- - `validators` - other validators of fields values. For details, see [Validators](##validators).
529
+ - `validators` - optional validator or a tuple of validators applied to fields values. For details, see [Validators](##validators).
527
530
 
528
531
  ```python
529
532
  from typing import Any
@@ -538,8 +541,8 @@ f1 = Field("example_named_field", ge=0)
538
541
  f2 = Field(gt=10, validators=(ExampleNumpyValidator(),))
539
542
  ```
540
543
 
541
- ## Array schema examples
542
- ### rectangles
544
+ ## Array schema examples<a id="array-schema-examples"></a>
545
+ ### rectangles<a id="rectangles"></a>
543
546
  An array of arbitrary number of rectangles defined by min and max coordinates which has two axes: *n_rects* and *rect*.
544
547
  Axis *rect* is has 4 fields: *x_min*,*y_min*,*x_max*,*y_max*, where values must be greater or equal to zero.
545
548
 
@@ -572,10 +575,10 @@ arr = np.array(
572
575
  Rect.validate(arr)
573
576
  ```
574
577
 
575
- # Validators
578
+ # Validators<a id="validators"></a>
576
579
  Validators are objects that perform arbitrary validation of array or field values defined by user.
577
580
 
578
- ## Defining a validator
581
+ ## Defining a validator<a id="defining-a-validator"></a>
579
582
  Validators must subclass `valarray.numpy.NumpyValidator` Abstract Base Class
580
583
  and implement the `.validate()` method that takes an array as an input and results in success/failure of validation using these options:
581
584
 
@@ -588,7 +591,7 @@ and implement the `.validate()` method that takes an array as an input and resul
588
591
  - *returns* `False`
589
592
  - *raises* `ValueError`
590
593
 
591
- ### ValidationResult
594
+ ### ValidationResult<a id="validationresult"></a>
592
595
  Contains result status of validation `status="OK"`/`status="FAIL"`
593
596
 
594
597
  Can also optionally contain:
@@ -620,7 +623,7 @@ indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
620
623
  res = ValidationResult(status="FAIL", indices_invalid=indices, msg="Optional error message.")
621
624
  ```
622
625
 
623
- ### Example Validator
626
+ ### Example Validator<a id="example-validator"></a>
624
627
  ```python
625
628
  from dataclasses import dataclass
626
629
  from typing import Literal
@@ -657,7 +660,7 @@ class ExampleIsEvenValidator(NumpyValidator[np.uint8]):
657
660
  return ValidationResult("FAIL", indices_invalid=~even)
658
661
  ```
659
662
 
660
- # Catching exceptions
663
+ # Catching exceptions<a id="catching-exceptions"></a>
661
664
  Failed validation results in `valarray.core.errors_exceptions.ValidationException` being raised containing list of errors responsible (and name of array class if available).
662
665
 
663
666
  Main error types are:
@@ -683,42 +686,43 @@ except ValidationException as exc:
683
686
  axis_errs = exc.errs[(IncorrectAxSizesError, IncorrectAxNumberError)]
684
687
  ```
685
688
 
686
- ## Special exceptions and errors
689
+ ## Special exceptions and errors<a id="special-exceptions-and-errors"></a>
687
690
  There are two special subclasses of `ValidationException` with associated validation errors raised during [instantiation](#creating-a-validated-array-instance):
688
691
  - `CreateArrayException` -> `CannotCreateArrayError` - Array cannot be created from supplied object.
689
692
  - `CoerceDTypeException` -> `CannotCoerceDTypeError` - If array data type cannot be coerced when creating array with `ValidatedArray(coerce_dtype=True)`
690
693
 
691
694
 
692
- ## Generic Errors
695
+ ## Generic Errors<a id="generic-errors"></a>
693
696
  These error types have subclasses ensuring proper type hints:
694
697
  - `IncorrectDTypeError` -> `NumpyIncorrectDTypeError`
695
698
  - `CannotCoerceDTypeError` -> `NumpyCannotCoerceDTypeError`
696
699
  - `InvalidArrayValuesError` -> `NumpyInvalidArrayValuesError`
697
700
  - `InvalidFieldValuesError` -> `NumpyInvalidFieldValuesError`
698
701
 
699
- # Settings
702
+ # Settings<a id="settings"></a>
700
703
  Global settings for the library are defined in `valarray.settings` and can be modified using environment variables.
701
704
  | ***variable name*** | ***environment variable*** | default value | description |
702
705
  |---------------------|------------------------------|---------------|-----------------------------------------------------|
703
706
  | function_cache_size | VALARRAY_FUNCTION_CACHE_SIZE | 512 | cache size for (internal) frequently used functions |
704
707
 
705
-
706
-
707
- # Caveats
708
+ # Caveats<a id="caveats"></a>
708
709
  - I cannot guarantee that the test suite is foolproof ATM as I'm currently the only one testing this library.
709
710
  - Library has so far only been tested with `python==3.12` and `numpy==2.4.0`
710
711
  - Library isn't tested for performance, use in production only if the primary bottleneck is brain and not hardware.
711
712
 
712
- # Changelog
713
- ## 0.4.1
713
+ # Changelog<a id="changelog"></a>
714
+ ## 0.4.2<a id="042"></a>
715
+ - changed `ValidatedArray`, `Field` classes and `validate_array`, `validate_array_values` to accept a single validator as a parameter.
716
+
717
+ ## 0.4.1<a id="041"></a>
714
718
  - added cache for often used functions
715
719
  - added __str__ and __len__ methods
716
720
 
717
- ## 0.4
721
+ ## 0.4<a id="04"></a>
718
722
  - first version with all basic features: creating a validated array, validating dtype, shape, array and field values
719
723
 
720
724
 
721
- # Breaking changes
725
+ # Breaking changes<a id="breaking-changes"></a>
722
726
  - **0.4** -> **0.4.1**
723
727
  - changed __str__ method for `Validator` to `.error_string` property (to allow different string representation for error messages and general printing)
724
728
  - changed imports due to refactoring to simplify dependencies:
@@ -1,4 +1,4 @@
1
- ![](assets/images/valarray_logo.svg)
1
+ ![valarray logo](https://codeberg.org/jfranek/valarray/raw/branch/main/assets/images/valarray_logo.svg)
2
2
 
3
3
  In short, library for validating numpy arrays that also helps with static analysis and documentation. In long, see [Library rationale](#library-rationale).
4
4
 
@@ -39,8 +39,10 @@ except ValidationException as v_exc:
39
39
  >>> [-2.0, -6.0]
40
40
  ```
41
41
 
42
- # Table of contents
43
- - [Table of contents](#table-of-contents)
42
+ <!-- NOTE: Headings that are used as relative links (so most of them) must have id tag defined
43
+ (see https://github.com/pypa/readme_renderer/issues/169#issuecomment-808577486) otherwise links do not work on pypi.-->
44
+
45
+ # Table of contents <!-- omit from toc -->
44
46
  - [Library rationale](#library-rationale)
45
47
  - [1) Invalid values causing unintended behaviour](#1-invalid-values-causing-unintended-behaviour)
46
48
  - [Problem](#problem)
@@ -70,15 +72,16 @@ except ValidationException as v_exc:
70
72
  - [Settings](#settings)
71
73
  - [Caveats](#caveats)
72
74
  - [Changelog](#changelog)
75
+ - [0.4.2](#042)
73
76
  - [0.4.1](#041)
74
77
  - [0.4](#04)
75
78
  - [Breaking changes](#breaking-changes)
76
79
 
77
- # Library rationale
80
+ # Library rationale<a id="library-rationale"></a>
78
81
  This library aims to help with 3 issues encountered when working with numpy arrays:
79
82
 
80
- ## 1) Invalid values causing unintended behaviour
81
- ### Problem
83
+ ## 1) Invalid values causing unintended behaviour<a id="1-invalid-values-causing-unintended-behaviour"></a>
84
+ ### Problem<a id="problem"></a>
82
85
  Invalid values can cause crashes, or worse, cause silent failures.
83
86
 
84
87
  For example the following code fails silently when attempting to cut patches from image using bounding boxes with invalid coordinates.
@@ -112,7 +115,7 @@ for patch in patches:
112
115
  >>> (50, 200, 3)
113
116
  ```
114
117
 
115
- ### Solution
118
+ ### Solution<a id="solution"></a>
116
119
  Validate boxes array first. If errors are encountered, print descriptive error message(s).
117
120
 
118
121
  ```python
@@ -166,8 +169,8 @@ except ValidationException as exc:
166
169
  >>> Field < 0 >: [-10]
167
170
  ```
168
171
 
169
- ## 2) Limited support for static analysis
170
- ### Problem
172
+ ## 2) Limited support for static analysis<a id="2-limited-support-for-static-analysis"></a>
173
+ ### Problem<a id="problem-1"></a>
171
174
  Support for static analysis is limited. Tools can only check whether the datatype is correct, but not shape, values or what those values actually represent.
172
175
 
173
176
  For example, the function to crop patches needs the boxes to be defined by `xmin, ymin, xmax, ymax` but doesn't throw an error if input boxes are defined by `x_center, y_center, width, height` and static analysis tools cannot detect this error using bulit-in numpy types.
@@ -211,7 +214,7 @@ for patch in patches_inv:
211
214
  >>> (0, 200, 3)
212
215
  ```
213
216
 
214
- ### Solution
217
+ ### Solution<a id="solution-1"></a>
215
218
  `ValidatedNumpyArray` subclasses can represent these two types of boxes arrays, and can be used instead of bare numpy arrays in function/method signatures and such.
216
219
  ```python
217
220
  import numpy as np
@@ -278,8 +281,8 @@ for patch in patches_inv:
278
281
  print(patch.shape)
279
282
  ```
280
283
 
281
- ## 3) Need for explicit documentation
282
- ### Problem
284
+ ## 3) Need for explicit documentation<a id="3-need-for-explicit-documentation"></a>
285
+ ### Problem<a id="problem-2"></a>
283
286
  Using built-in numpy types provides only documentation for data types. Shape, values, constraints and what the array represents need to be explicitly documented either in comments or docstrings.
284
287
 
285
288
  If this type of array is used in multiple places / functions, this can cause duplicated documentation.
@@ -308,7 +311,7 @@ def cut_patches(
308
311
  return patches
309
312
  ```
310
313
 
311
- ### Solution
314
+ ### Solution<a id="solution-2"></a>
312
315
  Defining data type, schema and constraints on a `ValidatedNumpyArray` subclass already implicitly documents them.
313
316
 
314
317
  This can be complemented by adding additional (or summary) documentation in the class docstring.
@@ -356,8 +359,8 @@ def cut_patches(
356
359
  ```
357
360
 
358
361
 
359
- # Validated Array
360
- ## Defining a validated array
362
+ # Validated Array<a id="validated-array"></a>
363
+ ## Defining a validated array<a id="defining-a-validated-array"></a>
361
364
  Subclass `ValidatedNumpyArray` and define:
362
365
  - `dtype` - expected data type specification (such as `float`, `"float64"`, `np.float64`).
363
366
  If not specified, data type is not validated.
@@ -366,7 +369,7 @@ Subclass `ValidatedNumpyArray` and define:
366
369
  - `schema` - expected shape specification (of type `valarray.numpy.axes_and_fields.AxesTuple`). For details, see [Array Schema](#array-schema).
367
370
  If not specified, shape is not validated (and no field validators are applied).
368
371
  - `lt`/`le`/`ge`/`gt`/`eq` - basic array value constraints -> less (or equal) than, greater (or equal) than, equal to
369
- - `validators` - optional list of validators applied to the whole array. For details, see [Validators](##validators).
372
+ - `validators` - optional validator or a tuple of validators applied to the whole array. For details, see [Validators](##validators).
370
373
 
371
374
  ```python
372
375
  import numpy as np
@@ -377,7 +380,7 @@ class ExampleValidatedNumpyArray(ValidatedNumpyArray):
377
380
  schema = ('batch_size', 3, 5)
378
381
  ```
379
382
 
380
- ## Creating a validated array instance
383
+ ## Creating a validated array instance<a id="creating-a-validated-array-instance"></a>
381
384
  There are 4 ways to create a validated array instance:
382
385
  - validate an existing array
383
386
  ```python
@@ -420,7 +423,7 @@ v_arr = ExampleValidatedNumpyArray(np.array([1,2],dtype=np.float32), coerce_dtyp
420
423
  v_arr = ExampleValidatedNumpyArray(np.array([1,2],dtype=np.float32), coerce_dtype=True, validate=False)
421
424
  ```
422
425
 
423
- ## Accessing array values
426
+ ## Accessing array values<a id="accessing-array-values"></a>
424
427
  You can access the underlying array using the `.array`/`.a_` property:
425
428
  ```python
426
429
  arr = v_arr.array
@@ -443,7 +446,7 @@ class SpecifiedDataTypeArray(ValidatedNumpyArray[np.float32]): ...
443
446
  arr = SpecifiedDataTypeArray(...).array # np.typing.NDArray[np.float32]
444
447
  ```
445
448
 
446
- # Validation functions
449
+ # Validation functions<a id="validation-functions"></a>
447
450
  Array validation is designed to be modular and composable and validation functions can be used on they own if only runtime validation is required.
448
451
  Each validation function returns a list of errors, from which a `ValidationException` can be raised. For details see [Catching exceptions](#catching-exceptions).
449
452
  ```python
@@ -482,7 +485,7 @@ and a "composite" validation function:
482
485
  - *returns* `NumpyInvalidArrayValuesError`/`NumpyInvalidFieldValuesError` or no errors.
483
486
 
484
487
 
485
- # Array schema
488
+ # Array schema<a id="array-schema"></a>
486
489
  Schema defines expected axes, and for each axis its' fields and optionally constraints on the field values.
487
490
 
488
491
  Axes can be defined with:
@@ -503,11 +506,11 @@ schema = (
503
506
  ("field_a", Field())
504
507
  )
505
508
  ```
506
- ## Field
509
+ ## Field<a id="field"></a>
507
510
  Defines (optional) name and value constrints for array field. More specifically:
508
511
  - `name` - descriptive name used in error messages (if missing, field index is used instead)
509
512
  - `lt`/`le`/`ge`/`gt`/`eq` - basic array value constraints -> less (or equal) than, greater (or equal) than, equal to
510
- - `validators` - other validators of fields values. For details, see [Validators](##validators).
513
+ - `validators` - optional validator or a tuple of validators applied to fields values. For details, see [Validators](##validators).
511
514
 
512
515
  ```python
513
516
  from typing import Any
@@ -522,8 +525,8 @@ f1 = Field("example_named_field", ge=0)
522
525
  f2 = Field(gt=10, validators=(ExampleNumpyValidator(),))
523
526
  ```
524
527
 
525
- ## Array schema examples
526
- ### rectangles
528
+ ## Array schema examples<a id="array-schema-examples"></a>
529
+ ### rectangles<a id="rectangles"></a>
527
530
  An array of arbitrary number of rectangles defined by min and max coordinates which has two axes: *n_rects* and *rect*.
528
531
  Axis *rect* is has 4 fields: *x_min*,*y_min*,*x_max*,*y_max*, where values must be greater or equal to zero.
529
532
 
@@ -556,10 +559,10 @@ arr = np.array(
556
559
  Rect.validate(arr)
557
560
  ```
558
561
 
559
- # Validators
562
+ # Validators<a id="validators"></a>
560
563
  Validators are objects that perform arbitrary validation of array or field values defined by user.
561
564
 
562
- ## Defining a validator
565
+ ## Defining a validator<a id="defining-a-validator"></a>
563
566
  Validators must subclass `valarray.numpy.NumpyValidator` Abstract Base Class
564
567
  and implement the `.validate()` method that takes an array as an input and results in success/failure of validation using these options:
565
568
 
@@ -572,7 +575,7 @@ and implement the `.validate()` method that takes an array as an input and resul
572
575
  - *returns* `False`
573
576
  - *raises* `ValueError`
574
577
 
575
- ### ValidationResult
578
+ ### ValidationResult<a id="validationresult"></a>
576
579
  Contains result status of validation `status="OK"`/`status="FAIL"`
577
580
 
578
581
  Can also optionally contain:
@@ -604,7 +607,7 @@ indices = (np.array([0, 1, 1]), np.array([1, 0, 1]))
604
607
  res = ValidationResult(status="FAIL", indices_invalid=indices, msg="Optional error message.")
605
608
  ```
606
609
 
607
- ### Example Validator
610
+ ### Example Validator<a id="example-validator"></a>
608
611
  ```python
609
612
  from dataclasses import dataclass
610
613
  from typing import Literal
@@ -641,7 +644,7 @@ class ExampleIsEvenValidator(NumpyValidator[np.uint8]):
641
644
  return ValidationResult("FAIL", indices_invalid=~even)
642
645
  ```
643
646
 
644
- # Catching exceptions
647
+ # Catching exceptions<a id="catching-exceptions"></a>
645
648
  Failed validation results in `valarray.core.errors_exceptions.ValidationException` being raised containing list of errors responsible (and name of array class if available).
646
649
 
647
650
  Main error types are:
@@ -667,42 +670,43 @@ except ValidationException as exc:
667
670
  axis_errs = exc.errs[(IncorrectAxSizesError, IncorrectAxNumberError)]
668
671
  ```
669
672
 
670
- ## Special exceptions and errors
673
+ ## Special exceptions and errors<a id="special-exceptions-and-errors"></a>
671
674
  There are two special subclasses of `ValidationException` with associated validation errors raised during [instantiation](#creating-a-validated-array-instance):
672
675
  - `CreateArrayException` -> `CannotCreateArrayError` - Array cannot be created from supplied object.
673
676
  - `CoerceDTypeException` -> `CannotCoerceDTypeError` - If array data type cannot be coerced when creating array with `ValidatedArray(coerce_dtype=True)`
674
677
 
675
678
 
676
- ## Generic Errors
679
+ ## Generic Errors<a id="generic-errors"></a>
677
680
  These error types have subclasses ensuring proper type hints:
678
681
  - `IncorrectDTypeError` -> `NumpyIncorrectDTypeError`
679
682
  - `CannotCoerceDTypeError` -> `NumpyCannotCoerceDTypeError`
680
683
  - `InvalidArrayValuesError` -> `NumpyInvalidArrayValuesError`
681
684
  - `InvalidFieldValuesError` -> `NumpyInvalidFieldValuesError`
682
685
 
683
- # Settings
686
+ # Settings<a id="settings"></a>
684
687
  Global settings for the library are defined in `valarray.settings` and can be modified using environment variables.
685
688
  | ***variable name*** | ***environment variable*** | default value | description |
686
689
  |---------------------|------------------------------|---------------|-----------------------------------------------------|
687
690
  | function_cache_size | VALARRAY_FUNCTION_CACHE_SIZE | 512 | cache size for (internal) frequently used functions |
688
691
 
689
-
690
-
691
- # Caveats
692
+ # Caveats<a id="caveats"></a>
692
693
  - I cannot guarantee that the test suite is foolproof ATM as I'm currently the only one testing this library.
693
694
  - Library has so far only been tested with `python==3.12` and `numpy==2.4.0`
694
695
  - Library isn't tested for performance, use in production only if the primary bottleneck is brain and not hardware.
695
696
 
696
- # Changelog
697
- ## 0.4.1
697
+ # Changelog<a id="changelog"></a>
698
+ ## 0.4.2<a id="042"></a>
699
+ - changed `ValidatedArray`, `Field` classes and `validate_array`, `validate_array_values` to accept a single validator as a parameter.
700
+
701
+ ## 0.4.1<a id="041"></a>
698
702
  - added cache for often used functions
699
703
  - added __str__ and __len__ methods
700
704
 
701
- ## 0.4
705
+ ## 0.4<a id="04"></a>
702
706
  - first version with all basic features: creating a validated array, validating dtype, shape, array and field values
703
707
 
704
708
 
705
- # Breaking changes
709
+ # Breaking changes<a id="breaking-changes"></a>
706
710
  - **0.4** -> **0.4.1**
707
711
  - changed __str__ method for `Validator` to `.error_string` property (to allow different string representation for error messages and general printing)
708
712
  - changed imports due to refactoring to simplify dependencies:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "valarray"
7
- version = "0.4.1"
7
+ version = "0.4.2"
8
8
  authors = [
9
9
  { name="J. Franek", email="franek.j27@email.cz" },
10
10
  ]
@@ -17,15 +17,17 @@ class TestIncorrectDTypeError(IncorrectDTypeError[TestDtypeLike, TestDtype]): ..
17
17
  class TestCannotCoerceDTypeError(CannotCoerceDTypeError[TestDtypeLike, TestDtype]): ...
18
18
 
19
19
 
20
- class TestInvalidArrayValuesError(InvalidArrayValuesError[TestArray, list[int]]):
20
+ class TestInvalidArrayValuesError(InvalidArrayValuesError[TestArray, list[int], int]):
21
21
  """Blank"""
22
22
 
23
23
 
24
- class TestInvalidFieldValuesError(InvalidFieldValuesError[TestArray, list[int]]): ...
24
+ class TestInvalidFieldValuesError(
25
+ InvalidFieldValuesError[TestArray, list[int], int]
26
+ ): ...
25
27
 
26
28
 
27
29
  @dataclass
28
- class TestErrors(GenericErrors[TestArray, TestDtypeLike, TestDtype, list[int]]):
30
+ class TestErrors(GenericErrors[TestArray, TestDtypeLike, TestDtype, list[int], int]):
29
31
  incorrect_dtype: type[TestIncorrectDTypeError] = TestIncorrectDTypeError
30
32
  cannot_coerce_dtype: type[TestCannotCoerceDTypeError] = TestCannotCoerceDTypeError
31
33
  invalid_array_values: type[TestInvalidArrayValuesError] = (
@@ -127,6 +127,3 @@ def test_apply_validator(
127
127
  assert (
128
128
  validation_result == expected_validation_result
129
129
  ), "actual/expected values for 'validation_result' are not equal"
130
- assert (
131
- validation_result == expected_validation_result
132
- ), "actual/expected values for 'validation_result' are not equal"
@@ -52,6 +52,11 @@ RESOLVED_FIELD_WITH_VALIDATORS = _ResolvedField(
52
52
  Field(name="example_field", ge=0, validators=(TestDummyValidator(),)),
53
53
  RESOLVED_FIELD_WITH_VALIDATORS,
54
54
  ),
55
+ (
56
+ 0,
57
+ Field(name="example_field", ge=0, validators=TestDummyValidator()),
58
+ RESOLVED_FIELD_WITH_VALIDATORS,
59
+ ),
55
60
  ],
56
61
  )
57
62
  def test__resolve_field(
@@ -10,7 +10,7 @@ from tests.core.classes_for_testing import (
10
10
  )
11
11
  from valarray.core.errors_exceptions import ValidationErrorList
12
12
  from valarray.core.validation_functions import validate_array_values
13
- from valarray.core.validators import ComparisonValidator, Validator
13
+ from valarray.core.validators import ComparisonValidator, ValidatorOrValidatorSequence
14
14
 
15
15
  COMP_VAL = ComparisonValidator("gt", 0, TestComparisons())
16
16
 
@@ -18,6 +18,7 @@ COMP_VAL = ComparisonValidator("gt", 0, TestComparisons())
18
18
  @pytest.mark.parametrize(
19
19
  "arr, validator, expected_errs",
20
20
  [
21
+ (TestArray(val=[1, 2, 3]), [COMP_VAL], []),
21
22
  (TestArray(val=[1, 2, 3]), COMP_VAL, []),
22
23
  (
23
24
  TestArray(val=[1, 1, 0]),
@@ -42,10 +43,10 @@ COMP_VAL = ComparisonValidator("gt", 0, TestComparisons())
42
43
  )
43
44
  def test_validate_array_values(
44
45
  arr: TestArray,
45
- validator: Validator,
46
+ validator: ValidatorOrValidatorSequence,
46
47
  expected_errs: ValidationErrorList[TestInvalidArrayValuesError],
47
48
  ):
48
49
 
49
- errs = validate_array_values(arr, [validator], TestArrayTypeAdapter())
50
+ errs = validate_array_values(arr, validator, TestArrayTypeAdapter())
50
51
 
51
52
  assert errs == expected_errs, "actual/expected values for 'errs' are not equal"
@@ -52,6 +52,9 @@ class M:
52
52
  (M("valarray.core.validators", "ComparisonValidator")),
53
53
  (M("valarray.core.validators", "ValidationResult")),
54
54
  (M("valarray.core.validators", "Validator")),
55
+ (M("valarray.core.validators", "ValidatorOrValidatorTuple")),
56
+ (M("valarray.core.validators", "ValidatorOrComparisonValidator")),
57
+ (M("valarray.core.validators", "ValidatorOrValidatorSequence")),
55
58
  ### 1.5 utils
56
59
  (M("valarray.core.utils", "ax_sizes_from_schema")),
57
60
  (M("valarray.core.utils", "constraints_to_validators")),
@@ -20,7 +20,7 @@ from .errors_exceptions import ValidationException
20
20
  from .types import ArrayIndicesT, ArrayT, ComparableValueT, DTypeLikeT, DTypeT
21
21
  from .utils import constraints_to_validators, setup_array
22
22
  from .validation_functions import validate_array
23
- from .validators.base import Validator
23
+ from .validators import ValidatorOrValidatorTuple
24
24
 
25
25
 
26
26
  class ValidatedArray(
@@ -44,7 +44,7 @@ class ValidatedArray(
44
44
 
45
45
  dtype: DTypeLikeT | EllipsisType = ...
46
46
  schema: AxesTuple[ArrayT, ArrayIndicesT, ComparableValueT] | EllipsisType = ...
47
- validators: tuple[Validator[ArrayT, ArrayIndicesT], ...] = ()
47
+ validators: ValidatorOrValidatorTuple[ArrayT, ArrayIndicesT, ComparableValueT] = ()
48
48
 
49
49
  lt: Optional[ComparableValueT] = None
50
50
  le: Optional[ComparableValueT] = None
@@ -116,7 +116,11 @@ class ValidatedArray(
116
116
  )
117
117
 
118
118
  if errs:
119
- raise ValidationException(self.__class__.__name__, errs)
119
+ # T!: need to refactor exceptions
120
+ # so ValidationException only accepts a list of errors returned by validation functions.
121
+ raise ValidationException(
122
+ self.__class__.__name__, errs # pyright: ignore[reportArgumentType]
123
+ )
120
124
 
121
125
  self.is_validated = True
122
126
 
@@ -73,7 +73,9 @@ class ArrayTypeAdapter(
73
73
 
74
74
  @property
75
75
  @abstractmethod
76
- def errors(self) -> GenericErrors[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT]: ...
76
+ def errors(
77
+ self,
78
+ ) -> GenericErrors[ArrayT, DTypeLikeT, DTypeT, ArrayIndicesT, ComparableValueT]: ...
77
79
 
78
80
  @property
79
81
  @abstractmethod