bindings/python: Bump bindings version to 0.6
[notmuch] / bindings / python / notmuch / tag.py
1 """
2 This file is part of notmuch.
3
4 Notmuch is free software: you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation, either version 3 of the License, or (at your
7 option) any later version.
8
9 Notmuch is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
18 """
19 from ctypes import c_char_p
20 from notmuch.globals import nmlib, STATUS, NotmuchError
21
22 #------------------------------------------------------------------------------
23 class Tags(object):
24     """Represents a list of notmuch tags
25
26     This object provides an iterator over a list of notmuch tags. Do
27     note that the underlying library only provides a one-time iterator
28     (it cannot reset the iterator to the start). Thus iterating over
29     the function will "exhaust" the list of tags, and a subsequent
30     iteration attempt will raise a :exc:`NotmuchError`
31     STATUS.NOT_INITIALIZED. Also note, that any function that uses
32     iteration (nearly all) will also exhaust the tags. So both::
33
34       for tag in tags: print tag 
35
36     as well as::
37
38        number_of_tags = len(tags)
39
40     and even a simple::
41
42        #str() iterates over all tags to construct a space separated list
43        print(str(tags))
44
45     will "exhaust" the Tags. If you need to re-iterate over a list of
46     tags you will need to retrieve a new :class:`Tags` object.
47     """
48
49     #notmuch_tags_get
50     _get = nmlib.notmuch_tags_get
51     _get.restype = c_char_p
52
53     def __init__(self, tags_p, parent=None):
54         """
55         :param tags_p: A pointer to an underlying *notmuch_tags_t*
56              structure. These are not publically exposed, so a user
57              will almost never instantiate a :class:`Tags` object
58              herself. They are usually handed back as a result,
59              e.g. in :meth:`Database.get_all_tags`.  *tags_p* must be
60              valid, we will raise an :exc:`NotmuchError`
61              (STATUS.NULL_POINTER) if it is `None`.
62         :type tags_p: :class:`ctypes.c_void_p`
63         :param parent: The parent object (ie :class:`Database` or 
64              :class:`Message` these tags are derived from, and saves a
65              reference to it, so we can automatically delete the db object
66              once all derived objects are dead.
67         :TODO: Make the iterator optionally work more than once by
68                cache the tags in the Python object(?)
69         """
70         if tags_p is None:
71             NotmuchError(STATUS.NULL_POINTER)
72
73         self._tags = tags_p
74         #save reference to parent object so we keep it alive
75         self._parent = parent
76     
77     def __iter__(self):
78         """ Make Tags an iterator """
79         return self
80
81     def next(self):
82         if self._tags is None:
83             raise NotmuchError(STATUS.NOT_INITIALIZED)
84         # No need to call nmlib.notmuch_tags_valid(self._tags);
85         # Tags._get safely returns None, if there is no more valid tag.
86         tag = Tags._get (self._tags)
87         if tag is None:
88             self._tags = None
89             raise StopIteration
90         nmlib.notmuch_tags_move_to_next(self._tags)
91         return tag
92
93     def __nonzero__(self):
94         """Implement bool(Tags) check that can be repeatedly used
95
96         If __nonzero__ is not implemented, "if Tags()"
97         will implicitly call __len__, using up our iterator, so it is
98         important that this function is defined.
99
100         :returns: True if the Tags() iterator has at least one more Tag
101             left."""
102         return nmlib.notmuch_tags_valid(self._tags) > 0
103
104     def __len__(self):
105         """len(:class:`Tags`) returns the number of contained tags
106
107         .. note:: As this iterates over the tags, we will not be able
108                to iterate over them again (as in retrieve them)! If
109                the tags have been exhausted already, this will raise a
110                :exc:`NotmuchError` STATUS.NOT_INITIALIZED on
111                subsequent attempts.
112         """
113         if self._tags is None:
114             raise NotmuchError(STATUS.NOT_INITIALIZED)
115
116         i=0
117         while nmlib.notmuch_tags_valid(self._msgs):
118             nmlib.notmuch_tags_move_to_next(self._msgs)
119             i += 1
120         self._tags = None
121         return i
122
123     def __str__(self):
124         """The str() representation of Tags() is a space separated list of tags
125
126         .. note:: As this iterates over the tags, we will not be able
127                to iterate over them again (as in retrieve them)! If
128                the tags have been exhausted already, this will raise a
129                :exc:`NotmuchError` STATUS.NOT_INITIALIZED on
130                subsequent attempts.
131         """
132         return " ".join(self)
133
134     def __del__(self):
135         """Close and free the notmuch tags"""
136         if self._tags is not None:
137             nmlib.notmuch_tags_destroy (self._tags)