unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH] python: add bindings for notmuch_message_get_property
@ 2017-11-15 22:29 Ruben Pollan
  2017-11-15 22:48 ` meskio
  2017-11-17  9:03 ` Daniel Kahn Gillmor
  0 siblings, 2 replies; 21+ messages in thread
From: Ruben Pollan @ 2017-11-15 22:29 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property.
---
 bindings/python/notmuch/message.py | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index d5b98e4f..11263736 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -113,6 +113,11 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +438,26 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p("")
+        status = Message._get_property(self._msg, prop, byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_property
  2017-11-15 22:29 [PATCH] python: add bindings for notmuch_message_get_property Ruben Pollan
@ 2017-11-15 22:48 ` meskio
  2017-11-17  9:03 ` Daniel Kahn Gillmor
  1 sibling, 0 replies; 21+ messages in thread
From: meskio @ 2017-11-15 22:48 UTC (permalink / raw)
  To: notmuch

[-- Attachment #1: Type: text/plain, Size: 705 bytes --]

Quoting Ruben Pollan (2017-11-15 23:29:54)
> Message.get_property (prop) returns a string with the value of the property.

I only implemented get_property as is the only one I need to add support for 
session keys in alot (https://github.com/meskio/alot/tree/session-key). From the 
point of view of the MUAs I don't see much interest in exporting all the other 
functions to modify properties. But I was not sure if adding them to have the 
whole set of message property functions in python.

-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAloMxCQACgkQUrj1rJei
2oYH7Q//SwjbPbLr2TA8x+8HHUDEI3x2I6mhcCqNOZeeUj1w6lKOL6ramehaXZxy
maekxvk6JDUlnwEJjKpT1ybWD7wshS5dwznO52YDlAN/AitIVWzpQkL20V4DuQxF
lazVP17XDqDu57tuLpMtFmpr8PdbmSyvlmlyexb73HYWs+hNhKd5kFz9K0SvssQ9
1nuSmHRU3JsESLyqvyHpbsMY8E5bp1SEAOT9gv5jjJa/GECZSvD9DDo3FRU1QDJu
mQihptuyyzRLgPnv/SxfXdDBFG2rcACs7QItodxUvVH8Ph4EzUoyt3qxg0tuHFmS
R7SOJXXkUs9kV4jTKan4Tkq1Liff+H2VJP+iiWnIYuWmeWfIH/NcSprtdJb4X9ce
/g/2Ji94gOrTGeMZybrm69O5C71/0bKATI6jOLWEiogIXtV+WX+edS/IpkozqbIu
moxxiHNvGF0OsjXCQtY1j4hd+mVpS/EL08w0u3R+3I+wAyBQOVz2kCWjV9NwkHKw
cNIzrKaXPamnex25CHb4j+Tdk0oj+WwC4oa7pWdmcIstDMUaP+5VuTgSMtgECMAN
0Mev4Vz7cau5PjAu4hSorkvGN2nZrY0Kj4+blgMaP0UQc/5orMurzqQ7KrKMSHqV
OtW6kjVU4pyvWbzasOM9brlVG6QlJaj08COVtVeMKVTP/xllSDc=
=c3Es
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_property
  2017-11-15 22:29 [PATCH] python: add bindings for notmuch_message_get_property Ruben Pollan
  2017-11-15 22:48 ` meskio
@ 2017-11-17  9:03 ` Daniel Kahn Gillmor
  2017-11-28 22:46   ` [PATCH] python: add bindings for notmuch_message_get_propert(y/ies) Ruben Pollan
  1 sibling, 1 reply; 21+ messages in thread
From: Daniel Kahn Gillmor @ 2017-11-17  9:03 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

On Wed 2017-11-15 23:29:54 +0100, Ruben Pollan wrote:
> Message.get_property (prop) returns a string with the value of the property.

Upon review, this is actually insufficient for making robust use of the
session-key series :(

In particular, it only returns the first value for the session key
returned.

There are (at least) two situations where a message may have more than
one session key:

 * if two copies of the message are received by different channels, and
   each channel somehow obtains a different session key.

   For example: i send the message to an encrypted mailing list like
   schleuder that unwraps and then rewraps the encrypted message -- in
   this case, the version saved to sent-mail during sending has session
   key A, and the version received back from schleuder has session key B

 * if one encrypted message contains another encrypted message.  then
   the outer message has session key A, and the inner attachment has
   session key B.

of course there are more ways this can happen, as well as combinations
of these ways :/

it mostly won't happen!  so things will look like they're looking fine,
but then you'll get a message (or two copies of a single message) and at
some point you'll try to render one part or one version, but you'll only
have the other session key available.

In the session-key series, i work around this by simply trying each
session key against an encrypted part until i find one that works. It
would be "cleaner" (more principled) to somehow associate each session
key with the part(s) of the message file(s) that it is capable of
decrypting, but that's a lot of bookkeeping -- i think it's actually
"cleaner" (less code, less computation in the standard case) to just
take the current approach.

     --dkg

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-17  9:03 ` Daniel Kahn Gillmor
@ 2017-11-28 22:46   ` Ruben Pollan
  2017-11-28 22:51     ` meskio
  2017-11-29  1:57     ` Daniel Kahn Gillmor
  0 siblings, 2 replies; 21+ messages in thread
From: Ruben Pollan @ 2017-11-28 22:46 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property and
Message.get_properties (prop, exact=False) returns a list [(key, value)]
---
 bindings/python/notmuch/globals.py |  5 +++
 bindings/python/notmuch/message.py | 78 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 71426c84..801062dc 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -75,6 +75,11 @@ class NotmuchMessageS(Structure):
 NotmuchMessageP = POINTER(NotmuchMessageS)
 
 
+class NotmuchMessagePropertiesS(Structure):
+    pass
+NotmuchMessagePropertiesP = POINTER(NotmuchMessagePropertiesS)
+
+
 class NotmuchTagsS(Structure):
     pass
 NotmuchTagsP = POINTER(NotmuchTagsS)
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index d5b98e4f..7b737943 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -29,6 +29,7 @@ from .globals import (
     NotmuchTagsP,
     NotmuchMessageP,
     NotmuchMessagesP,
+    NotmuchMessagePropertiesP,
     NotmuchFilenamesP,
 )
 from .errors import (
@@ -113,6 +114,36 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
+    """notmuch_message_get_properties"""
+    _get_properties = nmlib.notmuch_message_get_properties
+    _get_properties.argtypes = [NotmuchMessageP, c_char_p, c_int]
+    _get_properties.restype = NotmuchMessagePropertiesP
+
+    """notmuch_message_properties_valid"""
+    _properties_valid = nmlib.notmuch_message_properties_valid
+    _properties_valid.argtypes = [NotmuchMessagePropertiesP]
+    _properties_valid.restype = bool
+
+    """notmuch_message_properties_value"""
+    _properties_value = nmlib.notmuch_message_properties_value
+    _properties_value.argtypes = [NotmuchMessagePropertiesP]
+    _properties_value.restype = c_char_p
+
+    """notmuch_message_properties_key"""
+    _properties_key = nmlib.notmuch_message_properties_key
+    _properties_key.argtypes = [NotmuchMessagePropertiesP]
+    _properties_key.restype = c_char_p
+
+    """notmuch_message_properties_move_to_next"""
+    _properties_move_to_next = nmlib.notmuch_message_properties_move_to_next
+    _properties_move_to_next.argtypes = [NotmuchMessagePropertiesP]
+    _properties_move_to_next.restype = None
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +464,51 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p("")
+        status = Message._get_property(self._msg, prop, byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value
+
+    def get_properties(self, prop, exact=False):
+        """ Get the properties for *message*, returning
+        notmuch_message_properties_t object which can be used to iterate
+        over all properties.
+
+        :param prop: The name of the property to get.
+        :param exact: if True, require exact match with key. Otherwise
+                      treat as prefix.
+        :returns: [(key, value)]
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        properties_list = []
+        properties = Message._get_properties(self._msg, prop, exact)
+        while Message._properties_valid(properties):
+            key = Message._properties_key(properties)
+            value = Message._properties_value(properties)
+            properties_list.append((key, value))
+            Message._properties_move_to_next(properties)
+
+        return properties_list
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-28 22:46   ` [PATCH] python: add bindings for notmuch_message_get_propert(y/ies) Ruben Pollan
@ 2017-11-28 22:51     ` meskio
  2017-11-29  1:57     ` Daniel Kahn Gillmor
  1 sibling, 0 replies; 21+ messages in thread
From: meskio @ 2017-11-28 22:51 UTC (permalink / raw)
  To: notmuch

[-- Attachment #1: Type: text/plain, Size: 1268 bytes --]

Quoting Daniel Kahn Gillmor (2017-11-17 10:03:09)
> On Wed 2017-11-15 23:29:54 +0100, Ruben Pollan wrote:
> > Message.get_property (prop) returns a string with the value of the property.
> 
> Upon review, this is actually insufficient for making robust use of the
> session-key series :(
> 
> In particular, it only returns the first value for the session key
> returned.

See the last patch. I added the implementation of get_properties (and I use it 
in my session-key branch of alot). Hopefully this solves the problem.

> In the session-key series, i work around this by simply trying each
> session key against an encrypted part until i find one that works. It
> would be "cleaner" (more principled) to somehow associate each session
> key with the part(s) of the message file(s) that it is capable of
> decrypting, but that's a lot of bookkeeping -- i think it's actually
> "cleaner" (less code, less computation in the standard case) to just
> take the current approach.

Fair enough for me, I'm copying this approach in alot as well.

-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAlod6F0ACgkQUrj1rJei
2oYRDA/+LdqqUNCrB01gjsl0Lohw5DUxfp1Hpswi/J/yBUJY2RYbMO4wWMypKaJt
GN5ZZZp5C6opCnBdWmR7/0b8LLGNNFwhj4OkTbA1t8qJLYrMFfOSlyIfBXt1Qtmc
eJ9exca8Tp8dewixqmGG6TfHUuaKrSkKosEYJY2qsyTFVKcoecIn3VDnoQckEEN9
/qX/c7C9zer3h0odU+cAaJQDIuIOZCq3rxijtzueK1Yt5cS4BT3y9J52glUD2CLr
FnBVpO4fJiItPGnHC8msqQk1AeYcGp92a0TbAQIwiIi5EbH875M/oHZmrJb73XXn
JpU9ezH3t0ZHGObdMX1aRuJUtZS16WguiLzLebBcEemCaE30C08ow4Tykh4GJkMg
lO3dgEvK3uMQww5WO6N6godSbxoQtpvsJL85GRpX/8g5uT8q09mZ/okCtSOPu9Qc
lablQcOK0L1DvIqSLgKuMpRRzEZQ9mG9kMaEZzj3FlaK4ltxaGSZUmQrcQn4yikf
PsLAob5oVVW0YxlvhMl9miI4nFAPzmvN/uM/FaQwh78RbBmqWG1KnAcjU110pVFc
T5D2dTRLQBl+wzw/Q+ZDllUC1Fy2OlleOH9Yjyj46diVbcD3gvr22ZtqCpZ482yN
UYBPWbkYjJaSLacxrnYnTrtQZ52SxNIUMKU6OBpdbkgtyku+vC4=
=6nxo
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-28 22:46   ` [PATCH] python: add bindings for notmuch_message_get_propert(y/ies) Ruben Pollan
  2017-11-28 22:51     ` meskio
@ 2017-11-29  1:57     ` Daniel Kahn Gillmor
  2017-11-29  8:02       ` meskio
  2017-11-29 21:40       ` Floris Bruynooghe
  1 sibling, 2 replies; 21+ messages in thread
From: Daniel Kahn Gillmor @ 2017-11-29  1:57 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

[-- Attachment #1: Type: text/plain, Size: 1175 bytes --]

On Tue 2017-11-28 23:46:11 +0100, Ruben Pollan wrote:
> Message.get_property (prop) returns a string with the value of the property and
> Message.get_properties (prop, exact=False) returns a list [(key, value)]

This looks like a sensible approach to me.  I'd be curious to hear what
others think of this.

In considering the API design space here, it occurs to me that it might
be more pythonic for get_properties to return a dict like:

   { key: [ value, … ], key: [ value, … ] }

Any reason you chose one over the other?  My python-fu is shallow, so
please don't take my aesthetic guesswork as authoritative; but i'm
imagining a user wanting to grab a bunch of properties and then easily
access them by key, and the dict seems like the simple way to do that.

Also, does get_properties() work with prop=None to fetch all properties?
if so, maybe that should be the default?

To be clear, I'd be fine with a response that disagrees with these
suggestions (especially if it explains why) and then adopting this
patch; i just want to make sure they've been considered before we lock
in the API.

Thanks for working on this, Meskio!

   --dkg

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-29  1:57     ` Daniel Kahn Gillmor
@ 2017-11-29  8:02       ` meskio
  2017-11-29  8:03         ` Ruben Pollan
  2017-11-29 21:40       ` Floris Bruynooghe
  1 sibling, 1 reply; 21+ messages in thread
From: meskio @ 2017-11-29  8:02 UTC (permalink / raw)
  To: Daniel Kahn Gillmor, notmuch

[-- Attachment #1: Type: text/plain, Size: 1544 bytes --]

Quoting Daniel Kahn Gillmor (2017-11-29 02:57:24)
> On Tue 2017-11-28 23:46:11 +0100, Ruben Pollan wrote:
> > Message.get_property (prop) returns a string with the value of the property and
> > Message.get_properties (prop, exact=False) returns a list [(key, value)]
> 
> This looks like a sensible approach to me.  I'd be curious to hear what
> others think of this.
> 
> In considering the API design space here, it occurs to me that it might
> be more pythonic for get_properties to return a dict like:
> 
>    { key: [ value, … ], key: [ value, … ] }
> 
> Any reason you chose one over the other?  My python-fu is shallow, so
> please don't take my aesthetic guesswork as authoritative; but i'm
> imagining a user wanting to grab a bunch of properties and then easily
> access them by key, and the dict seems like the simple way to do that.

Yes, the dict is more pythonic. I thought about it, I went for the tuples it was 
simpler to implement (and use in my use case). But giving a second thought it 
makes more sense to do a dict.

> Also, does get_properties() work with prop=None to fetch all properties?
> if so, maybe that should be the default?

I didn't thought about that, but you are right, with prop="" you get the full 
list of properties of the message. Nice, let's put it as default value.

-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAloeaXYACgkQUrj1rJei
2oaaCg//cB1YJGzuaPDOUrs7G3ZrdQ5hm9BFgPZBK8WFd9i55MrUfvffx1q3qOqZ
3a/qi1YUl+SCOJmtGNdrem/+KnHvIDQKS336K07hukEbPDMD/OLdmB7WJy4geBwi
FAF1TIX1P1voaie+yEeqTquRk2NqoczAQ3DNyW7AIjhulBI+Ris0AdnN8yXm/MB7
lZ0/WtLOJz6l5TaLkKICMgsk6FzibxkfxvDcA/zGYu4Rl9PKOjnB+K0IwPTRxofF
5S5FIbp5BVgb5ty1/zXcsZjuzRkehnr3zjDppmPd89EFLiGfN/NXTh0KlK0X7tKG
CgG8sEkoV0AxPHRWyMrVyF0WRJrsJcbtJ3MZkJHhSOSUfN5R6y5JyR4g2/YoZE2j
qi2wFjZiLut+BsJJ8glju97SpsdXy+0C8mSixYTvlCP31REngES4rnuJnVilBIPG
Sf2A00OvVvir8DZvxYJieJOklQxjeQLO7F0NOktuBnKFrNmjb+RpapwmODHVM80s
N45mECSjJT6ar9x+MEpUIWoBt7U+HH/A0+rwA7DuPrxR01ohv1U0rgxll1ckfk/K
Kpk+ZhJGC/rFi6pvffau/VTlu9ZFiESfFhYt7NtZkCBtdNp1XoU9SAqtt8CQWI/z
o5paezmIXqBBkWJ1hU9AKLJO+ADvXAvM2FHqkppx1l1nZFygUQw=
=GAXj
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-29  8:02       ` meskio
@ 2017-11-29  8:03         ` Ruben Pollan
  2017-12-23 15:59           ` David Bremner
  0 siblings, 1 reply; 21+ messages in thread
From: Ruben Pollan @ 2017-11-29  8:03 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property and
Message.get_properties (prop, exact=False) returns a list [(key, value)]
---
 bindings/python/notmuch/globals.py |  5 +++
 bindings/python/notmuch/message.py | 81 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 71426c84..801062dc 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -75,6 +75,11 @@ class NotmuchMessageS(Structure):
 NotmuchMessageP = POINTER(NotmuchMessageS)
 
 
+class NotmuchMessagePropertiesS(Structure):
+    pass
+NotmuchMessagePropertiesP = POINTER(NotmuchMessagePropertiesS)
+
+
 class NotmuchTagsS(Structure):
     pass
 NotmuchTagsP = POINTER(NotmuchTagsS)
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index d5b98e4f..2025f979 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -29,6 +29,7 @@ from .globals import (
     NotmuchTagsP,
     NotmuchMessageP,
     NotmuchMessagesP,
+    NotmuchMessagePropertiesP,
     NotmuchFilenamesP,
 )
 from .errors import (
@@ -113,6 +114,36 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
+    """notmuch_message_get_properties"""
+    _get_properties = nmlib.notmuch_message_get_properties
+    _get_properties.argtypes = [NotmuchMessageP, c_char_p, c_int]
+    _get_properties.restype = NotmuchMessagePropertiesP
+
+    """notmuch_message_properties_valid"""
+    _properties_valid = nmlib.notmuch_message_properties_valid
+    _properties_valid.argtypes = [NotmuchMessagePropertiesP]
+    _properties_valid.restype = bool
+
+    """notmuch_message_properties_value"""
+    _properties_value = nmlib.notmuch_message_properties_value
+    _properties_value.argtypes = [NotmuchMessagePropertiesP]
+    _properties_value.restype = c_char_p
+
+    """notmuch_message_properties_key"""
+    _properties_key = nmlib.notmuch_message_properties_key
+    _properties_key.argtypes = [NotmuchMessagePropertiesP]
+    _properties_key.restype = c_char_p
+
+    """notmuch_message_properties_move_to_next"""
+    _properties_move_to_next = nmlib.notmuch_message_properties_move_to_next
+    _properties_move_to_next.argtypes = [NotmuchMessagePropertiesP]
+    _properties_move_to_next.restype = None
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +464,54 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p("")
+        status = Message._get_property(self._msg, prop, byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value
+
+    def get_properties(self, prop="", exact=False):
+        """ Get the properties for *message*, returning
+        notmuch_message_properties_t object which can be used to iterate
+        over all properties.
+
+        :param prop: The name of the property to get. Otherwise it will return
+                     the full list of properties of the message.
+        :param exact: if True, require exact match with key. Otherwise
+                      treat as prefix.
+        :returns: A dictionary with the property names and values {key: value}
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        properties_dict = {}
+        properties = Message._get_properties(self._msg, prop, exact)
+        while Message._properties_valid(properties):
+            key = Message._properties_key(properties)
+            value = Message._properties_value(properties)
+            if key not in properties_dict:
+                properties_dict[key] = []
+            properties_dict[key].append(value)
+            Message._properties_move_to_next(properties)
+
+        return properties_dict
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-29  1:57     ` Daniel Kahn Gillmor
  2017-11-29  8:02       ` meskio
@ 2017-11-29 21:40       ` Floris Bruynooghe
  2017-11-30 13:44         ` David Bremner
  1 sibling, 1 reply; 21+ messages in thread
From: Floris Bruynooghe @ 2017-11-29 21:40 UTC (permalink / raw)
  To: Daniel Kahn Gillmor, Ruben Pollan, notmuch

Daniel Kahn Gillmor <dkg@fifthhorseman.net> writes:

> On Tue 2017-11-28 23:46:11 +0100, Ruben Pollan wrote:
>> Message.get_property (prop) returns a string with the value of the property and
>> Message.get_properties (prop, exact=False) returns a list [(key, value)]
>
> This looks like a sensible approach to me.  I'd be curious to hear what
> others think of this.
>
> In considering the API design space here, it occurs to me that it might
> be more pythonic for get_properties to return a dict like:

I would probably model properties as a dictionary in notdb, making this
a collections.abc.MutableMapping implementation with a .get_all(prop)
method inspired from the stdlib email.message package.  This kind of
also implies making properties access a property rather then a method
call:

msg.properties['prop'] = 'foo'
msg.properties['prop'] = 'bar'
msg.properties['prop'] == 'foo'  # pot luck
msg.properties.get_all('prop') == {'foo', 'bar'}  # properties are unsorted are they?

This also has the binary question problem, is this returned as bytes or
as str?  Current Python bindings seem to go for .decode('utf-8',
errors='ignore') afaik which is somewhat lossy.


Cheers,
Floris

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-29 21:40       ` Floris Bruynooghe
@ 2017-11-30 13:44         ` David Bremner
  2017-11-30 14:19           ` Daniel Kahn Gillmor
  0 siblings, 1 reply; 21+ messages in thread
From: David Bremner @ 2017-11-30 13:44 UTC (permalink / raw)
  To: Floris Bruynooghe, Daniel Kahn Gillmor, Ruben Pollan, notmuch

Floris Bruynooghe <flub@devork.be> writes:

> Daniel Kahn Gillmor <dkg@fifthhorseman.net> writes:
>
> This also has the binary question problem, is this returned as bytes or
> as str?  Current Python bindings seem to go for .decode('utf-8',
> errors='ignore') afaik which is somewhat lossy.
>

IMHO there's no reason to support non-utf8 properties. We should
document this restriction now while adoption is relatively light.

d

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-30 13:44         ` David Bremner
@ 2017-11-30 14:19           ` Daniel Kahn Gillmor
  0 siblings, 0 replies; 21+ messages in thread
From: Daniel Kahn Gillmor @ 2017-11-30 14:19 UTC (permalink / raw)
  To: David Bremner, Floris Bruynooghe, Ruben Pollan, notmuch

On Thu 2017-11-30 09:44:19 -0400, David Bremner wrote:
> Floris Bruynooghe <flub@devork.be> writes:
>
>> This also has the binary question problem, is this returned as bytes or
>> as str?  Current Python bindings seem to go for .decode('utf-8',
>> errors='ignore') afaik which is somewhat lossy.
>>
>
> IMHO there's no reason to support non-utf8 properties. We should
> document this restriction now while adoption is relatively light.

Agreed, my reading of the source is that we expect strings for both
property names and property values.  If they're both strings, we should
not support anything other than UTF-8 in either case.

      --dkg

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-11-29  8:03         ` Ruben Pollan
@ 2017-12-23 15:59           ` David Bremner
  2018-04-27 19:12             ` meskio
  0 siblings, 1 reply; 21+ messages in thread
From: David Bremner @ 2017-12-23 15:59 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

Ruben Pollan <meskio@sindominio.net> writes:
> +
> +    def get_properties(self, prop="", exact=False):

As far as I understand, you also need to update docs/source/message.rst
so that your new methods are documented in the sphinx docs.

> +        """ Get the properties for *message*, returning
> +        notmuch_message_properties_t object which can be used to iterate
> +        over all properties.

This seeems to be wrong (or at last confusing) for the python bindings.

> +
> +        :param prop: The name of the property to get. Otherwise it will return
> +                     the full list of properties of the message.
> +        :param exact: if True, require exact match with key. Otherwise
> +                      treat as prefix.
> +        :returns: A dictionary with the property names and values {key: value}
> +        :raises: :exc:`NotInitializedError` if message has not been
> +                 initialized
> +        """
> +        if not self._msg:
> +            raise NotInitializedError()
> +
> +        properties_dict = {}
> +        properties = Message._get_properties(self._msg, prop, exact)

Now that the database.get_configs method is merged, I'd prefer to be consistent
with that, and define a generator that yields key/value pairs. It's easy
enough for someone to use a dictionary comprehension to get a dict from
that if they want it.  Sorry to be making extra work for you.

d

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2017-12-23 15:59           ` David Bremner
@ 2018-04-27 19:12             ` meskio
  2018-04-27 19:15               ` Ruben Pollan
  0 siblings, 1 reply; 21+ messages in thread
From: meskio @ 2018-04-27 19:12 UTC (permalink / raw)
  To: David Bremner, notmuch

[-- Attachment #1: Type: text/plain, Size: 1862 bytes --]

Quoting David Bremner (2017-12-23 16:59:51)
> Ruben Pollan <meskio@sindominio.net> writes:
> > +
> > +    def get_properties(self, prop="", exact=False):
> 
> As far as I understand, you also need to update docs/source/message.rst
> so that your new methods are documented in the sphinx docs.
> 
> > +        """ Get the properties for *message*, returning
> > +        notmuch_message_properties_t object which can be used to iterate
> > +        over all properties.
> 
> This seeems to be wrong (or at last confusing) for the python bindings.
> 
> > +
> > +        :param prop: The name of the property to get. Otherwise it will return
> > +                     the full list of properties of the message.
> > +        :param exact: if True, require exact match with key. Otherwise
> > +                      treat as prefix.
> > +        :returns: A dictionary with the property names and values {key: value}
> > +        :raises: :exc:`NotInitializedError` if message has not been
> > +                 initialized
> > +        """
> > +        if not self._msg:
> > +            raise NotInitializedError()
> > +
> > +        properties_dict = {}
> > +        properties = Message._get_properties(self._msg, prop, exact)
> 
> Now that the database.get_configs method is merged, I'd prefer to be consistent
> with that, and define a generator that yields key/value pairs. It's easy
> enough for someone to use a dictionary comprehension to get a dict from
> that if they want it.  Sorry to be making extra work for you.

Good to me, I'm sending an update with all this fixed.

Sorry for letting it hung for so long.

-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAlrjdggACgkQUrj1rJei
2oY0lg/9H899SCbZQ++ZAPfWVqlu52i1ZdT4t1y+oaz0ILgeLGvylGM5es+j2uKX
7fJ+69YpkUiEvNDHvGgBZFr6tyGArACcq5fo/ZDNWMIQDR9rFQoFGcwnMyyDB0KF
ASn5i0TyUDTe0/JwAV7m5EEergyMwqnHYVRTDyKwff2ajKbwM7UyUldRTO4nl/3y
B3nZs3R3NFmNaeLPhJqJO+ED8gxKGcia/yS4vk1D7NlpJjUz1mz/+MkfcyKRxArx
HZBs2HNMoYA7l4tc6b2bdh9GXiy7yEV5mWnept7WBC8W/ywxv8U5d9cZ4FbM4OBK
jAWnh//tsba1OhA79XVskzw3RFUllR/E674iF7KK3IbM6CwpKX5ISc1SbaYz+h8W
IUxboHYAR1tynu3OhLkZO58CKsT4qFZDM7vFszBVcgmaltaMDcv54aAfVysC0nll
fxbyDPvBSCnprD6C4jGP4/3W04mLgt0esUpUPWk/52hUYLVpN7e4KyhH1POLLF4l
BpG/n1MiLshCKoChjiW+OwSgkgSSkAvWQcCKa8TY7el0NdlCdwZob9/Sq7o2skGL
QKm1JyqEKHCU4j77CmRARVvVsSucbthQJQJofcR5R0AYW5tLXjdXVn5CHnTXcl66
jVmSZ7CO87hQ+roB082pZqkct9fGWoYs3S0T0nCa691or9OhP8U=
=WebJ
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-04-27 19:12             ` meskio
@ 2018-04-27 19:15               ` Ruben Pollan
  2018-05-01 13:06                 ` David Bremner
  0 siblings, 1 reply; 21+ messages in thread
From: Ruben Pollan @ 2018-04-27 19:15 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property and
Message.get_properties (prop, exact=False) yields key, value pairs
---
 bindings/python/docs/source/message.rst |  4 ++
 bindings/python/notmuch/globals.py      |  5 +++
 bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst
index 1a6cc3d5..b0033924 100644
--- a/bindings/python/docs/source/message.rst
+++ b/bindings/python/docs/source/message.rst
@@ -33,6 +33,10 @@
 
    .. automethod:: get_tags
 
+   .. automethod:: get_property
+
+   .. automethod:: get_properties
+
    .. automethod:: maildir_flags_to_tags
 
    .. automethod:: tags_to_maildir_flags
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 97413996..11e328b7 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -75,6 +75,11 @@ class NotmuchMessageS(Structure):
 NotmuchMessageP = POINTER(NotmuchMessageS)
 
 
+class NotmuchMessagePropertiesS(Structure):
+    pass
+NotmuchMessagePropertiesP = POINTER(NotmuchMessagePropertiesS)
+
+
 class NotmuchTagsS(Structure):
     pass
 NotmuchTagsP = POINTER(NotmuchTagsS)
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 1b1f2174..f57dbc80 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -29,6 +29,7 @@ from .globals import (
     NotmuchTagsP,
     NotmuchMessageP,
     NotmuchMessagesP,
+    NotmuchMessagePropertiesP,
     NotmuchFilenamesP,
 )
 from .errors import (
@@ -113,6 +114,36 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
+    """notmuch_message_get_properties"""
+    _get_properties = nmlib.notmuch_message_get_properties
+    _get_properties.argtypes = [NotmuchMessageP, c_char_p, c_int]
+    _get_properties.restype = NotmuchMessagePropertiesP
+
+    """notmuch_message_properties_valid"""
+    _properties_valid = nmlib.notmuch_message_properties_valid
+    _properties_valid.argtypes = [NotmuchMessagePropertiesP]
+    _properties_valid.restype = bool
+
+    """notmuch_message_properties_value"""
+    _properties_value = nmlib.notmuch_message_properties_value
+    _properties_value.argtypes = [NotmuchMessagePropertiesP]
+    _properties_value.restype = c_char_p
+
+    """notmuch_message_properties_key"""
+    _properties_key = nmlib.notmuch_message_properties_key
+    _properties_key.argtypes = [NotmuchMessagePropertiesP]
+    _properties_key.restype = c_char_p
+
+    """notmuch_message_properties_move_to_next"""
+    _properties_move_to_next = nmlib.notmuch_message_properties_move_to_next
+    _properties_move_to_next.argtypes = [NotmuchMessagePropertiesP]
+    _properties_move_to_next.restype = None
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +464,53 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p("")
+        status = Message._get_property(self._msg, prop, byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value
+
+    def get_properties(self, prop="", exact=False):
+        """ Get the properties of the message, returning a generator of
+        name, value pairs.
+
+        The generator will yield once per value. There might be more than one
+        value on each name, so the generator might yield the same name several
+        times.
+
+        :param prop: The name of the property to get. Otherwise it will return
+                     the full list of properties of the message.
+        :param exact: if True, require exact match with key. Otherwise
+                      treat as prefix.
+        :yields:  Each property values as a pair of `name, value`
+        :ytype:   pairs of str
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        properties = Message._get_properties(self._msg, prop, exact)
+        while Message._properties_valid(properties):
+            key = Message._properties_key(properties)
+            value = Message._properties_value(properties)
+            yield key, value
+            Message._properties_move_to_next(properties)
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-04-27 19:15               ` Ruben Pollan
@ 2018-05-01 13:06                 ` David Bremner
  2018-05-01 15:24                   ` meskio
  0 siblings, 1 reply; 21+ messages in thread
From: David Bremner @ 2018-05-01 13:06 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

Ruben Pollan <meskio@sindominio.net> writes:

> Message.get_property (prop) returns a string with the value of the property and
> Message.get_properties (prop, exact=False) yields key, value pairs
> ---
>  bindings/python/docs/source/message.rst |  4 ++
>  bindings/python/notmuch/globals.py      |  5 +++
>  bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
>  3 files changed, 88 insertions(+), 1 deletion(-)

I started to write some simple tests for this, but I didn't get very
far.

running the test below, I get

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "/home/bremner/software/upstream/notmuch/bindings/python/notmuch/message.py", line 480, in get_property
    value = c_char_p("")
TypeError: bytes or integer address expected instead of str instance


diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh
index 74b3f5a1..f7220565 100755
--- a/test/T610-message-property.sh
+++ b/test/T610-message-property.sh
@@ -89,6 +89,18 @@ testkey2 = NULL
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "msg.get_property (python)"
+test_python <<'EOF'
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
+msg = db.find_message("4EFC743A.3060609@april.org")
+print("testkey1[1] = %s\n".format(msg.get_property("testkey1")))
+EOF
+cat <<'EOF' > EXPECTED
+testkey1[1] = testvalue1
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "notmuch_message_remove_all_properties"
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 EXPECT0(notmuch_message_remove_all_properties (message, NULL));

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-01 13:06                 ` David Bremner
@ 2018-05-01 15:24                   ` meskio
  2018-05-01 15:28                     ` Ruben Pollan
  0 siblings, 1 reply; 21+ messages in thread
From: meskio @ 2018-05-01 15:24 UTC (permalink / raw)
  To: David Bremner, notmuch

[-- Attachment #1: Type: text/plain, Size: 1380 bytes --]

Quoting David Bremner (2018-05-01 15:06:38)
> running the test below, I get
> 
> Traceback (most recent call last):
>   File "<stdin>", line 4, in <module>
>   File "/home/bremner/software/upstream/notmuch/bindings/python/notmuch/message.py", line 480, in get_property
>     value = c_char_p("")
> TypeError: bytes or integer address expected instead of str instance

Ups, I was using python2 to test it. I see it doesn't work with python three.  
I'll send an update.

> diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh
> index 74b3f5a1..f7220565 100755
> --- a/test/T610-message-property.sh
> +++ b/test/T610-message-property.sh
> @@ -89,6 +89,18 @@ testkey2 = NULL
>  EOF
>  test_expect_equal_file EXPECTED OUTPUT
>  
> +test_begin_subtest "msg.get_property (python)"
> +test_python <<'EOF'
> +import notmuch
> +db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
> +msg = db.find_message("4EFC743A.3060609@april.org")
> +print("testkey1[1] = %s\n".format(msg.get_property("testkey1")))

I think this should be (notice the {0} instead of %s):
print("testkey1[1] = {0}".format(msg.get_property("testkey1")))


-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAlrohqkACgkQUrj1rJei
2oaJSxAAj7r1lJFPzrqGy34PATiosUFOpVn61LhAPiaVUEddEAnLF9SsLGnRChcF
3QJsrE59SOQ7BwuXEOnjt4rf1s8GeG/SbhOsOec7rsCCGujCBWBjk5+pW4GLU47G
4/mdJ60IF6PMoSGhcRlQ4WgOkewcXLswWOEOvcMkQE+qfWTRb9RVa7WiqYOdYy/k
JkDFJ46mr0VbO04rydk3JHQuw5XcVdJSsGTFZmwgAGE+xR1IdD6gSCSmT7K2DTLH
TiWTxwe4AIO5HOiWWBTDGHGI8OaJe0ysDeEyRoBmIzAHK7EVeYYntPWuhxBKSsQG
vKcTiNVR551D+2othRl28V+CLEpbOWH7wtEnV46nKQcZyyX0rU/VEu17NfcrKFOs
GjpKjhJs8T3ySeooGyGYfw4//dSQ76Y8qw2tYHSFaFCNQ7BbFdEAKUcpQQOPcOEK
EzpksG0Zs7fHOJpYxbVLYpqulfubfn7JpDbdyverhNF3qU9BnKBbN8dbuBGgMtu+
NIt2Dd/QAAueVnESNxXLSsfTZTBUHERvc5aGggxknMUxBjtC5k6o2POzDxbm6ly0
Kq8hH1IGnYGncRPWyVhPLuA/nJRAaU3EcSlu+hAuXL6t7DTC7zrNEB05bM+0kYpc
k6z+/ociG7a2+MijllDqdwsdRu1U2bQhk17qNr40YcsMT82Ozms=
=7Xp3
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-01 15:24                   ` meskio
@ 2018-05-01 15:28                     ` Ruben Pollan
  2018-05-02  0:08                       ` David Bremner
  0 siblings, 1 reply; 21+ messages in thread
From: Ruben Pollan @ 2018-05-01 15:28 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property and
Message.get_properties (prop, exact=False) yields key, value pairs
---
 bindings/python/docs/source/message.rst |  4 ++
 bindings/python/notmuch/globals.py      |  5 +++
 bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst
index 1a6cc3d5..b0033924 100644
--- a/bindings/python/docs/source/message.rst
+++ b/bindings/python/docs/source/message.rst
@@ -33,6 +33,10 @@
 
    .. automethod:: get_tags
 
+   .. automethod:: get_property
+
+   .. automethod:: get_properties
+
    .. automethod:: maildir_flags_to_tags
 
    .. automethod:: tags_to_maildir_flags
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 97413996..11e328b7 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -75,6 +75,11 @@ class NotmuchMessageS(Structure):
 NotmuchMessageP = POINTER(NotmuchMessageS)
 
 
+class NotmuchMessagePropertiesS(Structure):
+    pass
+NotmuchMessagePropertiesP = POINTER(NotmuchMessagePropertiesS)
+
+
 class NotmuchTagsS(Structure):
     pass
 NotmuchTagsP = POINTER(NotmuchTagsS)
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 1b1f2174..cc945037 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -29,6 +29,7 @@ from .globals import (
     NotmuchTagsP,
     NotmuchMessageP,
     NotmuchMessagesP,
+    NotmuchMessagePropertiesP,
     NotmuchFilenamesP,
 )
 from .errors import (
@@ -113,6 +114,36 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
+    """notmuch_message_get_properties"""
+    _get_properties = nmlib.notmuch_message_get_properties
+    _get_properties.argtypes = [NotmuchMessageP, c_char_p, c_int]
+    _get_properties.restype = NotmuchMessagePropertiesP
+
+    """notmuch_message_properties_valid"""
+    _properties_valid = nmlib.notmuch_message_properties_valid
+    _properties_valid.argtypes = [NotmuchMessagePropertiesP]
+    _properties_valid.restype = bool
+
+    """notmuch_message_properties_value"""
+    _properties_value = nmlib.notmuch_message_properties_value
+    _properties_value.argtypes = [NotmuchMessagePropertiesP]
+    _properties_value.restype = c_char_p
+
+    """notmuch_message_properties_key"""
+    _properties_key = nmlib.notmuch_message_properties_key
+    _properties_key.argtypes = [NotmuchMessagePropertiesP]
+    _properties_key.restype = c_char_p
+
+    """notmuch_message_properties_move_to_next"""
+    _properties_move_to_next = nmlib.notmuch_message_properties_move_to_next
+    _properties_move_to_next.argtypes = [NotmuchMessagePropertiesP]
+    _properties_move_to_next.restype = None
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +464,53 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p()
+        status = Message._get_property(self._msg, _str(prop), byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value.decode('utf-8')
+
+    def get_properties(self, prop="", exact=False):
+        """ Get the properties of the message, returning a generator of
+        name, value pairs.
+
+        The generator will yield once per value. There might be more than one
+        value on each name, so the generator might yield the same name several
+        times.
+
+        :param prop: The name of the property to get. Otherwise it will return
+                     the full list of properties of the message.
+        :param exact: if True, require exact match with key. Otherwise
+                      treat as prefix.
+        :yields:  Each property values as a pair of `name, value`
+        :ytype:   pairs of str
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        properties = Message._get_properties(self._msg, _str(prop), exact)
+        while Message._properties_valid(properties):
+            key = Message._properties_key(properties)
+            value = Message._properties_value(properties)
+            yield key, value
+            Message._properties_move_to_next(properties)
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-01 15:28                     ` Ruben Pollan
@ 2018-05-02  0:08                       ` David Bremner
  2018-05-02 17:00                         ` meskio
  0 siblings, 1 reply; 21+ messages in thread
From: David Bremner @ 2018-05-02  0:08 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

Ruben Pollan <meskio@sindominio.net> writes:

> Message.get_property (prop) returns a string with the value of the property and
> Message.get_properties (prop, exact=False) yields key, value pairs
> ---
>  bindings/python/docs/source/message.rst |  4 ++
>  bindings/python/notmuch/globals.py      |  5 +++
>  bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
>  3 files changed, 88 insertions(+), 1 deletion(-)
>

This version passes the first test (after fixing the format, as you
noted), but it looks like get_properties is returning pairs of
bytestrings.

FAIL   [15] msg.get_properties (python)
	--- T610-message-property.16.EXPECTED	2018-05-02 00:02:11.160028179 +0000
	+++ T610-message-property.16.OUTPUT	2018-05-02 00:02:11.164028171 +0000
	@@ -1,4 +1,4 @@
	-testkey1 = alice
	-testkey1 = bob
	-testkey1 = testvalue1
	-testkey1 = testvalue2
	+b'testkey1' = b'alice'
	+b'testkey1' = b'bob'
	+b'testkey1' = b'testvalue1'
	+b'testkey1' = b'testvalue2'

I don't _think_ that's what we want. We had some discussion before and
decided that it was reasonable to only support utf-8 properties, so
converting to strings should be OK?

here's the proposed tests. 

diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh
index 74b3f5a1..c903b2b6 100755
--- a/test/T610-message-property.sh
+++ b/test/T610-message-property.sh
@@ -256,4 +256,34 @@ id:4EFC743A.3060609@april.org
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "msg.get_property (python)"
+test_python <<'EOF'
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
+msg = db.find_message("4EFC743A.3060609@april.org")
+print("testkey1 = {0}".format(msg.get_property("testkey1")))
+print("testkey3 = {0}".format(msg.get_property("testkey3")))
+EOF
+cat <<'EOF' > EXPECTED
+testkey1 = alice
+testkey3 = alice3
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "msg.get_properties (python)"
+test_python <<'EOF'
+import notmuch
+db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
+msg = db.find_message("4EFC743A.3060609@april.org")
+for (key,val) in msg.get_properties("testkey1"):
+        print("{0} = {1}".format(key,val))
+EOF
+cat <<'EOF' > EXPECTED
+testkey1 = alice
+testkey1 = bob
+testkey1 = testvalue1
+testkey1 = testvalue2
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-02  0:08                       ` David Bremner
@ 2018-05-02 17:00                         ` meskio
  2018-05-02 17:01                           ` Ruben Pollan
  0 siblings, 1 reply; 21+ messages in thread
From: meskio @ 2018-05-02 17:00 UTC (permalink / raw)
  To: David Bremner, notmuch

[-- Attachment #1: Type: text/plain, Size: 1691 bytes --]

Quoting David Bremner (2018-05-02 02:08:26)
> Ruben Pollan <meskio@sindominio.net> writes:
> 
> > Message.get_property (prop) returns a string with the value of the property and
> > Message.get_properties (prop, exact=False) yields key, value pairs
> > ---
> >  bindings/python/docs/source/message.rst |  4 ++
> >  bindings/python/notmuch/globals.py      |  5 +++
> >  bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
> >  3 files changed, 88 insertions(+), 1 deletion(-)
> >
> 
> This version passes the first test (after fixing the format, as you
> noted), but it looks like get_properties is returning pairs of
> bytestrings.
> 
> FAIL   [15] msg.get_properties (python)
>         --- T610-message-property.16.EXPECTED   2018-05-02 00:02:11.160028179 +0000
>         +++ T610-message-property.16.OUTPUT     2018-05-02 00:02:11.164028171 +0000
>         @@ -1,4 +1,4 @@
>         -testkey1 = alice
>         -testkey1 = bob
>         -testkey1 = testvalue1
>         -testkey1 = testvalue2
>         +b'testkey1' = b'alice'
>         +b'testkey1' = b'bob'
>         +b'testkey1' = b'testvalue1'
>         +b'testkey1' = b'testvalue2'
> 
> I don't _think_ that's what we want. We had some discussion before and
> decided that it was reasonable to only support utf-8 properties, so
> converting to strings should be OK?

I added the 'decode("utf-8")' to get_property but I didn't to get_properties.  
Next patch fixes it.

-- 
meskio | http://meskio.net/
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 My contact info: http://meskio.net/crypto.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Nos vamos a Croatan.

[-- Attachment #2: signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEs7M6f/ZpXzXMAQR+Urj1rJei2oYFAlrp7pYACgkQUrj1rJei
2oY9rg/8DUuYKJtYMWvWht+ghen06bFPKI/Tlf/qOj9XmIve85UKCLGlCiC/Cw8y
0FlCeukUYOXVf6IBdVHDt8weSlB+fQlqcjaeig8Oo/Y+PFgm8eNgCq4ZgyBFTVYa
NqsP4bwDWp6oR/yI89b6W6E9Mo/ubycoz/s21tawuipoDzgFZ+/gO9bXaJ2oIlpe
XByvXDZ9HRH30nKqKmvZxvw4QtdiRfe6vh+Nm2pCKrQZt/KvbQ9L5h+Vwc7xXQQt
PwNf9M6Rf4RO7FQcYij1w9MIXuNEuMI6hw5itmRZBK0hrGx6HWuig5QpNB0xIZyc
3PDUbuQnmHopISdYNg95C9Q180H+zqVCmf+xW6BT7Ccqw9EvjhA9rDmdHyI9SwVk
wRBJBHY5PDHvY+K0m++u2bHoi8UiYw4sz6iN3JODwlhka+2yAHny2eU8cw1dGXs3
p6F7zdnLBS+QJoWkWwdKaE0ZwQI7AcpyKZyPb/xosJRaD9Il2LKCxhYUddSt7lql
NT+K0WsjNuYov0d3yZHqWFytHjV5ZHEt3gc7hRYgtfT7p0pTFmuAdD3IrqtpUs5+
bVEGXCn4m0yI0XxBDqbjPufH5vdNMcfX1DKUTzFVDq7UxqyIEx6vmrgM2Cvfo3E2
lHYRQlTmLd/cEDsNK1xPsbfGwHf3A/25pTQ+WoiOqJrXQuwsvY0=
=LCB1
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-02 17:00                         ` meskio
@ 2018-05-02 17:01                           ` Ruben Pollan
  2018-05-02 23:50                             ` David Bremner
  0 siblings, 1 reply; 21+ messages in thread
From: Ruben Pollan @ 2018-05-02 17:01 UTC (permalink / raw)
  To: notmuch

Message.get_property (prop) returns a string with the value of the property and
Message.get_properties (prop, exact=False) yields key, value pairs
---
 bindings/python/docs/source/message.rst |  4 ++
 bindings/python/notmuch/globals.py      |  5 +++
 bindings/python/notmuch/message.py      | 80 ++++++++++++++++++++++++++++++++-
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst
index 1a6cc3d5..b0033924 100644
--- a/bindings/python/docs/source/message.rst
+++ b/bindings/python/docs/source/message.rst
@@ -33,6 +33,10 @@
 
    .. automethod:: get_tags
 
+   .. automethod:: get_property
+
+   .. automethod:: get_properties
+
    .. automethod:: maildir_flags_to_tags
 
    .. automethod:: tags_to_maildir_flags
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 97413996..11e328b7 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -75,6 +75,11 @@ class NotmuchMessageS(Structure):
 NotmuchMessageP = POINTER(NotmuchMessageS)
 
 
+class NotmuchMessagePropertiesS(Structure):
+    pass
+NotmuchMessagePropertiesP = POINTER(NotmuchMessagePropertiesS)
+
+
 class NotmuchTagsS(Structure):
     pass
 NotmuchTagsP = POINTER(NotmuchTagsS)
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 1b1f2174..d242097a 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 
 
-from ctypes import c_char_p, c_long, c_uint, c_int
+from ctypes import c_char_p, c_long, c_uint, c_int, POINTER, byref
 from datetime import date
 from .globals import (
     nmlib,
@@ -29,6 +29,7 @@ from .globals import (
     NotmuchTagsP,
     NotmuchMessageP,
     NotmuchMessagesP,
+    NotmuchMessagePropertiesP,
     NotmuchFilenamesP,
 )
 from .errors import (
@@ -113,6 +114,36 @@ class Message(Python3StringMixIn):
     _maildir_flags_to_tags.argtypes = [NotmuchMessageP]
     _maildir_flags_to_tags.restype = c_int
 
+    """notmuch_message_get_property"""
+    _get_property = nmlib.notmuch_message_get_property
+    _get_property.argtypes = [NotmuchMessageP, c_char_p, POINTER(c_char_p)]
+    _get_property.restype = c_int
+
+    """notmuch_message_get_properties"""
+    _get_properties = nmlib.notmuch_message_get_properties
+    _get_properties.argtypes = [NotmuchMessageP, c_char_p, c_int]
+    _get_properties.restype = NotmuchMessagePropertiesP
+
+    """notmuch_message_properties_valid"""
+    _properties_valid = nmlib.notmuch_message_properties_valid
+    _properties_valid.argtypes = [NotmuchMessagePropertiesP]
+    _properties_valid.restype = bool
+
+    """notmuch_message_properties_value"""
+    _properties_value = nmlib.notmuch_message_properties_value
+    _properties_value.argtypes = [NotmuchMessagePropertiesP]
+    _properties_value.restype = c_char_p
+
+    """notmuch_message_properties_key"""
+    _properties_key = nmlib.notmuch_message_properties_key
+    _properties_key.argtypes = [NotmuchMessagePropertiesP]
+    _properties_key.restype = c_char_p
+
+    """notmuch_message_properties_move_to_next"""
+    _properties_move_to_next = nmlib.notmuch_message_properties_move_to_next
+    _properties_move_to_next.argtypes = [NotmuchMessagePropertiesP]
+    _properties_move_to_next.restype = None
+
     #Constants: Flags that can be set/get with set_flag
     FLAG = Enum(['MATCH'])
 
@@ -433,6 +464,53 @@ class Message(Python3StringMixIn):
     _freeze.argtypes = [NotmuchMessageP]
     _freeze.restype = c_uint
 
+    def get_property(self, prop):
+        """ Retrieve the value for a single property key
+
+        :param prop: The name of the property to get.
+        :returns: String with the property value or None if there is no such
+                  key. In the case of multiple values for the given key, the
+                  first one is retrieved.
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        value = c_char_p()
+        status = Message._get_property(self._msg, _str(prop), byref(value))
+        if status != 0:
+            raise NotmuchError(status)
+
+        return value.value.decode('utf-8')
+
+    def get_properties(self, prop="", exact=False):
+        """ Get the properties of the message, returning a generator of
+        name, value pairs.
+
+        The generator will yield once per value. There might be more than one
+        value on each name, so the generator might yield the same name several
+        times.
+
+        :param prop: The name of the property to get. Otherwise it will return
+                     the full list of properties of the message.
+        :param exact: if True, require exact match with key. Otherwise
+                      treat as prefix.
+        :yields:  Each property values as a pair of `name, value`
+        :ytype:   pairs of str
+        :raises: :exc:`NotInitializedError` if message has not been
+                 initialized
+        """
+        if not self._msg:
+            raise NotInitializedError()
+
+        properties = Message._get_properties(self._msg, _str(prop), exact)
+        while Message._properties_valid(properties):
+            key = Message._properties_key(properties)
+            value = Message._properties_value(properties)
+            yield key.decode("utf-8"), value.decode("utf-8")
+            Message._properties_move_to_next(properties)
+
     def freeze(self):
         """Freezes the current state of 'message' within the database
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH] python: add bindings for notmuch_message_get_propert(y/ies)
  2018-05-02 17:01                           ` Ruben Pollan
@ 2018-05-02 23:50                             ` David Bremner
  0 siblings, 0 replies; 21+ messages in thread
From: David Bremner @ 2018-05-02 23:50 UTC (permalink / raw)
  To: Ruben Pollan, notmuch

Ruben Pollan <meskio@sindominio.net> writes:

> Message.get_property (prop) returns a string with the value of the property and
> Message.get_properties (prop, exact=False) yields key, value pairs

pushed this version to master.  Thanks for your contribution.

d

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2018-05-02 23:50 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-15 22:29 [PATCH] python: add bindings for notmuch_message_get_property Ruben Pollan
2017-11-15 22:48 ` meskio
2017-11-17  9:03 ` Daniel Kahn Gillmor
2017-11-28 22:46   ` [PATCH] python: add bindings for notmuch_message_get_propert(y/ies) Ruben Pollan
2017-11-28 22:51     ` meskio
2017-11-29  1:57     ` Daniel Kahn Gillmor
2017-11-29  8:02       ` meskio
2017-11-29  8:03         ` Ruben Pollan
2017-12-23 15:59           ` David Bremner
2018-04-27 19:12             ` meskio
2018-04-27 19:15               ` Ruben Pollan
2018-05-01 13:06                 ` David Bremner
2018-05-01 15:24                   ` meskio
2018-05-01 15:28                     ` Ruben Pollan
2018-05-02  0:08                       ` David Bremner
2018-05-02 17:00                         ` meskio
2018-05-02 17:01                           ` Ruben Pollan
2018-05-02 23:50                             ` David Bremner
2017-11-29 21:40       ` Floris Bruynooghe
2017-11-30 13:44         ` David Bremner
2017-11-30 14:19           ` Daniel Kahn Gillmor

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).