* [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 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
* 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
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).