diff options
| author | Floris Bruynooghe <flub@google.com> | 2019-10-08 23:03:12 +0200 |
|---|---|---|
| committer | David Bremner <david@tethera.net> | 2019-12-03 08:12:30 -0400 |
| commit | 83c2d158983875bf77a9b7662894df585b61741c (patch) | |
| tree | 8443e3ab530a9cbf00b17c395f03e19138d3bae0 /bindings/python-cffi/notdb/_errors.py | |
| parent | 5f9ea4d2908a597acaf0b809b6f27fa74b70520b (diff) | |
Introduce CFFI-based python bindings
This introduces CFFI-based Python3-only bindings.
The bindings aim at:
- Better performance on pypy
- Easier to use Python-C interface
- More "pythonic"
- The API should not allow invalid operations
- Use native object protocol where possible
- Memory safety; whatever you do from python, it should not coredump.
Diffstat (limited to 'bindings/python-cffi/notdb/_errors.py')
| -rw-r--r-- | bindings/python-cffi/notdb/_errors.py | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/bindings/python-cffi/notdb/_errors.py b/bindings/python-cffi/notdb/_errors.py new file mode 100644 index 00000000..924e722f --- /dev/null +++ b/bindings/python-cffi/notdb/_errors.py @@ -0,0 +1,112 @@ +from notdb import _capi as capi + + +class NotmuchError(Exception): + """Base exception for errors originating from the notmuch library. + + Usually this will have two attributes: + + :status: This is a numeric status code corresponding to the error + code in the notmuch library. This is normally fairly + meaningless, it can also often be ``None``. This exists mostly + to easily create new errors from notmuch status codes and + should not normally be used by users. + + :message: A user-facing message for the error. This can + occasionally also be ``None``. Usually you'll want to call + ``str()`` on the error object instead to get a sensible + message. + """ + + @classmethod + def exc_type(cls, status): + """Return correct exception type for notmuch status.""" + types = { + capi.lib.NOTMUCH_STATUS_OUT_OF_MEMORY: + OutOfMemoryError, + capi.lib.NOTMUCH_STATUS_READ_ONLY_DATABASE: + ReadOnlyDatabaseError, + capi.lib.NOTMUCH_STATUS_XAPIAN_EXCEPTION: + XapianError, + capi.lib.NOTMUCH_STATUS_FILE_ERROR: + FileError, + capi.lib.NOTMUCH_STATUS_FILE_NOT_EMAIL: + FileNotEmailError, + capi.lib.NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: + DuplicateMessageIdError, + capi.lib.NOTMUCH_STATUS_NULL_POINTER: + NullPointerError, + capi.lib.NOTMUCH_STATUS_TAG_TOO_LONG: + TagTooLongError, + capi.lib.NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: + UnbalancedFreezeThawError, + capi.lib.NOTMUCH_STATUS_UNBALANCED_ATOMIC: + UnbalancedAtomicError, + capi.lib.NOTMUCH_STATUS_UNSUPPORTED_OPERATION: + UnsupportedOperationError, + capi.lib.NOTMUCH_STATUS_UPGRADE_REQUIRED: + UpgradeRequiredError, + capi.lib.NOTMUCH_STATUS_PATH_ERROR: + PathError, + capi.lib.NOTMUCH_STATUS_ILLEGAL_ARGUMENT: + IllegalArgumentError, + } + return types[status] + + def __new__(cls, *args, **kwargs): + """Return the correct subclass based on status.""" + # This is simplistic, but the actual __init__ will fail if the + # signature is wrong anyway. + if args: + status = args[0] + else: + status = kwargs.get('status', None) + if status and cls == NotmuchError: + exc = cls.exc_type(status) + return exc.__new__(exc, *args, **kwargs) + else: + return super().__new__(cls) + + def __init__(self, status=None, message=None): + self.status = status + self.message = message + + def __str__(self): + if self.message: + return self.message + elif self.status: + return capi.lib.notmuch_status_to_string(self.status) + else: + return 'Unknown error' + + +class OutOfMemoryError(NotmuchError): pass +class ReadOnlyDatabaseError(NotmuchError): pass +class XapianError(NotmuchError): pass +class FileError(NotmuchError): pass +class FileNotEmailError(NotmuchError): pass +class DuplicateMessageIdError(NotmuchError): pass +class NullPointerError(NotmuchError): pass +class TagTooLongError(NotmuchError): pass +class UnbalancedFreezeThawError(NotmuchError): pass +class UnbalancedAtomicError(NotmuchError): pass +class UnsupportedOperationError(NotmuchError): pass +class UpgradeRequiredError(NotmuchError): pass +class PathError(NotmuchError): pass +class IllegalArgumentError(NotmuchError): pass + + +class ObjectDestroyedError(NotmuchError): + """The object has already been destoryed and it's memory freed. + + This occurs when :meth:`destroy` has been called on the object but + you still happen to have access to the object. This should not + normally occur since you should never call :meth:`destroy` by + hand. + """ + + def __str__(self): + if self.message: + return self.message + else: + return 'Memory already freed' |
