+
+#------------------------------------------------------------------------------
+class Messages(object):
+ """Represents a list of notmuch messages
+
+ 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::
+
+ db = Database()
+ msgs = Query(db,'').search_messages() #get a Messages() object
+ msglist = []
+ for m in msgs:
+ msglist.append(m)
+
+ # msgs is "exhausted" now and even len(msgs) will raise an exception.
+ # However it will be kept around until all retrieved Message() objects are
+ # also deleted. If you did e.g. an explicit del(msgs) here, the
+ # following lines would fail.
+
+ # You can reiterate over *msglist* however as often as you want.
+ # It is simply a list with Message objects.
+
+ print (msglist[0].get_filename())
+ print (msglist[1].get_filename())
+ print (msglist[0].get_message_id())
+ """
+
+ #notmuch_tags_get
+ _get = nmlib.notmuch_messages_get
+ _get.restype = c_void_p
+
+ _collect_tags = nmlib.notmuch_messages_collect_tags
+ _collect_tags.restype = c_void_p
+
+ def __init__(self, msgs_p, parent=None):
+ """
+ :param msgs_p: A pointer to an underlying *notmuch_messages_t*
+ structure. These are not publically exposed, so a user
+ will almost never instantiate a :class:`Messages` object
+ herself. They are usually handed back as a result,
+ e.g. in :meth:`Query.search_messages`. *msgs_p* must be
+ valid, we will raise an :exc:`NotmuchError`
+ (STATUS.NULL_POINTER) if it is `None`.
+ :type msgs_p: :class:`ctypes.c_void_p`
+ :param parent: The parent object
+ (ie :class:`Query`) these tags are derived from. It saves
+ a reference to it, so we can automatically delete the db
+ object once all derived objects are dead.
+ :TODO: Make the iterator work more than once and cache the tags in
+ the Python object.(?)
+ """
+ if msgs_p is None:
+ NotmuchError(STATUS.NULL_POINTER)
+
+ self._msgs = msgs_p
+ #store parent, so we keep them alive as long as self is alive
+ self._parent = parent
+ logging.debug("Inited Messages derived from %s" %(str(parent)))
+
+ def collect_tags(self):
+ """Return the unique :class:`Tags` in the contained messages
+
+ :returns: :class:`Tags`
+ :exceptions: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if not inited
+
+ .. note:: :meth:`collect_tags` will iterate over the messages and
+ therefore will not allow further iterations.
+ """
+ if self._msgs is None:
+ raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+ # collect all tags (returns NULL on error)
+ tags_p = Messages._collect_tags (self._msgs)
+ #reset _msgs as we iterated over it and can do so only once
+ self._msgs = None
+
+ if tags_p == None:
+ raise NotmuchError(STATUS.NULL_POINTER)
+ return Tags(tags_p, self)
+
+ def __iter__(self):
+ """ Make Messages an iterator """
+ return self
+
+ def next(self):
+ if self._msgs is None:
+ raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+ if not nmlib.notmuch_messages_valid(self._msgs):
+ self._msgs = None
+ raise StopIteration
+
+ msg = Message(Messages._get (self._msgs), self)
+ 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 (as in retrieve them)!
+ """
+ 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
+
+
+
+ def __del__(self):
+ """Close and free the notmuch Messages"""
+ if self._msgs is not None:
+ logging.debug("Freeing the Messages now")
+ nmlib.notmuch_messages_destroy (self._msgs)
+
+