2 This file is part of notmuch.
4 Notmuch is free software: you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation, either version 3 of the License, or (at your
7 option) any later version.
9 Notmuch is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with notmuch. If not, see <http://www.gnu.org/licenses/>.
17 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
20 from ctypes import CDLL, c_char_p, c_int, Structure, POINTER
21 from ctypes.util import find_library
23 #-----------------------------------------------------------------------------
24 #package-global instance of the notmuch library
26 nmlib = CDLL("libnotmuch.so.2")
28 raise ImportError("Could not find shared 'notmuch' library.")
32 """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
33 def __init__(self, names):
34 for number, name in enumerate(names):
35 setattr(self, name, number)
39 """Enum with a string representation of a notmuch_status_t value."""
40 _status2str = nmlib.notmuch_status_to_string
41 _status2str.restype = c_char_p
42 _status2str.argtypes = [c_int]
44 def __init__(self, statuslist):
45 """It is initialized with a list of strings that are available as
46 Status().string1 - Status().stringn attributes.
48 super(Status, self).__init__(statuslist)
51 def status2str(self, status):
52 """Get a string representation of a notmuch_status_t value."""
53 # define strings for custom error messages
54 if status == STATUS.NOT_INITIALIZED:
55 return "Operation on uninitialized object impossible."
56 return str(Status._status2str(status))
58 STATUS = Status(['SUCCESS',
64 'DUPLICATE_MESSAGE_ID',
67 'UNBALANCED_FREEZE_THAW',
70 """STATUS is a class, whose attributes provide constants that serve as return
71 indicators for notmuch functions. Currently the following ones are defined. For
72 possible return values and specific meaning for each method, see the method
81 * DUPLICATE_MESSAGE_ID
84 * UNBALANCED_FREEZE_THAW
88 Invoke the class method `notmuch.STATUS.status2str` with a status value as
89 argument to receive a human readable string"""
90 STATUS.__name__ = 'STATUS'
93 class NotmuchError(Exception):
94 """Is initiated with a (notmuch.STATUS[, message=None]). It will not
95 return an instance of the class NotmuchError, but a derived instance
96 of a more specific Error Message, e.g. OutOfMemoryError. Each status
97 but SUCCESS has a corresponding subclassed Exception."""
100 def get_exc_subclass(cls, status):
101 """Returns a fine grained Exception() type,
102 detailing the error status"""
104 STATUS.OUT_OF_MEMORY: OutOfMemoryError,
105 STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError,
106 STATUS.XAPIAN_EXCEPTION: XapianError,
107 STATUS.FILE_ERROR: FileError,
108 STATUS.FILE_NOT_EMAIL: FileNotEmailError,
109 STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError,
110 STATUS.NULL_POINTER: NullPointerError,
111 STATUS.TAG_TOO_LONG: TagTooLongError,
112 STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError,
113 STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError,
114 STATUS.NOT_INITIALIZED: NotInitializedError,
116 assert 0 < status <= len(subclasses)
117 return subclasses[status]
119 def __new__(cls, *args, **kwargs):
120 """Return a correct subclass of NotmuchError if needed
122 We return a NotmuchError instance if status is None (or 0) and a
123 subclass that inherits from NotmuchError depending on the
124 'status' parameter otherwise."""
125 # get 'status'. Passed in as arg or kwarg?
126 status = args[0] if len(args) else kwargs.get('status', None)
127 # no 'status' or cls is subclass already, return 'cls' instance
128 if not status or cls != NotmuchError:
129 return super(NotmuchError, cls).__new__(cls)
130 subclass = cls.get_exc_subclass(status) # which class to use?
131 return subclass.__new__(subclass, *args, **kwargs)
133 def __init__(self, status=None, message=None):
135 self.message = message
138 if self.message is not None:
140 elif self.status is not None:
141 return STATUS.status2str(self.status)
143 return 'Unknown error'
146 # List of Subclassed exceptions that correspond to STATUS values and are
147 # subclasses of NotmuchError.
148 class OutOfMemoryError(NotmuchError):
149 status = STATUS.OUT_OF_MEMORY
152 class ReadOnlyDatabaseError(NotmuchError):
153 status = STATUS.READ_ONLY_DATABASE
156 class XapianError(NotmuchError):
157 status = STATUS.XAPIAN_EXCEPTION
160 class FileError(NotmuchError):
161 status = STATUS.FILE_ERROR
164 class FileNotEmailError(NotmuchError):
165 status = STATUS.FILE_NOT_EMAIL
168 class DuplicateMessageIdError(NotmuchError):
169 status = STATUS.DUPLICATE_MESSAGE_ID
172 class NullPointerError(NotmuchError):
173 status = STATUS.NULL_POINTER
176 class TagTooLongError(NotmuchError):
177 status = STATUS.TAG_TOO_LONG
180 class UnbalancedFreezeThawError(NotmuchError):
181 status = STATUS.UNBALANCED_FREEZE_THAW
184 class UnbalancedAtomicError(NotmuchError):
185 status = STATUS.UNBALANCED_ATOMIC
188 class NotInitializedError(NotmuchError):
189 """Derived from NotmuchError, this occurs if the underlying data
190 structure (e.g. database is not initialized (yet) or an iterator has
191 been exhausted. You can test for NotmuchError with .status =
192 STATUS.NOT_INITIALIZED"""
193 status = STATUS.NOT_INITIALIZED
197 """Ensure a nicely utf-8 encoded string to pass to libnotmuch
199 C++ code expects strings to be well formatted and
200 unicode strings to have no null bytes."""
201 if not isinstance(value, basestring):
202 raise TypeError("Expected str or unicode, got %s" % str(type(value)))
203 if isinstance(value, unicode):
204 return value.encode('UTF-8')
208 class NotmuchDatabaseS(Structure):
210 NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
213 class NotmuchQueryS(Structure):
215 NotmuchQueryP = POINTER(NotmuchQueryS)
218 class NotmuchThreadsS(Structure):
220 NotmuchThreadsP = POINTER(NotmuchThreadsS)
223 class NotmuchThreadS(Structure):
225 NotmuchThreadP = POINTER(NotmuchThreadS)
228 class NotmuchMessagesS(Structure):
230 NotmuchMessagesP = POINTER(NotmuchMessagesS)
233 class NotmuchMessageS(Structure):
235 NotmuchMessageP = POINTER(NotmuchMessageS)
238 class NotmuchTagsS(Structure):
240 NotmuchTagsP = POINTER(NotmuchTagsS)
243 class NotmuchDirectoryS(Structure):
245 NotmuchDirectoryP = POINTER(NotmuchDirectoryS)
248 class NotmuchFilenamesS(Structure):
250 NotmuchFilenamesP = POINTER(NotmuchFilenamesS)