mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-12-23 09:54:52 +01:00
Implement Thread() and Threads()
Most of Thread() is implemented now and all of Threads(). Reorganized the source somewhat and various minor fixes throughout.
This commit is contained in:
parent
bb57345740
commit
2a14b523b0
4 changed files with 478 additions and 119 deletions
|
@ -1,6 +1,8 @@
|
|||
import ctypes, os
|
||||
from ctypes import c_int, c_char_p, c_void_p, c_uint, c_uint64, c_bool, byref
|
||||
from cnotmuch.globals import nmlib, STATUS, NotmuchError, Enum
|
||||
from cnotmuch.thread import Thread, Threads
|
||||
from cnotmuch.tags import Tags
|
||||
import logging
|
||||
from datetime import date
|
||||
|
||||
|
@ -355,6 +357,10 @@ class Query(object):
|
|||
A query selects and filters a subset of messages from the notmuch
|
||||
database we derive from.
|
||||
|
||||
Query() provides an instance attribute :attr:`sort`, which
|
||||
contains the sort order (if specified via :meth:`set_sort`) or
|
||||
`None`.
|
||||
|
||||
Technically, it wraps the underlying *notmuch_query_t* struct.
|
||||
|
||||
.. note:: Do remember that as soon as we tear down this object,
|
||||
|
@ -371,6 +377,10 @@ class Query(object):
|
|||
_create = nmlib.notmuch_query_create
|
||||
_create.restype = c_void_p
|
||||
|
||||
"""notmuch_query_search_threads"""
|
||||
_search_threads = nmlib.notmuch_query_search_threads
|
||||
_search_threads.restype = c_void_p
|
||||
|
||||
"""notmuch_query_search_messages"""
|
||||
_search_messages = nmlib.notmuch_query_search_messages
|
||||
_search_messages.restype = c_void_p
|
||||
|
@ -389,6 +399,7 @@ class Query(object):
|
|||
"""
|
||||
self._db = None
|
||||
self._query = None
|
||||
self.sort = None
|
||||
self.create(db, querystr)
|
||||
|
||||
def create(self, db, querystr):
|
||||
|
@ -432,8 +443,35 @@ class Query(object):
|
|||
if self._query is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
self.sort = sort
|
||||
nmlib.notmuch_query_set_sort(self._query, sort)
|
||||
|
||||
def search_threads(self):
|
||||
"""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.
|
||||
|
||||
Technically, it wraps the underlying
|
||||
*notmuch_query_search_threads* function.
|
||||
|
||||
:returns: :class:`Threads`
|
||||
:exception: :exc:`NotmuchError`
|
||||
|
||||
* STATUS.NOT_INITIALIZED if query is not inited
|
||||
* STATUS.NULL_POINTER if search_messages failed
|
||||
"""
|
||||
if self._query is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
threads_p = Query._search_threads(self._query)
|
||||
|
||||
if threads_p is None:
|
||||
NotmuchError(STATUS.NULL_POINTER)
|
||||
|
||||
return Threads(threads_p,self)
|
||||
|
||||
def search_messages(self):
|
||||
"""Filter messages according to the query and return
|
||||
:class:`Messages` in the defined sort order
|
||||
|
@ -483,115 +521,6 @@ class Query(object):
|
|||
logging.debug("Freeing the Query now")
|
||||
nmlib.notmuch_query_destroy (self._query)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
class Tags(object):
|
||||
"""Represents a list of notmuch tags
|
||||
|
||||
This object provides an iterator over a list of notmuch tags. Do
|
||||
note that the underlying library only provides a one-time iterator
|
||||
(it cannot reset the iterator to the start). Thus iterating over
|
||||
the function will "exhaust" the list of tags, and a subsequent
|
||||
iteration attempt will raise a :exc:`NotmuchError`
|
||||
STATUS.NOT_INITIALIZED. Also note, that any function that uses
|
||||
iteration (nearly all) will also exhaust the tags. So both::
|
||||
|
||||
for tag in tags: print tag
|
||||
|
||||
as well as::
|
||||
|
||||
number_of_tags = len(tags)
|
||||
|
||||
and even a simple::
|
||||
|
||||
#str() iterates over all tags to construct a space separated list
|
||||
print(str(tags))
|
||||
|
||||
will "exhaust" the Tags. If you need to re-iterate over a list of
|
||||
tags you will need to retrieve a new :class:`Tags` object.
|
||||
"""
|
||||
|
||||
#notmuch_tags_get
|
||||
_get = nmlib.notmuch_tags_get
|
||||
_get.restype = c_char_p
|
||||
|
||||
def __init__(self, tags_p, parent=None):
|
||||
"""
|
||||
:param tags_p: A pointer to an underlying *notmuch_tags_t*
|
||||
structure. These are not publically exposed, so a user
|
||||
will almost never instantiate a :class:`Tags` object
|
||||
herself. They are usually handed back as a result,
|
||||
e.g. in :meth:`Database.get_all_tags`. *tags_p* must be
|
||||
valid, we will raise an :exc:`NotmuchError`
|
||||
(STATUS.NULL_POINTER) if it is `None`.
|
||||
:type tags_p: :class:`ctypes.c_void_p`
|
||||
:param parent: The parent object (ie :class:`Database` or
|
||||
:class:`Message` these tags are derived from, and saves a
|
||||
reference to it, so we can automatically delete the db object
|
||||
once all derived objects are dead.
|
||||
:TODO: Make the iterator optionally work more than once by
|
||||
cache the tags in the Python object(?)
|
||||
"""
|
||||
if tags_p is None:
|
||||
NotmuchError(STATUS.NULL_POINTER)
|
||||
|
||||
self._tags = tags_p
|
||||
#save reference to parent object so we keep it alive
|
||||
self._parent = parent
|
||||
logging.debug("Inited Tags derived from %s" %(repr(parent)))
|
||||
|
||||
def __iter__(self):
|
||||
""" Make Tags an iterator """
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self._tags is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
if not nmlib.notmuch_tags_valid(self._tags):
|
||||
self._tags = None
|
||||
raise StopIteration
|
||||
|
||||
tag = Tags._get (self._tags)
|
||||
nmlib.notmuch_tags_move_to_next(self._tags)
|
||||
return tag
|
||||
|
||||
def __len__(self):
|
||||
"""len(:class:`Tags`) returns the number of contained tags
|
||||
|
||||
.. note:: As this iterates over the tags, we will not be able
|
||||
to iterate over them again (as in retrieve them)! If
|
||||
the tags have been exhausted already, this will raise a
|
||||
:exc:`NotmuchError` STATUS.NOT_INITIALIZED on
|
||||
subsequent attempts.
|
||||
"""
|
||||
if self._tags is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
i=0
|
||||
while nmlib.notmuch_tags_valid(self._msgs):
|
||||
nmlib.notmuch_tags_move_to_next(self._msgs)
|
||||
i += 1
|
||||
self._tags = None
|
||||
return i
|
||||
|
||||
def __str__(self):
|
||||
"""The str() representation of Tags() is a space separated list of tags
|
||||
|
||||
.. note:: As this iterates over the tags, we will not be able
|
||||
to iterate over them again (as in retrieve them)! If
|
||||
the tags have been exhausted already, this will raise a
|
||||
:exc:`NotmuchError` STATUS.NOT_INITIALIZED on
|
||||
subsequent attempts.
|
||||
"""
|
||||
return " ".join(self)
|
||||
|
||||
def __del__(self):
|
||||
"""Close and free the notmuch tags"""
|
||||
if self._tags is not None:
|
||||
logging.debug("Freeing the Tags now")
|
||||
nmlib.notmuch_tags_destroy (self._tags)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
class Messages(object):
|
||||
"""Represents a list of notmuch messages
|
||||
|
@ -721,6 +650,12 @@ class Messages(object):
|
|||
if len(msgs) > 0: #this 'exhausts' msgs
|
||||
# next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!!
|
||||
for msg in msgs: print msg
|
||||
|
||||
Most of the time, using the
|
||||
:meth:`Query.count_messages` is therefore more
|
||||
appropriate (and much faster). While not guaranteeing
|
||||
that it will return the exact same number than len(),
|
||||
in my tests it effectively always did so.
|
||||
"""
|
||||
if self._msgs is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
@ -855,7 +790,7 @@ class Message(object):
|
|||
message call notmuch_message_get_header() with a header value of
|
||||
"date".
|
||||
|
||||
:returns: a time_t timestamp
|
||||
:returns: A time_t timestamp.
|
||||
:rtype: c_unit64
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
|
||||
is not initialized.
|
||||
|
@ -892,7 +827,7 @@ class Message(object):
|
|||
return header
|
||||
|
||||
def get_filename(self):
|
||||
"""Return the file path of the message file
|
||||
"""Returns the file path of the message file
|
||||
|
||||
:returns: Absolute file path & name of the message file
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
|
||||
|
@ -903,10 +838,9 @@ class Message(object):
|
|||
return Message._get_filename(self._msg)
|
||||
|
||||
def get_tags(self):
|
||||
""" Return the message tags
|
||||
"""Returns the message tags
|
||||
|
||||
:returns: Message tags
|
||||
:rtype: :class:`Tags`
|
||||
:returns: A :class:`Tags` iterator.
|
||||
:exception: :exc:`NotmuchError`
|
||||
|
||||
* STATUS.NOT_INITIALIZED if the message
|
||||
|
@ -922,7 +856,7 @@ class Message(object):
|
|||
return Tags(tags_p, self)
|
||||
|
||||
def add_tag(self, tag):
|
||||
"""Add a tag to the given message
|
||||
"""Adds a tag to the given message
|
||||
|
||||
Adds a tag to the current message. The maximal tag length is defined in
|
||||
the notmuch library and is currently 200 bytes.
|
||||
|
|
|
@ -34,9 +34,7 @@ Many of its objects use python's logging module to log some output at DEBUG leve
|
|||
:class:`Message`, and :class:`Tags`.
|
||||
|
||||
"""
|
||||
import ctypes
|
||||
from ctypes import c_int, c_char_p
|
||||
from database import Database,Tags,Query,Messages,Message,Tags
|
||||
from database import Database, Query
|
||||
from cnotmuch.globals import nmlib, STATUS, NotmuchError
|
||||
__LICENSE__="GPL v3+"
|
||||
__VERSION__='0.1.1'
|
||||
|
|
108
cnotmuch/tags.py
Normal file
108
cnotmuch/tags.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
from ctypes import c_char_p
|
||||
from cnotmuch.globals import nmlib, STATUS, NotmuchError
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
class Tags(object):
|
||||
"""Represents a list of notmuch tags
|
||||
|
||||
This object provides an iterator over a list of notmuch tags. Do
|
||||
note that the underlying library only provides a one-time iterator
|
||||
(it cannot reset the iterator to the start). Thus iterating over
|
||||
the function will "exhaust" the list of tags, and a subsequent
|
||||
iteration attempt will raise a :exc:`NotmuchError`
|
||||
STATUS.NOT_INITIALIZED. Also note, that any function that uses
|
||||
iteration (nearly all) will also exhaust the tags. So both::
|
||||
|
||||
for tag in tags: print tag
|
||||
|
||||
as well as::
|
||||
|
||||
number_of_tags = len(tags)
|
||||
|
||||
and even a simple::
|
||||
|
||||
#str() iterates over all tags to construct a space separated list
|
||||
print(str(tags))
|
||||
|
||||
will "exhaust" the Tags. If you need to re-iterate over a list of
|
||||
tags you will need to retrieve a new :class:`Tags` object.
|
||||
"""
|
||||
|
||||
#notmuch_tags_get
|
||||
_get = nmlib.notmuch_tags_get
|
||||
_get.restype = c_char_p
|
||||
|
||||
def __init__(self, tags_p, parent=None):
|
||||
"""
|
||||
:param tags_p: A pointer to an underlying *notmuch_tags_t*
|
||||
structure. These are not publically exposed, so a user
|
||||
will almost never instantiate a :class:`Tags` object
|
||||
herself. They are usually handed back as a result,
|
||||
e.g. in :meth:`Database.get_all_tags`. *tags_p* must be
|
||||
valid, we will raise an :exc:`NotmuchError`
|
||||
(STATUS.NULL_POINTER) if it is `None`.
|
||||
:type tags_p: :class:`ctypes.c_void_p`
|
||||
:param parent: The parent object (ie :class:`Database` or
|
||||
:class:`Message` these tags are derived from, and saves a
|
||||
reference to it, so we can automatically delete the db object
|
||||
once all derived objects are dead.
|
||||
:TODO: Make the iterator optionally work more than once by
|
||||
cache the tags in the Python object(?)
|
||||
"""
|
||||
if tags_p is None:
|
||||
NotmuchError(STATUS.NULL_POINTER)
|
||||
|
||||
self._tags = tags_p
|
||||
#save reference to parent object so we keep it alive
|
||||
self._parent = parent
|
||||
|
||||
def __iter__(self):
|
||||
""" Make Tags an iterator """
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self._tags is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
if not nmlib.notmuch_tags_valid(self._tags):
|
||||
self._tags = None
|
||||
raise StopIteration
|
||||
|
||||
tag = Tags._get (self._tags)
|
||||
nmlib.notmuch_tags_move_to_next(self._tags)
|
||||
return tag
|
||||
|
||||
def __len__(self):
|
||||
"""len(:class:`Tags`) returns the number of contained tags
|
||||
|
||||
.. note:: As this iterates over the tags, we will not be able
|
||||
to iterate over them again (as in retrieve them)! If
|
||||
the tags have been exhausted already, this will raise a
|
||||
:exc:`NotmuchError` STATUS.NOT_INITIALIZED on
|
||||
subsequent attempts.
|
||||
"""
|
||||
if self._tags is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
i=0
|
||||
while nmlib.notmuch_tags_valid(self._msgs):
|
||||
nmlib.notmuch_tags_move_to_next(self._msgs)
|
||||
i += 1
|
||||
self._tags = None
|
||||
return i
|
||||
|
||||
def __str__(self):
|
||||
"""The str() representation of Tags() is a space separated list of tags
|
||||
|
||||
.. note:: As this iterates over the tags, we will not be able
|
||||
to iterate over them again (as in retrieve them)! If
|
||||
the tags have been exhausted already, this will raise a
|
||||
:exc:`NotmuchError` STATUS.NOT_INITIALIZED on
|
||||
subsequent attempts.
|
||||
"""
|
||||
return " ".join(self)
|
||||
|
||||
def __del__(self):
|
||||
"""Close and free the notmuch tags"""
|
||||
if self._tags is not None:
|
||||
nmlib.notmuch_tags_destroy (self._tags)
|
319
cnotmuch/thread.py
Normal file
319
cnotmuch/thread.py
Normal file
|
@ -0,0 +1,319 @@
|
|||
from ctypes import c_char_p, c_void_p, c_uint64
|
||||
from cnotmuch.globals import nmlib, STATUS, NotmuchError, Enum
|
||||
from cnotmuch.tags import Tags
|
||||
from datetime import date
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
class Threads(object):
|
||||
"""Represents a list of notmuch threads
|
||||
|
||||
This object provides an iterator over a list of notmuch threads
|
||||
(Technically, it provides a wrapper for the underlying
|
||||
*notmuch_threads_t* structure). Do note that the underlying
|
||||
library only provides a one-time iterator (it cannot reset the
|
||||
iterator to the start). Thus iterating over the function will
|
||||
"exhaust" the list of threads, and a subsequent iteration attempt
|
||||
will raise a :exc:`NotmuchError` STATUS.NOT_INITIALIZED. Also
|
||||
note, that any function that uses iteration will also
|
||||
exhaust the messages. So both::
|
||||
|
||||
for thread in threads: print thread
|
||||
|
||||
as well as::
|
||||
|
||||
number_of_msgs = len(threads)
|
||||
|
||||
will "exhaust" the threads. If you need to re-iterate over a list of
|
||||
messages you will need to retrieve a new :class:`Threads` object.
|
||||
|
||||
Things are not as bad as it seems though, you can store and reuse
|
||||
the single Thread objects as often as you want as long as you
|
||||
keep the parent Threads object around. (Recall that due to
|
||||
hierarchical memory allocation, all derived Threads objects will
|
||||
be invalid when we delete the parent Threads() object, even if it
|
||||
was already "exhausted".) So this works::
|
||||
|
||||
db = Database()
|
||||
threads = Query(db,'').search_threads() #get a Threads() object
|
||||
threadlist = []
|
||||
for thread in threads:
|
||||
threadlist.append(thread)
|
||||
|
||||
# threads is "exhausted" now and even len(threads) will raise an
|
||||
# exception.
|
||||
# However it will be kept around until all retrieved Thread() objects are
|
||||
# also deleted. If you did e.g. an explicit del(threads) here, the
|
||||
# following lines would fail.
|
||||
|
||||
# You can reiterate over *threadlist* however as often as you want.
|
||||
# It is simply a list with Thread objects.
|
||||
|
||||
print (threadlist[0].get_thread_id())
|
||||
print (threadlist[1].get_thread_id())
|
||||
print (threadlist[0].get_total_messages())
|
||||
"""
|
||||
|
||||
#notmuch_threads_get
|
||||
_get = nmlib.notmuch_threads_get
|
||||
_get.restype = c_void_p
|
||||
|
||||
def __init__(self, threads_p, parent=None):
|
||||
"""
|
||||
:param threads_p: A pointer to an underlying *notmuch_threads_t*
|
||||
structure. These are not publically exposed, so a user
|
||||
will almost never instantiate a :class:`Threads` object
|
||||
herself. They are usually handed back as a result,
|
||||
e.g. in :meth:`Query.search_threads`. *threads_p* must be
|
||||
valid, we will raise an :exc:`NotmuchError`
|
||||
(STATUS.NULL_POINTER) if it is `None`.
|
||||
:type threads_p: :class:`ctypes.c_void_p`
|
||||
:param parent: The parent object
|
||||
(ie :class:`Query`) these tags are derived from. It saves
|
||||
a reference to it, so we can automatically delete the db
|
||||
object once all derived objects are dead.
|
||||
:TODO: Make the iterator work more than once and cache the tags in
|
||||
the Python object.(?)
|
||||
"""
|
||||
if threads_p is None:
|
||||
NotmuchError(STATUS.NULL_POINTER)
|
||||
|
||||
self._threads = threads_p
|
||||
#store parent, so we keep them alive as long as self is alive
|
||||
self._parent = parent
|
||||
|
||||
def __iter__(self):
|
||||
""" Make Threads an iterator """
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self._threads is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
if not nmlib.notmuch_threads_valid(self._threads):
|
||||
self._threads = None
|
||||
raise StopIteration
|
||||
|
||||
thread = Thread(Threads._get (self._threads), self)
|
||||
nmlib.notmuch_threads_move_to_next(self._threads)
|
||||
return thread
|
||||
|
||||
def __len__(self):
|
||||
"""len(:class:`Threads`) returns the number of contained Threads
|
||||
|
||||
.. note:: As this iterates over the threads, we will not be able to
|
||||
iterate over them again! So this will fail::
|
||||
|
||||
#THIS FAILS
|
||||
threads = Database().create_query('').search_threads()
|
||||
if len(threads) > 0: #this 'exhausts' threads
|
||||
# next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!!
|
||||
for thread in threads: print thread
|
||||
"""
|
||||
if self._threads is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
i=0
|
||||
# returns 'bool'. On out-of-memory it returns None
|
||||
while nmlib.notmuch_threads_valid(self._threads):
|
||||
nmlib.notmuch_threads_move_to_next(self._threads)
|
||||
i += 1
|
||||
# reset self._threads to mark as "exhausted"
|
||||
self._threads = None
|
||||
return i
|
||||
|
||||
|
||||
|
||||
def __del__(self):
|
||||
"""Close and free the notmuch Threads"""
|
||||
if self._threads is not None:
|
||||
nmlib.notmuch_messages_destroy (self._threads)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
class Thread(object):
|
||||
"""Represents a single message thread."""
|
||||
|
||||
"""notmuch_thread_get_thread_id"""
|
||||
_get_thread_id = nmlib.notmuch_thread_get_thread_id
|
||||
_get_thread_id.restype = c_char_p
|
||||
|
||||
"""notmuch_thread_get_authors"""
|
||||
_get_authors = nmlib.notmuch_thread_get_authors
|
||||
_get_authors.restype = c_char_p
|
||||
|
||||
"""notmuch_thread_get_subject"""
|
||||
_get_subject = nmlib.notmuch_thread_get_subject
|
||||
_get_subject.restype = c_char_p
|
||||
|
||||
_get_newest_date = nmlib.notmuch_thread_get_newest_date
|
||||
_get_newest_date.restype = c_uint64
|
||||
|
||||
_get_oldest_date = nmlib.notmuch_thread_get_oldest_date
|
||||
_get_oldest_date.restype = c_uint64
|
||||
|
||||
"""notmuch_thread_get_tags"""
|
||||
_get_tags = nmlib.notmuch_thread_get_tags
|
||||
_get_tags.restype = c_void_p
|
||||
|
||||
def __init__(self, thread_p, parent=None):
|
||||
"""
|
||||
:param thread_p: A pointer to an internal notmuch_thread_t
|
||||
Structure. These are not publically exposed, so a user
|
||||
will almost never instantiate a :class:`Thread` object
|
||||
herself. They are usually handed back as a result,
|
||||
e.g. when iterating through :class:`Threads`. *thread_p*
|
||||
must be valid, we will raise an :exc:`NotmuchError`
|
||||
(STATUS.NULL_POINTER) if it is `None`.
|
||||
|
||||
:param parent: A 'parent' object is passed which this message is
|
||||
derived from. We save a reference to it, so we can
|
||||
automatically delete the parent object once all derived
|
||||
objects are dead.
|
||||
"""
|
||||
if thread_p is None:
|
||||
NotmuchError(STATUS.NULL_POINTER)
|
||||
self._thread = thread_p
|
||||
#keep reference to parent, so we keep it alive
|
||||
self._parent = parent
|
||||
|
||||
def get_thread_id(self):
|
||||
"""Get the thread ID of 'thread'
|
||||
|
||||
The returned string belongs to 'thread' and will only be valid
|
||||
for as long as the thread is valid.
|
||||
|
||||
:returns: String with a message ID
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
|
||||
is not initialized.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return Thread._get_thread_id(self._thread)
|
||||
|
||||
def get_total_messages(self):
|
||||
"""Get the total number of messages in 'thread'
|
||||
|
||||
:returns: The number of all messages in the database
|
||||
belonging to this thread. Contrast with
|
||||
:meth:`get_matched_messages`.
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
|
||||
is not initialized.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return nmlib.notmuch_thread_get_total_messages(self._thread)
|
||||
|
||||
|
||||
###TODO: notmuch_messages_t * notmuch_thread_get_toplevel_messages (notmuch_thread_t *thread);
|
||||
|
||||
def get_matched_messages(self):
|
||||
"""Returns the number of messages in 'thread' that matched the query
|
||||
|
||||
:returns: The number of all messages belonging to this thread that
|
||||
matched the :class:`Query`from which this thread was created.
|
||||
Contrast with :meth:`get_total_messages`.
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
|
||||
is not initialized.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return nmlib.notmuch_thread_get_matched_messages(self._thread)
|
||||
|
||||
def get_authors(self):
|
||||
"""Returns the authors of 'thread'
|
||||
|
||||
The returned string is a comma-separated list of the names of the
|
||||
authors of mail messages in the query results that belong to this
|
||||
thread.
|
||||
|
||||
The returned string belongs to 'thread' and will only be valid for
|
||||
as long as this Thread() is not deleted.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return Thread._get_authors(self._thread)
|
||||
|
||||
def get_subject(self):
|
||||
"""Returns the Subject of 'thread'
|
||||
|
||||
The returned string belongs to 'thread' and will only be valid for
|
||||
as long as this Thread() is not deleted.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return Thread._get_subject(self._thread)
|
||||
|
||||
def get_newest_date(self):
|
||||
"""Returns time_t of the newest message date
|
||||
|
||||
:returns: A time_t timestamp.
|
||||
:rtype: c_unit64
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
|
||||
is not initialized.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return Thread._get_newest_date(self._thread)
|
||||
|
||||
def get_oldest_date(self):
|
||||
"""Returns time_t of the oldest message date
|
||||
|
||||
:returns: A time_t timestamp.
|
||||
:rtype: c_unit64
|
||||
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
|
||||
is not initialized.
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
return Thread._get_oldest_date(self._thread)
|
||||
|
||||
def get_tags(self):
|
||||
""" Returns the message tags
|
||||
|
||||
In the Notmuch database, tags are stored on individual
|
||||
messages, not on threads. So the tags returned here will be all
|
||||
tags of the messages which matched the search and which belong to
|
||||
this thread.
|
||||
|
||||
The :class:`Tags` object is owned by the thread and as such, will only
|
||||
be valid for as long as this :class:`Thread` is valid (e.g. until the
|
||||
query from which it derived is explicitely deleted).
|
||||
|
||||
:returns: A :class:`Tags` iterator.
|
||||
:exception: :exc:`NotmuchError`
|
||||
|
||||
* STATUS.NOT_INITIALIZED if the thread
|
||||
is not initialized.
|
||||
* STATUS.NULL_POINTER, on error
|
||||
"""
|
||||
if self._thread is None:
|
||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
||||
|
||||
tags_p = Thread._get_tags(self._thread)
|
||||
if tags_p == None:
|
||||
raise NotmuchError(STATUS.NULL_POINTER)
|
||||
return Tags(tags_p, self)
|
||||
|
||||
def __str__(self):
|
||||
"""A str(Thread()) is represented by a 1-line summary"""
|
||||
thread = {}
|
||||
thread['id'] = self.get_thread_id()
|
||||
|
||||
###TODO: How do we find out the current sort order of Threads?
|
||||
###Add a "sort" attribute to the Threads() object?
|
||||
#if (sort == NOTMUCH_SORT_OLDEST_FIRST)
|
||||
# date = notmuch_thread_get_oldest_date (thread);
|
||||
#else
|
||||
# date = notmuch_thread_get_newest_date (thread);
|
||||
thread['date'] = date.fromtimestamp(self.get_newest_date())
|
||||
thread['matched'] = self.get_matched_messages()
|
||||
thread['total'] = self.get_total_messages()
|
||||
thread['authors'] = self.get_authors()
|
||||
thread['subject'] = self.get_subject()
|
||||
thread['tags'] = self.get_tags()
|
||||
|
||||
return "thread:%(id)s %(date)12s [%(matched)d/%(total)d] %(authors)s; %(subject)s (%(tags)s)" % (thread)
|
||||
|
||||
def __del__(self):
|
||||
"""Close and free the notmuch Thread"""
|
||||
if self._thread is not None:
|
||||
nmlib.notmuch_thread_destroy (self._thread)
|
Loading…
Reference in a new issue