|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | | -from collections.abc import Hashable |
| 3 | +from collections.abc import Hashable, Iterable |
4 | 4 | from typing import Callable, Collection, Protocol, Sized, TypeVar |
5 | 5 |
|
6 | 6 | from .._compat import ExceptionGroup |
| 7 | +from ..errors import IterableValidationError, IterableValidationNote |
7 | 8 | from ._fluent import ValidatorFactory |
8 | 9 |
|
9 | 10 | T = TypeVar("T") |
@@ -94,3 +95,50 @@ def skip_none(val: T | None, _validators=validators) -> None: |
94 | 95 | return skip_none |
95 | 96 |
|
96 | 97 | return factory |
| 98 | + |
| 99 | + |
| 100 | +def all_elements_must( |
| 101 | + validator: Callable[[T], None | bool], *validators: Callable[[T], None | bool] |
| 102 | +) -> ValidatorFactory[T]: |
| 103 | + """A helper validator included with cattrs. |
| 104 | +
|
| 105 | + Run all the given validators against all members of the |
| 106 | + iterable. |
| 107 | + """ |
| 108 | + |
| 109 | + validators = (validator, *validators) |
| 110 | + |
| 111 | + def factory(detailed_validation: bool) -> Callable[[T], None]: |
| 112 | + if detailed_validation: |
| 113 | + |
| 114 | + def assert_all_elements(val: Iterable[T], _validators=validators) -> None: |
| 115 | + errors = [] |
| 116 | + ix = 0 |
| 117 | + for e in val: |
| 118 | + try: |
| 119 | + for v in _validators: |
| 120 | + try: |
| 121 | + v(e) |
| 122 | + except Exception as exc: |
| 123 | + exc.__notes__ = [ |
| 124 | + *getattr(exc, "__notes__", []), |
| 125 | + IterableValidationNote( |
| 126 | + f"Validating @ index {ix}", ix, None |
| 127 | + ), |
| 128 | + ] |
| 129 | + errors.append(exc) |
| 130 | + finally: |
| 131 | + ix += 1 |
| 132 | + if errors: |
| 133 | + raise IterableValidationError("", errors, val.__class__) |
| 134 | + |
| 135 | + else: |
| 136 | + |
| 137 | + def assert_all_elements(val: Iterable[T], _validators=validators) -> None: |
| 138 | + for e in val: |
| 139 | + for v in _validators: |
| 140 | + v(e) |
| 141 | + |
| 142 | + return assert_all_elements |
| 143 | + |
| 144 | + return factory |
0 commit comments