]> git.notmuchmail.org Git - notmuch/blob - bindings/python-cffi/notmuch2/_thread.py
Rename package to notmuch2
[notmuch] / bindings / python-cffi / notmuch2 / _thread.py
1 import collections.abc
2 import weakref
3
4 from notmuch2 import _base as base
5 from notmuch2 import _capi as capi
6 from notmuch2 import _errors as errors
7 from notmuch2 import _message as message
8 from notmuch2 import _tags as tags
9
10
11 __all__ = ['Thread']
12
13
14 class Thread(base.NotmuchObject, collections.abc.Iterable):
15     _thread_p = base.MemoryPointer()
16
17     def __init__(self, parent, thread_p, *, db):
18         self._parent = parent
19         self._thread_p = thread_p
20         self._db = db
21
22     @property
23     def alive(self):
24         if not self._parent.alive:
25             return False
26         try:
27             self._thread_p
28         except errors.ObjectDestroyedError:
29             return False
30         else:
31             return True
32
33     def __del__(self):
34         self._destroy()
35
36     def _destroy(self):
37         if self.alive:
38             capi.lib.notmuch_thread_destroy(self._thread_p)
39         self._thread_p = None
40
41     @property
42     def threadid(self):
43         """The thread ID as a :class:`BinString`.
44
45         :raises ObjectDestroyedError: if used after destoryed.
46         """
47         ret = capi.lib.notmuch_thread_get_thread_id(self._thread_p)
48         return base.BinString.from_cffi(ret)
49
50     def __len__(self):
51         """Return the number of messages in the thread.
52
53         :raises ObjectDestroyedError: if used after destoryed.
54         """
55         return capi.lib.notmuch_thread_get_total_messages(self._thread_p)
56
57     def toplevel(self):
58         """Return an iterator of the toplevel messages.
59
60         :returns: An iterator yielding :class:`Message` instances.
61
62         :raises ObjectDestroyedError: if used after destoryed.
63         """
64         msgs_p = capi.lib.notmuch_thread_get_toplevel_messages(self._thread_p)
65         return message.MessageIter(self, msgs_p, db=self._db)
66
67     def __iter__(self):
68         """Return an iterator over all the messages in the thread.
69
70         :returns: An iterator yielding :class:`Message` instances.
71
72         :raises ObjectDestroyedError: if used after destoryed.
73         """
74         msgs_p = capi.lib.notmuch_thread_get_messages(self._thread_p)
75         return message.MessageIter(self, msgs_p, db=self._db)
76
77     @property
78     def matched(self):
79         """The number of messages in this thread which matched the query.
80
81         Of the messages in the thread this gives the count of messages
82         which did directly match the search query which this thread
83         originates from.
84
85         :raises ObjectDestroyedError: if used after destoryed.
86         """
87         return capi.lib.notmuch_thread_get_matched_messages(self._thread_p)
88
89     @property
90     def authors(self):
91         """A comma-separated string of all authors in the thread.
92
93         Authors of messages which matched the query the thread was
94         retrieved from will be at the head of the string, ordered by
95         date of their messages.  Following this will be the authors of
96         the other messages in the thread, also ordered by date of
97         their messages.  Both groups of authors are separated by the
98         ``|`` character.
99
100         :returns: The stringified list of authors.
101         :rtype: BinString
102
103         :raises ObjectDestroyedError: if used after destoryed.
104         """
105         ret = capi.lib.notmuch_thread_get_authors(self._thread_p)
106         return base.BinString.from_cffi(ret)
107
108     @property
109     def subject(self):
110         """The subject of the thread, taken from the first message.
111
112         The thread's subject is taken to be the subject of the first
113         message according to query sort order.
114
115         :returns: The thread's subject.
116         :rtype: BinString
117
118         :raises ObjectDestroyedError: if used after destoryed.
119         """
120         ret = capi.lib.notmuch_thread_get_subject(self._thread_p)
121         return base.BinString.from_cffi(ret)
122
123     @property
124     def first(self):
125         """Return the date of the oldest message in the thread.
126
127         The time the first message was sent as an integer number of
128         seconds since the *epoch*, 1 Jan 1970.
129
130         :raises ObjectDestroyedError: if used after destoryed.
131         """
132         return capi.lib.notmuch_thread_get_oldest_date(self._thread_p)
133
134     @property
135     def last(self):
136         """Return the date of the newest message in the thread.
137
138         The time the last message was sent as an integer number of
139         seconds since the *epoch*, 1 Jan 1970.
140
141         :raises ObjectDestroyedError: if used after destoryed.
142         """
143         return capi.lib.notmuch_thread_get_newest_date(self._thread_p)
144
145     @property
146     def tags(self):
147         """Return an immutable set with all tags used in this thread.
148
149         This returns an immutable set-like object implementing the
150         collections.abc.Set Abstract Base Class.  Due to the
151         underlying libnotmuch implementation some operations have
152         different performance characteristics then plain set objects.
153         Mainly any lookup operation is O(n) rather then O(1).
154
155         Normal usage treats tags as UTF-8 encoded unicode strings so
156         they are exposed to Python as normal unicode string objects.
157         If you need to handle tags stored in libnotmuch which are not
158         valid unicode do check the :class:`ImmutableTagSet` docs for
159         how to handle this.
160
161         :rtype: ImmutableTagSet
162
163         :raises ObjectDestroyedError: if used after destoryed.
164         """
165         try:
166             ref = self._cached_tagset
167         except AttributeError:
168             tagset = None
169         else:
170             tagset = ref()
171         if tagset is None:
172             tagset = tags.ImmutableTagSet(
173                 self, '_thread_p', capi.lib.notmuch_thread_get_tags)
174             self._cached_tagset = weakref.ref(tagset)
175         return tagset
176
177
178 class ThreadIter(base.NotmuchIter):
179
180     def __init__(self, parent, threads_p, *, db):
181         self._db = db
182         super().__init__(parent, threads_p,
183                          fn_destroy=capi.lib.notmuch_threads_destroy,
184                          fn_valid=capi.lib.notmuch_threads_valid,
185                          fn_get=capi.lib.notmuch_threads_get,
186                          fn_next=capi.lib.notmuch_threads_move_to_next)
187
188     def __next__(self):
189         thread_p = super().__next__()
190         return Thread(self, thread_p, db=self._db)