From 691c81b7c0df7096c6ee6c647b7d63e4172cea3f Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Tue, 19 Oct 2010 16:47:16 +0200 Subject: [PATCH] utils: Add function to find items in dictionary using regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This basically extracts a small piece of code from ganeti-rapi and puts it into a utility function. RAPI resources are found using a dictionary in which the keys can either be static strings or compiled regular expressions. This might be handy in other places, hence extracting it and adding unittests. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: RenΓ© Nussbaumer <rn@google.com> --- lib/rapi/connector.py | 23 +++++++---------------- lib/utils.py | 27 +++++++++++++++++++++++++++ test/ganeti.utils_unittest.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py index 648aa0b9e..ead1876e0 100644 --- a/lib/rapi/connector.py +++ b/lib/rapi/connector.py @@ -31,6 +31,7 @@ import re from ganeti import constants from ganeti import http +from ganeti import utils from ganeti.rapi import baserlib from ganeti.rapi import rlib2 @@ -76,25 +77,15 @@ class Mapper: query = None args = {} - result = None + # Try to find handler for request path + result = utils.FindMatch(self._connector, path) - for key, handler in self._connector.iteritems(): - # Regex objects - if hasattr(key, "match"): - m = key.match(path) - if m: - result = (handler, list(m.groups()), args) - break + if result is None: + raise http.HttpNotFound() - # String objects - elif key == path: - result = (handler, [], args) - break + (handler, groups) = result - if result: - return result - else: - raise http.HttpNotFound() + return (handler, groups, args) class R_root(baserlib.R_Generic): diff --git a/lib/utils.py b/lib/utils.py index 3bdf64221..919eab11c 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -2959,6 +2959,33 @@ def CommaJoin(names): return ", ".join([str(val) for val in names]) +def FindMatch(data, name): + """Tries to find an item in a dictionary matching a name. + + Callers have to ensure the data names aren't contradictory (e.g. a regexp + that matches a string). If the name isn't a direct key, all regular + expression objects in the dictionary are matched against it. + + @type data: dict + @param data: Dictionary containing data + @type name: string + @param name: Name to look for + @rtype: tuple; (value in dictionary, matched groups as list) + + """ + if name in data: + return (data[name], []) + + for key, value in data.items(): + # Regex objects + if hasattr(key, "match"): + m = key.match(name) + if m: + return (value, list(m.groups())) + + return None + + def BytesToMebibyte(value): """Converts bytes to mebibytes. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 78d747834..08c753e3b 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -2326,5 +2326,35 @@ class TestCommaJoin(unittest.TestCase): "Hello, World, 99") +class TestFindMatch(unittest.TestCase): + def test(self): + data = { + "aaaa": "Four A", + "bb": {"Two B": True}, + re.compile(r"^x(foo|bar|bazX)([0-9]+)$"): (1, 2, 3), + } + + self.assertEqual(utils.FindMatch(data, "aaaa"), ("Four A", [])) + self.assertEqual(utils.FindMatch(data, "bb"), ({"Two B": True}, [])) + + for i in ["foo", "bar", "bazX"]: + for j in range(1, 100, 7): + self.assertEqual(utils.FindMatch(data, "x%s%s" % (i, j)), + ((1, 2, 3), [i, str(j)])) + + def testNoMatch(self): + self.assert_(utils.FindMatch({}, "") is None) + self.assert_(utils.FindMatch({}, "foo") is None) + self.assert_(utils.FindMatch({}, 1234) is None) + + data = { + "X": "Hello World", + re.compile("^(something)$"): "Hello World", + } + + self.assert_(utils.FindMatch(data, "") is None) + self.assert_(utils.FindMatch(data, "Hello World") is None) + + if __name__ == '__main__': testutils.GanetiTestProgram() -- GitLab