X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=bindings%2Fpython%2Fnotmuch%2Fdatabase.py;h=841e808e33c6f22f4211be0f9cfa3b5a80e043c9;hb=05926adf73e7b1bad0faa4a0a5514d554353cdaa;hp=a19dd596e95b99b1705d41edca2dd4fce4973f99;hpb=94a1bb88aadd2d591815b47df9e886dc594df21f;p=notmuch diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index a19dd596..841e808e 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -19,7 +19,8 @@ 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, _str +from notmuch.globals import (nmlib, STATUS, NotmuchError, NotInitializedError, + OutOfMemoryError, XapianError, Enum, _str) from notmuch.thread import Threads from notmuch.message import Messages, Message from notmuch.tag import Tags @@ -61,11 +62,9 @@ class Database(object): """ notmuch_database_find_message""" _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 @@ -93,8 +92,8 @@ class Database(object): :param mode: Mode to open a database in. Is always :attr:`MODE`.READ_WRITE when creating a new one. :type mode: :attr:`MODE` - :returns: Nothing - :exception: :exc:`NotmuchError` in case of failure. + :exception: :exc:`NotmuchError` or derived exception in case of + failure. """ self._db = None if path is None: @@ -110,9 +109,9 @@ class Database(object): self.create(path) def _assert_db_is_initialized(self): - """Raises a NotmuchError in case self._db is still None""" + """Raises :exc:`NotInitializedError` if self._db is `None`""" if self._db is None: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() def create(self, path): """Creates a new notmuch database @@ -128,7 +127,7 @@ class Database(object): :type path: str :returns: Nothing :exception: :exc:`NotmuchError` in case of any failure - (after printing an error message on stderr). + (possibly after printing an error message on stderr). """ if self._db is not None: raise NotmuchError(message="Cannot create db, this Database() " @@ -157,14 +156,13 @@ class Database(object): res = Database._open(_str(path), mode) if res is None: - raise NotmuchError( - message="Could not open the specified database") + raise NotmuchError(message="Could not open the specified database") self._db = res def get_path(self): """Returns the file path of an open database - Wraps *notmuch_database_get_path*.""" + .. ..:: Wraps underlying `notmuch_database_get_path`""" self._assert_db_is_initialized() return Database._get_path(self._db).decode('utf-8') @@ -172,7 +170,7 @@ class Database(object): """Returns the database format version :returns: The database version as positive integer - :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if + :exception: :exc:`NotInitializedError` if the database was not intitialized. """ self._assert_db_is_initialized() @@ -187,7 +185,7 @@ class Database(object): etc.) will work unless :meth:`upgrade` is called successfully first. :returns: `True` or `False` - :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if + :exception: :exc:`NotInitializedError` if the database was not intitialized. """ self._assert_db_is_initialized() @@ -207,6 +205,9 @@ class Database(object): indicating the progress made so far in the upgrade process. :TODO: catch exceptions, document return values and etc... + + :exception: :exc:`NotInitializedError` if + the database was not intitialized. """ self._assert_db_is_initialized() status = Database._upgrade(self._db, None, None) @@ -222,12 +223,16 @@ class Database(object): transaction, this only ensures atomicity, not durability; neither begin nor end necessarily flush modifications to disk. - :returns: STATUS.SUCCESS or raises + :returns: :attr:`STATUS`.SUCCESS or raises + + :exception: :exc:`NotmuchError`: + :attr:`STATUS`.XAPIAN_EXCEPTION + Xapian exception occurred; atomic section not entered. - :exception: :exc:`NotmuchError` STATUS.XAPIAN_EXCEPTION:: + :exc:`NotInitializedError` if + the database was not intitialized. - A Xapian exception occurred; atomic section not - entered.""" + *Added in notmuch 0.9*""" self._assert_db_is_initialized() status = nmlib.notmuch_database_begin_atomic(self._db) if status != STATUS.SUCCESS: @@ -239,15 +244,20 @@ class Database(object): See :meth:`begin_atomic` for details. - :returns: STATUS.SUCCESS or raises + :returns: :attr:`STATUS`.SUCCESS or raises :exception: :exc:`NotmuchError`: - STATUS.XAPIAN_EXCEPTION + :attr:`STATUS`.XAPIAN_EXCEPTION A Xapian exception occurred; atomic section not ended. - STATUS.UNBALANCED_ATOMIC: - end_atomic has been called more times than begin_atomic.""" + :attr:`STATUS`.UNBALANCED_ATOMIC: + end_atomic has been called more times than begin_atomic. + + :exc:`NotInitializedError` if + the database was not intitialized. + + *Added in notmuch 0.9*""" self._assert_db_is_initialized() status = nmlib.notmuch_database_end_atomic(self._db) if status != STATUS.SUCCESS: @@ -259,22 +269,20 @@ class Database(object): (creating it if it does not exist(?)) .. warning:: This call needs a writeable database in - Database.MODE.READ_WRITE mode. The underlying library will exit the + :attr:`Database.MODE`.READ_WRITE mode. The underlying library will exit the program if this method is used on a read-only database! :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` - - STATUS.NOT_INITIALIZED - If the database was not intitialized. - - STATUS.FILE_ERROR + :exception: + :exc:`NotmuchError` with :attr:`STATUS`.FILE_ERROR If path is not relative database or absolute with initial components same as database. + :exc:`NotInitializedError` if + the database was not intitialized. """ self._assert_db_is_initialized() # sanity checking if path is valid, and make path absolute @@ -298,15 +306,16 @@ class Database(object): def add_message(self, filename, sync_maildir_flags=False): """Adds a new message to the database - :param filename: should be a path relative to the path of the open - database (see :meth:`get_path`), or else should be an absolute - filename with initial components that match the path of the - database. + :param filename: should be a path relative to the path of the + open database (see :meth:`get_path`), or else should be an + absolute filename with initial components that match the + path of the database. - The file should be a single mail message (not a multi-message mbox) - that is expected to remain at its current location, since the - notmuch database will reference the filename, and will not copy the - entire contents of the file. + The file should be a single mail message (not a + multi-message mbox) that is expected to remain at its + current location, since the notmuch database will reference + the filename, and will not copy the entire contents of the + file. :param sync_maildir_flags: If the message contains Maildir flags, we will -depending on the notmuch configuration- sync @@ -319,31 +328,32 @@ class Database(object): 1) a :class:`Message` object that can be used for things such as adding tags to the just-added message. - 2) one of the following STATUS values: + 2) one of the following :attr:`STATUS` values: - STATUS.SUCCESS + :attr:`STATUS`.SUCCESS Message successfully added to database. - STATUS.DUPLICATE_MESSAGE_ID + :attr:`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 list of the filenames for the existing message. - :rtype: 2-tuple(:class:`Message`, STATUS) + :rtype: 2-tuple(:class:`Message`, :attr:`STATUS`) :exception: Raises a :exc:`NotmuchError` with the following meaning. If such an exception occurs, nothing was added to the database. - STATUS.FILE_ERROR + :attr:`STATUS`.FILE_ERROR An error occurred trying to open the file, (such as permission denied, or file not found, etc.). - STATUS.FILE_NOT_EMAIL + :attr:`STATUS`.FILE_NOT_EMAIL The contents of filename don't look like an email message. - STATUS.READ_ONLY_DATABASE + :attr:`STATUS`.READ_ONLY_DATABASE Database was opened in read-only mode so no message can be added. - STATUS.NOT_INITIALIZED - The database has not been initialized. + + :exc:`NotInitializedError` if + the database was not intitialized. """ self._assert_db_is_initialized() msg_p = c_void_p() @@ -371,12 +381,12 @@ class Database(object): is removed for a particular message, the database content for that message will be entirely removed. - :returns: A STATUS value with the following meaning: + :returns: A :attr:`STATUS` value with the following meaning: - STATUS.SUCCESS + :attr:`STATUS`.SUCCESS The last filename was removed and the message was removed from the database. - STATUS.DUPLICATE_MESSAGE_ID + :attr:`STATUS`.DUPLICATE_MESSAGE_ID This filename was removed but the message persists in the database with at least one other filename. @@ -384,11 +394,12 @@ class Database(object): If such an exception occurs, nothing was removed from the database. - STATUS.READ_ONLY_DATABASE + :attr:`STATUS`.READ_ONLY_DATABASE Database was opened in read-only mode so no message can be removed. - STATUS.NOT_INITIALIZED - The database has not been initialized. + + :exc:`NotInitializedError` if + the database was not intitialized. """ self._assert_db_is_initialized() return nmlib.notmuch_database_remove_message(self._db, @@ -400,41 +411,68 @@ class Database(object): Wraps the underlying *notmuch_database_find_message* function. :param msgid: The message ID - :type msgid: string - :returns: :class:`Message` or `None` if no message is found or - if any xapian exception or out-of-memory situation - occurs. Do note that Xapian Exceptions include - "Database modified" situations, e.g. when the - notmuch database has been modified by - another program in the meantime. A return value of - `None` is therefore no guarantee that the message - does not exist. - :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if - the database was not intitialized. + :type msgid: unicode or str + :returns: :class:`Message` or `None` if no message is found. + :exception: + :exc:`OutOfMemoryError` + If an Out-of-memory occured while constructing the message. + :exc:`XapianError` + In case of a Xapian Exception. These exceptions + include "Database modified" situations, e.g. when the + notmuch database has been modified by another program + in the meantime. In this case, you should close and + reopen the database and retry. + + :exc:`NotInitializedError` if + the database was not intitialized. """ self._assert_db_is_initialized() - msg_p = Database._find_message(self._db, _str(msgid)) + msg_p = c_void_p() + status = Database._find_message(self._db, _str(msgid), byref(msg_p)) + if status != STATUS.SUCCESS: + raise NotmuchError(status) return msg_p and Message(msg_p, self) or None def find_message_by_filename(self, filename): """Find a message with the given filename + .. warning:: This call needs a writeable database in + :attr:`Database.MODE`.READ_WRITE mode. The underlying library will + exit the program if this method is used on a read-only + database! + :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: + function returns None if no message is found with the given + filename. + + :exception: + :exc:`OutOfMemoryError` + If an Out-of-memory occured while constructing the message. + :exc:`XapianError` + In case of a Xapian Exception. These exceptions + include "Database modified" situations, e.g. when the + notmuch database has been modified by another program + in the meantime. In this case, you should close and + reopen the database and retry. + + :exc:`NotInitializedError` if + the database was not intitialized. - * No message is found with the given filename - * An out-of-memory situation occurs - * A Xapian exception occurs""" + *Added in notmuch 0.9*""" self._assert_db_is_initialized() - msg_p = Database._find_message_by_filename(self._db, _str(filename)) + msg_p = c_void_p() + status = Database._find_message_by_filename(self._db, _str(filename), + byref(msg_p)) + if status != STATUS.SUCCESS: + raise NotmuchError(status) 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 :returns: :class:`Tags` - :execption: :exc:`NotmuchError` with STATUS.NULL_POINTER on error + :execption: :exc:`NotmuchError` with :attr:`STATUS`.NULL_POINTER on error """ self._assert_db_is_initialized() tags_p = Database._get_all_tags(self._db) @@ -558,8 +596,8 @@ class Query(object): :returns: Nothing :exception: :exc:`NotmuchError` - * STATUS.NOT_INITIALIZED if db is not inited - * STATUS.NULL_POINTER if the query creation failed + * :attr:`STATUS`.NOT_INITIALIZED if db is not inited + * :attr:`STATUS`.NULL_POINTER if the query creation failed (too little memory) """ if db.db_p is None: @@ -569,7 +607,7 @@ class Query(object): # create query, return None if too little mem available query_p = Query._create(db.db_p, _str(querystr)) if query_p is None: - NotmuchError(STATUS.NULL_POINTER) + raise NotmuchError(STATUS.NULL_POINTER) self._query = query_p def set_sort(self, sort): @@ -579,7 +617,7 @@ class Query(object): :param sort: Sort order (see :attr:`Query.SORT`) :returns: Nothing - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if query has not + :exception: :exc:`NotmuchError` :attr:`STATUS`.NOT_INITIALIZED if query has not been initialized. """ if self._query is None: @@ -605,8 +643,8 @@ class Query(object): :returns: :class:`Threads` :exception: :exc:`NotmuchError` - * STATUS.NOT_INITIALIZED if query is not inited - * STATUS.NULL_POINTER if search_threads failed + * :attr:`STATUS`.NOT_INITIALIZED if query is not inited + * :attr:`STATUS`.NULL_POINTER if search_threads failed """ if self._query is None: raise NotmuchError(STATUS.NOT_INITIALIZED) @@ -628,8 +666,8 @@ class Query(object): :returns: :class:`Messages` :exception: :exc:`NotmuchError` - * STATUS.NOT_INITIALIZED if query is not inited - * STATUS.NULL_POINTER if search_messages failed + * :attr:`STATUS`.NOT_INITIALIZED if query is not inited + * :attr:`STATUS`.NULL_POINTER if search_messages failed """ if self._query is None: raise NotmuchError(STATUS.NOT_INITIALIZED) @@ -637,7 +675,7 @@ class Query(object): msgs_p = Query._search_messages(self._query) if msgs_p is None: - NotmuchError(STATUS.NULL_POINTER) + raise NotmuchError(STATUS.NULL_POINTER) return Messages(msgs_p, self) @@ -654,7 +692,7 @@ class Query(object): :returns: :class:`Messages` :exception: :exc:`NotmuchError` - * STATUS.NOT_INITIALIZED if query is not inited + * :attr:`STATUS`.NOT_INITIALIZED if query is not inited """ if self._query is None: raise NotmuchError(STATUS.NOT_INITIALIZED) @@ -697,8 +735,8 @@ class Directory(object): _get_child_directories = nmlib.notmuch_directory_get_child_directories _get_child_directories.restype = c_void_p - def _verify_dir_initialized(self): - """Raises a NotmuchError(STATUS.NOT_INITIALIZED) if dir_p is None""" + def _assert_dir_is_initialized(self): + """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None""" if self._dir_p is None: raise NotmuchError(STATUS.NOT_INITIALIZED) @@ -744,17 +782,15 @@ class Directory(object): :returns: Nothing on success, raising an exception on failure. :exception: :exc:`NotmuchError`: - STATUS.XAPIAN_EXCEPTION + :attr:`STATUS`.XAPIAN_EXCEPTION A Xapian exception occurred, mtime not stored. - STATUS.READ_ONLY_DATABASE + :attr:`STATUS`.READ_ONLY_DATABASE Database was opened in read-only mode so directory mtime cannot be modified. - STATUS.NOT_INITIALIZED + :attr:`STATUS`.NOT_INITIALIZED The directory has not been initialized """ - #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if the dir_p is None - self._verify_dir_initialized() - + self._assert_dir_is_initialized() #TODO: make sure, we convert the mtime parameter to a 'c_long' status = Directory._set_mtime(self._dir_p, mtime) @@ -773,12 +809,10 @@ class Directory(object): :returns: Nothing on success, raising an exception on failure. :exception: :exc:`NotmuchError`: - STATUS.NOT_INITIALIZED + :attr:`STATUS`.NOT_INITIALIZED The directory has not been initialized """ - #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self.dir_p is None - self._verify_dir_initialized() - + self._assert_dir_is_initialized() return Directory._get_mtime(self._dir_p) # Make mtime attribute a property of Directory() @@ -795,9 +829,7 @@ class Directory(object): The returned filenames will be the basename-entries only (not complete paths. """ - #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self._dir_p is None - self._verify_dir_initialized() - + self._assert_dir_is_initialized() files_p = Directory._get_child_files(self._dir_p) return Filenames(files_p, self) @@ -808,9 +840,7 @@ class Directory(object): The returned filenames will be the basename-entries only (not complete paths. """ - #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self._dir_p is None - self._verify_dir_initialized() - + self._assert_dir_is_initialized() files_p = Directory._get_child_directories(self._dir_p) return Filenames(files_p, self) @@ -873,7 +903,7 @@ class Filenames(object): #THIS FAILS files = Database().get_directory('').get_child_files() if len(files) > 0: #this 'exhausts' msgs - # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!! + # next line raises NotmuchError(:attr:`STATUS`.NOT_INITIALIZED)!!! for file in files: print file """ if self._files_p is None: