-
Notifications
You must be signed in to change notification settings - Fork 420
/
property_decorators.py
157 lines (113 loc) · 4.6 KB
/
property_decorators.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import datetime
import re
from functools import wraps
from typing import Any, Container, Optional, Tuple
from tableauserverclient.datetime_helpers import parse_datetime
def property_is_enum(enum_type):
def property_type_decorator(func):
@wraps(func)
def wrapper(self, value):
if value is not None and not hasattr(enum_type, value):
error = "Invalid value: {0}. {1} must be of type {2}.".format(value, func.__name__, enum_type.__name__)
raise ValueError(error)
return func(self, value)
return wrapper
return property_type_decorator
def property_is_boolean(func):
@wraps(func)
def wrapper(self, value):
if not isinstance(value, bool):
error = "Boolean expected for {0} flag.".format(func.__name__)
raise ValueError(error)
return func(self, value)
return wrapper
def property_not_nullable(func):
@wraps(func)
def wrapper(self, value):
if value is None:
error = "{0} must be defined.".format(func.__name__)
raise ValueError(error)
return func(self, value)
return wrapper
def property_not_empty(func):
@wraps(func)
def wrapper(self, value):
if not value:
error = "{0} must not be empty.".format(func.__name__)
raise ValueError(error)
return func(self, value)
return wrapper
def property_is_valid_time(func):
@wraps(func)
def wrapper(self, value):
units_of_time = {"hour", "minute", "second"}
if not any(hasattr(value, unit) for unit in units_of_time):
error = "Invalid time object defined."
raise ValueError(error)
return func(self, value)
return wrapper
def property_is_int(range: Tuple[int, int], allowed: Optional[Container[Any]] = None):
"""Takes a range of ints and a list of exemptions to check against
when setting a property on a model. The range is a tuple of (min, max) and the
allowed list (empty by default) allows values outside that range.
This is useful for when we use sentinel values.
Example: Revisions allow a range of 2-10000, but use -1 as a sentinel for 'unlimited'.
"""
if allowed is None:
allowed = () # Empty tuple for fast no-op testing.
def property_type_decorator(func):
@wraps(func)
def wrapper(self, value):
error = "Invalid property defined: '{}'. Integer value expected.".format(value)
if range is None:
if isinstance(value, int):
return func(self, value)
else:
raise ValueError(error)
min, max = range
if value in allowed:
return func(self, value)
if value < min or value > max:
raise ValueError(error)
return func(self, value)
return wrapper
return property_type_decorator
def property_matches(regex_to_match, error):
compiled_re = re.compile(regex_to_match)
def wrapper(func):
@wraps(func)
def validate_regex_decorator(self, value):
if not compiled_re.match(value):
raise ValueError(error)
return func(self, value)
return validate_regex_decorator
return wrapper
def property_is_datetime(func):
"""Takes the following datetime format and turns it into a datetime object:
2016-08-18T18:25:36Z
Because we return everything with Z as the timezone, we assume everything is in UTC and create
a timezone aware datetime.
"""
@wraps(func)
def wrapper(self, value):
if isinstance(value, datetime.datetime):
return func(self, value)
if not isinstance(value, str):
raise ValueError(
"Cannot convert {} into a datetime, cannot update {}".format(value.__class__.__name__, func.__name__)
)
dt = parse_datetime(value)
return func(self, dt)
return wrapper
def property_is_data_acceleration_config(func):
@wraps(func)
def wrapper(self, value):
if not isinstance(value, dict):
raise ValueError("{} is not type 'dict', cannot update {})".format(value.__class__.__name__, func.__name__))
if len(value) < 2 or not all(attr in value.keys() for attr in ("acceleration_enabled", "accelerate_now")):
error = "{} should have 2 keys ".format(func.__name__)
error += "'acceleration_enabled' and 'accelerate_now'"
error += "instead you have {}".format(value.keys())
raise ValueError(error)
return func(self, value)
return wrapper