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
22 #-----------------------------------------------------------------------------
23 #package-global instance of the notmuch library
25 nmlib = CDLL("libnotmuch.so.2")
27 raise ImportError("Could not find shared 'notmuch' library.")
30 if sys.version_info[0] == 2:
31 class Python3StringMixIn(object):
33 return unicode(self).encode('utf-8')
35 class Python3StringMixIn(object):
37 return self.__unicode__()
41 """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
42 def __init__(self, names):
43 for number, name in enumerate(names):
44 setattr(self, name, number)
48 """Enum with a string representation of a notmuch_status_t value."""
49 _status2str = nmlib.notmuch_status_to_string
50 _status2str.restype = c_char_p
51 _status2str.argtypes = [c_int]
53 def __init__(self, statuslist):
54 """It is initialized with a list of strings that are available as
55 Status().string1 - Status().stringn attributes.
57 super(Status, self).__init__(statuslist)
60 def status2str(self, status):
61 """Get a (unicode) string representation of a notmuch_status_t value."""
62 # define strings for custom error messages
63 if status == STATUS.NOT_INITIALIZED:
64 return "Operation on uninitialized object impossible."
65 return unicode(Status._status2str(status))
67 STATUS = Status(['SUCCESS',
73 'DUPLICATE_MESSAGE_ID',
76 'UNBALANCED_FREEZE_THAW',
79 """STATUS is a class, whose attributes provide constants that serve as return
80 indicators for notmuch functions. Currently the following ones are defined. For
81 possible return values and specific meaning for each method, see the method
90 * DUPLICATE_MESSAGE_ID
93 * UNBALANCED_FREEZE_THAW
97 Invoke the class method `notmuch.STATUS.status2str` with a status value as
98 argument to receive a human readable string"""
99 STATUS.__name__ = 'STATUS'
102 class NotmuchError(Exception, Python3StringMixIn):
103 """Is initiated with a (notmuch.STATUS[, message=None]). It will not
104 return an instance of the class NotmuchError, but a derived instance
105 of a more specific Error Message, e.g. OutOfMemoryError. Each status
106 but SUCCESS has a corresponding subclassed Exception."""
109 def get_exc_subclass(cls, status):
110 """Returns a fine grained Exception() type,
111 detailing the error status"""
113 STATUS.OUT_OF_MEMORY: OutOfMemoryError,
114 STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError,
115 STATUS.XAPIAN_EXCEPTION: XapianError,
116 STATUS.FILE_ERROR: FileError,
117 STATUS.FILE_NOT_EMAIL: FileNotEmailError,
118 STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError,
119 STATUS.NULL_POINTER: NullPointerError,
120 STATUS.TAG_TOO_LONG: TagTooLongError,
121 STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError,
122 STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError,
123 STATUS.NOT_INITIALIZED: NotInitializedError,
125 assert 0 < status <= len(subclasses)
126 return subclasses[status]
128 def __new__(cls, *args, **kwargs):
129 """Return a correct subclass of NotmuchError if needed
131 We return a NotmuchError instance if status is None (or 0) and a
132 subclass that inherits from NotmuchError depending on the
133 'status' parameter otherwise."""
134 # get 'status'. Passed in as arg or kwarg?
135 status = args[0] if len(args) else kwargs.get('status', None)
136 # no 'status' or cls is subclass already, return 'cls' instance
137 if not status or cls != NotmuchError:
138 return super(NotmuchError, cls).__new__(cls)
139 subclass = cls.get_exc_subclass(status) # which class to use?
140 return subclass.__new__(subclass, *args, **kwargs)
142 def __init__(self, status=None, message=None):
144 self.message = message
146 def __unicode__(self):
147 if self.message is not None:
149 elif self.status is not None:
150 return STATUS.status2str(self.status)
152 return 'Unknown error'
155 # List of Subclassed exceptions that correspond to STATUS values and are
156 # subclasses of NotmuchError.
157 class OutOfMemoryError(NotmuchError):
158 status = STATUS.OUT_OF_MEMORY
161 class ReadOnlyDatabaseError(NotmuchError):
162 status = STATUS.READ_ONLY_DATABASE
165 class XapianError(NotmuchError):
166 status = STATUS.XAPIAN_EXCEPTION
169 class FileError(NotmuchError):
170 status = STATUS.FILE_ERROR
173 class FileNotEmailError(NotmuchError):
174 status = STATUS.FILE_NOT_EMAIL
177 class DuplicateMessageIdError(NotmuchError):
178 status = STATUS.DUPLICATE_MESSAGE_ID
181 class NullPointerError(NotmuchError):
182 status = STATUS.NULL_POINTER
185 class TagTooLongError(NotmuchError):
186 status = STATUS.TAG_TOO_LONG
189 class UnbalancedFreezeThawError(NotmuchError):
190 status = STATUS.UNBALANCED_FREEZE_THAW
193 class UnbalancedAtomicError(NotmuchError):
194 status = STATUS.UNBALANCED_ATOMIC
197 class NotInitializedError(NotmuchError):
198 """Derived from NotmuchError, this occurs if the underlying data
199 structure (e.g. database is not initialized (yet) or an iterator has
200 been exhausted. You can test for NotmuchError with .status =
201 STATUS.NOT_INITIALIZED"""
202 status = STATUS.NOT_INITIALIZED
206 """Ensure a nicely utf-8 encoded string to pass to libnotmuch
208 C++ code expects strings to be well formatted and
209 unicode strings to have no null bytes."""
210 if not isinstance(value, basestring):
211 raise TypeError("Expected str or unicode, got %s" % str(type(value)))
212 if isinstance(value, unicode):
213 return value.encode('UTF-8')
217 class NotmuchDatabaseS(Structure):
219 NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
222 class NotmuchQueryS(Structure):
224 NotmuchQueryP = POINTER(NotmuchQueryS)
227 class NotmuchThreadsS(Structure):
229 NotmuchThreadsP = POINTER(NotmuchThreadsS)
232 class NotmuchThreadS(Structure):
234 NotmuchThreadP = POINTER(NotmuchThreadS)
237 class NotmuchMessagesS(Structure):
239 NotmuchMessagesP = POINTER(NotmuchMessagesS)
242 class NotmuchMessageS(Structure):
244 NotmuchMessageP = POINTER(NotmuchMessageS)
247 class NotmuchTagsS(Structure):
249 NotmuchTagsP = POINTER(NotmuchTagsS)
252 class NotmuchDirectoryS(Structure):
254 NotmuchDirectoryP = POINTER(NotmuchDirectoryS)
257 class NotmuchFilenamesS(Structure):
259 NotmuchFilenamesP = POINTER(NotmuchFilenamesS)