Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dd5e53a

Browse files
committed
Issue 8743: Improve interoperability between sets and the collections.Set abstract base class.
1 parent e8e2df3 commit dd5e53a

3 files changed

Lines changed: 180 additions & 6 deletions

File tree

Lib/_collections_abc.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,17 @@ def __lt__(self, other):
207207
def __gt__(self, other):
208208
if not isinstance(other, Set):
209209
return NotImplemented
210-
return other.__lt__(self)
210+
return len(self) > len(other) and self.__ge__(other)
211211

212212
def __ge__(self, other):
213213
if not isinstance(other, Set):
214214
return NotImplemented
215-
return other.__le__(self)
215+
if len(self) < len(other):
216+
return False
217+
for elem in other:
218+
if elem not in self:
219+
return False
220+
return True
216221

217222
def __eq__(self, other):
218223
if not isinstance(other, Set):
@@ -236,6 +241,8 @@ def __and__(self, other):
236241
return NotImplemented
237242
return self._from_iterable(value for value in other if value in self)
238243

244+
__rand__ = __and__
245+
239246
def isdisjoint(self, other):
240247
'Return True if two sets have a null intersection.'
241248
for value in other:
@@ -249,6 +256,8 @@ def __or__(self, other):
249256
chain = (e for s in (self, other) for e in s)
250257
return self._from_iterable(chain)
251258

259+
__ror__ = __or__
260+
252261
def __sub__(self, other):
253262
if not isinstance(other, Set):
254263
if not isinstance(other, Iterable):
@@ -257,13 +266,23 @@ def __sub__(self, other):
257266
return self._from_iterable(value for value in self
258267
if value not in other)
259268

269+
def __rsub__(self, other):
270+
if not isinstance(other, Set):
271+
if not isinstance(other, Iterable):
272+
return NotImplemented
273+
other = self._from_iterable(other)
274+
return self._from_iterable(value for value in other
275+
if value not in self)
276+
260277
def __xor__(self, other):
261278
if not isinstance(other, Set):
262279
if not isinstance(other, Iterable):
263280
return NotImplemented
264281
other = self._from_iterable(other)
265282
return (self - other) | (other - self)
266283

284+
__rxor__ = __xor__
285+
267286
def _hash(self):
268287
"""Compute the hash value of a set.
269288

Lib/test/test_collections.py

Lines changed: 156 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,14 +720,166 @@ def __lt__(self, x):
720720

721721
cs = MyComparableSet()
722722
ncs = MyNonComparableSet()
723+
self.assertFalse(ncs < cs)
724+
self.assertTrue(ncs <= cs)
725+
self.assertFalse(ncs > cs)
726+
self.assertTrue(ncs >= cs)
727+
728+
def assertSameSet(self, s1, s2):
729+
# coerce both to a real set then check equality
730+
self.assertSetEqual(set(s1), set(s2))
731+
732+
def test_Set_interoperability_with_real_sets(self):
733+
# Issue: 8743
734+
class ListSet(Set):
735+
def __init__(self, elements=()):
736+
self.data = []
737+
for elem in elements:
738+
if elem not in self.data:
739+
self.data.append(elem)
740+
def __contains__(self, elem):
741+
return elem in self.data
742+
def __iter__(self):
743+
return iter(self.data)
744+
def __len__(self):
745+
return len(self.data)
746+
def __repr__(self):
747+
return 'Set({!r})'.format(self.data)
748+
749+
r1 = set('abc')
750+
r2 = set('bcd')
751+
r3 = set('abcde')
752+
f1 = ListSet('abc')
753+
f2 = ListSet('bcd')
754+
f3 = ListSet('abcde')
755+
l1 = list('abccba')
756+
l2 = list('bcddcb')
757+
l3 = list('abcdeedcba')
758+
759+
target = r1 & r2
760+
self.assertSameSet(f1 & f2, target)
761+
self.assertSameSet(f1 & r2, target)
762+
self.assertSameSet(r2 & f1, target)
763+
self.assertSameSet(f1 & l2, target)
764+
765+
target = r1 | r2
766+
self.assertSameSet(f1 | f2, target)
767+
self.assertSameSet(f1 | r2, target)
768+
self.assertSameSet(r2 | f1, target)
769+
self.assertSameSet(f1 | l2, target)
770+
771+
fwd_target = r1 - r2
772+
rev_target = r2 - r1
773+
self.assertSameSet(f1 - f2, fwd_target)
774+
self.assertSameSet(f2 - f1, rev_target)
775+
self.assertSameSet(f1 - r2, fwd_target)
776+
self.assertSameSet(f2 - r1, rev_target)
777+
self.assertSameSet(r1 - f2, fwd_target)
778+
self.assertSameSet(r2 - f1, rev_target)
779+
self.assertSameSet(f1 - l2, fwd_target)
780+
self.assertSameSet(f2 - l1, rev_target)
781+
782+
target = r1 ^ r2
783+
self.assertSameSet(f1 ^ f2, target)
784+
self.assertSameSet(f1 ^ r2, target)
785+
self.assertSameSet(r2 ^ f1, target)
786+
self.assertSameSet(f1 ^ l2, target)
787+
788+
# Don't change the following to use assertLess or other
789+
# "more specific" unittest assertions. The current
790+
# assertTrue/assertFalse style makes the pattern of test
791+
# case combinations clear and allows us to know for sure
792+
# the exact operator being invoked.
793+
794+
# proper subset
795+
self.assertTrue(f1 < f3)
796+
self.assertFalse(f1 < f1)
797+
self.assertFalse(f1 < f2)
798+
self.assertTrue(r1 < f3)
799+
self.assertFalse(r1 < f1)
800+
self.assertFalse(r1 < f2)
801+
self.assertTrue(r1 < r3)
802+
self.assertFalse(r1 < r1)
803+
self.assertFalse(r1 < r2)
804+
with self.assertRaises(TypeError):
805+
f1 < l3
806+
with self.assertRaises(TypeError):
807+
f1 < l1
808+
with self.assertRaises(TypeError):
809+
f1 < l2
810+
811+
# any subset
812+
self.assertTrue(f1 <= f3)
813+
self.assertTrue(f1 <= f1)
814+
self.assertFalse(f1 <= f2)
815+
self.assertTrue(r1 <= f3)
816+
self.assertTrue(r1 <= f1)
817+
self.assertFalse(r1 <= f2)
818+
self.assertTrue(r1 <= r3)
819+
self.assertTrue(r1 <= r1)
820+
self.assertFalse(r1 <= r2)
821+
with self.assertRaises(TypeError):
822+
f1 <= l3
823+
with self.assertRaises(TypeError):
824+
f1 <= l1
825+
with self.assertRaises(TypeError):
826+
f1 <= l2
827+
828+
# proper superset
829+
self.assertTrue(f3 > f1)
830+
self.assertFalse(f1 > f1)
831+
self.assertFalse(f2 > f1)
832+
self.assertTrue(r3 > r1)
833+
self.assertFalse(f1 > r1)
834+
self.assertFalse(f2 > r1)
835+
self.assertTrue(r3 > r1)
836+
self.assertFalse(r1 > r1)
837+
self.assertFalse(r2 > r1)
838+
with self.assertRaises(TypeError):
839+
f1 > l3
840+
with self.assertRaises(TypeError):
841+
f1 > l1
723842
with self.assertRaises(TypeError):
724-
ncs < cs
843+
f1 > l2
844+
845+
# any superset
846+
self.assertTrue(f3 >= f1)
847+
self.assertTrue(f1 >= f1)
848+
self.assertFalse(f2 >= f1)
849+
self.assertTrue(r3 >= r1)
850+
self.assertTrue(f1 >= r1)
851+
self.assertFalse(f2 >= r1)
852+
self.assertTrue(r3 >= r1)
853+
self.assertTrue(r1 >= r1)
854+
self.assertFalse(r2 >= r1)
725855
with self.assertRaises(TypeError):
726-
ncs <= cs
856+
f1 >= l3
727857
with self.assertRaises(TypeError):
728-
cs > ncs
858+
f1 >=l1
729859
with self.assertRaises(TypeError):
730-
cs >= ncs
860+
f1 >= l2
861+
862+
# equality
863+
self.assertTrue(f1 == f1)
864+
self.assertTrue(r1 == f1)
865+
self.assertTrue(f1 == r1)
866+
self.assertFalse(f1 == f3)
867+
self.assertFalse(r1 == f3)
868+
self.assertFalse(f1 == r3)
869+
self.assertFalse(f1 == l3)
870+
self.assertFalse(f1 == l1)
871+
self.assertFalse(f1 == l2)
872+
873+
# inequality
874+
self.assertFalse(f1 != f1)
875+
self.assertFalse(r1 != f1)
876+
self.assertFalse(f1 != r1)
877+
self.assertTrue(f1 != f3)
878+
self.assertTrue(r1 != f3)
879+
self.assertTrue(f1 != r3)
880+
self.assertTrue(f1 != l3)
881+
self.assertTrue(f1 != l1)
882+
self.assertTrue(f1 != l2)
731883

732884
def test_Mapping(self):
733885
for sample in [dict]:

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Library
2424
- Issue #14710: pkgutil.find_loader() no longer raises an exception when a
2525
module doesn't exist.
2626

27+
- Issue #8743: Fix interoperability between set objects and the
28+
collections.Set() abstract base class.
29+
2730
- Issue #13355: random.triangular() no longer fails with a ZeroDivisionError
2831
when low equals high.
2932

0 commit comments

Comments
 (0)