From 8866a89e3cff46dbd791a1385ca5c800a5c9091e Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Wed, 15 Jun 2011 14:25:33 +0200 Subject: [PATCH] python: Remove Messages().__len__ Messages.__len__() exhausted the iterator and list() inherently calls len(), so we could not invoke list(msgs) without getting errors. Fix this by implementing __nonzero__ but removing __len__ on Messages. Use Query.count_messages() or len(list(msgs)) if you need to know the number. Signed-off-by: Sebastian Spaeth --- bindings/python/docs/source/index.rst | 7 ++- bindings/python/notmuch/message.py | 77 +++++++++------------------ 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index bf0cfd28..d58ba97e 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -127,7 +127,12 @@ More information on specific topics can be found on the following pages: .. automethod:: collect_tags - .. automethod:: __len__ + .. method:: __len__() + + .. note:: :meth:`__len__` was removed in version 0.6 as it exhausted + the iterator and broke list(Messages()). Use the + :meth:`Query.count_messages` function or use + `len(list(msgs))`. :class:`Message` -- A single message ---------------------------------------- diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 340c0b8b..8fd9eace 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -37,35 +37,27 @@ class Messages(object): This object provides an iterator over a list of notmuch messages (Technically, it provides a wrapper for the underlying - *notmuch_messages_t* structure). Do note that the underlying - library only provides a one-time iterator (it cannot reset the - iterator to the start). Thus iterating over the function will - "exhaust" the list of messages, and a subsequent iteration attempt - will raise a :exc:`NotmuchError` STATUS.NOT_INITIALIZED. Also - note, that any function that uses iteration will also - exhaust the messages. So both:: - - for msg in msgs: print msg - - as well as:: - - number_of_msgs = len(msgs) - - will "exhaust" the Messages. If you need to re-iterate over a list of - messages you will need to retrieve a new :class:`Messages` object. - - Things are not as bad as it seems though, you can store and reuse - the single Message objects as often as you want as long as you - keep the parent Messages object around. (Recall that due to - hierarchical memory allocation, all derived Message objects will - be invalid when we delete the parent Messages() object, even if it - was already "exhausted".) So this works:: + *notmuch_messages_t* structure). Do note that the underlying library + only provides a one-time iterator (it cannot reset the iterator to + the start). Thus iterating over the function will "exhaust" the list + of messages, and a subsequent iteration attempt will raise a + :exc:`NotmuchError` STATUS.NOT_INITIALIZED. Also note, that any + function that uses iteration will also exhaust the messages.If you + need to re-iterate over a list of messages you will need to retrieve + a new :class:`Messages` object or cache your :class:`Message`s in a + list via:: + + msglist = list(msgs) + + You can store and reuse the single Message objects as often as you + want as long as you keep the parent Messages object around. (Recall + that due to hierarchical memory allocation, all derived Message + objects will be invalid when we delete the parent Messages() object, + even if it was already "exhausted".) So this works:: db = Database() msgs = Query(db,'').search_messages() #get a Messages() object - msglist = [] - for m in msgs: - msglist.append(m) + msglist = list(msgs) # msgs is "exhausted" now and even len(msgs) will raise an exception. # However it will be kept around until all retrieved Message() objects are @@ -80,7 +72,7 @@ class Messages(object): print (msglist[0].get_message_id()) """ - #notmuch_tags_get + #notmuch_messages_get _get = nmlib.notmuch_messages_get _get.restype = c_void_p @@ -148,33 +140,12 @@ class Messages(object): nmlib.notmuch_messages_move_to_next(self._msgs) return msg - def __len__(self): - """len(:class:`Messages`) returns the number of contained messages - - .. note:: As this iterates over the messages, we will not be able to - iterate over them again! So this will fail:: - - #THIS FAILS - msgs = Database().create_query('').search_message() - if len(msgs) > 0: #this 'exhausts' msgs - # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!! - for msg in msgs: print msg - - Most of the time, using the - :meth:`Query.count_messages` is therefore more - appropriate (and much faster). While not guaranteeing - that it will return the exact same number than len(), - in my tests it effectively always did so. + def __nonzero__(self): """ - if self._msgs is None: - raise NotmuchError(STATUS.NOT_INITIALIZED) - - i=0 - while nmlib.notmuch_messages_valid(self._msgs): - nmlib.notmuch_messages_move_to_next(self._msgs) - i += 1 - self._msgs = None - return i + :return: True if there is at least one more thread in the + Iterator, False if not.""" + return self._msgs is not None and \ + nmlib.notmuch_messages_valid(self._msgs) > 0 def __del__(self): """Close and free the notmuch Messages""" -- 2.43.0