From 265cc332f1de0bd43a7cfe79d9edeee0859fbc47 Mon Sep 17 00:00:00 2001 From: Stuart Bishop Date: Fri, 3 Jan 2014 09:21:28 +0000 Subject: LazySet tests and fixes --- src/pytz/lazy.py | 40 +++++++------ src/pytz/tests/test_lazy.py | 141 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 158 insertions(+), 23 deletions(-) diff --git a/src/pytz/lazy.py b/src/pytz/lazy.py index 2d59335..f7fc597 100644 --- a/src/pytz/lazy.py +++ b/src/pytz/lazy.py @@ -116,6 +116,22 @@ LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)] class LazySet(set): """Set populated on first use.""" + + _props = ( + '__str__', '__repr__', '__unicode__', + '__hash__', '__sizeof__', '__cmp__', + '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', + '__contains__', '__len__', '__nonzero__', + '__getitem__', '__setitem__', '__delitem__', '__iter__', + '__sub__', '__and__', '__xor__', '__or__', + '__rsub__', '__rand__', '__rxor__', '__ror__', + '__isub__', '__iand__', '__ixor__', '__ior__', + 'add', 'clear', 'copy', 'difference', 'difference_update', + 'discard', 'intersection', 'intersection_update', 'isdisjoint', + 'issubset', 'issuperset', 'pop', 'remove', + 'symmetric_difference', 'symmetric_difference_update', + 'union', 'update') + def __new__(cls, fill_iter=None): if fill_iter is None: @@ -124,21 +140,6 @@ class LazySet(set): class LazySet(set): pass - _props = ( - '__str__', '__repr__', '__unicode__', - '__hash__', '__sizeof__', '__cmp__', - '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', - '__contains__', '__len__', '__nonzero__', - '__getitem__', '__setitem__', '__delitem__', '__iter__', - '__sub__', '__and__', '__xor__', '__or__', - '__rsub__', '__rand__', '__rxor__', '__ror__', - '__isub__', '__iand__', '__ixor__', '__ior__', - 'add', 'clear', 'copy', 'difference', 'difference_update', - 'discard', 'intersection', 'intersection_update', 'isdisjoint', - 'issubset', 'issuperset', 'pop', 'remove', - 'symmetric_difference', 'symmetric_difference_update', - 'union', 'update') - fill_iter = [fill_iter] def lazy(name): @@ -148,15 +149,20 @@ class LazySet(set): if len(fill_iter) > 0: for i in fill_iter.pop(): set.add(self, i) - for method_name in _props: + for method_name in cls._props: delattr(LazySet, method_name) finally: _fill_lock.release() return getattr(set, name)(self, *args, **kw) return _lazy - for name in _props: + for name in cls._props: setattr(LazySet, name, lazy(name)) new_set = LazySet() return new_set + +# Not all versions of Python declare the same magic methods. +# Filter out properties that don't exist in this version of Python +# from the list. +LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)] diff --git a/src/pytz/tests/test_lazy.py b/src/pytz/tests/test_lazy.py index 2641bd9..3a4afa6 100644 --- a/src/pytz/tests/test_lazy.py +++ b/src/pytz/tests/test_lazy.py @@ -11,7 +11,7 @@ if __name__ == '__main__': sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir))) -import pytz.lazy as lazy +from pytz.lazy import LazyList, LazySet class LazyListTestCase(unittest.TestCase): @@ -22,10 +22,10 @@ class LazyListTestCase(unittest.TestCase): self.lesser = [2, 1, 0] self.greater = [4, 3, 2] - self.lazy = lazy.LazyList(iter(list(self.base))) + self.lazy = LazyList(iter(list(self.base))) def test_unary_ops(self): - unary_ops = [str, repr, len] + unary_ops = [str, repr, len, bool, not_] try: unary_ops.append(unicode) except NameError: @@ -36,7 +36,7 @@ class LazyListTestCase(unittest.TestCase): op(self.lazy), op(self.base), str(op)) - def test_binary_list_ops(self): + def test_binary_ops(self): binary_ops = [eq, ge, gt, le, lt, ne, add, concat] try: binary_ops.append(cmp) @@ -63,10 +63,15 @@ class LazyListTestCase(unittest.TestCase): self.assertTrue(2 in self.lazy) self.assertFalse(42 in self.lazy) + def test_iadd(self): + self.lazy += [1] + self.base += [1] + self.assertEqual(self.lazy, self.base) + def test_bool(self): self.assertTrue(bool(self.lazy)) - self.assertFalse(bool(lazy.LazyList())) - self.assertFalse(bool(lazy.LazyList(iter([])))) + self.assertFalse(bool(LazyList())) + self.assertFalse(bool(LazyList(iter([])))) def test_hash(self): self.assertRaises(TypeError, hash, self.lazy) @@ -179,6 +184,130 @@ class LazyListTestCase(unittest.TestCase): self.assertEqual(self.lazy, self.base) +class LazySetTestCase(unittest.TestCase): + initial_data = set([3,2,1]) + + def setUp(self): + self.base = set([3, 2, 1]) + self.lazy = LazySet(iter(set(self.base))) + + def test_unary_ops(self): + # These ops just need to work. + unary_ops = [str, repr] + try: + unary_ops.append(unicode) + except NameError: + pass # unicode no longer exists in Python 3. + + for op in unary_ops: + op(self.lazy) # These ops just need to work. + + # These ops should return identical values as a real set. + unary_ops = [len, bool, not_] + + for op in unary_ops: + self.assertEqual( + op(self.lazy), + op(self.base), '%s(lazy) == %r' % (op, op(self.lazy))) + + def test_binary_ops(self): + binary_ops = [eq, ge, gt, le, lt, ne, sub, and_, or_, xor] + try: + binary_ops.append(cmp) + except NameError: + pass # cmp no longer exists in Python 3. + + for op in binary_ops: + self.assertEqual( + op(self.lazy, self.lazy), + op(self.base, self.base), str(op)) + self.assertEqual( + op(self.lazy, self.base), + op(self.base, self.base), str(op)) + self.assertEqual( + op(self.base, self.lazy), + op(self.base, self.base), str(op)) + + # Contains + self.assertTrue(2 in self.lazy) + self.assertFalse(42 in self.lazy) + + def test_iops(self): + try: + iops = [isub, iand, ior, ixor] + except NameError: + return # Don't exist in older Python versions. + for op in iops: + # Mutating operators, so make fresh copies. + lazy = LazySet(self.base) + base = self.base.copy() + op(lazy, set([1])) + op(base, set([1])) + self.assertEqual(lazy, base, str(op)) + + def test_bool(self): + self.assertTrue(bool(self.lazy)) + self.assertFalse(bool(LazySet())) + self.assertFalse(bool(LazySet(iter([])))) + + def test_hash(self): + self.assertRaises(TypeError, hash, self.lazy) + + def test_isinstance(self): + self.assertTrue(isinstance(self.lazy, set)) + + def test_callable(self): + try: + callable + except NameError: + return # No longer exists with Python 3. + self.assertFalse(callable(self.lazy)) + + def test_add(self): + self.base.add('extra') + self.lazy.add('extra') + self.assertEqual(self.lazy, self.base) + + def test_copy(self): + self.assertEqual(self.lazy.copy(), self.base) + + def test_method_ops(self): + ops = [ + 'difference', 'intersection', 'isdisjoint', + 'issubset', 'issuperset', 'symmetric_difference', 'union', + 'difference_update', 'intersection_update', + 'symmetric_difference_update', 'update'] + for op in ops: + if not hasattr(set, op): + continue # Not in this version of Python. + # Make a copy, as some of the ops are mutating. + lazy = LazySet(set(self.base)) + base = set(self.base) + self.assertEqual( + getattr(self.lazy, op)(set([1])), + getattr(self.base, op)(set([1])), op) + self.assertEqual(self.lazy, self.base, op) + + def test_discard(self): + self.base.discard(1) + self.assertNotEqual(self.lazy, self.base) + self.lazy.discard(1) + self.assertEqual(self.lazy, self.base) + + def test_pop(self): + self.assertEqual(self.lazy.pop(), self.base.pop()) + self.assertEqual(self.lazy, self.base) + + def test_remove(self): + self.base.remove(2) + self.lazy.remove(2) + self.assertEqual(self.lazy, self.base) + + def test_clear(self): + self.lazy.clear() + self.assertEqual(self.lazy, set()) + + if __name__ == '__main__': warnings.simplefilter("error") # Warnings should be fatal in tests. unittest.main() -- cgit v1.2.1