Revision a464ce71
b/lib/ht.py | ||
---|---|---|
292 | 292 |
compat.all(val_type(v) for v in container.values())) |
293 | 293 |
|
294 | 294 |
return desc(TAnd(TDict, fn)) |
295 |
|
|
296 |
|
|
297 |
def _TStrictDictCheck(require_all, exclusive, items, val): |
|
298 |
"""Helper function for L{TStrictDict}. |
|
299 |
|
|
300 |
""" |
|
301 |
notfound_fn = lambda _: not exclusive |
|
302 |
|
|
303 |
if require_all and not frozenset(val.keys()).issuperset(items.keys()): |
|
304 |
# Requires items not found in value |
|
305 |
return False |
|
306 |
|
|
307 |
return compat.all(items.get(key, notfound_fn)(value) |
|
308 |
for (key, value) in val.items()) |
|
309 |
|
|
310 |
|
|
311 |
def TStrictDict(require_all, exclusive, items): |
|
312 |
"""Strict dictionary check with specific keys. |
|
313 |
|
|
314 |
@type require_all: boolean |
|
315 |
@param require_all: Whether all keys in L{items} are required |
|
316 |
@type exclusive: boolean |
|
317 |
@param exclusive: Whether only keys listed in L{items} should be accepted |
|
318 |
@type items: dictionary |
|
319 |
@param items: Mapping from key (string) to verification function |
|
320 |
|
|
321 |
""" |
|
322 |
descparts = ["Dictionary containing"] |
|
323 |
|
|
324 |
if exclusive: |
|
325 |
descparts.append(" none but the") |
|
326 |
|
|
327 |
if require_all: |
|
328 |
descparts.append(" required") |
|
329 |
|
|
330 |
if len(items) == 1: |
|
331 |
descparts.append(" key ") |
|
332 |
else: |
|
333 |
descparts.append(" keys ") |
|
334 |
|
|
335 |
descparts.append(utils.CommaJoin("\"%s\" (value %s)" % (key, value) |
|
336 |
for (key, value) in items.items())) |
|
337 |
|
|
338 |
desc = WithDesc("".join(descparts)) |
|
339 |
|
|
340 |
return desc(TAnd(TDict, |
|
341 |
compat.partial(_TStrictDictCheck, require_all, exclusive, |
|
342 |
items))) |
b/test/ganeti.ht_unittest.py | ||
---|---|---|
187 | 187 |
self.assertFalse(fn({"x": None})) |
188 | 188 |
self.assertFalse(fn({"": 8234})) |
189 | 189 |
|
190 |
def testStrictDictRequireAllExclusive(self): |
|
191 |
fn = ht.TStrictDict(True, True, { "a": ht.TInt, }) |
|
192 |
self.assertFalse(fn(1)) |
|
193 |
self.assertFalse(fn(None)) |
|
194 |
self.assertFalse(fn({})) |
|
195 |
self.assertFalse(fn({"a": "Hello", })) |
|
196 |
self.assertFalse(fn({"unknown": 999,})) |
|
197 |
self.assertFalse(fn({"unknown": None,})) |
|
198 |
|
|
199 |
self.assertTrue(fn({"a": 123, })) |
|
200 |
self.assertTrue(fn({"a": -5, })) |
|
201 |
|
|
202 |
fn = ht.TStrictDict(True, True, { "a": ht.TInt, "x": ht.TString, }) |
|
203 |
self.assertFalse(fn({})) |
|
204 |
self.assertFalse(fn({"a": -5, })) |
|
205 |
self.assertTrue(fn({"a": 123, "x": "", })) |
|
206 |
self.assertFalse(fn({"a": 123, "x": None, })) |
|
207 |
|
|
208 |
def testStrictDictExclusive(self): |
|
209 |
fn = ht.TStrictDict(False, True, { "a": ht.TInt, "b": ht.TList, }) |
|
210 |
self.assertTrue(fn({})) |
|
211 |
self.assertTrue(fn({"a": 123, })) |
|
212 |
self.assertTrue(fn({"b": range(4), })) |
|
213 |
self.assertFalse(fn({"b": 123, })) |
|
214 |
|
|
215 |
self.assertFalse(fn({"foo": {}, })) |
|
216 |
self.assertFalse(fn({"bar": object(), })) |
|
217 |
|
|
218 |
def testStrictDictRequireAll(self): |
|
219 |
fn = ht.TStrictDict(True, False, { "a": ht.TInt, "m": ht.TInt, }) |
|
220 |
self.assertTrue(fn({"a": 1, "m": 2, "bar": object(), })) |
|
221 |
self.assertFalse(fn({})) |
|
222 |
self.assertFalse(fn({"a": 1, "bar": object(), })) |
|
223 |
self.assertFalse(fn({"a": 1, "m": [], "bar": object(), })) |
|
224 |
|
|
225 |
def testStrictDict(self): |
|
226 |
fn = ht.TStrictDict(False, False, { "a": ht.TInt, }) |
|
227 |
self.assertTrue(fn({})) |
|
228 |
self.assertFalse(fn({"a": ""})) |
|
229 |
self.assertTrue(fn({"a": 11})) |
|
230 |
self.assertTrue(fn({"other": 11})) |
|
231 |
self.assertTrue(fn({"other": object()})) |
|
232 |
|
|
190 | 233 |
|
191 | 234 |
if __name__ == "__main__": |
192 | 235 |
testutils.GanetiTestProgram() |
Also available in: Unified diff