mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-25 12:28:09 +01:00
python: provide more exception classes
To make the exception handling more effective in code using the python bindings it is necessary to differentiate between the different kind of failures. Add an exception class for each status code and add a decode classmethod to the NotmuchError class that acts as a factory. Import the new classes in __init__.py so they can be easily imported by anyone. Patch modifed by Sebastian Spaeth. Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de> Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
This commit is contained in:
parent
a378a91ba2
commit
b6a01735d2
3 changed files with 86 additions and 24 deletions
|
@ -50,13 +50,28 @@ for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
|
along with notmuch. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
|
Copyright 2010-2011 Sebastian Spaeth <Sebastian@SSpaeth.de>
|
||||||
"""
|
"""
|
||||||
from notmuch.database import Database, Query
|
from notmuch.database import Database, Query
|
||||||
from notmuch.message import Messages, Message
|
from notmuch.message import Messages, Message
|
||||||
from notmuch.thread import Threads, Thread
|
from notmuch.thread import Threads, Thread
|
||||||
from notmuch.tag import Tags
|
from notmuch.tag import Tags
|
||||||
from notmuch.globals import nmlib, STATUS, NotmuchError
|
from notmuch.globals import (
|
||||||
|
nmlib,
|
||||||
|
STATUS,
|
||||||
|
NotmuchError,
|
||||||
|
OutOfMemoryError,
|
||||||
|
ReadOnlyDatabaseError,
|
||||||
|
XapianError,
|
||||||
|
FileError,
|
||||||
|
FileNotEmailError,
|
||||||
|
DuplicateMessageIdError,
|
||||||
|
NullPointerError,
|
||||||
|
TagTooLongError,
|
||||||
|
UnbalancedFreezeThawError,
|
||||||
|
UnbalancedAtomicError,
|
||||||
|
NotInitializedError
|
||||||
|
)
|
||||||
from notmuch.version import __VERSION__
|
from notmuch.version import __VERSION__
|
||||||
__LICENSE__ = "GPL v3+"
|
__LICENSE__ = "GPL v3+"
|
||||||
__AUTHOR__ = 'Sebastian Spaeth <Sebastian@SSpaeth.de>'
|
__AUTHOR__ = 'Sebastian Spaeth <Sebastian@SSpaeth.de>'
|
||||||
|
|
|
@ -112,7 +112,7 @@ class Database(object):
|
||||||
def _assert_db_is_initialized(self):
|
def _assert_db_is_initialized(self):
|
||||||
"""Raises a NotmuchError in case self._db is still None"""
|
"""Raises a NotmuchError in case self._db is still None"""
|
||||||
if self._db is None:
|
if self._db is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
def create(self, path):
|
def create(self, path):
|
||||||
"""Creates a new notmuch database
|
"""Creates a new notmuch database
|
||||||
|
@ -157,8 +157,7 @@ class Database(object):
|
||||||
res = Database._open(_str(path), mode)
|
res = Database._open(_str(path), mode)
|
||||||
|
|
||||||
if res is None:
|
if res is None:
|
||||||
raise NotmuchError(
|
raise NotmuchError(message="Could not open the specified database")
|
||||||
message="Could not open the specified database")
|
|
||||||
self._db = res
|
self._db = res
|
||||||
|
|
||||||
def get_path(self):
|
def get_path(self):
|
||||||
|
@ -232,7 +231,7 @@ class Database(object):
|
||||||
self._assert_db_is_initialized()
|
self._assert_db_is_initialized()
|
||||||
status = nmlib.notmuch_database_begin_atomic(self._db)
|
status = nmlib.notmuch_database_begin_atomic(self._db)
|
||||||
if status != STATUS.SUCCESS:
|
if status != STATUS.SUCCESS:
|
||||||
raise NotmuchError(status)
|
raise NotmuchError.get_subclass_exc(status)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def end_atomic(self):
|
def end_atomic(self):
|
||||||
|
@ -254,7 +253,7 @@ class Database(object):
|
||||||
self._assert_db_is_initialized()
|
self._assert_db_is_initialized()
|
||||||
status = nmlib.notmuch_database_end_atomic(self._db)
|
status = nmlib.notmuch_database_end_atomic(self._db)
|
||||||
if status != STATUS.SUCCESS:
|
if status != STATUS.SUCCESS:
|
||||||
raise NotmuchError(status)
|
raise NotmuchError.get_subclass_exc(status)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def get_directory(self, path):
|
def get_directory(self, path):
|
||||||
|
@ -285,7 +284,7 @@ class Database(object):
|
||||||
# we got an absolute path
|
# we got an absolute path
|
||||||
if not path.startswith(self.get_path()):
|
if not path.startswith(self.get_path()):
|
||||||
# but its initial components are not equal to the db path
|
# but its initial components are not equal to the db path
|
||||||
raise NotmuchError(STATUS.FILE_ERROR,
|
raise NotmuchError.get_subclass_exc(STATUS.FILE_ERROR,
|
||||||
message="Database().get_directory() called "
|
message="Database().get_directory() called "
|
||||||
"with a wrong absolute path.")
|
"with a wrong absolute path.")
|
||||||
abs_dirpath = path
|
abs_dirpath = path
|
||||||
|
@ -356,7 +355,7 @@ class Database(object):
|
||||||
byref(msg_p))
|
byref(msg_p))
|
||||||
|
|
||||||
if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:
|
if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:
|
||||||
raise NotmuchError(status)
|
raise NotmuchError.get_subclass_exc(status)
|
||||||
|
|
||||||
#construct Message() and return
|
#construct Message() and return
|
||||||
msg = Message(msg_p, self)
|
msg = Message(msg_p, self)
|
||||||
|
@ -450,7 +449,7 @@ class Database(object):
|
||||||
self._assert_db_is_initialized()
|
self._assert_db_is_initialized()
|
||||||
tags_p = Database._get_all_tags(self._db)
|
tags_p = Database._get_all_tags(self._db)
|
||||||
if tags_p == None:
|
if tags_p == None:
|
||||||
raise NotmuchError(STATUS.NULL_POINTER)
|
raise NotmuchError.get_subclass_exc(STATUS.NULL_POINTER)
|
||||||
return Tags(tags_p, self)
|
return Tags(tags_p, self)
|
||||||
|
|
||||||
def create_query(self, querystring):
|
def create_query(self, querystring):
|
||||||
|
@ -574,13 +573,13 @@ class Query(object):
|
||||||
(too little memory)
|
(too little memory)
|
||||||
"""
|
"""
|
||||||
if db.db_p is None:
|
if db.db_p is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
# create reference to parent db to keep it alive
|
# create reference to parent db to keep it alive
|
||||||
self._db = db
|
self._db = db
|
||||||
# create query, return None if too little mem available
|
# create query, return None if too little mem available
|
||||||
query_p = Query._create(db.db_p, _str(querystr))
|
query_p = Query._create(db.db_p, _str(querystr))
|
||||||
if query_p is None:
|
if query_p is None:
|
||||||
raise NotmuchError(STATUS.NULL_POINTER)
|
raise NotmuchError.get_subclass_exc(STATUS.NULL_POINTER)
|
||||||
self._query = query_p
|
self._query = query_p
|
||||||
|
|
||||||
def set_sort(self, sort):
|
def set_sort(self, sort):
|
||||||
|
@ -594,7 +593,7 @@ class Query(object):
|
||||||
been initialized.
|
been initialized.
|
||||||
"""
|
"""
|
||||||
if self._query is None:
|
if self._query is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
self.sort = sort
|
self.sort = sort
|
||||||
nmlib.notmuch_query_set_sort(self._query, sort)
|
nmlib.notmuch_query_set_sort(self._query, sort)
|
||||||
|
@ -620,7 +619,7 @@ class Query(object):
|
||||||
* :attr:`STATUS`.NULL_POINTER if search_threads failed
|
* :attr:`STATUS`.NULL_POINTER if search_threads failed
|
||||||
"""
|
"""
|
||||||
if self._query is None:
|
if self._query is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
threads_p = Query._search_threads(self._query)
|
threads_p = Query._search_threads(self._query)
|
||||||
|
|
||||||
|
@ -643,12 +642,12 @@ class Query(object):
|
||||||
* :attr:`STATUS`.NULL_POINTER if search_messages failed
|
* :attr:`STATUS`.NULL_POINTER if search_messages failed
|
||||||
"""
|
"""
|
||||||
if self._query is None:
|
if self._query is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
msgs_p = Query._search_messages(self._query)
|
msgs_p = Query._search_messages(self._query)
|
||||||
|
|
||||||
if msgs_p is None:
|
if msgs_p is None:
|
||||||
raise NotmuchError(STATUS.NULL_POINTER)
|
raise NotmuchError.get_subclass_exc(STATUS.NULL_POINTER)
|
||||||
|
|
||||||
return Messages(msgs_p, self)
|
return Messages(msgs_p, self)
|
||||||
|
|
||||||
|
@ -668,7 +667,7 @@ class Query(object):
|
||||||
* :attr:`STATUS`.NOT_INITIALIZED if query is not inited
|
* :attr:`STATUS`.NOT_INITIALIZED if query is not inited
|
||||||
"""
|
"""
|
||||||
if self._query is None:
|
if self._query is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
return Query._count_messages(self._query)
|
return Query._count_messages(self._query)
|
||||||
|
|
||||||
|
@ -711,7 +710,7 @@ class Directory(object):
|
||||||
def _assert_dir_is_initialized(self):
|
def _assert_dir_is_initialized(self):
|
||||||
"""Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None"""
|
"""Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None"""
|
||||||
if self._dir_p is None:
|
if self._dir_p is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
def __init__(self, path, dir_p, parent):
|
def __init__(self, path, dir_p, parent):
|
||||||
"""
|
"""
|
||||||
|
@ -771,7 +770,7 @@ class Directory(object):
|
||||||
if status == STATUS.SUCCESS:
|
if status == STATUS.SUCCESS:
|
||||||
return
|
return
|
||||||
#fail with Exception otherwise
|
#fail with Exception otherwise
|
||||||
raise NotmuchError(status)
|
raise NotmuchError.get_subclass_exc(status)
|
||||||
|
|
||||||
def get_mtime(self):
|
def get_mtime(self):
|
||||||
"""Gets the mtime value of this directory in the database
|
"""Gets the mtime value of this directory in the database
|
||||||
|
@ -857,7 +856,7 @@ class Filenames(object):
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
if self._files_p is None:
|
if self._files_p is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
if not nmlib.notmuch_filenames_valid(self._files_p):
|
if not nmlib.notmuch_filenames_valid(self._files_p):
|
||||||
self._files_p = None
|
self._files_p = None
|
||||||
|
@ -880,7 +879,7 @@ class Filenames(object):
|
||||||
for file in files: print file
|
for file in files: print file
|
||||||
"""
|
"""
|
||||||
if self._files_p is None:
|
if self._files_p is None:
|
||||||
raise NotmuchError(STATUS.NOT_INITIALIZED)
|
raise NotmuchError.get_subclass_exc(STATUS.NOT_INITIALIZED)
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while nmlib.notmuch_filenames_valid(self._files_p):
|
while nmlib.notmuch_filenames_valid(self._files_p):
|
||||||
|
|
|
@ -89,10 +89,32 @@ Invoke the class method `notmuch.STATUS.status2str` with a status value as
|
||||||
argument to receive a human readable string"""
|
argument to receive a human readable string"""
|
||||||
STATUS.__name__ = 'STATUS'
|
STATUS.__name__ = 'STATUS'
|
||||||
|
|
||||||
|
|
||||||
class NotmuchError(Exception):
|
class NotmuchError(Exception):
|
||||||
def __init__(self, status=None, message=None):
|
"""Is initiated with a (notmuch.STATUS[, message=None]). It will not
|
||||||
"""Is initiated with a (notmuch.STATUS[,message=None])"""
|
return an instance of the class NotmuchError, but a derived instance
|
||||||
|
of a more specific Error Message, e.g. OutOfMemoryError. Each status
|
||||||
|
but SUCCESS has a corresponding subclassed Exception."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_subclass_exc(cls, status, message=None):
|
||||||
|
"""Returns a fine grained Exception() type,detailing the error status"""
|
||||||
|
subclasses = {
|
||||||
|
STATUS.OUT_OF_MEMORY: OutOfMemoryError,
|
||||||
|
STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError,
|
||||||
|
STATUS.XAPIAN_EXCEPTION: XapianError,
|
||||||
|
STATUS.FILE_ERROR: FileError,
|
||||||
|
STATUS.FILE_NOT_EMAIL: FileNotEmailError,
|
||||||
|
STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError,
|
||||||
|
STATUS.NULL_POINTER: NullPointerError,
|
||||||
|
STATUS.TAG_TOO_LONG: TagTooLongError,
|
||||||
|
STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError,
|
||||||
|
STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError,
|
||||||
|
STATUS.NOT_INITIALIZED: NotInitializedError
|
||||||
|
}
|
||||||
|
assert 0 < status <= len(subclasses)
|
||||||
|
return subclasses[status](status, message)
|
||||||
|
|
||||||
|
def __init__(self, status, message=None):
|
||||||
self.status = status
|
self.status = status
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
|
@ -104,6 +126,32 @@ class NotmuchError(Exception):
|
||||||
else:
|
else:
|
||||||
return 'Unknown error'
|
return 'Unknown error'
|
||||||
|
|
||||||
|
# List of Subclassed exceptions that correspond to STATUS values and are
|
||||||
|
# subclasses of NotmuchError:
|
||||||
|
class OutOfMemoryError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class ReadOnlyDatabaseError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class XapianError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class FileError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class FileNotEmailError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class DuplicateMessageIdError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class NullPointerError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class TagTooLongError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class UnbalancedFreezeThawError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class UnbalancedAtomicError(NotmuchError):
|
||||||
|
pass
|
||||||
|
class NotInitializedError(NotmuchError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _str(value):
|
def _str(value):
|
||||||
"""Ensure a nicely utf-8 encoded string to pass to libnotmuch
|
"""Ensure a nicely utf-8 encoded string to pass to libnotmuch
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue