]> git.notmuchmail.org Git - notmuch/blobdiff - bindings/python/notmuch/tag.py
emacs: Add new option notmuch-search-hide-excluded
[notmuch] / bindings / python / notmuch / tag.py
index 65a9118a6ce94d38c825e2f35e62a1a5838a9bef..fbb18ce47f004fe137a59ef13893f72481b276a9 100644 (file)
@@ -12,28 +12,36 @@ 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/>.
+along with notmuch.  If not, see <https://www.gnu.org/licenses/>.
 
-Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
+Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
 """
 from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError
-
-#------------------------------------------------------------------------------
-class Tags(object):
+from .globals import (
+    nmlib,
+    Python3StringMixIn,
+    NotmuchTagsP,
+)
+from .errors import (
+    NullPointerError,
+    NotInitializedError,
+)
+
+
+class Tags(Python3StringMixIn):
     """Represents a list of notmuch tags
 
     This object provides an iterator over a list of notmuch tags (which
-    are unicode instances). 
+    are unicode instances).
 
     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::
+    iteration attempt will raise a :exc:`NotInitializedError`.
+    Also note, that any function that uses iteration (nearly all) will
+    also exhaust the tags. So both::
 
-      for tag in tags: print tag 
+      for tag in tags: print tag
 
     as well as::
 
@@ -50,90 +58,84 @@ class Tags(object):
 
     #notmuch_tags_get
     _get = nmlib.notmuch_tags_get
+    _get.argtypes = [NotmuchTagsP]
     _get.restype = c_char_p
 
     def __init__(self, tags_p, parent=None):
         """
         :param tags_p: A pointer to an underlying *notmuch_tags_t*
-             structure. These are not publically exposed, so a user
+             structure. These are not publicly 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`.
+             valid, we will raise an :exc:`NullPointerError` if it is
+             `None`.
         :type tags_p: :class:`ctypes.c_void_p`
-        :param parent: The parent object (ie :class:`Database` or 
+        :param parent: The parent object (ie :class:`Database` or
              :class:`Message` these tags are derived from, and saves a
              reference to it, so we can automatically delete the db object
              once all derived objects are dead.
         :TODO: Make the iterator optionally work more than once by
                cache the tags in the Python object(?)
         """
-        if tags_p is None:
-            NotmuchError(STATUS.NULL_POINTER)
+        if not tags_p:
+            raise NullPointerError()
 
         self._tags = tags_p
         #save reference to parent object so we keep it alive
         self._parent = parent
-    
+
     def __iter__(self):
         """ Make Tags an iterator """
         return self
 
-    def next(self):
-        if self._tags is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
-        # No need to call nmlib.notmuch_tags_valid(self._tags);
-        # Tags._get safely returns None, if there is no more valid tag.
-        tag = Tags._get(self._tags).decode('utf-8')
-        if tag is None:
+    _valid = nmlib.notmuch_tags_valid
+    _valid.argtypes = [NotmuchTagsP]
+    _valid.restype = bool
+
+    _move_to_next = nmlib.notmuch_tags_move_to_next
+    _move_to_next.argtypes = [NotmuchTagsP]
+    _move_to_next.restype = None
+
+    def __next__(self):
+        if not self._tags:
+            raise NotInitializedError()
+        if not self._valid(self._tags):
             self._tags = None
             raise StopIteration
-        nmlib.notmuch_tags_move_to_next(self._tags)
+        tag = Tags._get(self._tags).decode('UTF-8')
+        self._move_to_next(self._tags)
         return tag
+    next = __next__ # python2.x iterator protocol compatibility
 
     def __nonzero__(self):
-        """Implement bool(Tags) check that can be repeatedly used
+        '''
+        Implement truth value testing. If __nonzero__ is not
+        implemented, the python runtime would fall back to `len(..) >
+        0` thus exhausting the iterator.
 
-        If __nonzero__ is not implemented, "if Tags()"
-        will implicitly call __len__, using up our iterator, so it is
-        important that this function is defined.
+        :returns: True if the wrapped iterator has at least one more object
+                  left.
+        '''
+        return self._tags and self._valid(self._tags)
 
-        :returns: True if the Tags() iterator has at least one more Tag
-            left."""
-        return nmlib.notmuch_tags_valid(self._tags) > 0
+    def __unicode__(self):
+        """string representation of :class:`Tags`: a space separated list of tags
 
-    def __len__(self):
-        """len(:class:`Tags`) returns the number of contained tags
+        .. note::
 
-        .. note:: As this iterates over the tags, 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.
-        """
-        if self._tags is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
-
-        i=0
-        while nmlib.notmuch_tags_valid(self._msgs):
-            nmlib.notmuch_tags_move_to_next(self._msgs)
-            i += 1
-        self._tags = None
-        return i
-
-    def __str__(self):
-        """The str() representation of Tags() is a space separated list of tags
-
-        .. note:: As this iterates over the tags, 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.
+            As this iterates over the tags, 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:`NotInitializedError`on subsequent
+            attempts.
         """
         return " ".join(self)
 
+    _destroy = nmlib.notmuch_tags_destroy
+    _destroy.argtypes = [NotmuchTagsP]
+    _destroy.restype = None
+
     def __del__(self):
         """Close and free the notmuch tags"""
-        if self._tags is not None:
-            nmlib.notmuch_tags_destroy (self._tags)
+        if self._tags:
+            self._destroy(self._tags)