-import ctypes
+import ctypes, os
from ctypes import c_int, c_char_p, c_void_p, c_uint, c_uint64, c_bool
from cnotmuch.globals import nmlib, STATUS, NotmuchError, Enum
import logging
as well. Accessing these objects will lead to segfaults and
other unexpected behavior. See above for more details.
"""
- MODE = Enum(['READ_ONLY','READ_WRITE'])
- """Constants: Mode in which to open the database"""
-
_std_db_path = None
"""Class attribute to cache user's default database"""
+ MODE = Enum(['READ_ONLY','READ_WRITE'])
+ """Constants: Mode in which to open the database"""
+
"""notmuch_database_get_path (notmuch_database_t *database)"""
_get_path = nmlib.notmuch_database_get_path
_get_path.restype = c_char_p
_create = nmlib.notmuch_database_create
_create.restype = c_void_p
- def __init__(self, path=None, create=False, mode= MODE.READ_ONLY):
- """If *path* is *None*, we will try to read a users notmuch
- configuration and use his default database. If *create* is `True`,
- the database will always be created in
- :attr:`MODE`.READ_WRITE mode.
+ def __init__(self, path=None, create=False, mode= 0):
+ """If *path* is *None*, we will try to read a users notmuch
+ configuration and use his configured database. The location of the
+ configuration file can be specified through the environment variable
+ *NOTMUCH_CONFIG*, falling back to the default `~/.notmuch-config`.
+
+ If *create* is `True`, the database will always be created in
+ :attr:`MODE`.READ_WRITE mode. Default mode for opening is READ_ONLY.
:param path: Directory to open/create the database in (see
above for behavior if `None`)
else:
self.create(path)
+ def _verify_initialized_db(self):
+ """Raises a NotmuchError in case self._db is still None"""
+ if self._db is None:
+ raise NotmuchError(STATUS.NOT_INITIALIZED)
+
def create(self, path):
"""Creates a new notmuch database
raise NotmuchError(
message="Cannot create db, this Database() already has an open one.")
- res = Database._create(path, MODE.READ_WRITE)
+ res = Database._create(path, Database.MODE.READ_WRITE)
if res is None:
raise NotmuchError(
message="Could not create the specified database")
self._db = res
- def open(self, path, mode= MODE.READ_ONLY):
+ def open(self, path, mode= 0):
"""Opens an existing database
This function is used by __init__() and usually does not need
"""Returns the file path of an open database
Wraps notmuch_database_get_path"""
+ # Raise a NotmuchError if not initialized
+ self._verify_initialized_db()
+
return Database._get_path(self._db)
def get_version(self):
:exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
the database was not intitialized.
"""
- if self._db is None:
- raise NotmuchError(STATUS.NOT_INITIALIZED)
+ # Raise a NotmuchError if not initialized
+ self._verify_initialized_db()
return Database._get_version (self._db)
:exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
the database was not intitialized.
"""
- if self._db is None:
- raise NotmuchError(STATUS.NOT_INITIALIZED)
+ # Raise a NotmuchError if not initialized
+ self._verify_initialized_db()
return notmuch_database_needs_upgrade(self.db)
:exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
the database was not intitialized.
"""
- if self._db is None:
- raise NotmuchError(STATUS.NOT_INITIALIZED)
+ # Raise a NotmuchError if not initialized
+ self._verify_initialized_db()
+
msg_p = Database._find_message(self._db, msgid)
if msg_p is None:
return None
:returns: :class:`Tags`
:execption: :exc:`NotmuchError` with STATUS.NULL_POINTER on error
"""
- if self._db is None:
- raise NotmuchError(STATUS.NOT_INITIALIZED)
+ # Raise a NotmuchError if not initialized
+ self._verify_initialized_db()
tags_p = Database._get_all_tags (self._db)
if tags_p == None:
Throws a NotmuchError if it cannot find it"""
from ConfigParser import SafeConfigParser
- import os.path
config = SafeConfigParser()
- config.read(os.path.expanduser('~/.notmuch-config'))
+ conf_f = os.getenv('NOTMUCH_CONFIG',
+ os.path.expanduser('~/.notmuch-config'))
+ config.read(conf_f)
if not config.has_option('database','path'):
raise NotmuchError(message=
"No DB path specified and no user default found")
_search_messages = nmlib.notmuch_query_search_messages
_search_messages.restype = c_void_p
+
+ """notmuch_query_count_messages"""
+ _count_messages = nmlib.notmuch_query_count_messages
+ _count_messages.restype = c_uint
+
def __init__(self, db, querystr):
"""
:param db: An open database which we derive the Query from.
return Messages(msgs_p,self)
+ def count_messages(self):
+ """Estimate the number of messages matching the query
+
+ This function performs a search and returns Xapian's best
+ guess as to the number of matching messages. It is much faster
+ than performing :meth:`search_messages` and counting the
+ result with `len()` (although it always returned the same
+ result in my tests). Technically, it wraps the underlying
+ *notmuch_query_count_messages* function.
+
+ :returns: :class:`Messages`
+ :exception: :exc:`NotmuchError`
+
+ * STATUS.NOT_INITIALIZED if query is not inited
+ """
+ if self._query is None:
+ raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+ return Query._count_messages(self._query)
def __del__(self):
"""Close and free the Query"""
"""notmuch_message_get_filename (notmuch_message_t *message)"""
_get_filename = nmlib.notmuch_message_get_filename
_get_filename.restype = c_char_p
+
"""notmuch_message_get_message_id (notmuch_message_t *message)"""
_get_message_id = nmlib.notmuch_message_get_message_id
_get_message_id.restype = c_char_p
+ """notmuch_message_get_thread_id"""
+ _get_thread_id = nmlib.notmuch_message_get_thread_id
+ _get_thread_id.restype = c_char_p
+
"""notmuch_message_get_tags (notmuch_message_t *message)"""
_get_tags = nmlib.notmuch_message_get_tags
_get_tags.restype = c_void_p
def get_message_id(self):
- """Return the message ID
+ """Returns the message ID
:returns: String with a message ID
:exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
raise NotmuchError(STATUS.NOT_INITIALIZED)
return Message._get_message_id(self._msg)
+ def get_thread_id(self):
+ """Returns the thread ID
+
+ The returned string belongs to 'message' will only be valid for as
+ long as the message is valid.
+
+ This function will not return None since Notmuch ensures that every
+ message belongs to a single thread.
+
+ :returns: String with a thread ID
+ :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+ is not initialized.
+ """
+ if self._msg is None:
+ raise NotmuchError(STATUS.NOT_INITIALIZED)
+
+ return Message._get_thread_id (self._msg);
+
def get_date(self):
"""Returns time_t of the message date