Statistics
| Branch: | Tag: | Revision:

root / lib / ht.py @ 6b9b18a2

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))