2 This file is part of notmuch.
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.
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
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/>.
17 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
20 from notmuch.globals import (
30 from .thread import Thread
32 class Threads(Python3StringMixIn):
33 """Represents a list of notmuch threads
35 This object provides an iterator over a list of notmuch threads
36 (Technically, it provides a wrapper for the underlying
37 *notmuch_threads_t* structure). Do note that the underlying
38 library only provides a one-time iterator (it cannot reset the
39 iterator to the start). Thus iterating over the function will
40 "exhaust" the list of threads, and a subsequent iteration attempt
41 will raise a :exc:`NotInitializedError`. Also
42 note, that any function that uses iteration will also
43 exhaust the messages. So both::
45 for thread in threads: print thread
49 number_of_msgs = len(threads)
51 will "exhaust" the threads. If you need to re-iterate over a list of
52 messages you will need to retrieve a new :class:`Threads` object.
54 Things are not as bad as it seems though, you can store and reuse
55 the single Thread objects as often as you want as long as you
56 keep the parent Threads object around. (Recall that due to
57 hierarchical memory allocation, all derived Threads objects will
58 be invalid when we delete the parent Threads() object, even if it
59 was already "exhausted".) So this works::
62 threads = Query(db,'').search_threads() #get a Threads() object
64 for thread in threads:
65 threadlist.append(thread)
67 # threads is "exhausted" now and even len(threads) will raise an
69 # However it will be kept around until all retrieved Thread() objects are
70 # also deleted. If you did e.g. an explicit del(threads) here, the
71 # following lines would fail.
73 # You can reiterate over *threadlist* however as often as you want.
74 # It is simply a list with Thread objects.
76 print (threadlist[0].get_thread_id())
77 print (threadlist[1].get_thread_id())
78 print (threadlist[0].get_total_messages())
82 _get = nmlib.notmuch_threads_get
83 _get.argtypes = [NotmuchThreadsP]
84 _get.restype = NotmuchThreadP
86 def __init__(self, threads_p, parent=None):
88 :param threads_p: A pointer to an underlying *notmuch_threads_t*
89 structure. These are not publically exposed, so a user
90 will almost never instantiate a :class:`Threads` object
91 herself. They are usually handed back as a result,
92 e.g. in :meth:`Query.search_threads`. *threads_p* must be
93 valid, we will raise an :exc:`NullPointerError` if it is
95 :type threads_p: :class:`ctypes.c_void_p`
96 :param parent: The parent object
97 (ie :class:`Query`) these tags are derived from. It saves
98 a reference to it, so we can automatically delete the db
99 object once all derived objects are dead.
100 :TODO: Make the iterator work more than once and cache the tags in
101 the Python object.(?)
104 raise NullPointerError()
106 self._threads = threads_p
107 #store parent, so we keep them alive as long as self is alive
108 self._parent = parent
111 """ Make Threads an iterator """
114 _valid = nmlib.notmuch_threads_valid
115 _valid.argtypes = [NotmuchThreadsP]
116 _valid.restype = bool
118 _move_to_next = nmlib.notmuch_threads_move_to_next
119 _move_to_next.argtypes = [NotmuchThreadsP]
120 _move_to_next.restype = None
123 if not self._threads:
124 raise NotInitializedError()
126 if not self._valid(self._threads):
130 thread = Thread(Threads._get(self._threads), self)
131 self._move_to_next(self._threads)
133 next = __next__ # python2.x iterator protocol compatibility
136 """len(:class:`Threads`) returns the number of contained Threads
138 .. note:: As this iterates over the threads, we will not be able to
139 iterate over them again! So this will fail::
142 threads = Database().create_query('').search_threads()
143 if len(threads) > 0: #this 'exhausts' threads
144 # next line raises :exc:`NotInitializedError`!!!
145 for thread in threads: print thread
147 if not self._threads:
148 raise NotInitializedError()
151 # returns 'bool'. On out-of-memory it returns None
152 while self._valid(self._threads):
153 self._move_to_next(self._threads)
155 # reset self._threads to mark as "exhausted"
159 def __nonzero__(self):
161 Implement truth value testing. If __nonzero__ is not
162 implemented, the python runtime would fall back to `len(..) >
163 0` thus exhausting the iterator.
165 :returns: True if the wrapped iterator has at least one more object
168 return self._threads and self._valid(self._threads)
170 _destroy = nmlib.notmuch_threads_destroy
171 _destroy.argtypes = [NotmuchThreadsP]
172 _destroy.restype = None
175 """Close and free the notmuch Threads"""
177 self._destroy(self._threads)