|
38 | 38 |
|
39 | 39 | class Validator(Protocol[ValueT_contra]): |
40 | 40 | """ |
41 | | - Structura type for an option validator. |
| 41 | + Structural type for an option validator. |
| 42 | + There are two ways to signal that a value is invalid: |
| 43 | +
|
| 44 | + - returning :obj:`False` |
| 45 | + - raising any :class:`Exception` |
| 46 | +
|
| 47 | + There are two ways to signal that a value is valid: |
| 48 | +
|
| 49 | + - returning :obj:`True` (as opposed to :obj:`False`) |
| 50 | + - returning :obj:`None` (as opposed to raising an exception) |
| 51 | +
|
| 52 | + In the context of option validation, a :obj:`ValueError` will be raised |
| 53 | + if validation fails: if the validator raised an exception, the |
| 54 | + :obj:`ValueError` is re-raised from it. |
| 55 | +
|
42 | 56 | """ |
43 | 57 |
|
44 | | - def __call__(self, value: ValueT_contra, /) -> bool: |
| 58 | + def __call__(self, value: ValueT_contra, /) -> bool|None: |
45 | 59 | ... |
46 | 60 |
|
47 | 61 |
|
@@ -84,9 +98,7 @@ def __new__( |
84 | 98 |
|
85 | 99 | :param ty: The type of the option. |
86 | 100 | :param default: The default value for the option. |
87 | | - :param validator: A callable that takes a value and returns whether |
88 | | - it is valid for this option. If not specified, |
89 | | - defaults to :obj:`None` (no validation) |
| 101 | + :param validator: An optional validator function, see :class:`Validator` |
90 | 102 |
|
91 | 103 | :meta public: |
92 | 104 | """ |
@@ -151,16 +163,25 @@ def validate(self, value: ValueT) -> None: |
151 | 163 |
|
152 | 164 | - Checks that the value has the correct type. |
153 | 165 | - If a validator is specified, checks that the value is valid. |
| 166 | +
|
| 167 | + If the value is not valid, :obj:`ValueError` is raised. |
154 | 168 | """ |
155 | 169 | validate(value, self.__type) |
156 | 170 | if (validator := self.__validator) is not None: |
157 | | - if not validator(value): |
| 171 | + validator_res: bool|None |
| 172 | + validator_err: Exception|None = None |
| 173 | + try: |
| 174 | + validator_res = validator(value) |
| 175 | + except Exception as e: |
| 176 | + validator_res = False |
| 177 | + validator_err = e |
| 178 | + if validator_res is False: |
158 | 179 | name_str = ( |
159 | 180 | f" {self.__name!r}" if hasattr(self, "__name") else "" |
160 | 181 | ) |
161 | 182 | raise ValueError( |
162 | 183 | f"Invalid value for option{name_str}: " f"{value!r}." |
163 | | - ) |
| 184 | + ) from validator_err |
164 | 185 |
|
165 | 186 | def reset(self, instance: OptionManager) -> ValueT: |
166 | 187 | """ |
|
0 commit comments