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 string representation of a notmuch_status_t value."""
52 # define strings for custom error messages
53 if status == STATUS.NOT_INITIALIZED:
54 return "Operation on uninitialized object impossible."
55 return str(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 if self.message is not None:
139 elif self.status is not None:
140 return STATUS.status2str(self.status)
142 return 'Unknown error'
145 # List of Subclassed exceptions that correspond to STATUS values and are
146 # subclasses of NotmuchError.
147 class OutOfMemoryError(NotmuchError):
148 status = STATUS.OUT_OF_MEMORY
151 class ReadOnlyDatabaseError(NotmuchError):
152 status = STATUS.READ_ONLY_DATABASE
155 class XapianError(NotmuchError):
156 status = STATUS.XAPIAN_EXCEPTION
159 class FileError(NotmuchError):
160 status = STATUS.FILE_ERROR
163 class FileNotEmailError(NotmuchError):
164 status = STATUS.FILE_NOT_EMAIL
167 class DuplicateMessageIdError(NotmuchError):
168 status = STATUS.DUPLICATE_MESSAGE_ID
171 class NullPointerError(NotmuchError):
172 status = STATUS.NULL_POINTER
175 class TagTooLongError(NotmuchError):
176 status = STATUS.TAG_TOO_LONG
179 class UnbalancedFreezeThawError(NotmuchError):
180 status = STATUS.UNBALANCED_FREEZE_THAW
183 class UnbalancedAtomicError(NotmuchError):
184 status = STATUS.UNBALANCED_ATOMIC
187 class NotInitializedError(NotmuchError):
188 """Derived from NotmuchError, this occurs if the underlying data
189 structure (e.g. database is not initialized (yet) or an iterator has
190 been exhausted. You can test for NotmuchError with .status =
191 STATUS.NOT_INITIALIZED"""
192 status = STATUS.NOT_INITIALIZED
196 """Ensure a nicely utf-8 encoded string to pass to libnotmuch
198 C++ code expects strings to be well formatted and
199 unicode strings to have no null bytes."""
200 if not isinstance(value, basestring):
201 raise TypeError("Expected str or unicode, got %s" % str(type(value)))
202 if isinstance(value, unicode):
203 return value.encode('UTF-8')
207 class NotmuchDatabaseS(Structure):
209 NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
212 class NotmuchQueryS(Structure):
214 NotmuchQueryP = POINTER(NotmuchQueryS)
217 class NotmuchThreadsS(Structure):
219 NotmuchThreadsP = POINTER(NotmuchThreadsS)
222 class NotmuchThreadS(Structure):
224 NotmuchThreadP = POINTER(NotmuchThreadS)
227 class NotmuchMessagesS(Structure):
229 NotmuchMessagesP = POINTER(NotmuchMessagesS)
232 class NotmuchMessageS(Structure):
234 NotmuchMessageP = POINTER(NotmuchMessageS)
237 class NotmuchTagsS(Structure):
239 NotmuchTagsP = POINTER(NotmuchTagsS)
242 class NotmuchDirectoryS(Structure):
244 NotmuchDirectoryP = POINTER(NotmuchDirectoryS)
247 class NotmuchFilenamesS(Structure):
249 NotmuchFilenamesP = POINTER(NotmuchFilenamesS)