root / lib / ht.py @ f22433c0
History | View | Annotate | Download (10.7 kB)
1 | 62e0e880 | Iustin Pop | #
|
---|---|---|---|
2 | 62e0e880 | Iustin Pop | #
|
3 | 62e0e880 | Iustin Pop | |
4 | 2c9fa1ff | Iustin Pop | # Copyright (C) 2010, 2011, 2012 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 | b247c6fc | Michael Hanselmann | import operator |
26 | 8c9ee749 | Michael Hanselmann | |
27 | 62e0e880 | Iustin Pop | from ganeti import compat |
28 | 8c9ee749 | Michael Hanselmann | from ganeti import utils |
29 | 8620f50e | Michael Hanselmann | from ganeti import constants |
30 | 8c9ee749 | Michael Hanselmann | |
31 | 8c9ee749 | Michael Hanselmann | |
32 | 8c9ee749 | Michael Hanselmann | _PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$")
|
33 | 8c9ee749 | Michael Hanselmann | |
34 | 8c9ee749 | Michael Hanselmann | |
35 | 8c9ee749 | Michael Hanselmann | def Parens(text): |
36 | 8c9ee749 | Michael Hanselmann | """Enclose text in parens if necessary.
|
37 | 8c9ee749 | Michael Hanselmann |
|
38 | 8c9ee749 | Michael Hanselmann | @param text: Text
|
39 | 8c9ee749 | Michael Hanselmann |
|
40 | 8c9ee749 | Michael Hanselmann | """
|
41 | 8c9ee749 | Michael Hanselmann | text = str(text)
|
42 | 8c9ee749 | Michael Hanselmann | |
43 | 8c9ee749 | Michael Hanselmann | if _PAREN_RE.match(text):
|
44 | 8c9ee749 | Michael Hanselmann | return text
|
45 | 8c9ee749 | Michael Hanselmann | else:
|
46 | 8c9ee749 | Michael Hanselmann | return "(%s)" % text |
47 | 8c9ee749 | Michael Hanselmann | |
48 | 8c9ee749 | Michael Hanselmann | |
49 | 9eec6d67 | Michael Hanselmann | class _WrapperBase(object): |
50 | 7fc548e9 | Michael Hanselmann | __slots__ = [ |
51 | 7fc548e9 | Michael Hanselmann | "_fn",
|
52 | 7fc548e9 | Michael Hanselmann | "_text",
|
53 | 7fc548e9 | Michael Hanselmann | ] |
54 | 7fc548e9 | Michael Hanselmann | |
55 | 7fc548e9 | Michael Hanselmann | def __init__(self, text, fn): |
56 | 7fc548e9 | Michael Hanselmann | """Initializes this class.
|
57 | 7fc548e9 | Michael Hanselmann |
|
58 | 7fc548e9 | Michael Hanselmann | @param text: Description
|
59 | 7fc548e9 | Michael Hanselmann | @param fn: Wrapped function
|
60 | 7fc548e9 | Michael Hanselmann |
|
61 | 7fc548e9 | Michael Hanselmann | """
|
62 | 9eec6d67 | Michael Hanselmann | assert text.strip()
|
63 | 9eec6d67 | Michael Hanselmann | |
64 | 7fc548e9 | Michael Hanselmann | self._text = text
|
65 | 7fc548e9 | Michael Hanselmann | self._fn = fn
|
66 | 7fc548e9 | Michael Hanselmann | |
67 | 7fc548e9 | Michael Hanselmann | def __call__(self, *args): |
68 | 7fc548e9 | Michael Hanselmann | return self._fn(*args) |
69 | 7fc548e9 | Michael Hanselmann | |
70 | 9eec6d67 | Michael Hanselmann | |
71 | 9eec6d67 | Michael Hanselmann | class _DescWrapper(_WrapperBase): |
72 | 9eec6d67 | Michael Hanselmann | """Wrapper class for description text.
|
73 | 9eec6d67 | Michael Hanselmann |
|
74 | 9eec6d67 | Michael Hanselmann | """
|
75 | 7fc548e9 | Michael Hanselmann | def __str__(self): |
76 | 7fc548e9 | Michael Hanselmann | return self._text |
77 | 7fc548e9 | Michael Hanselmann | |
78 | 7fc548e9 | Michael Hanselmann | |
79 | 9eec6d67 | Michael Hanselmann | class _CommentWrapper(_WrapperBase): |
80 | 9eec6d67 | Michael Hanselmann | """Wrapper class for comment.
|
81 | 9eec6d67 | Michael Hanselmann |
|
82 | 9eec6d67 | Michael Hanselmann | """
|
83 | 9eec6d67 | Michael Hanselmann | def __str__(self): |
84 | 9eec6d67 | Michael Hanselmann | return "%s [%s]" % (self._fn, self._text) |
85 | 9eec6d67 | Michael Hanselmann | |
86 | 9eec6d67 | Michael Hanselmann | |
87 | 8c9ee749 | Michael Hanselmann | def WithDesc(text): |
88 | 8c9ee749 | Michael Hanselmann | """Builds wrapper class with description text.
|
89 | 8c9ee749 | Michael Hanselmann |
|
90 | 8c9ee749 | Michael Hanselmann | @type text: string
|
91 | 8c9ee749 | Michael Hanselmann | @param text: Description text
|
92 | 8c9ee749 | Michael Hanselmann | @return: Callable class
|
93 | 8c9ee749 | Michael Hanselmann |
|
94 | 8c9ee749 | Michael Hanselmann | """
|
95 | 8c9ee749 | Michael Hanselmann | assert text[0] == text[0].upper() |
96 | 8c9ee749 | Michael Hanselmann | |
97 | 7fc548e9 | Michael Hanselmann | return compat.partial(_DescWrapper, text)
|
98 | 8c9ee749 | Michael Hanselmann | |
99 | 8c9ee749 | Michael Hanselmann | |
100 | 9eec6d67 | Michael Hanselmann | def Comment(text): |
101 | 9eec6d67 | Michael Hanselmann | """Builds wrapper for adding comment to description text.
|
102 | 9eec6d67 | Michael Hanselmann |
|
103 | 9eec6d67 | Michael Hanselmann | @type text: string
|
104 | 9eec6d67 | Michael Hanselmann | @param text: Comment text
|
105 | 9eec6d67 | Michael Hanselmann | @return: Callable class
|
106 | 9eec6d67 | Michael Hanselmann |
|
107 | 9eec6d67 | Michael Hanselmann | """
|
108 | 9eec6d67 | Michael Hanselmann | assert not frozenset(text).intersection("[]") |
109 | 9eec6d67 | Michael Hanselmann | |
110 | 9eec6d67 | Michael Hanselmann | return compat.partial(_CommentWrapper, text)
|
111 | 9eec6d67 | Michael Hanselmann | |
112 | 9eec6d67 | Michael Hanselmann | |
113 | 8c9ee749 | Michael Hanselmann | def CombinationDesc(op, args, fn): |
114 | 8c9ee749 | Michael Hanselmann | """Build description for combinating operator.
|
115 | 8c9ee749 | Michael Hanselmann |
|
116 | 8c9ee749 | Michael Hanselmann | @type op: string
|
117 | 8c9ee749 | Michael Hanselmann | @param op: Operator as text (e.g. "and")
|
118 | 8c9ee749 | Michael Hanselmann | @type args: list
|
119 | 8c9ee749 | Michael Hanselmann | @param args: Operator arguments
|
120 | 8c9ee749 | Michael Hanselmann | @type fn: callable
|
121 | 8c9ee749 | Michael Hanselmann | @param fn: Wrapped function
|
122 | 8c9ee749 | Michael Hanselmann |
|
123 | 8c9ee749 | Michael Hanselmann | """
|
124 | a138ead7 | Michael Hanselmann | # Some type descriptions are rather long. If "None" is listed at the
|
125 | a138ead7 | Michael Hanselmann | # end or somewhere in between it is easily missed. Therefore it should
|
126 | a138ead7 | Michael Hanselmann | # be at the beginning, e.g. "None or (long description)".
|
127 | a138ead7 | Michael Hanselmann | if __debug__ and TNone in args and args.index(TNone) > 0: |
128 | a138ead7 | Michael Hanselmann | raise Exception("TNone must be listed first") |
129 | a138ead7 | Michael Hanselmann | |
130 | 8c9ee749 | Michael Hanselmann | if len(args) == 1: |
131 | 8c9ee749 | Michael Hanselmann | descr = str(args[0]) |
132 | 8c9ee749 | Michael Hanselmann | else:
|
133 | 8c9ee749 | Michael Hanselmann | descr = (" %s " % op).join(Parens(i) for i in args) |
134 | 8c9ee749 | Michael Hanselmann | |
135 | 8c9ee749 | Michael Hanselmann | return WithDesc(descr)(fn)
|
136 | 8c9ee749 | Michael Hanselmann | |
137 | 62e0e880 | Iustin Pop | |
138 | 62e0e880 | Iustin Pop | # Modifiable default values; need to define these here before the
|
139 | 62e0e880 | Iustin Pop | # actual LUs
|
140 | 62e0e880 | Iustin Pop | |
141 | 8c9ee749 | Michael Hanselmann | @WithDesc(str([])) |
142 | 62e0e880 | Iustin Pop | def EmptyList(): |
143 | 62e0e880 | Iustin Pop | """Returns an empty list.
|
144 | 62e0e880 | Iustin Pop |
|
145 | 62e0e880 | Iustin Pop | """
|
146 | 62e0e880 | Iustin Pop | return []
|
147 | 62e0e880 | Iustin Pop | |
148 | 62e0e880 | Iustin Pop | |
149 | 8c9ee749 | Michael Hanselmann | @WithDesc(str({})) |
150 | 62e0e880 | Iustin Pop | def EmptyDict(): |
151 | 62e0e880 | Iustin Pop | """Returns an empty dict.
|
152 | 62e0e880 | Iustin Pop |
|
153 | 62e0e880 | Iustin Pop | """
|
154 | 62e0e880 | Iustin Pop | return {}
|
155 | 62e0e880 | Iustin Pop | |
156 | 62e0e880 | Iustin Pop | |
157 | 62e0e880 | Iustin Pop | #: The without-default default value
|
158 | 62e0e880 | Iustin Pop | NoDefault = object()
|
159 | 62e0e880 | Iustin Pop | |
160 | 62e0e880 | Iustin Pop | |
161 | 8c9ee749 | Michael Hanselmann | #: The no-type (value too complex to check it in the type system)
|
162 | 62e0e880 | Iustin Pop | NoType = object()
|
163 | 62e0e880 | Iustin Pop | |
164 | 62e0e880 | Iustin Pop | |
165 | 62e0e880 | Iustin Pop | # Some basic types
|
166 | 8620f50e | Michael Hanselmann | @WithDesc("Anything") |
167 | 8620f50e | Michael Hanselmann | def TAny(_): |
168 | 8620f50e | Michael Hanselmann | """Accepts any value.
|
169 | 8620f50e | Michael Hanselmann |
|
170 | 8620f50e | Michael Hanselmann | """
|
171 | 8620f50e | Michael Hanselmann | return True |
172 | 8620f50e | Michael Hanselmann | |
173 | 8620f50e | Michael Hanselmann | |
174 | 8c9ee749 | Michael Hanselmann | @WithDesc("NotNone") |
175 | 62e0e880 | Iustin Pop | def TNotNone(val): |
176 | 62e0e880 | Iustin Pop | """Checks if the given value is not None.
|
177 | 62e0e880 | Iustin Pop |
|
178 | 62e0e880 | Iustin Pop | """
|
179 | 62e0e880 | Iustin Pop | return val is not None |
180 | 62e0e880 | Iustin Pop | |
181 | 62e0e880 | Iustin Pop | |
182 | 8c9ee749 | Michael Hanselmann | @WithDesc("None") |
183 | 62e0e880 | Iustin Pop | def TNone(val): |
184 | 62e0e880 | Iustin Pop | """Checks if the given value is None.
|
185 | 62e0e880 | Iustin Pop |
|
186 | 62e0e880 | Iustin Pop | """
|
187 | 62e0e880 | Iustin Pop | return val is None |
188 | 62e0e880 | Iustin Pop | |
189 | 62e0e880 | Iustin Pop | |
190 | e055a2ab | Dimitris Aragiorgis | @WithDesc("ValueNone") |
191 | e055a2ab | Dimitris Aragiorgis | def TValueNone(val): |
192 | e055a2ab | Dimitris Aragiorgis | """Checks if the given value is L{constants.VALUE_NONE}.
|
193 | e055a2ab | Dimitris Aragiorgis |
|
194 | e055a2ab | Dimitris Aragiorgis | """
|
195 | e055a2ab | Dimitris Aragiorgis | return val == constants.VALUE_NONE
|
196 | e055a2ab | Dimitris Aragiorgis | |
197 | e055a2ab | Dimitris Aragiorgis | |
198 | 8c9ee749 | Michael Hanselmann | @WithDesc("Boolean") |
199 | 62e0e880 | Iustin Pop | def TBool(val): |
200 | 62e0e880 | Iustin Pop | """Checks if the given value is a boolean.
|
201 | 62e0e880 | Iustin Pop |
|
202 | 62e0e880 | Iustin Pop | """
|
203 | 62e0e880 | Iustin Pop | return isinstance(val, bool) |
204 | 62e0e880 | Iustin Pop | |
205 | 62e0e880 | Iustin Pop | |
206 | 8c9ee749 | Michael Hanselmann | @WithDesc("Integer") |
207 | 62e0e880 | Iustin Pop | def TInt(val): |
208 | 62e0e880 | Iustin Pop | """Checks if the given value is an integer.
|
209 | 62e0e880 | Iustin Pop |
|
210 | 62e0e880 | Iustin Pop | """
|
211 | 8568de9e | Michael Hanselmann | # For backwards compatibility with older Python versions, boolean values are
|
212 | 8568de9e | Michael Hanselmann | # also integers and should be excluded in this test.
|
213 | 8568de9e | Michael Hanselmann | #
|
214 | 8568de9e | Michael Hanselmann | # >>> (isinstance(False, int), isinstance(True, int))
|
215 | 8568de9e | Michael Hanselmann | # (True, True)
|
216 | b99b607f | Michael Hanselmann | return isinstance(val, (int, long)) and not isinstance(val, bool) |
217 | 62e0e880 | Iustin Pop | |
218 | 62e0e880 | Iustin Pop | |
219 | 8c9ee749 | Michael Hanselmann | @WithDesc("Float") |
220 | 62e0e880 | Iustin Pop | def TFloat(val): |
221 | 62e0e880 | Iustin Pop | """Checks if the given value is a float.
|
222 | 62e0e880 | Iustin Pop |
|
223 | 62e0e880 | Iustin Pop | """
|
224 | 62e0e880 | Iustin Pop | return isinstance(val, float) |
225 | 62e0e880 | Iustin Pop | |
226 | 62e0e880 | Iustin Pop | |
227 | 8c9ee749 | Michael Hanselmann | @WithDesc("String") |
228 | 62e0e880 | Iustin Pop | def TString(val): |
229 | 62e0e880 | Iustin Pop | """Checks if the given value is a string.
|
230 | 62e0e880 | Iustin Pop |
|
231 | 62e0e880 | Iustin Pop | """
|
232 | 62e0e880 | Iustin Pop | return isinstance(val, basestring) |
233 | 62e0e880 | Iustin Pop | |
234 | 62e0e880 | Iustin Pop | |
235 | 8c9ee749 | Michael Hanselmann | @WithDesc("EvalToTrue") |
236 | 62e0e880 | Iustin Pop | def TTrue(val): |
237 | 62e0e880 | Iustin Pop | """Checks if a given value evaluates to a boolean True value.
|
238 | 62e0e880 | Iustin Pop |
|
239 | 62e0e880 | Iustin Pop | """
|
240 | 62e0e880 | Iustin Pop | return bool(val) |
241 | 62e0e880 | Iustin Pop | |
242 | 62e0e880 | Iustin Pop | |
243 | 62e0e880 | Iustin Pop | def TElemOf(target_list): |
244 | 62e0e880 | Iustin Pop | """Builds a function that checks if a given value is a member of a list.
|
245 | 62e0e880 | Iustin Pop |
|
246 | 62e0e880 | Iustin Pop | """
|
247 | 8c9ee749 | Michael Hanselmann | def fn(val): |
248 | 8c9ee749 | Michael Hanselmann | return val in target_list |
249 | 8c9ee749 | Michael Hanselmann | |
250 | 8c9ee749 | Michael Hanselmann | return WithDesc("OneOf %s" % (utils.CommaJoin(target_list), ))(fn) |
251 | 62e0e880 | Iustin Pop | |
252 | 62e0e880 | Iustin Pop | |
253 | 62e0e880 | Iustin Pop | # Container types
|
254 | 8c9ee749 | Michael Hanselmann | @WithDesc("List") |
255 | 62e0e880 | Iustin Pop | def TList(val): |
256 | 62e0e880 | Iustin Pop | """Checks if the given value is a list.
|
257 | 62e0e880 | Iustin Pop |
|
258 | 62e0e880 | Iustin Pop | """
|
259 | 62e0e880 | Iustin Pop | return isinstance(val, list) |
260 | 62e0e880 | Iustin Pop | |
261 | 62e0e880 | Iustin Pop | |
262 | dd076c21 | Iustin Pop | @WithDesc("Tuple") |
263 | dd076c21 | Iustin Pop | def TTuple(val): |
264 | dd076c21 | Iustin Pop | """Checks if the given value is a tuple.
|
265 | dd076c21 | Iustin Pop |
|
266 | dd076c21 | Iustin Pop | """
|
267 | dd076c21 | Iustin Pop | return isinstance(val, tuple) |
268 | dd076c21 | Iustin Pop | |
269 | dd076c21 | Iustin Pop | |
270 | 8c9ee749 | Michael Hanselmann | @WithDesc("Dictionary") |
271 | 62e0e880 | Iustin Pop | def TDict(val): |
272 | 62e0e880 | Iustin Pop | """Checks if the given value is a dictionary.
|
273 | 62e0e880 | Iustin Pop |
|
274 | 62e0e880 | Iustin Pop | """
|
275 | 62e0e880 | Iustin Pop | return isinstance(val, dict) |
276 | 62e0e880 | Iustin Pop | |
277 | 62e0e880 | Iustin Pop | |
278 | 62e0e880 | Iustin Pop | def TIsLength(size): |
279 | 62e0e880 | Iustin Pop | """Check is the given container is of the given size.
|
280 | 62e0e880 | Iustin Pop |
|
281 | 62e0e880 | Iustin Pop | """
|
282 | 8c9ee749 | Michael Hanselmann | def fn(container): |
283 | 8c9ee749 | Michael Hanselmann | return len(container) == size |
284 | 8c9ee749 | Michael Hanselmann | |
285 | 8c9ee749 | Michael Hanselmann | return WithDesc("Length %s" % (size, ))(fn) |
286 | 62e0e880 | Iustin Pop | |
287 | 62e0e880 | Iustin Pop | |
288 | 62e0e880 | Iustin Pop | # Combinator types
|
289 | 62e0e880 | Iustin Pop | def TAnd(*args): |
290 | 62e0e880 | Iustin Pop | """Combine multiple functions using an AND operation.
|
291 | 62e0e880 | Iustin Pop |
|
292 | 62e0e880 | Iustin Pop | """
|
293 | 62e0e880 | Iustin Pop | def fn(val): |
294 | 62e0e880 | Iustin Pop | return compat.all(t(val) for t in args) |
295 | 8c9ee749 | Michael Hanselmann | |
296 | 8c9ee749 | Michael Hanselmann | return CombinationDesc("and", args, fn) |
297 | 62e0e880 | Iustin Pop | |
298 | 62e0e880 | Iustin Pop | |
299 | 62e0e880 | Iustin Pop | def TOr(*args): |
300 | 62e0e880 | Iustin Pop | """Combine multiple functions using an AND operation.
|
301 | 62e0e880 | Iustin Pop |
|
302 | 62e0e880 | Iustin Pop | """
|
303 | 62e0e880 | Iustin Pop | def fn(val): |
304 | 62e0e880 | Iustin Pop | return compat.any(t(val) for t in args) |
305 | 8c9ee749 | Michael Hanselmann | |
306 | 8c9ee749 | Michael Hanselmann | return CombinationDesc("or", args, fn) |
307 | 62e0e880 | Iustin Pop | |
308 | 62e0e880 | Iustin Pop | |
309 | 62e0e880 | Iustin Pop | def TMap(fn, test): |
310 | 62e0e880 | Iustin Pop | """Checks that a modified version of the argument passes the given test.
|
311 | 62e0e880 | Iustin Pop |
|
312 | 62e0e880 | Iustin Pop | """
|
313 | 8c9ee749 | Michael Hanselmann | return WithDesc("Result of %s must be %s" % |
314 | 8c9ee749 | Michael Hanselmann | (Parens(fn), Parens(test)))(lambda val: test(fn(val)))
|
315 | 62e0e880 | Iustin Pop | |
316 | 62e0e880 | Iustin Pop | |
317 | 8620f50e | Michael Hanselmann | def TRegex(pobj): |
318 | 8620f50e | Michael Hanselmann | """Checks whether a string matches a specific regular expression.
|
319 | 8620f50e | Michael Hanselmann |
|
320 | 8620f50e | Michael Hanselmann | @param pobj: Compiled regular expression as returned by C{re.compile}
|
321 | 8620f50e | Michael Hanselmann |
|
322 | 8620f50e | Michael Hanselmann | """
|
323 | 8620f50e | Michael Hanselmann | desc = WithDesc("String matching regex \"%s\"" %
|
324 | 8620f50e | Michael Hanselmann | pobj.pattern.encode("string_escape"))
|
325 | 8620f50e | Michael Hanselmann | |
326 | 8620f50e | Michael Hanselmann | return desc(TAnd(TString, pobj.match))
|
327 | 8620f50e | Michael Hanselmann | |
328 | 8620f50e | Michael Hanselmann | |
329 | fd9f58fd | Iustin Pop | def TMaybe(test): |
330 | fd9f58fd | Iustin Pop | """Wrap a test in a TOr(TNone, test).
|
331 | fd9f58fd | Iustin Pop |
|
332 | fd9f58fd | Iustin Pop | This makes it easier to define TMaybe* types.
|
333 | fd9f58fd | Iustin Pop |
|
334 | fd9f58fd | Iustin Pop | """
|
335 | fd9f58fd | Iustin Pop | return TOr(TNone, test)
|
336 | fd9f58fd | Iustin Pop | |
337 | fd9f58fd | Iustin Pop | |
338 | e055a2ab | Dimitris Aragiorgis | def TMaybeValueNone(test): |
339 | e055a2ab | Dimitris Aragiorgis | """Used for unsetting values.
|
340 | e055a2ab | Dimitris Aragiorgis |
|
341 | e055a2ab | Dimitris Aragiorgis | """
|
342 | e055a2ab | Dimitris Aragiorgis | return TMaybe(TOr(TValueNone, test))
|
343 | e055a2ab | Dimitris Aragiorgis | |
344 | e055a2ab | Dimitris Aragiorgis | |
345 | 62e0e880 | Iustin Pop | # Type aliases
|
346 | 62e0e880 | Iustin Pop | |
347 | 62e0e880 | Iustin Pop | #: a non-empty string
|
348 | 8c9ee749 | Michael Hanselmann | TNonEmptyString = WithDesc("NonEmptyString")(TAnd(TString, TTrue))
|
349 | 62e0e880 | Iustin Pop | |
350 | 62e0e880 | Iustin Pop | #: a maybe non-empty string
|
351 | fd9f58fd | Iustin Pop | TMaybeString = TMaybe(TNonEmptyString) |
352 | 62e0e880 | Iustin Pop | |
353 | 62e0e880 | Iustin Pop | #: a maybe boolean (bool or none)
|
354 | fd9f58fd | Iustin Pop | TMaybeBool = TMaybe(TBool) |
355 | 62e0e880 | Iustin Pop | |
356 | 5f074973 | Michael Hanselmann | #: Maybe a dictionary (dict or None)
|
357 | fd9f58fd | Iustin Pop | TMaybeDict = TMaybe(TDict) |
358 | 62e0e880 | Iustin Pop | |
359 | 2c9fa1ff | Iustin Pop | #: a non-negative integer (value >= 0)
|
360 | 2c9fa1ff | Iustin Pop | TNonNegativeInt = \ |
361 | 2c9fa1ff | Iustin Pop | TAnd(TInt, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0)) |
362 | 2c9fa1ff | Iustin Pop | |
363 | 2c9fa1ff | Iustin Pop | #: a positive integer (value > 0)
|
364 | 8c9ee749 | Michael Hanselmann | TPositiveInt = \ |
365 | 2c9fa1ff | Iustin Pop | TAnd(TInt, WithDesc("GreaterThanZero")(lambda v: v > 0)) |
366 | 62e0e880 | Iustin Pop | |
367 | 2c0af7da | Guido Trotter | #: a maybe positive integer (positive integer or None)
|
368 | fd9f58fd | Iustin Pop | TMaybePositiveInt = TMaybe(TPositiveInt) |
369 | 2c0af7da | Guido Trotter | |
370 | 2c9fa1ff | Iustin Pop | #: a negative integer (value < 0)
|
371 | 2c9fa1ff | Iustin Pop | TNegativeInt = \ |
372 | b247c6fc | Michael Hanselmann | TAnd(TInt, WithDesc("LessThanZero")(compat.partial(operator.gt, 0))) |
373 | b247c6fc | Michael Hanselmann | |
374 | beff3779 | René Nussbaumer | #: a positive float
|
375 | 2c9fa1ff | Iustin Pop | TNonNegativeFloat = \ |
376 | 2c9fa1ff | Iustin Pop | TAnd(TFloat, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0.0)) |
377 | beff3779 | René Nussbaumer | |
378 | 8620f50e | Michael Hanselmann | #: Job ID
|
379 | 2c9fa1ff | Iustin Pop | TJobId = WithDesc("JobId")(TOr(TNonNegativeInt,
|
380 | bdfd7802 | Michael Hanselmann | TRegex(re.compile("^%s$" %
|
381 | bdfd7802 | Michael Hanselmann | constants.JOB_ID_TEMPLATE)))) |
382 | 8620f50e | Michael Hanselmann | |
383 | 697f49d5 | Michael Hanselmann | #: Number
|
384 | 697f49d5 | Michael Hanselmann | TNumber = TOr(TInt, TFloat) |
385 | 697f49d5 | Michael Hanselmann | |
386 | b247c6fc | Michael Hanselmann | #: Relative job ID
|
387 | 2c9fa1ff | Iustin Pop | TRelativeJobId = WithDesc("RelativeJobId")(TNegativeInt)
|
388 | b247c6fc | Michael Hanselmann | |
389 | 62e0e880 | Iustin Pop | |
390 | 16091a6e | Michael Hanselmann | def TInstanceOf(cls): |
391 | 16091a6e | Michael Hanselmann | """Checks if a given value is an instance of C{cls}.
|
392 | 16091a6e | Michael Hanselmann |
|
393 | 16091a6e | Michael Hanselmann | @type cls: class
|
394 | 16091a6e | Michael Hanselmann | @param cls: Class object
|
395 | b1e47e2d | René Nussbaumer |
|
396 | b1e47e2d | René Nussbaumer | """
|
397 | 16091a6e | Michael Hanselmann | name = "%s.%s" % (cls.__module__, cls.__name__)
|
398 | 16091a6e | Michael Hanselmann | |
399 | 16091a6e | Michael Hanselmann | desc = WithDesc("Instance of %s" % (Parens(name), ))
|
400 | 16091a6e | Michael Hanselmann | |
401 | 16091a6e | Michael Hanselmann | return desc(lambda val: isinstance(val, cls)) |
402 | b1e47e2d | René Nussbaumer | |
403 | b1e47e2d | René Nussbaumer | |
404 | 62e0e880 | Iustin Pop | def TListOf(my_type): |
405 | 62e0e880 | Iustin Pop | """Checks if a given value is a list with all elements of the same type.
|
406 | 62e0e880 | Iustin Pop |
|
407 | 62e0e880 | Iustin Pop | """
|
408 | 8c9ee749 | Michael Hanselmann | desc = WithDesc("List of %s" % (Parens(my_type), ))
|
409 | 8c9ee749 | Michael Hanselmann | return desc(TAnd(TList, lambda lst: compat.all(my_type(v) for v in lst))) |
410 | 62e0e880 | Iustin Pop | |
411 | 62e0e880 | Iustin Pop | |
412 | fd9f58fd | Iustin Pop | TMaybeListOf = lambda item_type: TMaybe(TListOf(item_type))
|
413 | ff8067cf | Michael Hanselmann | |
414 | ff8067cf | Michael Hanselmann | |
415 | 62e0e880 | Iustin Pop | def TDictOf(key_type, val_type): |
416 | 62e0e880 | Iustin Pop | """Checks a dict type for the type of its key/values.
|
417 | 62e0e880 | Iustin Pop |
|
418 | 62e0e880 | Iustin Pop | """
|
419 | 8c9ee749 | Michael Hanselmann | desc = WithDesc("Dictionary with keys of %s and values of %s" %
|
420 | 8c9ee749 | Michael Hanselmann | (Parens(key_type), Parens(val_type))) |
421 | 8c9ee749 | Michael Hanselmann | |
422 | 8c9ee749 | Michael Hanselmann | def fn(container): |
423 | 8c9ee749 | Michael Hanselmann | return (compat.all(key_type(v) for v in container.keys()) and |
424 | 8c9ee749 | Michael Hanselmann | compat.all(val_type(v) for v in container.values())) |
425 | 8c9ee749 | Michael Hanselmann | |
426 | 8c9ee749 | Michael Hanselmann | return desc(TAnd(TDict, fn))
|
427 | a464ce71 | Michael Hanselmann | |
428 | a464ce71 | Michael Hanselmann | |
429 | a464ce71 | Michael Hanselmann | def _TStrictDictCheck(require_all, exclusive, items, val): |
430 | a464ce71 | Michael Hanselmann | """Helper function for L{TStrictDict}.
|
431 | a464ce71 | Michael Hanselmann |
|
432 | a464ce71 | Michael Hanselmann | """
|
433 | a464ce71 | Michael Hanselmann | notfound_fn = lambda _: not exclusive |
434 | a464ce71 | Michael Hanselmann | |
435 | a464ce71 | Michael Hanselmann | if require_all and not frozenset(val.keys()).issuperset(items.keys()): |
436 | a464ce71 | Michael Hanselmann | # Requires items not found in value
|
437 | a464ce71 | Michael Hanselmann | return False |
438 | a464ce71 | Michael Hanselmann | |
439 | a464ce71 | Michael Hanselmann | return compat.all(items.get(key, notfound_fn)(value)
|
440 | a464ce71 | Michael Hanselmann | for (key, value) in val.items()) |
441 | a464ce71 | Michael Hanselmann | |
442 | a464ce71 | Michael Hanselmann | |
443 | a464ce71 | Michael Hanselmann | def TStrictDict(require_all, exclusive, items): |
444 | a464ce71 | Michael Hanselmann | """Strict dictionary check with specific keys.
|
445 | a464ce71 | Michael Hanselmann |
|
446 | a464ce71 | Michael Hanselmann | @type require_all: boolean
|
447 | a464ce71 | Michael Hanselmann | @param require_all: Whether all keys in L{items} are required
|
448 | a464ce71 | Michael Hanselmann | @type exclusive: boolean
|
449 | a464ce71 | Michael Hanselmann | @param exclusive: Whether only keys listed in L{items} should be accepted
|
450 | a464ce71 | Michael Hanselmann | @type items: dictionary
|
451 | a464ce71 | Michael Hanselmann | @param items: Mapping from key (string) to verification function
|
452 | a464ce71 | Michael Hanselmann |
|
453 | a464ce71 | Michael Hanselmann | """
|
454 | a464ce71 | Michael Hanselmann | descparts = ["Dictionary containing"]
|
455 | a464ce71 | Michael Hanselmann | |
456 | a464ce71 | Michael Hanselmann | if exclusive:
|
457 | a464ce71 | Michael Hanselmann | descparts.append(" none but the")
|
458 | a464ce71 | Michael Hanselmann | |
459 | a464ce71 | Michael Hanselmann | if require_all:
|
460 | a464ce71 | Michael Hanselmann | descparts.append(" required")
|
461 | a464ce71 | Michael Hanselmann | |
462 | a464ce71 | Michael Hanselmann | if len(items) == 1: |
463 | a464ce71 | Michael Hanselmann | descparts.append(" key ")
|
464 | a464ce71 | Michael Hanselmann | else:
|
465 | a464ce71 | Michael Hanselmann | descparts.append(" keys ")
|
466 | a464ce71 | Michael Hanselmann | |
467 | a464ce71 | Michael Hanselmann | descparts.append(utils.CommaJoin("\"%s\" (value %s)" % (key, value)
|
468 | a464ce71 | Michael Hanselmann | for (key, value) in items.items())) |
469 | a464ce71 | Michael Hanselmann | |
470 | a464ce71 | Michael Hanselmann | desc = WithDesc("".join(descparts))
|
471 | a464ce71 | Michael Hanselmann | |
472 | a464ce71 | Michael Hanselmann | return desc(TAnd(TDict,
|
473 | a464ce71 | Michael Hanselmann | compat.partial(_TStrictDictCheck, require_all, exclusive, |
474 | a464ce71 | Michael Hanselmann | items))) |
475 | 8620f50e | Michael Hanselmann | |
476 | 8620f50e | Michael Hanselmann | |
477 | 8620f50e | Michael Hanselmann | def TItems(items): |
478 | 8620f50e | Michael Hanselmann | """Checks individual items of a container.
|
479 | 8620f50e | Michael Hanselmann |
|
480 | 8620f50e | Michael Hanselmann | If the verified value and the list of expected items differ in length, this
|
481 | 8620f50e | Michael Hanselmann | check considers only as many items as are contained in the shorter list. Use
|
482 | 8620f50e | Michael Hanselmann | L{TIsLength} to enforce a certain length.
|
483 | 8620f50e | Michael Hanselmann |
|
484 | 8620f50e | Michael Hanselmann | @type items: list
|
485 | 8620f50e | Michael Hanselmann | @param items: List of checks
|
486 | 8620f50e | Michael Hanselmann |
|
487 | 8620f50e | Michael Hanselmann | """
|
488 | 8620f50e | Michael Hanselmann | assert items, "Need items" |
489 | 8620f50e | Michael Hanselmann | |
490 | 8620f50e | Michael Hanselmann | text = ["Item", "item"] |
491 | 8620f50e | Michael Hanselmann | desc = WithDesc(utils.CommaJoin("%s %s is %s" %
|
492 | 8620f50e | Michael Hanselmann | (text[int(idx > 0)], idx, Parens(check)) |
493 | 8620f50e | Michael Hanselmann | for (idx, check) in enumerate(items))) |
494 | 8620f50e | Michael Hanselmann | |
495 | 8620f50e | Michael Hanselmann | return desc(lambda value: compat.all(check(i) |
496 | 8620f50e | Michael Hanselmann | for (check, i) in zip(items, value))) |