-
Notifications
You must be signed in to change notification settings - Fork 13
/
validate.py
120 lines (98 loc) · 3.49 KB
/
validate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import datetime
import numpy as np
from marshmallow import (
validate as marshmallow_validate,
ValidationError,
fields as marshmallow_fields,
)
from paramtools import utils
class Range(marshmallow_validate.Range):
"""
Implements "range" :ref:`spec:Validator object`.
"""
error = ""
def __init__(
self, min=None, max=None, error_min=None, error_max=None, step=None
):
self.min = min
self.max = max
self.error_min = error_min
self.error_max = error_max
self.step = step or 1 # default to 1
def _format_error(self, value, message):
return message.format(input=value, min=self.min, max=self.max)
def __call__(self, value):
if value is None:
return value
if not isinstance(value, list):
value_list = [value]
else:
value_list = utils.ravel(value)
for val in value_list:
if self.min is not None and val < self.min:
message = self.error_min or self.message_min
raise ValidationError(self._format_error(value, message))
if self.max is not None and val > self.max:
message = self.error_max or self.message_max
raise ValidationError(self._format_error(value, message))
return value
def grid(self):
# make np.arange inclusive.
max_ = self.max + self.step
arr = np.arange(self.min, max_, self.step)
return arr[arr <= self.max].tolist()
class DateRange(Range):
"""
Implements "date_range" :ref:`spec:Validator object`.
Behaves like ``Range``, except values are ensured to be
``datetime.date`` type and ``grid`` has special logic for dates.
"""
def __init__(
self, min=None, max=None, error_min=None, error_max=None, step=None
):
if min is not None and not isinstance(min, datetime.date):
min = marshmallow_fields.Date()._deserialize(min, None, None)
if max is not None and not isinstance(max, datetime.date):
max = marshmallow_fields.Date()._deserialize(max, None, None)
super().__init__(min, max, error_min, error_max)
if step is None:
# set to to default step.
step = {"days": 1}
# check against allowed args:
# https://docs.python.org/3/library/datetime.html#datetime.timedelta
timedelta_args = {
"days",
"seconds",
"microseconds",
"milliseconds",
"minutes",
"hours",
"weeks",
}
assert len(set(step.keys()) - timedelta_args) == 0
self.step = datetime.timedelta(**step)
def grid(self):
# make np.arange inclusive.
max_ = self.max + self.step
arr = np.arange(self.min, max_, self.step, dtype=datetime.date)
return arr[arr <= self.max].tolist()
class OneOf(marshmallow_validate.OneOf):
"""
Implements "choice" :ref:`spec:Validator object`.
"""
def __call__(self, value):
if value is None:
return value
if not isinstance(value, list):
values = [value]
else:
values = utils.ravel(value)
for val in values:
try:
if val not in self.choices:
raise ValidationError(self._format_error(val))
except TypeError:
raise ValidationError(self._format_error(val))
return value
def grid(self):
return self.choices