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.")
31 """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc..."""
32 def __init__(self, names):
33 for number, name in enumerate(names):
34 setattr(self, name, number)
38 """Enum with a string representation of a notmuch_status_t value."""
39 _status2str = nmlib.notmuch_status_to_string
40 _status2str.restype = c_char_p
41 _status2str.argtypes = [c_int]
43 def __init__(self, statuslist):
44 """It is initialized with a list of strings that are available as
45 Status().string1 - Status().stringn attributes.
47 super(Status, self).__init__(statuslist)
50 def status2str(self, status):
51 """Get a (unicode) string representation of a notmuch_status_t value."""
52 # define strings for custom error messages
53 if status == STATUS.NOT_INITIALIZED:
54 return u"Operation on uninitialized object impossible."
55 return unicode(Status._status2str(status))
57 STATUS = Status(['SUCCESS',
63 'DUPLICATE_MESSAGE_ID',
66 'UNBALANCED_FREEZE_THAW',
69 """STATUS is a class, whose attributes provide constants that serve as return
70 indicators for notmuch functions. Currently the following ones are defined. For
71 possible return values and specific meaning for each method, see the method
80 * DUPLICATE_MESSAGE_ID
83 * UNBALANCED_FREEZE_THAW
87 Invoke the class method `notmuch.STATUS.status2str` with a status value as
88 argument to receive a human readable string"""
89 STATUS.__name__ = 'STATUS'
92 class NotmuchError(Exception):
93 """Is initiated with a (notmuch.STATUS[, message=None]). It will not
94 return an instance of the class NotmuchError, but a derived instance
95 of a more specific Error Message, e.g. OutOfMemoryError. Each status
96 but SUCCESS has a corresponding subclassed Exception."""
99 def get_exc_subclass(cls, status):
100 """Returns a fine grained Exception() type,
101 detailing the error status"""
103 STATUS.OUT_OF_MEMORY: OutOfMemoryError,
104 STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError,
105 STATUS.XAPIAN_EXCEPTION: XapianError,
106 STATUS.FILE_ERROR: FileError,
107 STATUS.FILE_NOT_EMAIL: FileNotEmailError,
108 STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError,
109 STATUS.NULL_POINTER: NullPointerError,
110 STATUS.TAG_TOO_LONG: TagTooLongError,
111 STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError,
112 STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError,
113 STATUS.NOT_INITIALIZED: NotInitializedError,
115 assert 0 < status <= len(subclasses)
116 return subclasses[status]
118 def __new__(cls, *args, **kwargs):
119 """Return a correct subclass of NotmuchError if needed
121 We return a NotmuchError instance if status is None (or 0) and a
122 subclass that inherits from NotmuchError depending on the
123 'status' parameter otherwise."""
124 # get 'status'. Passed in as arg or kwarg?
125 status = args[0] if len(args) else kwargs.get('status', None)
126 # no 'status' or cls is subclass already, return 'cls' instance
127 if not status or cls != NotmuchError:
128 return super(NotmuchError, cls).__new__(cls)
129 subclass = cls.get_exc_subclass(status) # which class to use?
130 return subclass.__new__(subclass, *args, **kwargs)
132 def __init__(self, status=None, message=None):
134 self.message = message
137 return unicode(self).encode('utf-8')
139 def __unicode__(self):
140 if self.message is not None:
142 elif self.status is not None:
143 return STATUS.status2str(self.status)
145 return u'Unknown error'
148 # List of Subclassed exceptions that correspond to STATUS values and are
149 # subclasses of NotmuchError.
150 class OutOfMemoryError(NotmuchError):
151 status = STATUS.OUT_OF_MEMORY
154 class ReadOnlyDatabaseError(NotmuchError):
155 status = STATUS.READ_ONLY_DATABASE
158 class XapianError(NotmuchError):
159 status = STATUS.XAPIAN_EXCEPTION
162 class FileError(NotmuchError):
163 status = STATUS.FILE_ERROR
166 class FileNotEmailError(NotmuchError):
167 status = STATUS.FILE_NOT_EMAIL
170 class DuplicateMessageIdError(NotmuchError):
171 status = STATUS.DUPLICATE_MESSAGE_ID
174 class NullPointerError(NotmuchError):
175 status = STATUS.NULL_POINTER
178 class TagTooLongError(NotmuchError):
179 status = STATUS.TAG_TOO_LONG
182 class UnbalancedFreezeThawError(NotmuchError):
183 status = STATUS.UNBALANCED_FREEZE_THAW
186 class UnbalancedAtomicError(NotmuchError):
187 status = STATUS.UNBALANCED_ATOMIC
190 class NotInitializedError(NotmuchError):
191 """Derived from NotmuchError, this occurs if the underlying data
192 structure (e.g. database is not initialized (yet) or an iterator has
193 been exhausted. You can test for NotmuchError with .status =
194 STATUS.NOT_INITIALIZED"""
195 status = STATUS.NOT_INITIALIZED
199 """Ensure a nicely utf-8 encoded string to pass to libnotmuch
201 C++ code expects strings to be well formatted and
202 unicode strings to have no null bytes."""
203 if not isinstance(value, basestring):
204 raise TypeError("Expected str or unicode, got %s" % str(type(value)))
205 if isinstance(value, unicode):
206 return value.encode('UTF-8')
210 class NotmuchDatabaseS(Structure):
212 NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
215 class NotmuchQueryS(Structure):
217 NotmuchQueryP = POINTER(NotmuchQueryS)
220 class NotmuchThreadsS(Structure):
222 NotmuchThreadsP = POINTER(NotmuchThreadsS)
225 class NotmuchThreadS(Structure):
227 NotmuchThreadP = POINTER(NotmuchThreadS)
230 class NotmuchMessagesS(Structure):
232 NotmuchMessagesP = POINTER(NotmuchMessagesS)
235 class NotmuchMessageS(Structure):
237 NotmuchMessageP = POINTER(NotmuchMessageS)
240 class NotmuchTagsS(Structure):
242 NotmuchTagsP = POINTER(NotmuchTagsS)
245 class NotmuchDirectoryS(Structure):
247 NotmuchDirectoryP = POINTER(NotmuchDirectoryS)
250 class NotmuchFilenamesS(Structure):
252 NotmuchFilenamesP = POINTER(NotmuchFilenamesS)