From fde0203b0e640575f04249e0bbf5aab9abb0eca7 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Wed, 21 Apr 2010 15:46:34 +0200 Subject: [PATCH] utils: Add function for partial application of function arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function's code was mostly copied from Python's documentation and it's equivalent to βfunctools.partialβ in Python 2.5 and above. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Iustin Pop <iustin@google.com> --- lib/utils.py | 30 ++++++++++++++++++++++++++++++ test/ganeti.utils_unittest.py | 27 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/utils.py b/lib/utils.py index d0d07bcdc..20a3b9b3f 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -55,6 +55,11 @@ except ImportError: import sha sha1 = sha.new +try: + import functools +except ImportError: + functools = None + from ganeti import errors from ganeti import constants @@ -1501,6 +1506,31 @@ def any(seq, pred=bool): # pylint: disable-msg=W0622 return False +# Even though we're using Python's built-in "partial" function if available, +# this one is always defined for testing. +def _partial(func, *args, **keywords): # pylint: disable-msg=W0622 + """Decorator with partial application of arguments and keywords. + + This function was copied from Python's documentation. + + """ + def newfunc(*fargs, **fkeywords): + newkeywords = keywords.copy() + newkeywords.update(fkeywords) + return func(*(args + fargs), **newkeywords) # pylint: disable-msg=W0142 + + newfunc.func = func + newfunc.args = args + newfunc.keywords = keywords + return newfunc + + +if functools is None: + partial = _partial +else: + partial = functools.partial + + def SingleWaitForFdCondition(fdobj, event, timeout): """Waits for a condition to occur on the socket. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 6adb630b8..fa900c934 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -1592,5 +1592,32 @@ class TestLineSplitter(unittest.TestCase): "", "x"]) +class TestPartial(testutils.GanetiTestCase): + def test(self): + self._Test(utils.partial) + self._Test(utils._partial) + + def _Test(self, fn): + def _TestFunc1(x, power=2): + return x ** power + + cubic = fn(_TestFunc1, power=3) + self.assertEqual(cubic(1), 1) + self.assertEqual(cubic(3), 27) + self.assertEqual(cubic(4), 64) + + def _TestFunc2(*args, **kwargs): + return (args, kwargs) + + self.assertEqualValues(fn(_TestFunc2, "Hello", "World")("Foo"), + (("Hello", "World", "Foo"), {})) + + self.assertEqualValues(fn(_TestFunc2, "Hello", xyz=123)("Foo"), + (("Hello", "Foo"), {"xyz": 123})) + + self.assertEqualValues(fn(_TestFunc2, xyz=123)("Foo", xyz=999), + (("Foo", ), {"xyz": 999,})) + + if __name__ == '__main__': testutils.GanetiTestProgram() -- GitLab