unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
blob bdc18790abca01280acb6c95d02f3192481b2190 8202 bytes (raw)
name: bindings/python/notmuch/query.py 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
 
"""
This file is part of notmuch.

Notmuch is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

Notmuch is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with notmuch.  If not, see <https://www.gnu.org/licenses/>.

Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
"""

from ctypes import c_char_p, c_uint, POINTER, byref
from .globals import (
    nmlib,
    Enum,
    _str,
    NotmuchQueryP,
    NotmuchThreadsP,
    NotmuchDatabaseP,
    NotmuchMessagesP,
)
from .errors import (
    NotmuchError,
    NullPointerError,
    NotInitializedError,
)
from .threads import Threads
from .messages import Messages


class Query(object):
    """Represents a search query on an opened :class:`Database`.

    A query selects and filters a subset of messages from the notmuch
    database we derive from.

    :class:`Query` provides an instance attribute :attr:`sort`, which
    contains the sort order (if specified via :meth:`set_sort`) or
    `None`.

    Any function in this class may throw an :exc:`NotInitializedError`
    in case the underlying query object was not set up correctly.

    .. note:: Do remember that as soon as we tear down this object,
           all underlying derived objects such as threads,
           messages, tags etc will be freed by the underlying library
           as well. Accessing these objects will lead to segfaults and
           other unexpected behavior. See above for more details.
    """
    # constants
    SORT = Enum(['OLDEST_FIRST', 'NEWEST_FIRST', 'MESSAGE_ID', 'UNSORTED'])
    """Constants: Sort order in which to return results"""

    def __init__(self, db, querystr):
        """
        :param db: An open database which we derive the Query from.
        :type db: :class:`Database`
        :param querystr: The query string for the message.
        :type querystr: utf-8 encoded str or unicode
        """
        self._db = None
        self._query = None
        self.sort = None
        self.create(db, querystr)

    def _assert_query_is_initialized(self):
        """Raises :exc:`NotInitializedError` if self._query is `None`"""
        if not self._query:
            raise NotInitializedError()

    """notmuch_query_create"""
    _create = nmlib.notmuch_query_create
    _create.argtypes = [NotmuchDatabaseP, c_char_p]
    _create.restype = NotmuchQueryP

    def create(self, db, querystr):
        """Creates a new query derived from a Database

        This function is utilized by __init__() and usually does not need to
        be called directly.

        :param db: Database to create the query from.
        :type db: :class:`Database`
        :param querystr: The query string
        :type querystr: utf-8 encoded str or unicode
        :raises:
            :exc:`NullPointerError` if the query creation failed
                (e.g. too little memory).
            :exc:`NotInitializedError` if the underlying db was not
                intitialized.
        """
        db._assert_db_is_initialized()
        # create reference to parent db to keep it alive
        self._db = db
        # create query, return None if too little mem available
        query_p = Query._create(db._db, _str(querystr))
        if not query_p:
            raise NullPointerError
        self._query = query_p

    _set_sort = nmlib.notmuch_query_set_sort
    _set_sort.argtypes = [NotmuchQueryP, c_uint]
    _set_sort.restype = None

    def set_sort(self, sort):
        """Set the sort order future results will be delivered in

        :param sort: Sort order (see :attr:`Query.SORT`)
        """
        self._assert_query_is_initialized()
        self.sort = sort
        self._set_sort(self._query, sort)

    _exclude_tag = nmlib.notmuch_query_add_tag_exclude
    _exclude_tag.argtypes = [NotmuchQueryP, c_char_p]
    _exclude_tag.restype = None

    def exclude_tag(self, tagname):
        """Add a tag that will be excluded from the query results by default.

        This exclusion will be overridden if this tag appears explicitly in the
        query.

        :param tagname: Name of the tag to be excluded
        """
        self._assert_query_is_initialized()
        self._exclude_tag(self._query, _str(tagname))

    """notmuch_query_search_threads"""
    _search_threads = nmlib.notmuch_query_search_threads
    _search_threads.argtypes = [NotmuchQueryP, POINTER(NotmuchThreadsP)]
    _search_threads.restype = c_uint

    def search_threads(self):
        r"""Execute a query for threads

        Execute a query for threads, returning a :class:`Threads` iterator.
        The returned threads are owned by the query and as such, will only be
        valid until the Query is deleted.

        The method sets :attr:`Message.FLAG`\.MATCH for those messages that
        match the query. The method :meth:`Message.get_flag` allows us
        to get the value of this flag.

        :returns: :class:`Threads`
        :raises: :exc:`NullPointerError` if search_threads failed
        """
        self._assert_query_is_initialized()
        threads_p = NotmuchThreadsP() # == NULL
        status = Query._search_threads(self._query, byref(threads_p))
        if status != 0:
            raise NotmuchError(status)

        if not threads_p:
            raise NullPointerError
        return Threads(threads_p, self)

    """notmuch_query_search_messages_st"""
    _search_messages = nmlib.notmuch_query_search_messages
    _search_messages.argtypes = [NotmuchQueryP, POINTER(NotmuchMessagesP)]
    _search_messages.restype = c_uint

    def search_messages(self):
        """Filter messages according to the query and return
        :class:`Messages` in the defined sort order

        :returns: :class:`Messages`
        :raises: :exc:`NullPointerError` if search_messages failed
        """
        self._assert_query_is_initialized()
        msgs_p = NotmuchMessagesP() # == NULL
        status = Query._search_messages(self._query, byref(msgs_p))
        if status != 0:
            raise NotmuchError(status)

        if not msgs_p:
            raise NullPointerError
        return Messages(msgs_p, self)

    _count_messages = nmlib.notmuch_query_count_messages
    _count_messages.argtypes = [NotmuchQueryP, POINTER(c_uint)]
    _count_messages.restype = c_uint

    def count_messages(self):
        '''
        This function performs a search and returns Xapian's best
        guess as to the number of matching messages.

        :returns: the estimated number of messages matching this query
        :rtype:   int
        '''
        self._assert_query_is_initialized()
        count = c_uint(0)
        status = Query._count_messages(self._query, byref(count))
        if status != 0:
            raise NotmuchError(status)
        return count.value

    _count_threads = nmlib.notmuch_query_count_threads
    _count_threads.argtypes = [NotmuchQueryP, POINTER(c_uint)]
    _count_threads.restype = c_uint

    def count_threads(self):
        '''
        This function performs a search and returns the number of
        unique thread IDs in the matching messages. This is the same
        as number of threads matching a search.

        Note that this is a significantly heavier operation than
        meth:`Query.count_messages`.

        :returns: the number of threads returned by this query
        :rtype:   int
        '''
        self._assert_query_is_initialized()
        count = c_uint(0)
        status = Query._count_threads(self._query, byref(count))
        if status != 0:
            raise NotmuchError(status)
        return count.value

    _destroy = nmlib.notmuch_query_destroy
    _destroy.argtypes = [NotmuchQueryP]
    _destroy.restype = None

    def __del__(self):
        """Close and free the Query"""
        if self._query:
            self._destroy(self._query)

debug log:

solving bdc18790 ...
found bdc18790 in https://yhetil.org/notmuch.git/

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).