]> git.notmuchmail.org Git - notmuch/commitdiff
bindings/python: Implement Message().get_filenames()
authorSebastian Spaeth <Sebastian@SSpaeth.de>
Thu, 2 Jun 2011 06:56:03 +0000 (08:56 +0200)
committerSebastian Spaeth <Sebastian@SSpaeth.de>
Thu, 2 Jun 2011 07:03:18 +0000 (09:03 +0200)
Message().get_filenames() will return a generator that allows to
iterator over the recorded filenames for a certain Message. Do ntoe that
as all generators, these are one-time use only. You will have to reget
them to perform various actions. So this works::

  len(Message().get_filenames())
  list(Message().get_filenames())
  for n in Message().get_filenames():
    print n

But this won't::

  names = Message().get_filenames()
  len(names) #uses up the iterator
  list(names) #outch, already used up...

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
bindings/python/notmuch/filename.py [new file with mode: 0644]
bindings/python/notmuch/message.py

diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
new file mode 100644 (file)
index 0000000..20b90e9
--- /dev/null
@@ -0,0 +1,108 @@
+"""
+This file is part of notmuch.
+
+Notmuch is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Notmuch is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+"""
+from ctypes import c_char_p
+from notmuch.globals import nmlib, STATUS, NotmuchError
+
+#------------------------------------------------------------------------------
+class Filenames(object):
+    """Represents a list of filenames as returned by notmuch
+
+    This object contains the Filenames iterator. The main function is as_generator() which will return a generator so we can do a Filenamesth an iterator over a list of notmuch filenames. 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 tags, and a subsequent
+    iteration attempt will raise a :exc:`NotmuchError`
+    STATUS.NOT_INITIALIZED. Also note, that any function that uses
+    iteration (nearly all) will also exhaust the tags. So both::
+
+      for name in filenames: print name 
+
+    as well as::
+
+       number_of_names = len(names)
+
+    and even a simple::
+
+       #str() iterates over all tags to construct a space separated list
+       print(str(filenames))
+
+    will "exhaust" the Filenames. However, you can use
+    :meth:`Message.get_filenames` repeatedly to get fresh Filenames
+    objects to perform various actions on filenames.
+    """
+
+    #notmuch_filenames_get
+    _get = nmlib.notmuch_filenames_get
+    _get.restype = c_char_p
+
+    def __init__(self, files_p, parent):
+        """
+        :param files_p: A pointer to an underlying *notmuch_tags_t*
+             structure. These are not publically exposed, so a user
+             will almost never instantiate a :class:`Tags` object
+             herself. They are usually handed back as a result,
+             e.g. in :meth:`Database.get_all_tags`.  *tags_p* must be
+             valid, we will raise an :exc:`NotmuchError`
+             (STATUS.NULL_POINTER) if it is `None`.
+        :type files_p: :class:`ctypes.c_void_p`
+        :param parent: The parent object (ie :class:`Message` these
+             filenames are derived from, and saves a
+             reference to it, so we can automatically delete the db object
+             once all derived objects are dead.
+        """
+        if files_p is None:
+            NotmuchError(STATUS.NULL_POINTER)
+
+        self._files = files_p
+        #save reference to parent object so we keep it alive
+        self._parent = parent
+
+    def as_generator(self):
+        """Return generator of Filenames
+
+        This is the main function that will usually be used by the
+        user."""
+        if self._files is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+        if not nmlib.notmuch_filenames_valid(self._files):
+            self._files = None
+            return
+
+        file = Filenames._get (self._files)
+        nmlib.notmuch_filenames_move_to_next(self._files)
+        yield file
+        
+    def __str__(self):
+        """Represent Filenames() as newline-separated list of full paths
+
+        .. note:: As this iterates over the filenames, we will not be
+               able to iterate over them again (as in retrieve them)! If
+               the tags have been exhausted already, this will raise a
+               :exc:`NotmuchError` STATUS.NOT_INITIALIZED on subsequent
+               attempts. However, you can use
+               :meth:`Message.get_filenames` repeatedly to perform
+               various actions on filenames.
+        """
+        return "\n".join(self)
+
+    def __del__(self):
+        """Close and free the notmuch filenames"""
+        if self._files is not None:
+            nmlib.notmuch_filenames_destroy (self._files)
index ac85cbb453b83aa474298f43cd0066b40b23b28f..340c0b8b742be49dcd1123e7e22f66be8ad29cd3 100644 (file)
@@ -23,6 +23,7 @@ from ctypes import c_char_p, c_void_p, c_long, c_uint
 from datetime import date
 from notmuch.globals import nmlib, STATUS, NotmuchError, Enum
 from notmuch.tag import Tags
 from datetime import date
 from notmuch.globals import nmlib, STATUS, NotmuchError, Enum
 from notmuch.tag import Tags
+from notmuch.filename import Filenames
 import sys
 import email
 import types
 import sys
 import email
 import types
@@ -244,6 +245,10 @@ class Message(object):
     _get_filename = nmlib.notmuch_message_get_filename
     _get_filename.restype = c_char_p 
 
     _get_filename = nmlib.notmuch_message_get_filename
     _get_filename.restype = c_char_p 
 
+    """return all filenames for a message"""
+    _get_filenames = nmlib.notmuch_message_get_filenames
+    _get_filenames.restype = c_void_p
+
     """notmuch_message_get_flag"""
     _get_flag = nmlib.notmuch_message_get_flag
     _get_flag.restype = c_uint
     """notmuch_message_get_flag"""
     _get_flag = nmlib.notmuch_message_get_flag
     _get_flag.restype = c_uint
@@ -400,6 +405,19 @@ class Message(object):
             raise NotmuchError(STATUS.NOT_INITIALIZED)
         return Message._get_filename(self._msg)
 
             raise NotmuchError(STATUS.NOT_INITIALIZED)
         return Message._get_filename(self._msg)
 
+    def get_filenames(self):
+        """Get all filenames for the email corresponding to 'message'
+
+        Returns a Filenames() generator with all absolute filepaths for
+        messages recorded to have the same Message-ID. These files must
+        not necessarily have identical content."""
+        if self._msg is None:
+            raise NotmuchError(STATUS.NOT_INITIALIZED)
+        
+        files_p = Message._get_filenames(self._msg)
+
+        return Filenames(files_p, self).as_generator()
+
     def get_flag(self, flag):
         """Checks whether a specific flag is set for this message
 
     def get_flag(self, flag):
         """Checks whether a specific flag is set for this message