[PATCH] Add missing set methods to tagsets

Floris Bruynooghe flub at devork.be
Sun Jun 14 11:33:55 PDT 2020


Even though we use collections.abc.Set which implements all these
methods under their operator names, the actual named variations of
these methods are shockingly missing.  So let's add them manually.
---
 bindings/python-cffi/notmuch2/_tags.py  | 21 +++++++++
 bindings/python-cffi/tests/test_tags.py | 62 +++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/bindings/python-cffi/notmuch2/_tags.py b/bindings/python-cffi/notmuch2/_tags.py
index 212852a8..3b14c981 100644
--- a/bindings/python-cffi/notmuch2/_tags.py
+++ b/bindings/python-cffi/notmuch2/_tags.py
@@ -110,6 +110,27 @@ class ImmutableTagSet(base.NotmuchObject, collections.abc.Set):
     def __eq__(self, other):
         return tuple(sorted(self.iter())) == tuple(sorted(other.iter()))
 
+    def issubset(self, other):
+        return self <= other
+
+    def issuperset(self, other):
+        return self >= other
+
+    def union(self, other):
+        return self | other
+
+    def intersection(self, other):
+        return self & other
+
+    def difference(self, other):
+        return self - other
+
+    def symmetric_difference(self, other):
+        return self ^ other
+
+    def copy(self):
+        return set(self)
+
     def __hash__(self):
         return hash(tuple(self.iter()))
 
diff --git a/bindings/python-cffi/tests/test_tags.py b/bindings/python-cffi/tests/test_tags.py
index f12fa1e6..faf3947b 100644
--- a/bindings/python-cffi/tests/test_tags.py
+++ b/bindings/python-cffi/tests/test_tags.py
@@ -50,6 +50,22 @@ class TestImmutable:
         assert 'unread' in tagset
         assert 'foo' not in tagset
 
+    def test_isdisjoint(self, tagset):
+        assert tagset.isdisjoint(set(['spam', 'ham']))
+        assert not tagset.isdisjoint(set(['inbox']))
+
+    def test_issubset(self, tagset):
+        assert {'inbox'} <= tagset
+        assert {'inbox'}.issubset(tagset)
+        assert tagset <= {'inbox', 'unread', 'spam'}
+        assert tagset.issubset({'inbox', 'unread', 'spam'})
+
+    def test_issuperset(self, tagset):
+        assert {'inbox', 'unread', 'spam'} >= tagset
+        assert {'inbox', 'unread', 'spam'}.issuperset(tagset)
+        assert tagset >= {'inbox'}
+        assert tagset.issuperset({'inbox'})
+
     def test_iter(self, tagset):
         expected = sorted(['unread', 'inbox'])
         found = []
@@ -78,18 +94,30 @@ class TestImmutable:
         assert isinstance(common, set)
         assert isinstance(common, collections.abc.Set)
         assert common == {'unread'}
+        common = tagset.intersection({'unread'})
+        assert isinstance(common, set)
+        assert isinstance(common, collections.abc.Set)
+        assert common == {'unread'}
 
     def test_or(self, tagset):
         res = tagset | {'foo'}
         assert isinstance(res, set)
         assert isinstance(res, collections.abc.Set)
         assert res == {'unread', 'inbox', 'foo'}
+        res = tagset.union({'foo'})
+        assert isinstance(res, set)
+        assert isinstance(res, collections.abc.Set)
+        assert res == {'unread', 'inbox', 'foo'}
 
     def test_sub(self, tagset):
         res = tagset - {'unread'}
         assert isinstance(res, set)
         assert isinstance(res, collections.abc.Set)
         assert res == {'inbox'}
+        res = tagset.difference({'unread'})
+        assert isinstance(res, set)
+        assert isinstance(res, collections.abc.Set)
+        assert res == {'inbox'}
 
     def test_rsub(self, tagset):
         res = {'foo', 'unread'} - tagset
@@ -102,6 +130,10 @@ class TestImmutable:
         assert isinstance(res, set)
         assert isinstance(res, collections.abc.Set)
         assert res == {'inbox', 'foo'}
+        res = tagset.symmetric_difference({'unread', 'foo'})
+        assert isinstance(res, set)
+        assert isinstance(res, collections.abc.Set)
+        assert res == {'inbox', 'foo'}
 
     def test_rxor(self, tagset):
         res = {'unread', 'foo'} ^ tagset
@@ -109,6 +141,12 @@ class TestImmutable:
         assert isinstance(res, collections.abc.Set)
         assert res == {'inbox', 'foo'}
 
+    def test_copy(self, tagset):
+        res = tagset.copy()
+        assert isinstance(res, set)
+        assert isinstance(res, collections.abc.Set)
+        assert res == {'inbox', 'unread'}
+
 
 class TestMutableTagset:
 
@@ -175,3 +213,27 @@ class TestMutableTagset:
             msg.tags.to_maildir_flags()
             flags = msg.path.name.split(',')[-1]
             assert 'F' not in flags
+
+    def test_isdisjoint(self, tagset):
+        assert tagset.isdisjoint(set(['spam', 'ham']))
+        assert not tagset.isdisjoint(set(['inbox']))
+
+    def test_issubset(self, tagset):
+        assert {'inbox'} <= tagset
+        assert {'inbox'}.issubset(tagset)
+        assert not {'spam'} <= tagset
+        assert not {'spam'}.issubset(tagset)
+        assert tagset <= {'inbox', 'unread', 'spam'}
+        assert tagset.issubset({'inbox', 'unread', 'spam'})
+        assert not {'inbox', 'unread', 'spam'} <= tagset
+        assert not {'inbox', 'unread', 'spam'}.issubset(tagset)
+
+    def test_issuperset(self, tagset):
+        assert {'inbox', 'unread', 'spam'} >= tagset
+        assert {'inbox', 'unread', 'spam'}.issuperset(tagset)
+        assert tagset >= {'inbox'}
+        assert tagset.issuperset({'inbox'})
+
+    def test_union(self, tagset):
+        assert {'spam'}.union(tagset) == {'inbox', 'unread', 'spam'}
+        assert tagset.union({'spam'}) == {'inbox', 'unread', 'spam'}
-- 
2.27.0



More information about the notmuch mailing list