From b31247c354b54a3cbeb1c7f9df830e16f7c921d9 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Thu, 2 Jun 2011 08:56:03 +0200 Subject: [PATCH] bindings/python: Implement Message().get_filenames() 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 --- bindings/python/notmuch/filename.py | 108 ++++++++++++++++++++++++++++ bindings/python/notmuch/message.py | 18 +++++ 2 files changed, 126 insertions(+) create mode 100644 bindings/python/notmuch/filename.py diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py new file mode 100644 index 00000000..20b90e98 --- /dev/null +++ b/bindings/python/notmuch/filename.py @@ -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 . + +Copyright 2010 Sebastian Spaeth ' +""" +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) diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index ac85cbb4..340c0b8b 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -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 notmuch.filename import Filenames 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 + """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 @@ -400,6 +405,19 @@ class Message(object): 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 -- 2.43.0