1"""Between."""
2
3# standard
4from datetime import datetime
5from typing import TypeVar, Union
6
7# local
8from ._extremes import AbsMax, AbsMin
9from .utils import validator
10
11PossibleValueTypes = TypeVar("PossibleValueTypes", int, float, str, datetime, None)
12
13
14@validator
15def between(
16 value: PossibleValueTypes,
17 /,
18 *,
19 min_val: Union[PossibleValueTypes, AbsMin, None] = None,
20 max_val: Union[PossibleValueTypes, AbsMax, None] = None,
21):
22 """Validate that a number is between minimum and/or maximum value.
23
24 This will work with any comparable type, such as floats, decimals and dates
25 not just integers. This validator is originally based on [WTForms-NumberRange-Validator][1].
26
27 [1]: https://github.com/wtforms/wtforms/blob/master/src/wtforms/validators.py#L166-L220
28
29 Examples:
30 >>> from datetime import datetime
31 >>> between(5, min_val=2)
32 True
33 >>> between(13.2, min_val=13, max_val=14)
34 True
35 >>> between(500, max_val=400)
36 ValidationError(func=between, args={'value': 500, 'max_val': 400})
37 >>> between(
38 ... datetime(2000, 11, 11),
39 ... min_val=datetime(1999, 11, 11)
40 ... )
41 True
42
43 Args:
44 value:
45 Value which is to be compared.
46 min_val:
47 The minimum required value of the number.
48 If not provided, minimum value will not be checked.
49 max_val:
50 The maximum value of the number.
51 If not provided, maximum value will not be checked.
52
53 Returns:
54 (Literal[True]): If `value` is in between the given conditions.
55 (ValidationError): If `value` is not in between the given conditions.
56
57 Raises:
58 (ValueError): If `min_val` is greater than `max_val`.
59 (TypeError): If there's a type mismatch during comparison.
60
61 Note:
62 - `PossibleValueTypes` = `TypeVar("PossibleValueTypes", int, float, str, datetime)`
63 - If neither `min_val` nor `max_val` is provided, result will always be `True`.
64 """
65 if value is None:
66 return False
67
68 if max_val is None:
69 max_val = AbsMax()
70 if min_val is None:
71 min_val = AbsMin()
72
73 try:
74 if min_val > max_val:
75 raise ValueError("`min_val` cannot be greater than `max_val`")
76 except TypeError as err:
77 raise TypeError("Comparison type mismatch") from err
78
79 return min_val <= value <= max_val