]> git.cworth.org Git - notmuch/blob - bindings/python/notmuch/errors.py
Merge branch 'release'
[notmuch] / bindings / python / notmuch / errors.py
1 """
2 This file is part of notmuch.
3
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.
8
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
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with notmuch.  If not, see <https://www.gnu.org/licenses/>.
16
17 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
18 """
19
20 from ctypes import c_char_p, c_int
21
22 from .globals import (
23     nmlib,
24     Enum,
25     Python3StringMixIn,
26 )
27
28 class Status(Enum):
29     """Enum with a string representation of a notmuch_status_t value."""
30     _status2str = nmlib.notmuch_status_to_string
31     _status2str.restype = c_char_p
32     _status2str.argtypes = [c_int]
33
34     def __init__(self, statuslist):
35         """It is initialized with a list of strings that are available as
36         Status().string1 - Status().stringn attributes.
37         """
38         super(Status, self).__init__(statuslist)
39
40     @classmethod
41     def status2str(self, status):
42         """Get a (unicode) string representation of a notmuch_status_t value."""
43         # define strings for custom error messages
44         if status == STATUS.NOT_INITIALIZED:
45             return "Operation on uninitialized object impossible."
46         return unicode(Status._status2str(status))
47
48 STATUS = Status(['SUCCESS',
49   'OUT_OF_MEMORY',
50   'READ_ONLY_DATABASE',
51   'XAPIAN_EXCEPTION',
52   'FILE_ERROR',
53   'FILE_NOT_EMAIL',
54   'DUPLICATE_MESSAGE_ID',
55   'NULL_POINTER',
56   'TAG_TOO_LONG',
57   'UNBALANCED_FREEZE_THAW',
58   'UNBALANCED_ATOMIC',
59   'UNSUPPORTED_OPERATION',
60   'UPGRADE_REQUIRED',
61   'PATH_ERROR',
62   'NOT_INITIALIZED'])
63 """STATUS is a class, whose attributes provide constants that serve as return
64 indicators for notmuch functions. Currently the following ones are defined. For
65 possible return values and specific meaning for each method, see the method
66 description.
67
68   * SUCCESS
69   * OUT_OF_MEMORY
70   * READ_ONLY_DATABASE
71   * XAPIAN_EXCEPTION
72   * FILE_ERROR
73   * FILE_NOT_EMAIL
74   * DUPLICATE_MESSAGE_ID
75   * NULL_POINTER
76   * TAG_TOO_LONG
77   * UNBALANCED_FREEZE_THAW
78   * UNBALANCED_ATOMIC
79   * UNSUPPORTED_OPERATION
80   * UPGRADE_REQUIRED
81   * PATH_ERROR
82   * NOT_INITIALIZED
83
84 Invoke the class method `notmuch.STATUS.status2str` with a status value as
85 argument to receive a human readable string"""
86 STATUS.__name__ = 'STATUS'
87
88
89 class NotmuchError(Exception, Python3StringMixIn):
90     """Is initiated with a (notmuch.STATUS[, message=None]). It will not
91     return an instance of the class NotmuchError, but a derived instance
92     of a more specific Error Message, e.g. OutOfMemoryError. Each status
93     but SUCCESS has a corresponding subclassed Exception."""
94
95     @classmethod
96     def get_exc_subclass(cls, status):
97         """Returns a fine grained Exception() type,
98         detailing the error status"""
99         subclasses = {
100             STATUS.OUT_OF_MEMORY: OutOfMemoryError,
101             STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError,
102             STATUS.XAPIAN_EXCEPTION: XapianError,
103             STATUS.FILE_ERROR: FileError,
104             STATUS.FILE_NOT_EMAIL: FileNotEmailError,
105             STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError,
106             STATUS.NULL_POINTER: NullPointerError,
107             STATUS.TAG_TOO_LONG: TagTooLongError,
108             STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError,
109             STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError,
110             STATUS.UNSUPPORTED_OPERATION: UnsupportedOperationError,
111             STATUS.UPGRADE_REQUIRED: UpgradeRequiredError,
112             STATUS.PATH_ERROR: PathError,
113             STATUS.NOT_INITIALIZED: NotInitializedError,
114         }
115         assert 0 < status <= len(subclasses)
116         return subclasses[status]
117
118     def __new__(cls, *args, **kwargs):
119         """Return a correct subclass of NotmuchError if needed
120
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)
131
132     def __init__(self, status=None, message=None):
133         self.status = status
134         self.message = message
135
136     def __unicode__(self):
137         if self.message is not None:
138             return self.message
139         elif self.status is not None:
140             return STATUS.status2str(self.status)
141         else:
142             return 'Unknown error'
143
144
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
149
150
151 class ReadOnlyDatabaseError(NotmuchError):
152     status = STATUS.READ_ONLY_DATABASE
153
154
155 class XapianError(NotmuchError):
156     status = STATUS.XAPIAN_EXCEPTION
157
158
159 class FileError(NotmuchError):
160     status = STATUS.FILE_ERROR
161
162
163 class FileNotEmailError(NotmuchError):
164     status = STATUS.FILE_NOT_EMAIL
165
166
167 class DuplicateMessageIdError(NotmuchError):
168     status = STATUS.DUPLICATE_MESSAGE_ID
169
170
171 class NullPointerError(NotmuchError):
172     status = STATUS.NULL_POINTER
173
174
175 class TagTooLongError(NotmuchError):
176     status = STATUS.TAG_TOO_LONG
177
178
179 class UnbalancedFreezeThawError(NotmuchError):
180     status = STATUS.UNBALANCED_FREEZE_THAW
181
182
183 class UnbalancedAtomicError(NotmuchError):
184     status = STATUS.UNBALANCED_ATOMIC
185
186
187 class UnsupportedOperationError(NotmuchError):
188     status = STATUS.UNSUPPORTED_OPERATION
189
190
191 class UpgradeRequiredError(NotmuchError):
192     status = STATUS.UPGRADE_REQUIRED
193
194
195 class PathError(NotmuchError):
196     status = STATUS.PATH_ERROR
197
198
199 class NotInitializedError(NotmuchError):
200     """Derived from NotmuchError, this occurs if the underlying data
201     structure (e.g. database is not initialized (yet) or an iterator has
202     been exhausted. You can test for NotmuchError with .status =
203     STATUS.NOT_INITIALIZED"""
204     status = STATUS.NOT_INITIALIZED