X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=bindings%2Fpython%2Fnotmuch%2Fdatabase.py;h=bafe497e02c4f0466b3e230f0ce3117148edafea;hb=0241a68e9eb67904ac1805ccc82910c555711ac6;hp=c607011172845c95d18d941d363ce22e3fba95e5;hpb=e69e30edd71eb6c7ea3a004e80ff84accbd12199;p=notmuch diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index c6070111..bafe497e 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -19,12 +19,11 @@ Copyright 2010 Sebastian Spaeth ' import os from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref -from notmuch.globals import nmlib, STATUS, NotmuchError, Enum +from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str from notmuch.thread import Threads from notmuch.message import Messages, Message from notmuch.tag import Tags - class Database(object): """Represents a notmuch database (wraps notmuch_database_t) @@ -64,6 +63,10 @@ class Database(object): _find_message = nmlib.notmuch_database_find_message _find_message.restype = c_void_p + """notmuch_database_find_message_by_filename""" + _find_message_by_filename = nmlib.notmuch_database_find_message_by_filename + _find_message_by_filename.restype = c_void_p + """notmuch_database_get_all_tags""" _get_all_tags = nmlib.notmuch_database_get_all_tags _get_all_tags.restype = c_void_p @@ -101,7 +104,6 @@ class Database(object): Database._std_db_path = self._get_user_default_db() path = Database._std_db_path - assert isinstance(path, basestring), 'Path must be a string or None.' if create == False: self.open(path, mode) else: @@ -132,7 +134,7 @@ class Database(object): raise NotmuchError(message="Cannot create db, this Database() " "already has an open one.") - res = Database._create(path, Database.MODE.READ_WRITE) + res = Database._create(_str(path), Database.MODE.READ_WRITE) if res is None: raise NotmuchError( @@ -152,8 +154,7 @@ class Database(object): :exception: Raises :exc:`NotmuchError` in case of any failure (after printing an error message on stderr). """ - - res = Database._open(path, mode) + res = Database._open(_str(path), mode) if res is None: raise NotmuchError( @@ -167,7 +168,7 @@ class Database(object): # Raise a NotmuchError if not initialized self._verify_initialized_db() - return Database._get_path(self._db) + return Database._get_path(self._db).decode('utf-8') def get_version(self): """Returns the database format version @@ -220,6 +221,49 @@ class Database(object): #TODO: catch exceptions, document return values and etc return status + def begin_atomic(self): + """Begin an atomic database operation + + Any modifications performed between a successful + :meth:`begin_atomic` and a :meth:`end_atomic` will be applied to + the database atomically. Note that, unlike a typical database + transaction, this only ensures atomicity, not durability; + neither begin nor end necessarily flush modifications to disk. + + :returns: STATUS.SUCCESS or raises + + :exception: :exc:`NotmuchError` STATUS.XAPIAN_EXCEPTION:: + + A Xapian exception occurred; atomic section not + entered.""" + # Raise a NotmuchError if not initialized + self._verify_initialized_db() + status = nmlib.notmuch_database_begin_atomic(self._db) + if status != STATUS.SUCCESS: + raise NotmuchError(status) + return status + + def end_atomic(self): + """Indicate the end of an atomic database operation + + See :meth:`begin_atomic` for details. + + :returns: STATUS.SUCCESS or raises + + :exception: + :exc:`NotmuchError`: + STATUS.XAPIAN_EXCEPTION + A Xapian exception occurred; atomic section not + ended. + STATUS.UNBALANCED_ATOMIC: + end_atomic has been called more times than begin_atomic.""" + # Raise a NotmuchError if not initialized + self._verify_initialized_db() + status = nmlib.notmuch_database_end_atomic(self._db) + if status != STATUS.SUCCESS: + raise NotmuchError(status) + return status + def get_directory(self, path): """Returns a :class:`Directory` of path, (creating it if it does not exist(?)) @@ -228,8 +272,8 @@ class Database(object): Database.MODE.READ_WRITE mode. The underlying library will exit the program if this method is used on a read-only database! - :param path: A str containing the path relative to the path of database - (see :meth:`get_path`), or else should be an absolute path + :param path: An unicode string containing the path relative to the path + of database (see :meth:`get_path`), or else should be an absolute path with initial components that match the path of 'database'. :returns: :class:`Directory` or raises an exception. :exception: :exc:`NotmuchError` @@ -258,10 +302,10 @@ class Database(object): #we got a relative path, make it absolute abs_dirpath = os.path.abspath(os.path.join(self.get_path(), path)) - dir_p = Database._get_directory(self._db, path) + dir_p = Database._get_directory(self._db, _str(path)) # return the Directory, init it with the absolute path - return Directory(abs_dirpath, dir_p, self) + return Directory(_str(abs_dirpath), dir_p, self) def add_message(self, filename, sync_maildir_flags=False): """Adds a new message to the database @@ -294,7 +338,7 @@ class Database(object): STATUS.DUPLICATE_MESSAGE_ID Message has the same message ID as another message already in the database. The new filename was successfully added - to the message in the database. + to the list of the filenames for the existing message. :rtype: 2-tuple(:class:`Message`, STATUS) @@ -318,7 +362,7 @@ class Database(object): msg_p = c_void_p() status = nmlib.notmuch_database_add_message(self._db, - filename, + _str(filename), byref(msg_p)) if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: @@ -332,7 +376,7 @@ class Database(object): return (msg, status) def remove_message(self, filename): - """Removes a message from the given notmuch database + """Removes a message (filename) from the given notmuch database Note that only this particular filename association is removed from the database. If the same message (as determined by the message ID) @@ -387,10 +431,22 @@ class Database(object): # 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 - return Message(msg_p, self) + msg_p = Database._find_message(self._db, _str(msgid)) + return msg_p and Message(msg_p, self) or None + + def find_message_by_filename(self, filename): + """Find a message with the given filename + + :returns: If the database contains a message with the given + filename, then a class:`Message:` is returned. This + function returns None in the following situations: + + * No message is found with the given filename + * An out-of-memory situation occurs + * A Xapian exception occurs""" + self._verify_initialized_db() + msg_p = Database._find_message_by_filename(self._db, _str(filename)) + return msg_p and Message(msg_p, self) or None def get_all_tags(self): """Returns :class:`Tags` with a list of all tags found in the database @@ -449,7 +505,7 @@ class Database(object): if not config.has_option('database', 'path'): raise NotmuchError(message="No DB path specified" " and no user default found") - return config.get('database', 'path') + return config.get('database', 'path').decode('utf-8') @property def db_p(self): @@ -532,11 +588,8 @@ class Query(object): raise NotmuchError(STATUS.NOT_INITIALIZED) # create reference to parent db to keep it alive self._db = db - if isinstance(querystr, unicode): - # xapian takes utf-8 encoded byte arrays - querystr = querystr.encode('utf-8') # create query, return None if too little mem available - query_p = Query._create(db.db_p, querystr) + query_p = Query._create(db.db_p, _str(querystr)) if query_p is None: NotmuchError(STATUS.NULL_POINTER) self._query = query_p @@ -673,7 +726,7 @@ class Directory(object): def __init__(self, path, dir_p, parent): """ - :param path: The absolute path of the directory object. + :param path: The absolute path of the directory object as unicode. :param dir_p: The pointer to an internal notmuch_directory_t object. :param parent: The object this Directory is derived from (usually a :class:`Database`). We do not directly use @@ -681,6 +734,7 @@ class Directory(object): this Directory object lives. This keeps the parent object alive. """ + assert isinstance(path, unicode), "Path needs to be an UNICODE object" self._path = path self._dir_p = dir_p self._parent = parent