From 329e7279c161ae5160c2af8287887b1fc9e6fc25 Mon Sep 17 00:00:00 2001 From: Mikolaj Izdebski Date: Jun 17 2016 10:09:51 +0000 Subject: Implement ClientSession.itercall() --- diff --git a/koji/__init__.py b/koji/__init__.py index b453017..f8cd6b3 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -2174,6 +2174,31 @@ class ClientSession(object): raise err return ret + def itercall(self, args, fn): + """Alternative way of using multiCall. Iterates over list of items, + calls a hub API function for each item. Returns generator of + call results. + + "args" is list of arbitrary items. + "fn" is a function (typically lambda) taking one argument, a + single item from the list. + + itercall() will call "fn" for each item in the list. When executed, + "fn" is expected to make a single API call on ClientSession. + itercall() groups these API calls into chunks of configurable + size and handles them with multiCall. It returns generator of + replies for each call made. + + """ + chunk_size = self.opts.get('itercall_chunk_size', 100) + while args: + self.multicall = True + for arg in args[:chunk_size]: + fn(arg) + for [info] in self.multiCall(): + yield info + args = args[chunk_size:] + def __getattr__(self,name): #if name[:1] == '_': # raise AttributeError, "no attribute %r" % name diff --git a/tests/test_client/test_itercall.py b/tests/test_client/test_itercall.py new file mode 100644 index 0000000..10c361a --- /dev/null +++ b/tests/test_client/test_itercall.py @@ -0,0 +1,31 @@ +import mock +import unittest +import koji + + +class TestItercall(unittest.TestCase): + + def test_itercall(self): + + ks = koji.ClientSession('http://dumy.hub/address') + ks.multiCall = mock.Mock(return_value=[['ret1'], ['ret2'], ['ret3']]) + + args = ['arg1', 'arg2', 'arg3'] + rets = list(ks.itercall(args, lambda arg: ks.foo(arg))) + + ks.multiCall.assert_called_once_with() + self.assertEquals(['ret1', 'ret2', 'ret3'], rets) + + + def test_itercall_chunk_size(self): + + ks = koji.ClientSession('http://dumy.hub/address', + opts={'itercall_chunk_size': 2}) + mock_rets = [[[1], [2]], [[3], [4]], [[5], [6]], [[7]]] + ks.multiCall = mock.Mock(side_effect=lambda: mock_rets.pop(0)) + + args = [111, 222, 333, 444, 555, 666, 777] + rets = list(ks.itercall(args, lambda arg: ks.foo(arg))) + + ks.multiCall.assert_has_calls([mock.call()] * 4) + self.assertEquals(range(1,8), rets)