[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
------------------------------------------------------------------------------