diff options
-rw-r--r-- | indra/lib/python/indra/util/iterators.py | 63 | ||||
-rwxr-xr-x | indra/lib/python/indra/util/iterators_test.py | 72 |
2 files changed, 135 insertions, 0 deletions
diff --git a/indra/lib/python/indra/util/iterators.py b/indra/lib/python/indra/util/iterators.py new file mode 100644 index 0000000000..6a98c97f8b --- /dev/null +++ b/indra/lib/python/indra/util/iterators.py @@ -0,0 +1,63 @@ +"""\ +@file iterators.py +@brief Useful general-purpose iterators. + +$LicenseInfo:firstyear=2008&license=mit$ + +Copyright (c) 2008, Linden Research, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +$/LicenseInfo$ +""" + +from __future__ import nested_scopes + +def iter_chunks(rows, aggregate_size=100): + """ + Given an iterable set of items (@p rows), produces lists of up to @p + aggregate_size items at a time, for example: + + iter_chunks([1,2,3,4,5,6,7,8,9,10], 3) + + Values for @p aggregate_size < 1 will raise ValueError. + + Will return a generator that produces, in the following order: + - [1, 2, 3] + - [4, 5, 6] + - [7, 8, 9] + - [10] + """ + if aggregate_size < 1: + raise ValueError() + + def iter_chunks_inner(): + row_iter = iter(rows) + done = False + agg = [] + while not done: + try: + row = row_iter.next() + agg.append(row) + except StopIteration: + done = True + if agg and (len(agg) >= aggregate_size or done): + yield agg + agg = [] + + return iter_chunks_inner() diff --git a/indra/lib/python/indra/util/iterators_test.py b/indra/lib/python/indra/util/iterators_test.py new file mode 100755 index 0000000000..7fd9e73b35 --- /dev/null +++ b/indra/lib/python/indra/util/iterators_test.py @@ -0,0 +1,72 @@ +"""\ +@file iterators_test.py +@brief Test cases for iterators module. + +$LicenseInfo:firstyear=2008&license=mit$ + +Copyright (c) 2008, Linden Research, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +$/LicenseInfo$ +""" + +import unittest + +from indra.util.iterators import iter_chunks + +class TestIterChunks(unittest.TestCase): + """Unittests for iter_chunks""" + def test_bad_agg_size(self): + rows = [1,2,3,4] + self.assertRaises(ValueError, iter_chunks, rows, 0) + self.assertRaises(ValueError, iter_chunks, rows, -1) + + try: + for i in iter_chunks(rows, 0): + pass + except ValueError: + pass + else: + self.fail() + + try: + result = list(iter_chunks(rows, 0)) + except ValueError: + pass + else: + self.fail() + def test_empty(self): + rows = [] + result = list(iter_chunks(rows)) + self.assertEqual(result, []) + def test_small(self): + rows = [[1]] + result = list(iter_chunks(rows, 2)) + self.assertEqual(result, [[[1]]]) + def test_size(self): + rows = [[1],[2]] + result = list(iter_chunks(rows, 2)) + self.assertEqual(result, [[[1],[2]]]) + def test_multi_agg(self): + rows = [[1],[2],[3],[4],[5]] + result = list(iter_chunks(rows, 2)) + self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]]) + +if __name__ == "__main__": + unittest.main() |