Statistics
| Branch: | Tag: | Revision:

root / lib / ht.py @ ab98e236

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 b3ab9a8a Christos Stavrakakis
  """Combine multiple functions using an OR 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 ab98e236 Michele Tartara
#: Maybe a list (list or None)
360 ab98e236 Michele Tartara
TMaybeList = TMaybe(TList)
361 ab98e236 Michele Tartara
362 2c9fa1ff Iustin Pop
#: a non-negative integer (value >= 0)
363 2c9fa1ff Iustin Pop
TNonNegativeInt = \
364 2c9fa1ff Iustin Pop
  TAnd(TInt, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0))
365 2c9fa1ff Iustin Pop
366 2c9fa1ff Iustin Pop
#: a positive integer (value > 0)
367 8c9ee749 Michael Hanselmann
TPositiveInt = \
368 2c9fa1ff Iustin Pop
  TAnd(TInt, WithDesc("GreaterThanZero")(lambda v: v > 0))
369 62e0e880 Iustin Pop
370 2c0af7da Guido Trotter
#: a maybe positive integer (positive integer or None)
371 fd9f58fd Iustin Pop
TMaybePositiveInt = TMaybe(TPositiveInt)
372 2c0af7da Guido Trotter
373 2c9fa1ff Iustin Pop
#: a negative integer (value < 0)
374 2c9fa1ff Iustin Pop
TNegativeInt = \
375 b247c6fc Michael Hanselmann
  TAnd(TInt, WithDesc("LessThanZero")(compat.partial(operator.gt, 0)))
376 b247c6fc Michael Hanselmann
377 beff3779 René Nussbaumer
#: a positive float
378 2c9fa1ff Iustin Pop
TNonNegativeFloat = \
379 2c9fa1ff Iustin Pop
  TAnd(TFloat, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0.0))
380 beff3779 René Nussbaumer
381 8620f50e Michael Hanselmann
#: Job ID
382 2c9fa1ff Iustin Pop
TJobId = WithDesc("JobId")(TOr(TNonNegativeInt,
383 bdfd7802 Michael Hanselmann
                               TRegex(re.compile("^%s$" %
384 bdfd7802 Michael Hanselmann
                                                 constants.JOB_ID_TEMPLATE))))
385 8620f50e Michael Hanselmann
386 697f49d5 Michael Hanselmann
#: Number
387 697f49d5 Michael Hanselmann
TNumber = TOr(TInt, TFloat)
388 697f49d5 Michael Hanselmann
389 b247c6fc Michael Hanselmann
#: Relative job ID
390 2c9fa1ff Iustin Pop
TRelativeJobId = WithDesc("RelativeJobId")(TNegativeInt)
391 b247c6fc Michael Hanselmann
392 62e0e880 Iustin Pop
393 16091a6e Michael Hanselmann
def TInstanceOf(cls):
394 16091a6e Michael Hanselmann
  """Checks if a given value is an instance of C{cls}.
395 16091a6e Michael Hanselmann

396 16091a6e Michael Hanselmann
  @type cls: class
397 16091a6e Michael Hanselmann
  @param cls: Class object
398 b1e47e2d René Nussbaumer

399 b1e47e2d René Nussbaumer
  """
400 16091a6e Michael Hanselmann
  name = "%s.%s" % (cls.__module__, cls.__name__)
401 16091a6e Michael Hanselmann
402 16091a6e Michael Hanselmann
  desc = WithDesc("Instance of %s" % (Parens(name), ))
403 16091a6e Michael Hanselmann
404 16091a6e Michael Hanselmann
  return desc(lambda val: isinstance(val, cls))
405 b1e47e2d René Nussbaumer
406 b1e47e2d René Nussbaumer
407 62e0e880 Iustin Pop
def TListOf(my_type):
408 62e0e880 Iustin Pop
  """Checks if a given value is a list with all elements of the same type.
409 62e0e880 Iustin Pop

410 62e0e880 Iustin Pop
  """
411 8c9ee749 Michael Hanselmann
  desc = WithDesc("List of %s" % (Parens(my_type), ))
412 8c9ee749 Michael Hanselmann
  return desc(TAnd(TList, lambda lst: compat.all(my_type(v) for v in lst)))
413 62e0e880 Iustin Pop
414 62e0e880 Iustin Pop
415 fd9f58fd Iustin Pop
TMaybeListOf = lambda item_type: TMaybe(TListOf(item_type))
416 ff8067cf Michael Hanselmann
417 ff8067cf Michael Hanselmann
418 62e0e880 Iustin Pop
def TDictOf(key_type, val_type):
419 62e0e880 Iustin Pop
  """Checks a dict type for the type of its key/values.
420 62e0e880 Iustin Pop

421 62e0e880 Iustin Pop
  """
422 8c9ee749 Michael Hanselmann
  desc = WithDesc("Dictionary with keys of %s and values of %s" %
423 8c9ee749 Michael Hanselmann
                  (Parens(key_type), Parens(val_type)))
424 8c9ee749 Michael Hanselmann
425 8c9ee749 Michael Hanselmann
  def fn(container):
426 8c9ee749 Michael Hanselmann
    return (compat.all(key_type(v) for v in container.keys()) and
427 8c9ee749 Michael Hanselmann
            compat.all(val_type(v) for v in container.values()))
428 8c9ee749 Michael Hanselmann
429 8c9ee749 Michael Hanselmann
  return desc(TAnd(TDict, fn))
430 a464ce71 Michael Hanselmann
431 a464ce71 Michael Hanselmann
432 a464ce71 Michael Hanselmann
def _TStrictDictCheck(require_all, exclusive, items, val):
433 a464ce71 Michael Hanselmann
  """Helper function for L{TStrictDict}.
434 a464ce71 Michael Hanselmann

435 a464ce71 Michael Hanselmann
  """
436 a464ce71 Michael Hanselmann
  notfound_fn = lambda _: not exclusive
437 a464ce71 Michael Hanselmann
438 a464ce71 Michael Hanselmann
  if require_all and not frozenset(val.keys()).issuperset(items.keys()):
439 a464ce71 Michael Hanselmann
    # Requires items not found in value
440 a464ce71 Michael Hanselmann
    return False
441 a464ce71 Michael Hanselmann
442 a464ce71 Michael Hanselmann
  return compat.all(items.get(key, notfound_fn)(value)
443 a464ce71 Michael Hanselmann
                    for (key, value) in val.items())
444 a464ce71 Michael Hanselmann
445 a464ce71 Michael Hanselmann
446 a464ce71 Michael Hanselmann
def TStrictDict(require_all, exclusive, items):
447 a464ce71 Michael Hanselmann
  """Strict dictionary check with specific keys.
448 a464ce71 Michael Hanselmann

449 a464ce71 Michael Hanselmann
  @type require_all: boolean
450 a464ce71 Michael Hanselmann
  @param require_all: Whether all keys in L{items} are required
451 a464ce71 Michael Hanselmann
  @type exclusive: boolean
452 a464ce71 Michael Hanselmann
  @param exclusive: Whether only keys listed in L{items} should be accepted
453 a464ce71 Michael Hanselmann
  @type items: dictionary
454 a464ce71 Michael Hanselmann
  @param items: Mapping from key (string) to verification function
455 a464ce71 Michael Hanselmann

456 a464ce71 Michael Hanselmann
  """
457 a464ce71 Michael Hanselmann
  descparts = ["Dictionary containing"]
458 a464ce71 Michael Hanselmann
459 a464ce71 Michael Hanselmann
  if exclusive:
460 a464ce71 Michael Hanselmann
    descparts.append(" none but the")
461 a464ce71 Michael Hanselmann
462 a464ce71 Michael Hanselmann
  if require_all:
463 a464ce71 Michael Hanselmann
    descparts.append(" required")
464 a464ce71 Michael Hanselmann
465 a464ce71 Michael Hanselmann
  if len(items) == 1:
466 a464ce71 Michael Hanselmann
    descparts.append(" key ")
467 a464ce71 Michael Hanselmann
  else:
468 a464ce71 Michael Hanselmann
    descparts.append(" keys ")
469 a464ce71 Michael Hanselmann
470 a464ce71 Michael Hanselmann
  descparts.append(utils.CommaJoin("\"%s\" (value %s)" % (key, value)
471 a464ce71 Michael Hanselmann
                                   for (key, value) in items.items()))
472 a464ce71 Michael Hanselmann
473 a464ce71 Michael Hanselmann
  desc = WithDesc("".join(descparts))
474 a464ce71 Michael Hanselmann
475 a464ce71 Michael Hanselmann
  return desc(TAnd(TDict,
476 a464ce71 Michael Hanselmann
                   compat.partial(_TStrictDictCheck, require_all, exclusive,
477 a464ce71 Michael Hanselmann
                                  items)))
478 8620f50e Michael Hanselmann
479 8620f50e Michael Hanselmann
480 8620f50e Michael Hanselmann
def TItems(items):
481 8620f50e Michael Hanselmann
  """Checks individual items of a container.
482 8620f50e Michael Hanselmann

483 8620f50e Michael Hanselmann
  If the verified value and the list of expected items differ in length, this
484 8620f50e Michael Hanselmann
  check considers only as many items as are contained in the shorter list. Use
485 8620f50e Michael Hanselmann
  L{TIsLength} to enforce a certain length.
486 8620f50e Michael Hanselmann

487 8620f50e Michael Hanselmann
  @type items: list
488 8620f50e Michael Hanselmann
  @param items: List of checks
489 8620f50e Michael Hanselmann

490 8620f50e Michael Hanselmann
  """
491 8620f50e Michael Hanselmann
  assert items, "Need items"
492 8620f50e Michael Hanselmann
493 8620f50e Michael Hanselmann
  text = ["Item", "item"]
494 8620f50e Michael Hanselmann
  desc = WithDesc(utils.CommaJoin("%s %s is %s" %
495 8620f50e Michael Hanselmann
                                  (text[int(idx > 0)], idx, Parens(check))
496 8620f50e Michael Hanselmann
                                  for (idx, check) in enumerate(items)))
497 8620f50e Michael Hanselmann
498 8620f50e Michael Hanselmann
  return desc(lambda value: compat.all(check(i)
499 8620f50e Michael Hanselmann
                                       for (check, i) in zip(items, value)))