]> git.notmuchmail.org Git - notmuch/blob - bindings/python/notmuch/filenames.py
python: update the docstrings of Filenames.{__len__,__unicode}
[notmuch] / bindings / python / notmuch / filenames.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 (
21     nmlib,
22     NotmuchMessageP,
23     NotmuchFilenamesP,
24     Python3StringMixIn,
25 )
26 from .errors import (
27     NullPointerError,
28     NotInitializedError,
29 )
30
31
32 class Filenames(Python3StringMixIn):
33     """Represents a list of filenames as returned by notmuch
34
35     Objects of this class implement the iterator protocol.
36
37     .. note::
38
39         The underlying library only provides a one-time iterator (it
40         cannot reset the iterator to the start). Thus iterating over
41         the function will "exhaust" the list of tags, and a subsequent
42         iteration attempt will raise a
43         :exc:`NotInitializedError`. Also note, that any function that
44         uses iteration (nearly all) will also exhaust the tags. So
45         both::
46
47            for name in filenames: print name
48
49         as well as::
50
51            number_of_names = len(names)
52
53         and even a simple::
54
55            #str() iterates over all tags to construct a space separated list
56            print(str(filenames))
57
58         will "exhaust" the Filenames. However, you can use
59         :meth:`Message.get_filenames` repeatedly to get fresh
60         Filenames objects to perform various actions on filenames.
61     """
62
63     #notmuch_filenames_get
64     _get = nmlib.notmuch_filenames_get
65     _get.argtypes = [NotmuchFilenamesP]
66     _get.restype = c_char_p
67
68     def __init__(self, files_p, parent):
69         """
70         :param files_p: A pointer to an underlying *notmuch_tags_t*
71              structure. These are not publically exposed, so a user
72              will almost never instantiate a :class:`Tags` object
73              herself. They are usually handed back as a result,
74              e.g. in :meth:`Database.get_all_tags`.  *tags_p* must be
75              valid, we will raise an :exc:`NullPointerError`
76              if it is `None`.
77         :type files_p: :class:`ctypes.c_void_p`
78         :param parent: The parent object (ie :class:`Message` these
79              filenames are derived from, and saves a
80              reference to it, so we can automatically delete the db object
81              once all derived objects are dead.
82         """
83         if not files_p:
84             raise NullPointerError()
85
86         self._files_p = files_p
87         #save reference to parent object so we keep it alive
88         self._parent = parent
89
90     def __iter__(self):
91         """ Make Filenames an iterator """
92         return self
93
94     _valid = nmlib.notmuch_filenames_valid
95     _valid.argtypes = [NotmuchFilenamesP]
96     _valid.restype = bool
97
98     _move_to_next = nmlib.notmuch_filenames_move_to_next
99     _move_to_next.argtypes = [NotmuchFilenamesP]
100     _move_to_next.restype = None
101
102     def __next__(self):
103         if not self._files_p:
104             raise NotInitializedError()
105
106         if not self._valid(self._files_p):
107             self._files_p = None
108             raise StopIteration
109
110         file_ = Filenames._get(self._files_p)
111         self._move_to_next(self._files_p)
112         return file_.decode('utf-8', 'ignore')
113     next = __next__ # python2.x iterator protocol compatibility
114
115     def __unicode__(self):
116         """Represent Filenames() as newline-separated list of full paths
117
118         .. note::
119
120             This method exhausts the iterator object, so you will not be able to
121             iterate over them again.
122         """
123         return "\n".join(self)
124
125     _destroy = nmlib.notmuch_filenames_destroy
126     _destroy.argtypes = [NotmuchMessageP]
127     _destroy.restype = None
128
129     def __del__(self):
130         """Close and free the notmuch filenames"""
131         if self._files_p is not None:
132             self._destroy(self._files_p)
133
134     def __len__(self):
135         """len(:class:`Filenames`) returns the number of contained files
136
137         .. note::
138
139             This method exhausts the iterator object, so you will not be able to
140             iterate over them again.
141         """
142         if not self._files_p:
143             raise NotInitializedError()
144
145         i = 0
146         while self._valid(self._files_p):
147             self._move_to_next(self._files_p)
148             i += 1
149         self._files_p = None
150         return i