From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id LCheDbBt5l6bJwAA0tVLHw (envelope-from ) for ; Sun, 14 Jun 2020 18:34:24 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2 with LMTPS id sNoCCbBt5l6jLwAAB5/wlQ (envelope-from ) for ; Sun, 14 Jun 2020 18:34:24 +0000 Received: from arlo.cworth.org (arlo.cworth.org [50.126.95.6]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 74835940414 for ; Sun, 14 Jun 2020 18:34:23 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 4E46D6DE13CD; Sun, 14 Jun 2020 11:34:17 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VktE_mFMg9d9; Sun, 14 Jun 2020 11:34:16 -0700 (PDT) Received: from arlo.cworth.org (localhost [IPv6:::1]) by arlo.cworth.org (Postfix) with ESMTP id 8C6A36DE13AE; Sun, 14 Jun 2020 11:34:09 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 8FC116DE0F4A for ; Sun, 14 Jun 2020 11:34:07 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rRXZajGrkvWt for ; Sun, 14 Jun 2020 11:34:06 -0700 (PDT) Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) by arlo.cworth.org (Postfix) with ESMTPS id 39DE56DE0F07 for ; Sun, 14 Jun 2020 11:34:06 -0700 (PDT) Received: by mail-wm1-f51.google.com with SMTP id f185so12650256wmf.3 for ; Sun, 14 Jun 2020 11:34:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=50FP8Q70mqGXFbDNzfRDQu5OhM6deWa3GpTIC0v2PeY=; b=qv8VPWbTbtX55nK6dWGlX9ZrFaxpQofiQn481PNaBOL22BGEL7hHYR5KrMJCTLMbIV vD8PKln0DWlRaoLVkMxen4iwqhVvVjEd2GXs5BRdw3ZBs5wgLnel3l9pMWbyMXHmFeY8 /Pnq+ObwEFqOIlHHsWLzUiMaXdnkanaBipomqCbMol+UwctfZqez12gqw7Rcij/8o3Mc +BnNNVN/IhiknjjL79kO3ixK3kZCIwsRZgB0ZXQfDjDGRmsHbyoIR+rTeb6C0esi/LAp J6KW3v63FkZSSjLq9VXcSonKC7ORjz95Oa60oi7qYG1UX/cEKm9pDsNS2z/cM4kvyybg 80Jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=50FP8Q70mqGXFbDNzfRDQu5OhM6deWa3GpTIC0v2PeY=; b=BoLIFyB0O0w4F8E5W0+ycmRIwADb6a5yLOJ8C6cXUs2Ct+H/KgAK5QYJavLW2CIO7b Z5ubW0WF/R/KE7cYwB5zyK3B2lDOs5yzQoaPupH4hPkcPpfTOYBE/tLlqM7839UnSEuT fK5OyHJk9NuA7jwXdZzEDoFUrOtaYHbc95gvn01/hs/01suNg4Pta1GEZDbptlfRLjnX aFExnwEPesjsj0NfFwS10xM4tdJvmvykIDg+CnUxaW/hBTbvOBkj2cpTHp0hT0jUsCAV Q4b9iwUwbIEQuFQKBI8hdxz6pslU9w73AGoFeK49cmxvnut+eJ8X7r5cbF8gk9JDkfhf nKtg== X-Gm-Message-State: AOAM5315J3O24Y3MaQnV1mmo0vDdxKExqtAXkSRy3gtyCsR5b8kJBIgJ 1ihWnVIuo1luvNQA4q2KTVMbWNrf X-Google-Smtp-Source: ABdhPJwt1XqvqGkOF0U+fu9h+QuGyn6IXosjJ6AAqAxQcMV8ZsppXLtO+bvEaM099rG2Eofa1G9VPQ== X-Received: by 2002:a1c:2d54:: with SMTP id t81mr9989571wmt.154.1592159644500; Sun, 14 Jun 2020 11:34:04 -0700 (PDT) Received: from powell.devork.be (2a02-8388-8480-1180-4c18-fc69-8d8c-22b5.cable.dynamic.v6.surfer.at. [2a02:8388:8480:1180:4c18:fc69:8d8c:22b5]) by smtp.gmail.com with ESMTPSA id y14sm18773337wma.25.2020.06.14.11.34.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Jun 2020 11:34:04 -0700 (PDT) Received: (nullmailer pid 72836 invoked by uid 1000); Sun, 14 Jun 2020 18:34:00 -0000 From: Floris Bruynooghe To: notmuch@notmuchmail.org Subject: [PATCH] Add missing set methods to tagsets Date: Sun, 14 Jun 2020 20:33:55 +0200 Message-Id: <20200614183355.72770-2-flub@devork.be> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200614183355.72770-1-flub@devork.be> References: <20200614183355.72770-1-flub@devork.be> MIME-Version: 1.0 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: notmuch-bounces@notmuchmail.org Sender: "notmuch" X-Scanner: scn0 Authentication-Results: aspmx1.migadu.com; dkim=fail (body hash did not verify) header.d=gmail.com header.s=20161025 header.b=qv8VPWbT; dmarc=none; spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 50.126.95.6 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Spam-Score: 0.99 X-TUID: sejn2CoKCtGT 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