[PyObjC-svn] r2473 - in trunk/pyobjc/pyobjc-core: . Lib/objc PyObjCTest

[email protected] Sun, 09 May 2010 06:04:35 -0500
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Sun May  9 06:04:35 2010
New Revision: 2473

Log:
Add more tests for the set interface, and fix
the issues found by those tests


Modified:
   trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
   trunk/pyobjc/pyobjc-core/NEWS.txt
   trunk/pyobjc/pyobjc-core/PyObjCTest/test_set_interface.py

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py	Sun May  9 06:04:35 2010
@@ -1136,7 +1136,8 @@
     return True
 
 def nsset_union(self, *other):
-    result = self.mutableCopy()
+    result = NSMutableSet()
+    result.unionSet_(self)
     for val in other:
         if isinstance(val, Set):
             result.unionSet_(val)
@@ -1168,14 +1169,14 @@
     return result
 
 def nsset_symmetric_difference(self, other):
-    result = set()
+    result = NSMutableSet()
     for item in self:
         if item not in other:
             result.add(item)
     for item in other:
         if item not in self:
             result.add(item)
-    return NSMutableSet(result)
+    return result
     
 
 def nsset__contains__(self, value):
@@ -1232,7 +1233,16 @@
     return nsset_symmetric_difference(other, self)
 
 def nsset_issubset(self, other):
-    return self.isSubsetOfSet_(other)
+    if isinstance(other, Set):
+        return self.isSubsetOfSet_(other)
+
+    else:
+        return self.isSubsetOfSet_(set(other))
+
+def nsset__le__(self, other):
+    if not isinstance(other, Set):
+        raise TypeError()
+    return nsset_issubset(self, other)
 
 def nsset__eq__(self, other):
     if not isinstance(other, Set):
@@ -1247,16 +1257,29 @@
     return not self.isEqualToSet_(other)
 
 def nsset__lt__(self, other):
+    if not isinstance(other, Set):
+        raise TypeError()
+
     return (self <= other) and (self != other)
 
 def nsset_issuperset(self, other):
+    if not isinstance(other, Set):
+        other = set(other)
+
     for item in other:
         if item not in self:
             return False
 
     return True
 
+def nsset__ge__(self, other):
+    if not isinstance(other, Set):
+        raise TypeError()
+    return nsset_issuperset(self, other)
+
 def nsset__gt__(self, other):
+    if not isinstance(other, Set):
+        raise TypeError()
     return (self >= other) and (self != other)
 
 if sys.version_info[0] == 2:
@@ -1271,10 +1294,91 @@
         except TypeError:
             return cmp(id(self), id(other))
 
+def nsset__length_hint__(self):
+    return len(self)
+
+def nsset_update(self, *others):
+    for other in others:
+        if isinstance(other, Set):
+            self.unionSet_(other)
+        else:
+            self.unionSet_(set(other))
+
+def nsset_intersection_update(self, *others):
+    for other in others:
+        if isinstance(other, Set):
+            self.intersectSet_(other)
+        else:
+            self.intersectSet_(set(other))
+
+def nsset_difference_update(self, *others):
+    for other in others:
+        if isinstance(other, Set):
+            self.minusSet_(other)
+        else:
+            self.minusSet_(set(other))
+
+def nsset_symmetric_difference_update(self, other):
+    toadd = set()
+    toremove = set()
+
+    if isinstance(other, Set):
+        totest = other
+    else:
+        totest = set(other)
+
+    for value in self:
+        if value in totest:
+            toremove.add(value)
+    for value in other:
+        if value not in self:
+            toadd.add(value)
+
+    self.minusSet_(toremove)
+    self.unionSet_(toadd)
+
+def nsset_pop(self):
+    if len(self) == 0:
+        raise KeyError()
+
+    v = self.anyObject()
+    self.removeObject_(v)
+    return v
+
+def nsset_remove(self, value):
+    hash(value)
+    if value not in self:
+        raise KeyError(value)
+    self.removeObject_(value)
+
+def nsset_discard(self, value):
+    hash(value)
+    self.removeObject_(value)
+
+def nsset_add(self, value):
+    hash(value)
+    self.addObject_(value)
+
+class nsset__iter__ (object):
+    def __init__(self, value):
+        self._size = len(value)
+        self._enum = value.objectEnumerator()
+
+    def __length_hint__(self):
+        return self._size
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        self._size -= 1
+        return container_unwrap(self._enum.nextObject(), StopIteration)
+
 
 CLASS_METHODS['NSSet'] = (
+    ('__iter__', lambda self: nsset__iter__(self)),
+    ('__length_hint__', nsset__length_hint__),
     ('__contains__',  nsset__contains__),
-    ('add',  lambda self, value: self.addObject_(value)),
     ('isdisjoint',  nsset_isdisjoint),
     ('union',  nsset_union),
     ('intersection',  nsset_intersection),
@@ -1283,10 +1387,10 @@
     ('issubset', nsset_issubset),
     ('__eq__', nsset__eq__),
     ('__ne__', nsset__ne__),
-    ('__le__', nsset_issubset),
+    ('__le__', nsset__le__),
     ('__lt__', nsset__lt__),
     ('issuperset', nsset_issuperset),
-    ('__ge__', nsset_issuperset),
+    ('__ge__', nsset__ge__),
     ('__gt__', nsset__gt__),
     ('__or__', nsset__or__),
     ('__ror__', nsset__ror__),
@@ -1302,6 +1406,18 @@
         ('__cmp__', 'nsset__cmp__'),
     )
 
+CLASS_METHODS['NSMutableSet'] = (
+    ('add',  nsset_add), 
+    ('remove',  nsset_remove),
+    ('discard',  nsset_discard),
+    ('update', nsset_update),
+    ('intersection_update', nsset_intersection_update),
+    ('difference_update', nsset_difference_update),
+    ('symmetric_difference_update', nsset_symmetric_difference_update),
+    ('clear', lambda self: self.removeAllObjects()),
+    ('pop', nsset_pop),
+)
+
 def nsset_new(cls, sequence=None):
     if not sequence:
         return NSSet.set()
@@ -1314,13 +1430,17 @@
 
 def nsmutableset_new(cls, sequence=None):
     if not sequence:
-        return NSMutableSet.set()
+        value = NSMutableSet.set()
 
-    if isinstance(sequence, (NSSet, set, frozenset)):
-        return NSMutableSet.set().setByAddingObjectsFromSet_(sequence)
+    elif isinstance(sequence, (NSSet, set, frozenset)):
+        value = NSMutableSet.set()
+        value.unionSet_(sequence)
 
     else:
-        return NSMutableSet.set().setByAddingObjectsFromSet_(set(sequence))
+        value = NSMutableSet.set()
+        value.unionSet_(set(sequence))
+
+    return value
 
 NSSet.__new__ = nsset_new
 NSMutableSet.__new__ = nsmutableset_new

Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt	(original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt	Sun May  9 06:04:35 2010
@@ -38,8 +38,25 @@
 
   * Instances of ``NSSet`` cannot be pickled
 
-  FIXME: This is currently tested using ``TestJointOps`` from the stdlib 
-  testset, add the other set related tests as well.
+  * In-place operators are not implemented, which means that ``aSet |= value``
+    will assign a new object to ``aSet`` (as if you wrote ``aSet = aSet | value``.
+
+    This is needed because the bridge cannot know if if ``aSet`` is mutable,
+    let alone if ``aSet`` is a value that you are allowed to mutate by API
+    contracts.
+
+  * It is not possible to subclass ``NSSet`` and ``NSMutableSet`` in the same
+    way as Python's ``set`` and ``frozenset`` classes because the Cocoa
+    classes are class clusters (which means that all instances of ``NSSet``
+    are actually instances of, non-necessarily public, subclasses.
+
+  * Sadly enough ``set([1,2,3]) == NSSet([1, 2, 3])`` evaluates to False,
+    even though the values are equavalent. Reversing the order of
+    the test (``NSSet([1, 2, 3]) == set([1,2,3])``) results in the 
+    expected result. 
+
+    This is caused by the way equality tests for sets are implemented in
+    CPython and is not something that can be fixed in PyObjC.
 
 - BUGFIX: accessing methods through ``anObject.pyobjc_instancMethods`` is
   now safer, before this release this could cause unlimited recursion

Modified: trunk/pyobjc/pyobjc-core/PyObjCTest/test_set_interface.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/PyObjCTest/test_set_interface.py	(original)
+++ trunk/pyobjc/pyobjc-core/PyObjCTest/test_set_interface.py	Sun May  9 06:04:35 2010
@@ -6,17 +6,20 @@
 from PyObjCTools.TestSupport import *
 
 import objc
+import operator
 NSSet = objc.lookUpClass('NSSet')
 NSMutableSet = objc.lookUpClass('NSMutableSet')
 
 import test.test_set
 from test.test_set import PassThru, check_pass_thru
+test.test_set.empty_set = NSMutableSet()
 
 
 
-class TestMutableSet (test.test_set.TestJointOps, TestCase):
-    thetype = NSMutableSet
-    basetype = NSMutableSet
+
+class TestSet (test.test_set.TestJointOps, TestCase):
+    thetype = NSSet
+    basetype = NSSet
 
     def test_cyclical_repr(self): pass
     def test_pickling(self): pass
@@ -105,10 +108,150 @@
             self.assertNotEqual(id(s), id(z))
 
 
+    def test_copy(self):
+        dup = self.s.copy()
+        self.assertEqual(id(self.s), id(dup))
+
+class TestMutableSet (TestSet, test.test_set.TestSet):
+    thetype = NSMutableSet
+    basetype = NSMutableSet
+
+    def test_copy(self):
+        test.test_set.TestSet.test_copy(self)
+
+    # Tests from 'TestSet'
+    def test_init(self): pass
+    def test_hash(self): pass
+    def test_weakref(self): pass
+
+class TestBasicOpsEmpty (test.test_set.TestBasicOps):
+    def setUp(self):
+        self.case   = "empty set"
+        self.values = []
+        self.set    = NSMutableSet(self.values)
+        self.dup    = NSMutableSet(self.values)
+        self.length = 0
+        self.repr   = "{(\n)}"
+
+    def test_pickling(self): pass
+
+class TestBasicOpsSingleton (test.test_set.TestBasicOps):
+    def setUp(self):
+        self.case   = "unit set (number)"
+        self.values = [3]
+        self.set    = NSMutableSet(self.values)
+        self.dup    = NSMutableSet(self.values)
+        self.length = 1
+        self.repr   = "{(\n    3\n)}"
+        test.test_set.set = NSMutableSet
+
+    def tearDown(self):
+        del test.test_set.set
+
+    def test_pickling(self): pass
+
+class TestBasicOpsTuple (test.test_set.TestBasicOps):
+    def setUp(self):
+        self.case   = "unit set (tuple)"
+        self.values = [(0, "zero")]
+        self.set    = NSMutableSet(self.values)
+        self.dup    = NSMutableSet(self.values)
+        self.length = 1
+        self.repr   = "{(\n        (\n        0,\n        zero\n    )\n)}"
+        test.test_set.set = NSMutableSet
+
+    def tearDown(self):
+        del test.test_set.set
+
+    def test_pickling(self): pass
+
+class TestBasicOpsTriple (test.test_set.TestBasicOps):
+    def setUp(self):
+        self.case   = "triple set"
+        self.values = [0, "zero", operator.add]
+        self.set    = NSMutableSet(self.values)
+        self.dup    = NSMutableSet(self.values)
+        self.length = 3
+        self.repr   = None
+
+        test.test_set.set = NSMutableSet
+
+    def tearDown(self):
+        del test.test_set.set
+
+
+    def test_pickling(self): pass
+
+class TestBinaryOps (test.test_set.TestBinaryOps):
+    def setUp(self):
+        self.set = NSMutableSet((2, 4, 6))
+
+class TestUpdateOps (test.test_set.TestUpdateOps):
+    def setUp(self):
+        self.set = NSMutableSet((2, 4, 6))
+
+class TestMutate (test.test_set.TestMutate):
+    def setUp(self):
+        self.values = ["a", "b", "c"]
+        self.set = NSMutableSet(self.values)
+
+        test.test_set.set = NSMutableSet
+
+    def tearDown(self):
+        del test.test_set.set
+
+class TestSubsetEqualEmpty (test.test_set.TestSubsetEqualEmpty):
+    left = NSMutableSet()
+    right = NSMutableSet()
+
+
+class TestSubsetEqualNonEmpty (test.test_set.TestSubsetEqualNonEmpty):
+    left  = NSMutableSet([1, 2])
+    right = NSMutableSet([1, 2])
+
+    
+class TestSubsetPartial (test.test_set.TestSubsetPartial):
+    left  = NSMutableSet([1])
+    right = NSMutableSet([1, 2])
+
+class TestOnlySetsNumeric (test.test_set.TestOnlySetsNumeric):
+    def setUp(self):
+        self.set   = NSMutableSet((1, 2, 3))
+        self.other = 19
+        self.otherIsIterable = False
+
+class TestOnlySetsOperator (test.test_set.TestOnlySetsOperator):
+    def setUp(self):
+        self.set   = NSMutableSet((1, 2, 3))
+        self.other = operator.add
+        self.otherIsIterable = False
+
+
+class TestOnlySetsTuple (test.test_set.TestOnlySetsTuple):
+    def setUp(self):
+        self.set   = NSMutableSet((1, 2, 3))
+        self.other = (2, 4, 6)
+        self.otherIsIterable = True
+
+class TestOnlySetsString (test.test_set.TestOnlySetsString):
+    def setUp(self):
+        def gen():
+            for i in xrange(0, 10, 2):
+                yield i
+        self.set   = NSMutableSet((1, 2, 3))
+        self.other = gen()
+        self.otherIsIterable = True
+
+class TestIdentities (test.test_set.TestIdentities):
+    def setUp(self):
+        self.a = NSMutableSet('abracadabra')
+        self.b = NSMutableSet('alacazam')
+
+
+# TestVariousIteratorArgs
+# TestGraphs
+
 
-class TestSet (TestMutableSet):
-    thetype = NSSet
-    basetype = NSSet
 
 
 

------------------------------------------------------------------------------