Statistics
| Branch: | Tag: | Revision:

root / lib / ht.py @ 6b9b18a2

History | View | Annotate | Download (5.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2010, 2011 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Module implementing the parameter types code."""
23

    
24
import re
25

    
26
from ganeti import compat
27
from ganeti import utils
28

    
29

    
30
_PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$")
31

    
32

    
33
def Parens(text):
34
  """Enclose text in parens if necessary.
35

36
  @param text: Text
37

38
  """
39
  text = str(text)
40

    
41
  if _PAREN_RE.match(text):
42
    return text
43
  else:
44
    return "(%s)" % text
45

    
46

    
47
def WithDesc(text):
48
  """Builds wrapper class with description text.
49

50
  @type text: string
51
  @param text: Description text
52
  @return: Callable class
53

54
  """
55
  assert text[0] == text[0].upper()
56

    
57
  class wrapper(object): # pylint: disable-msg=C0103
58
    __slots__ = ["__call__"]
59

    
60
    def __init__(self, fn):
61
      """Initializes this class.
62

63
      @param fn: Wrapped function
64

65
      """
66
      self.__call__ = fn
67

    
68
    def __str__(self):
69
      return text
70

    
71
  return wrapper
72

    
73

    
74
def CombinationDesc(op, args, fn):
75
  """Build description for combinating operator.
76

77
  @type op: string
78
  @param op: Operator as text (e.g. "and")
79
  @type args: list
80
  @param args: Operator arguments
81
  @type fn: callable
82
  @param fn: Wrapped function
83

84
  """
85
  if len(args) == 1:
86
    descr = str(args[0])
87
  else:
88
    descr = (" %s " % op).join(Parens(i) for i in args)
89

    
90
  return WithDesc(descr)(fn)
91

    
92

    
93
# Modifiable default values; need to define these here before the
94
# actual LUs
95

    
96
@WithDesc(str([]))
97
def EmptyList():
98
  """Returns an empty list.
99

100
  """
101
  return []
102

    
103

    
104
@WithDesc(str({}))
105
def EmptyDict():
106
  """Returns an empty dict.
107

108
  """
109
  return {}
110

    
111

    
112
#: The without-default default value
113
NoDefault = object()
114

    
115

    
116
#: The no-type (value too complex to check it in the type system)
117
NoType = object()
118

    
119

    
120
# Some basic types
121
@WithDesc("NotNone")
122
def TNotNone(val):
123
  """Checks if the given value is not None.
124

125
  """
126
  return val is not None
127

    
128

    
129
@WithDesc("None")
130
def TNone(val):
131
  """Checks if the given value is None.
132

133
  """
134
  return val is None
135

    
136

    
137
@WithDesc("Boolean")
138
def TBool(val):
139
  """Checks if the given value is a boolean.
140

141
  """
142
  return isinstance(val, bool)
143

    
144

    
145
@WithDesc("Integer")
146
def TInt(val):
147
  """Checks if the given value is an integer.
148

149
  """
150
  # For backwards compatibility with older Python versions, boolean values are
151
  # also integers and should be excluded in this test.
152
  #
153
  # >>> (isinstance(False, int), isinstance(True, int))
154
  # (True, True)
155
  return isinstance(val, int) and not isinstance(val, bool)
156

    
157

    
158
@WithDesc("Float")
159
def TFloat(val):
160
  """Checks if the given value is a float.
161

162
  """
163
  return isinstance(val, float)
164

    
165

    
166
@WithDesc("String")
167
def TString(val):
168
  """Checks if the given value is a string.
169

170
  """
171
  return isinstance(val, basestring)
172

    
173

    
174
@WithDesc("EvalToTrue")
175
def TTrue(val):
176
  """Checks if a given value evaluates to a boolean True value.
177

178
  """
179
  return bool(val)
180

    
181

    
182
def TElemOf(target_list):
183
  """Builds a function that checks if a given value is a member of a list.
184

185
  """
186
  def fn(val):
187
    return val in target_list
188

    
189
  return WithDesc("OneOf %s" % (utils.CommaJoin(target_list), ))(fn)
190

    
191

    
192
# Container types
193
@WithDesc("List")
194
def TList(val):
195
  """Checks if the given value is a list.
196

197
  """
198
  return isinstance(val, list)
199

    
200

    
201
@WithDesc("Dictionary")
202
def TDict(val):
203
  """Checks if the given value is a dictionary.
204

205
  """
206
  return isinstance(val, dict)
207

    
208

    
209
def TIsLength(size):
210
  """Check is the given container is of the given size.
211

212
  """
213
  def fn(container):
214
    return len(container) == size
215

    
216
  return WithDesc("Length %s" % (size, ))(fn)
217

    
218

    
219
# Combinator types
220
def TAnd(*args):
221
  """Combine multiple functions using an AND operation.
222

223
  """
224
  def fn(val):
225
    return compat.all(t(val) for t in args)
226

    
227
  return CombinationDesc("and", args, fn)
228

    
229

    
230
def TOr(*args):
231
  """Combine multiple functions using an AND operation.
232

233
  """
234
  def fn(val):
235
    return compat.any(t(val) for t in args)
236

    
237
  return CombinationDesc("or", args, fn)
238

    
239

    
240
def TMap(fn, test):
241
  """Checks that a modified version of the argument passes the given test.
242

243
  """
244
  return WithDesc("Result of %s must be %s" %
245
                  (Parens(fn), Parens(test)))(lambda val: test(fn(val)))
246

    
247

    
248
# Type aliases
249

    
250
#: a non-empty string
251
TNonEmptyString = WithDesc("NonEmptyString")(TAnd(TString, TTrue))
252

    
253
#: a maybe non-empty string
254
TMaybeString = TOr(TNonEmptyString, TNone)
255

    
256
#: a maybe boolean (bool or none)
257
TMaybeBool = TOr(TBool, TNone)
258

    
259
#: Maybe a dictionary (dict or None)
260
TMaybeDict = TOr(TDict, TNone)
261

    
262
#: a positive integer
263
TPositiveInt = \
264
  TAnd(TInt, WithDesc("EqualGreaterZero")(lambda v: v >= 0))
265

    
266
#: a strictly positive integer
267
TStrictPositiveInt = \
268
  TAnd(TInt, WithDesc("GreaterThanZero")(lambda v: v > 0))
269

    
270

    
271
def TListOf(my_type):
272
  """Checks if a given value is a list with all elements of the same type.
273

274
  """
275
  desc = WithDesc("List of %s" % (Parens(my_type), ))
276
  return desc(TAnd(TList, lambda lst: compat.all(my_type(v) for v in lst)))
277

    
278

    
279
def TDictOf(key_type, val_type):
280
  """Checks a dict type for the type of its key/values.
281

282
  """
283
  desc = WithDesc("Dictionary with keys of %s and values of %s" %
284
                  (Parens(key_type), Parens(val_type)))
285

    
286
  def fn(container):
287
    return (compat.all(key_type(v) for v in container.keys()) and
288
            compat.all(val_type(v) for v in container.values()))
289

    
290
  return desc(TAnd(TDict, fn))