]> git.notmuchmail.org Git - notmuch/blob - bindings/python/notmuch/filenames.py
python: update the docstring of class Filenames
[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:: As this iterates over the filenames, we will not be
119                able to iterate over them again (as in retrieve them)! If
120                the tags have been exhausted already, this will raise a
121                :exc:`NotInitializedError` on subsequent
122                attempts. However, you can use
123                :meth:`Message.get_filenames` repeatedly to perform
124                various actions on filenames.
125         """
126         return "\n".join(self)
127
128     _destroy = nmlib.notmuch_filenames_destroy
129     _destroy.argtypes = [NotmuchMessageP]
130     _destroy.restype = None
131
132     def __del__(self):
133         """Close and free the notmuch filenames"""
134         if self._files_p is not None:
135             self._destroy(self._files_p)
136
137     def __len__(self):
138         """len(:class:`Filenames`) returns the number of contained files
139
140         .. note::
141
142             As this iterates over the files, we will not be able to
143             iterate over them again! So this will fail::
144
145                  #THIS FAILS
146                  files = Database().get_directory('').get_child_files()
147                  if len(files) > 0:  # this 'exhausts' msgs
148                      # next line raises
149                      # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)
150                      for file in files: print file
151         """
152         if not self._files_p:
153             raise NotInitializedError()
154
155         i = 0
156         while self._valid(self._files_p):
157             self._move_to_next(self._files_p)
158             i += 1
159         self._files_p = None
160         return i