summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/lib/python/indra/util/iterators.py63
-rwxr-xr-xindra/lib/python/indra/util/iterators_test.py72
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()