root / lib / ht.py @ 88bc199a
History | View | Annotate | Download (5.8 kB)
1 | 62e0e880 | Iustin Pop | #
|
---|---|---|---|
2 | 62e0e880 | Iustin Pop | #
|
3 | 62e0e880 | Iustin Pop | |
4 | 8c9ee749 | Michael Hanselmann | # Copyright (C) 2010, 2011 Google Inc.
|
5 | 62e0e880 | Iustin Pop | #
|
6 | 62e0e880 | Iustin Pop | # This program is free software; you can redistribute it and/or modify
|
7 | 62e0e880 | Iustin Pop | # it under the terms of the GNU General Public License as published by
|
8 | 62e0e880 | Iustin Pop | # the Free Software Foundation; either version 2 of the License, or
|
9 | 62e0e880 | Iustin Pop | # (at your option) any later version.
|
10 | 62e0e880 | Iustin Pop | #
|
11 | 62e0e880 | Iustin Pop | # This program is distributed in the hope that it will be useful, but
|
12 | 62e0e880 | Iustin Pop | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 62e0e880 | Iustin Pop | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 62e0e880 | Iustin Pop | # General Public License for more details.
|
15 | 62e0e880 | Iustin Pop | #
|
16 | 62e0e880 | Iustin Pop | # You should have received a copy of the GNU General Public License
|
17 | 62e0e880 | Iustin Pop | # along with this program; if not, write to the Free Software
|
18 | 62e0e880 | Iustin Pop | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 62e0e880 | Iustin Pop | # 02110-1301, USA.
|
20 | 62e0e880 | Iustin Pop | |
21 | 62e0e880 | Iustin Pop | |
22 | 62e0e880 | Iustin Pop | """Module implementing the parameter types code."""
|
23 | 62e0e880 | Iustin Pop | |
24 | 8c9ee749 | Michael Hanselmann | import re |
25 | 8c9ee749 | Michael Hanselmann | |
26 | 62e0e880 | Iustin Pop | from ganeti import compat |
27 | 8c9ee749 | Michael Hanselmann | from ganeti import utils |
28 | 8c9ee749 | Michael Hanselmann | |
29 | 8c9ee749 | Michael Hanselmann | |
30 | 8c9ee749 | Michael Hanselmann | _PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$")
|
31 | 8c9ee749 | Michael Hanselmann | |
32 | 8c9ee749 | Michael Hanselmann | |
33 | 8c9ee749 | Michael Hanselmann | def Parens(text): |
34 | 8c9ee749 | Michael Hanselmann | """Enclose text in parens if necessary.
|
35 | 8c9ee749 | Michael Hanselmann |
|
36 | 8c9ee749 | Michael Hanselmann | @param text: Text
|
37 | 8c9ee749 | Michael Hanselmann |
|
38 | 8c9ee749 | Michael Hanselmann | """
|
39 | 8c9ee749 | Michael Hanselmann | text = str(text)
|
40 | 8c9ee749 | Michael Hanselmann | |
41 | 8c9ee749 | Michael Hanselmann | if _PAREN_RE.match(text):
|
42 | 8c9ee749 | Michael Hanselmann | return text
|
43 | 8c9ee749 | Michael Hanselmann | else:
|
44 | 8c9ee749 | Michael Hanselmann | return "(%s)" % text |
45 | 8c9ee749 | Michael Hanselmann | |
46 | 8c9ee749 | Michael Hanselmann | |
47 | 8c9ee749 | Michael Hanselmann | def WithDesc(text): |
48 | 8c9ee749 | Michael Hanselmann | """Builds wrapper class with description text.
|
49 | 8c9ee749 | Michael Hanselmann |
|
50 | 8c9ee749 | Michael Hanselmann | @type text: string
|
51 | 8c9ee749 | Michael Hanselmann | @param text: Description text
|
52 | 8c9ee749 | Michael Hanselmann | @return: Callable class
|
53 | 8c9ee749 | Michael Hanselmann |
|
54 | 8c9ee749 | Michael Hanselmann | """
|
55 | 8c9ee749 | Michael Hanselmann | assert text[0] == text[0].upper() |
56 | 8c9ee749 | Michael Hanselmann | |
57 | 8c9ee749 | Michael Hanselmann | class wrapper(object): # pylint: disable-msg=C0103 |
58 | 8c9ee749 | Michael Hanselmann | __slots__ = ["__call__"]
|
59 | 8c9ee749 | Michael Hanselmann | |
60 | 8c9ee749 | Michael Hanselmann | def __init__(self, fn): |
61 | 8c9ee749 | Michael Hanselmann | """Initializes this class.
|
62 | 8c9ee749 | Michael Hanselmann |
|
63 | 8c9ee749 | Michael Hanselmann | @param fn: Wrapped function
|
64 | 8c9ee749 | Michael Hanselmann |
|
65 | 8c9ee749 | Michael Hanselmann | """
|
66 | 8c9ee749 | Michael Hanselmann | self.__call__ = fn
|
67 | 8c9ee749 | Michael Hanselmann | |
68 | 8c9ee749 | Michael Hanselmann | def __str__(self): |
69 | 8c9ee749 | Michael Hanselmann | return text
|
70 | 8c9ee749 | Michael Hanselmann | |
71 | 8c9ee749 | Michael Hanselmann | return wrapper
|
72 | 8c9ee749 | Michael Hanselmann | |
73 | 8c9ee749 | Michael Hanselmann | |
74 | 8c9ee749 | Michael Hanselmann | def CombinationDesc(op, args, fn): |
75 | 8c9ee749 | Michael Hanselmann | """Build description for combinating operator.
|
76 | 8c9ee749 | Michael Hanselmann |
|
77 | 8c9ee749 | Michael Hanselmann | @type op: string
|
78 | 8c9ee749 | Michael Hanselmann | @param op: Operator as text (e.g. "and")
|
79 | 8c9ee749 | Michael Hanselmann | @type args: list
|
80 | 8c9ee749 | Michael Hanselmann | @param args: Operator arguments
|
81 | 8c9ee749 | Michael Hanselmann | @type fn: callable
|
82 | 8c9ee749 | Michael Hanselmann | @param fn: Wrapped function
|
83 | 8c9ee749 | Michael Hanselmann |
|
84 | 8c9ee749 | Michael Hanselmann | """
|
85 | 8c9ee749 | Michael Hanselmann | if len(args) == 1: |
86 | 8c9ee749 | Michael Hanselmann | descr = str(args[0]) |
87 | 8c9ee749 | Michael Hanselmann | else:
|
88 | 8c9ee749 | Michael Hanselmann | descr = (" %s " % op).join(Parens(i) for i in args) |
89 | 8c9ee749 | Michael Hanselmann | |
90 | 8c9ee749 | Michael Hanselmann | return WithDesc(descr)(fn)
|
91 | 8c9ee749 | Michael Hanselmann | |
92 | 62e0e880 | Iustin Pop | |
93 | 62e0e880 | Iustin Pop | # Modifiable default values; need to define these here before the
|
94 | 62e0e880 | Iustin Pop | # actual LUs
|
95 | 62e0e880 | Iustin Pop | |
96 | 8c9ee749 | Michael Hanselmann | @WithDesc(str([])) |
97 | 62e0e880 | Iustin Pop | def EmptyList(): |
98 | 62e0e880 | Iustin Pop | """Returns an empty list.
|
99 | 62e0e880 | Iustin Pop |
|
100 | 62e0e880 | Iustin Pop | """
|
101 | 62e0e880 | Iustin Pop | return []
|
102 | 62e0e880 | Iustin Pop | |
103 | 62e0e880 | Iustin Pop | |
104 | 8c9ee749 | Michael Hanselmann | @WithDesc(str({})) |
105 | 62e0e880 | Iustin Pop | def EmptyDict(): |
106 | 62e0e880 | Iustin Pop | """Returns an empty dict.
|
107 | 62e0e880 | Iustin Pop |
|
108 | 62e0e880 | Iustin Pop | """
|
109 | 62e0e880 | Iustin Pop | return {}
|
110 | 62e0e880 | Iustin Pop | |
111 | 62e0e880 | Iustin Pop | |
112 | 62e0e880 | Iustin Pop | #: The without-default default value
|
113 | 62e0e880 | Iustin Pop | NoDefault = object()
|
114 | 62e0e880 | Iustin Pop | |
115 | 62e0e880 | Iustin Pop | |
116 | 8c9ee749 | Michael Hanselmann | #: The no-type (value too complex to check it in the type system)
|
117 | 62e0e880 | Iustin Pop | NoType = object()
|
118 | 62e0e880 | Iustin Pop | |
119 | 62e0e880 | Iustin Pop | |
120 | 62e0e880 | Iustin Pop | # Some basic types
|
121 | 8c9ee749 | Michael Hanselmann | @WithDesc("NotNone") |
122 | 62e0e880 | Iustin Pop | def TNotNone(val): |
123 | 62e0e880 | Iustin Pop | """Checks if the given value is not None.
|
124 | 62e0e880 | Iustin Pop |
|
125 | 62e0e880 | Iustin Pop | """
|
126 | 62e0e880 | Iustin Pop | return val is not None |
127 | 62e0e880 | Iustin Pop | |
128 | 62e0e880 | Iustin Pop | |
129 | 8c9ee749 | Michael Hanselmann | @WithDesc("None") |
130 | 62e0e880 | Iustin Pop | def TNone(val): |
131 | 62e0e880 | Iustin Pop | """Checks if the given value is None.
|
132 | 62e0e880 | Iustin Pop |
|
133 | 62e0e880 | Iustin Pop | """
|
134 | 62e0e880 | Iustin Pop | return val is None |
135 | 62e0e880 | Iustin Pop | |
136 | 62e0e880 | Iustin Pop | |
137 | 8c9ee749 | Michael Hanselmann | @WithDesc("Boolean") |
138 | 62e0e880 | Iustin Pop | def TBool(val): |
139 | 62e0e880 | Iustin Pop | """Checks if the given value is a boolean.
|
140 | 62e0e880 | Iustin Pop |
|
141 | 62e0e880 | Iustin Pop | """
|
142 | 62e0e880 | Iustin Pop | return isinstance(val, bool) |
143 | 62e0e880 | Iustin Pop | |
144 | 62e0e880 | Iustin Pop | |
145 | 8c9ee749 | Michael Hanselmann | @WithDesc("Integer") |
146 | 62e0e880 | Iustin Pop | def TInt(val): |
147 | 62e0e880 | Iustin Pop | """Checks if the given value is an integer.
|
148 | 62e0e880 | Iustin Pop |
|
149 | 62e0e880 | Iustin Pop | """
|
150 | 8568de9e | Michael Hanselmann | # For backwards compatibility with older Python versions, boolean values are
|
151 | 8568de9e | Michael Hanselmann | # also integers and should be excluded in this test.
|
152 | 8568de9e | Michael Hanselmann | #
|
153 | 8568de9e | Michael Hanselmann | # >>> (isinstance(False, int), isinstance(True, int))
|
154 | 8568de9e | Michael Hanselmann | # (True, True)
|
155 | 8568de9e | Michael Hanselmann | return isinstance(val, int) and not isinstance(val, bool) |
156 | 62e0e880 | Iustin Pop | |
157 | 62e0e880 | Iustin Pop | |
158 | 8c9ee749 | Michael Hanselmann | @WithDesc("Float") |
159 | 62e0e880 | Iustin Pop | def TFloat(val): |
160 | 62e0e880 | Iustin Pop | """Checks if the given value is a float.
|
161 | 62e0e880 | Iustin Pop |
|
162 | 62e0e880 | Iustin Pop | """
|
163 | 62e0e880 | Iustin Pop | return isinstance(val, float) |
164 | 62e0e880 | Iustin Pop | |
165 | 62e0e880 | Iustin Pop | |
166 | 8c9ee749 | Michael Hanselmann | @WithDesc("String") |
167 | 62e0e880 | Iustin Pop | def TString(val): |
168 | 62e0e880 | Iustin Pop | """Checks if the given value is a string.
|
169 | 62e0e880 | Iustin Pop |
|
170 | 62e0e880 | Iustin Pop | """
|
171 | 62e0e880 | Iustin Pop | return isinstance(val, basestring) |
172 | 62e0e880 | Iustin Pop | |
173 | 62e0e880 | Iustin Pop | |
174 | 8c9ee749 | Michael Hanselmann | @WithDesc("EvalToTrue") |
175 | 62e0e880 | Iustin Pop | def TTrue(val): |
176 | 62e0e880 | Iustin Pop | """Checks if a given value evaluates to a boolean True value.
|
177 | 62e0e880 | Iustin Pop |
|
178 | 62e0e880 | Iustin Pop | """
|
179 | 62e0e880 | Iustin Pop | return bool(val) |
180 | 62e0e880 | Iustin Pop | |
181 | 62e0e880 | Iustin Pop | |
182 | 62e0e880 | Iustin Pop | def TElemOf(target_list): |
183 | 62e0e880 | Iustin Pop | """Builds a function that checks if a given value is a member of a list.
|
184 | 62e0e880 | Iustin Pop |
|
185 | 62e0e880 | Iustin Pop | """
|
186 | 8c9ee749 | Michael Hanselmann | def fn(val): |
187 | 8c9ee749 | Michael Hanselmann | return val in target_list |
188 | 8c9ee749 | Michael Hanselmann | |
189 | 8c9ee749 | Michael Hanselmann | return WithDesc("OneOf %s" % (utils.CommaJoin(target_list), ))(fn) |
190 | 62e0e880 | Iustin Pop | |
191 | 62e0e880 | Iustin Pop | |
192 | 62e0e880 | Iustin Pop | # Container types
|
193 | 8c9ee749 | Michael Hanselmann | @WithDesc("List") |
194 | 62e0e880 | Iustin Pop | def TList(val): |
195 | 62e0e880 | Iustin Pop | """Checks if the given value is a list.
|
196 | 62e0e880 | Iustin Pop |
|
197 | 62e0e880 | Iustin Pop | """
|
198 | 62e0e880 | Iustin Pop | return isinstance(val, list) |
199 | 62e0e880 | Iustin Pop | |
200 | 62e0e880 | Iustin Pop | |
201 | 8c9ee749 | Michael Hanselmann | @WithDesc("Dictionary") |
202 | 62e0e880 | Iustin Pop | def TDict(val): |
203 | 62e0e880 | Iustin Pop | """Checks if the given value is a dictionary.
|
204 | 62e0e880 | Iustin Pop |
|
205 | 62e0e880 | Iustin Pop | """
|
206 | 62e0e880 | Iustin Pop | return isinstance(val, dict) |
207 | 62e0e880 | Iustin Pop | |
208 | 62e0e880 | Iustin Pop | |
209 | 62e0e880 | Iustin Pop | def TIsLength(size): |
210 | 62e0e880 | Iustin Pop | """Check is the given container is of the given size.
|
211 | 62e0e880 | Iustin Pop |
|
212 | 62e0e880 | Iustin Pop | """
|
213 | 8c9ee749 | Michael Hanselmann | def fn(container): |
214 | 8c9ee749 | Michael Hanselmann | return len(container) == size |
215 | 8c9ee749 | Michael Hanselmann | |
216 | 8c9ee749 | Michael Hanselmann | return WithDesc("Length %s" % (size, ))(fn) |
217 | 62e0e880 | Iustin Pop | |
218 | 62e0e880 | Iustin Pop | |
219 | 62e0e880 | Iustin Pop | # Combinator types
|
220 | 62e0e880 | Iustin Pop | def TAnd(*args): |
221 | 62e0e880 | Iustin Pop | """Combine multiple functions using an AND operation.
|
222 | 62e0e880 | Iustin Pop |
|
223 | 62e0e880 | Iustin Pop | """
|
224 | 62e0e880 | Iustin Pop | def fn(val): |
225 | 62e0e880 | Iustin Pop | return compat.all(t(val) for t in args) |
226 | 8c9ee749 | Michael Hanselmann | |
227 | 8c9ee749 | Michael Hanselmann | return CombinationDesc("and", args, fn) |
228 | 62e0e880 | Iustin Pop | |
229 | 62e0e880 | Iustin Pop | |
230 | 62e0e880 | Iustin Pop | def TOr(*args): |
231 | 62e0e880 | Iustin Pop | """Combine multiple functions using an AND operation.
|
232 | 62e0e880 | Iustin Pop |
|
233 | 62e0e880 | Iustin Pop | """
|
234 | 62e0e880 | Iustin Pop | def fn(val): |
235 | 62e0e880 | Iustin Pop | return compat.any(t(val) for t in args) |
236 | 8c9ee749 | Michael Hanselmann | |
237 | 8c9ee749 | Michael Hanselmann | return CombinationDesc("or", args, fn) |
238 | 62e0e880 | Iustin Pop | |
239 | 62e0e880 | Iustin Pop | |
240 | 62e0e880 | Iustin Pop | def TMap(fn, test): |
241 | 62e0e880 | Iustin Pop | """Checks that a modified version of the argument passes the given test.
|
242 | 62e0e880 | Iustin Pop |
|
243 | 62e0e880 | Iustin Pop | """
|
244 | 8c9ee749 | Michael Hanselmann | return WithDesc("Result of %s must be %s" % |
245 | 8c9ee749 | Michael Hanselmann | (Parens(fn), Parens(test)))(lambda val: test(fn(val)))
|
246 | 62e0e880 | Iustin Pop | |
247 | 62e0e880 | Iustin Pop | |
248 | 62e0e880 | Iustin Pop | # Type aliases
|
249 | 62e0e880 | Iustin Pop | |
250 | 62e0e880 | Iustin Pop | #: a non-empty string
|
251 | 8c9ee749 | Michael Hanselmann | TNonEmptyString = WithDesc("NonEmptyString")(TAnd(TString, TTrue))
|
252 | 62e0e880 | Iustin Pop | |
253 | 62e0e880 | Iustin Pop | #: a maybe non-empty string
|
254 | 62e0e880 | Iustin Pop | TMaybeString = TOr(TNonEmptyString, TNone) |
255 | 62e0e880 | Iustin Pop | |
256 | 62e0e880 | Iustin Pop | #: a maybe boolean (bool or none)
|
257 | 62e0e880 | Iustin Pop | TMaybeBool = TOr(TBool, TNone) |
258 | 62e0e880 | Iustin Pop | |
259 | 5f074973 | Michael Hanselmann | #: Maybe a dictionary (dict or None)
|
260 | 5f074973 | Michael Hanselmann | TMaybeDict = TOr(TDict, TNone) |
261 | 62e0e880 | Iustin Pop | |
262 | 62e0e880 | Iustin Pop | #: a positive integer
|
263 | 8c9ee749 | Michael Hanselmann | TPositiveInt = \ |
264 | 8c9ee749 | Michael Hanselmann | TAnd(TInt, WithDesc("EqualGreaterZero")(lambda v: v >= 0)) |
265 | 62e0e880 | Iustin Pop | |
266 | 62e0e880 | Iustin Pop | #: a strictly positive integer
|
267 | 8c9ee749 | Michael Hanselmann | TStrictPositiveInt = \ |
268 | 8c9ee749 | Michael Hanselmann | TAnd(TInt, WithDesc("GreaterThanZero")(lambda v: v > 0)) |
269 | 62e0e880 | Iustin Pop | |
270 | 62e0e880 | Iustin Pop | |
271 | 62e0e880 | Iustin Pop | def TListOf(my_type): |
272 | 62e0e880 | Iustin Pop | """Checks if a given value is a list with all elements of the same type.
|
273 | 62e0e880 | Iustin Pop |
|
274 | 62e0e880 | Iustin Pop | """
|
275 | 8c9ee749 | Michael Hanselmann | desc = WithDesc("List of %s" % (Parens(my_type), ))
|
276 | 8c9ee749 | Michael Hanselmann | return desc(TAnd(TList, lambda lst: compat.all(my_type(v) for v in lst))) |
277 | 62e0e880 | Iustin Pop | |
278 | 62e0e880 | Iustin Pop | |
279 | 62e0e880 | Iustin Pop | def TDictOf(key_type, val_type): |
280 | 62e0e880 | Iustin Pop | """Checks a dict type for the type of its key/values.
|
281 | 62e0e880 | Iustin Pop |
|
282 | 62e0e880 | Iustin Pop | """
|
283 | 8c9ee749 | Michael Hanselmann | desc = WithDesc("Dictionary with keys of %s and values of %s" %
|
284 | 8c9ee749 | Michael Hanselmann | (Parens(key_type), Parens(val_type))) |
285 | 8c9ee749 | Michael Hanselmann | |
286 | 8c9ee749 | Michael Hanselmann | def fn(container): |
287 | 8c9ee749 | Michael Hanselmann | return (compat.all(key_type(v) for v in container.keys()) and |
288 | 8c9ee749 | Michael Hanselmann | compat.all(val_type(v) for v in container.values())) |
289 | 8c9ee749 | Michael Hanselmann | |
290 | 8c9ee749 | Michael Hanselmann | return desc(TAnd(TDict, fn)) |