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::
+ :exc:`NotmuchError` STATUS.NOT_INITIALIZED. 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::
+ You can store and reuse the single :class:`Message` objects as often
+ as you want as long as you keep the parent :class:`Messages` object
+ around. (Due to hierarchical memory allocation, all derived
+ :class:`Message` objects will be invalid when we delete the parent
+ :class:`Messages` object, even if it was already exhausted.) So
+ this works::
db = Database()
msgs = Query(db,'').search_messages() #get a Messages() object
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
- # also deleted. If you did e.g. an explicit del(msgs) here, the
- # following lines would fail.
+ # msgs is "exhausted" now and msgs.next() will raise an exception.
+ # However it will be kept alive until all retrieved Message()
+ # objects are also deleted. If you do 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.
+ # It is simply a list with :class:`Message`s.
print (msglist[0].get_filename())
print (msglist[1].get_filename())
print (msglist[0].get_message_id())
+
+
+ As :class:`Message` implements both __hash__() and __cmp__(), it is
+ possible to make sets out of :class:`Messages` and use set
+ arithmetic (this happens in python and will of course be *much*
+ slower than redoing a proper query with the appropriate filters::
+
+ s1, s2 = set(msgs1), set(msgs2)
+ s.union(s2)
+ s1 -= s2
+ ...
+
+ Be careful when using set arithmetic between message sets derived
+ from different Databases (ie the same database reopened after
+ messages have changed). If messages have added or removed associated
+ files in the meantime, it is possible that the same message would be
+ considered as a different object (as it points to a different file).
"""
#notmuch_messages_get
"""Represents a single Email message
Technically, this wraps the underlying *notmuch_message_t* structure.
+
+ As this implements __cmp__() it is possible to compare 2
+ :class:`Message`s with::
+
+ if msg1 == msg2:
"""
"""notmuch_message_get_filename (notmuch_message_t *message)"""
return output
+ def __hash__(self):
+ """Implement hash(), so we can use Message() sets"""
+ file = self.get_filename()
+ if file is None:
+ return None
+ return hash(file)
+
+ def __cmp__(self, other):
+ """Implement cmp(), so we can compare Message()s
+
+ 2 messages are considered equal if they point to the same
+ Message-Id and if they point to the same file names. If 2
+ Messages derive from different queries where some files have
+ been added or removed, the same messages would not be considered
+ equal (as they do not point to the same set of files
+ any more)."""
+ res = cmp(self.get_message_id(), other.get_message_id())
+ if res:
+ res = cmp(list(self.get_filenames()), list(other.get_filenames()))
+ return res
+
def __del__(self):
"""Close and free the notmuch Message"""
if self._msg is not None: