unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH 1/9] python: add a .gitignore file and refine the toplevel one
@ 2011-09-26  1:05 Justus Winter
  2011-09-26  1:05 ` [PATCH 2/9] python: add status and message attributes to NotmuchError Justus Winter
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

The line 'notmuch' in the toplevel .gitignore file is to broad
and matches bindings/python/notmuch making it cumbersome to
git-add files within that directory.

Refine the toplevel file to only match the generated notmuch
executable and add a more specialized .gitignore file to the
python directory.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 .gitignore                 |    2 +-
 bindings/python/.gitignore |    2 ++
 2 files changed, 3 insertions(+), 1 deletions(-)
 create mode 100644 bindings/python/.gitignore

diff --git a/.gitignore b/.gitignore
index 02ab004..9468e30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@ TAGS
 tags
 *cscope*
 .deps
-notmuch
+/notmuch
 notmuch.sym
 notmuch-shared
 notmuch.1.gz
diff --git a/bindings/python/.gitignore b/bindings/python/.gitignore
new file mode 100644
index 0000000..82e4918
--- /dev/null
+++ b/bindings/python/.gitignore
@@ -0,0 +1,2 @@
+*.py[co]
+/build
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/9] python: add status and message attributes to NotmuchError
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 3/9] python: reorder the arguments of NotmuchError.__init__() Justus Winter
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Providing exception objects with meaningful attribute names
is much nicer than using e.args[].

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/globals.py |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 05b9962..779ba5f 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -91,13 +91,14 @@ STATUS.__name__ = 'STATUS'
 class NotmuchError(Exception):
     def __init__(self, status=None, message=None):
         """Is initiated with a (notmuch.STATUS[,message=None])"""
-        super(NotmuchError, self).__init__(message, status)
+        self.status = status
+        self.message = message
 
     def __str__(self):
-        if self.args[0] is not None:
-            return self.args[0]
+        if self.message is not None:
+            return self.message
         else:
-            return STATUS.status2str(self.args[1])
+            return STATUS.status2str(self.status)
 
 def _str(value):
     """Ensure a nicely utf-8 encoded string to pass to libnotmuch
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/9] python: reorder the arguments of NotmuchError.__init__()
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
  2011-09-26  1:05 ` [PATCH 2/9] python: add status and message attributes to NotmuchError Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 4/9] python: fix NotmuchError.__str__ if status == None Justus Winter
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

It is customary for subclasses of Exception to take a string as
the first argument that describes the problem.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/database.py |   48 ++++++++++++++--------------
 bindings/python/notmuch/filename.py |    4 +-
 bindings/python/notmuch/globals.py  |    6 ++--
 bindings/python/notmuch/message.py  |   58 +++++++++++++++++-----------------
 bindings/python/notmuch/tag.py      |    4 +-
 bindings/python/notmuch/thread.py   |   32 +++++++++---------
 6 files changed, 76 insertions(+), 76 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index a462789..e174f55 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -108,7 +108,7 @@ class Database(object):
     def _verify_initialized_db(self):
         """Raises a NotmuchError in case self._db is still None"""
         if self._db is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
     def create(self, path):
         """Creates a new notmuch database
@@ -247,9 +247,9 @@ class Database(object):
             # we got an absolute path
             if not path.startswith(self.get_path()):
                 # but its initial components are not equal to the db path
-                raise NotmuchError(STATUS.FILE_ERROR,
-                                   message="Database().get_directory() called "
-                                           "with a wrong absolute path.")
+                raise NotmuchError(message="Database().get_directory() called "
+                                           "with a wrong absolute path.",
+                                   status=STATUS.FILE_ERROR)
             abs_dirpath = path
         else:
             #we got a relative path, make it absolute
@@ -319,7 +319,7 @@ class Database(object):
                                                   byref(msg_p))
 
         if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:
-            raise NotmuchError(status)
+            raise NotmuchError(status=status)
 
         #construct Message() and return
         msg = Message(msg_p, self)
@@ -398,7 +398,7 @@ class Database(object):
 
         tags_p = Database._get_all_tags(self._db)
         if tags_p == None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         return Tags(tags_p, self)
 
     def create_query(self, querystring):
@@ -524,13 +524,13 @@ class Query(object):
                         (too little memory)
         """
         if db.db_p is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         # create reference to parent db to keep it alive
         self._db = db
         # create query, return None if too little mem available
         query_p = Query._create(db.db_p, _str(querystr))
         if query_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         self._query = query_p
 
     def set_sort(self, sort):
@@ -544,7 +544,7 @@ class Query(object):
                     been initialized.
         """
         if self._query is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         self.sort = sort
         nmlib.notmuch_query_set_sort(self._query, sort)
@@ -570,12 +570,12 @@ class Query(object):
                       * STATUS.NULL_POINTER if search_threads failed
         """
         if self._query is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         threads_p = Query._search_threads(self._query)
 
         if threads_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         return Threads(threads_p, self)
 
@@ -593,12 +593,12 @@ class Query(object):
                       * STATUS.NULL_POINTER if search_messages failed
         """
         if self._query is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         msgs_p = Query._search_messages(self._query)
 
         if msgs_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         return Messages(msgs_p, self)
 
@@ -618,7 +618,7 @@ class Query(object):
                       * STATUS.NOT_INITIALIZED if query is not inited
         """
         if self._query is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         return Query._count_messages(self._query)
 
@@ -659,9 +659,9 @@ class Directory(object):
     _get_child_directories.restype = c_void_p
 
     def _verify_dir_initialized(self):
-        """Raises a NotmuchError(STATUS.NOT_INITIALIZED) if dir_p is None"""
+        """Raises a NotmuchError(status=STATUS.NOT_INITIALIZED) if dir_p is None"""
         if self._dir_p is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
     def __init__(self, path, dir_p, parent):
         """
@@ -713,7 +713,7 @@ class Directory(object):
                         STATUS.NOT_INITIALIZED
                           The directory has not been initialized
         """
-        #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if the dir_p is None
+        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if the dir_p is None
         self._verify_dir_initialized()
 
         #TODO: make sure, we convert the mtime parameter to a 'c_long'
@@ -723,7 +723,7 @@ class Directory(object):
         if status == STATUS.SUCCESS:
             return
         #fail with Exception otherwise
-        raise NotmuchError(status)
+        raise NotmuchError(status=status)
 
     def get_mtime(self):
         """Gets the mtime value of this directory in the database
@@ -737,7 +737,7 @@ class Directory(object):
                         STATUS.NOT_INITIALIZED
                           The directory has not been initialized
         """
-        #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self.dir_p is None
+        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self.dir_p is None
         self._verify_dir_initialized()
 
         return Directory._get_mtime(self._dir_p)
@@ -756,7 +756,7 @@ class Directory(object):
         The returned filenames will be the basename-entries only (not
         complete paths.
         """
-        #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self._dir_p is None
+        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self._dir_p is None
         self._verify_dir_initialized()
 
         files_p = Directory._get_child_files(self._dir_p)
@@ -769,7 +769,7 @@ class Directory(object):
         The returned filenames will be the basename-entries only (not
         complete paths.
         """
-        #Raise a NotmuchError(STATUS.NOT_INITIALIZED) if self._dir_p is None
+        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self._dir_p is None
         self._verify_dir_initialized()
 
         files_p = Directory._get_child_directories(self._dir_p)
@@ -815,7 +815,7 @@ class Filenames(object):
 
     def next(self):
         if self._files_p is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         if not nmlib.notmuch_filenames_valid(self._files_p):
             self._files_p = None
@@ -834,11 +834,11 @@ class Filenames(object):
                  #THIS FAILS
                  files = Database().get_directory('').get_child_files()
                  if len(files) > 0:              #this 'exhausts' msgs
-                     # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!!
+                     # next line raises NotmuchError(status=STATUS.NOT_INITIALIZED)!!!
                      for file in files: print file
         """
         if self._files_p is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         i = 0
         while nmlib.notmuch_filenames_valid(self._files_p):
diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index a16e717..c5dfd94 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -68,7 +68,7 @@ class Filenames(object):
              once all derived objects are dead.
         """
         if files_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         self._files = files_p
         #save reference to parent object so we keep it alive
@@ -80,7 +80,7 @@ class Filenames(object):
         This is the main function that will usually be used by the
         user."""
         if self._files is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         if not nmlib.notmuch_filenames_valid(self._files):
             self._files = None
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 779ba5f..dd0c858 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -89,10 +89,10 @@ STATUS.__name__ = 'STATUS'
 
 
 class NotmuchError(Exception):
-    def __init__(self, status=None, message=None):
-        """Is initiated with a (notmuch.STATUS[,message=None])"""
-        self.status = status
+    def __init__(self, message=None, status=None):
+        """Is initiated with a (message=None[,status=notmuch.STATUS])"""
         self.message = message
+        self.status = status
 
     def __str__(self):
         if self.message is not None:
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index a48900c..5cc3175 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -115,7 +115,7 @@ class Messages(object):
                the Python object.(?)
         """
         if msgs_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         self._msgs = msgs_p
         #store parent, so we keep them alive as long as self  is alive
@@ -131,7 +131,7 @@ class Messages(object):
           therefore will not allow further iterations.
         """
         if self._msgs is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         # collect all tags (returns NULL on error)
         tags_p = Messages._collect_tags(self._msgs)
@@ -139,7 +139,7 @@ class Messages(object):
         self._msgs = None
 
         if tags_p == None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         return Tags(tags_p, self)
 
     def __iter__(self):
@@ -148,7 +148,7 @@ class Messages(object):
 
     def next(self):
         if self._msgs is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         if not nmlib.notmuch_messages_valid(self._msgs):
             self._msgs = None
@@ -292,7 +292,7 @@ class Message(object):
               objects are dead.
         """
         if msg_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         self._msg = msg_p
         #keep reference to parent, so we keep it alive
         self._parent = parent
@@ -305,7 +305,7 @@ class Message(object):
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Message._get_message_id(self._msg)
 
     def get_thread_id(self):
@@ -322,7 +322,7 @@ class Message(object):
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         return Message._get_thread_id(self._msg)
 
@@ -345,7 +345,7 @@ class Message(object):
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         msgs_p = Message._get_replies(self._msg)
 
@@ -367,7 +367,7 @@ class Message(object):
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Message._get_date(self._msg)
 
     def get_header(self, header):
@@ -389,12 +389,12 @@ class Message(object):
                     * STATUS.NULL_POINTER, if no header was found
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         #Returns NULL if any error occurs.
         header = Message._get_header(self._msg, header)
         if header == None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         return header.decode('UTF-8')
 
     def get_filename(self):
@@ -405,7 +405,7 @@ class Message(object):
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Message._get_filename(self._msg)
 
     def get_filenames(self):
@@ -415,7 +415,7 @@ class Message(object):
         messages recorded to have the same Message-ID. These files must
         not necessarily have identical content."""
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         files_p = Message._get_filenames(self._msg)
 
@@ -435,7 +435,7 @@ class Message(object):
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Message._get_flag(self._msg, flag)
 
     def set_flag(self, flag, value):
@@ -450,7 +450,7 @@ class Message(object):
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         nmlib.notmuch_message_set_flag(self._msg, flag, value)
 
     def get_tags(self):
@@ -464,11 +464,11 @@ class Message(object):
                       * STATUS.NULL_POINTER, on error
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         tags_p = Message._get_tags(self._msg)
         if tags_p == None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         return Tags(tags_p, self)
 
     def add_tag(self, tag, sync_maildir_flags=False):
@@ -503,13 +503,13 @@ class Message(object):
                      The message has not been initialized.
        """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         status = nmlib.notmuch_message_add_tag(self._msg, _str(tag))
 
         # bail out on failure
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status)
+            raise NotmuchError(status=status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -547,12 +547,12 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         status = nmlib.notmuch_message_remove_tag(self._msg, _str(tag))
         # bail out on error
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status)
+            raise NotmuchError(status=status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -584,13 +584,13 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         status = nmlib.notmuch_message_remove_all_tags(self._msg)
 
         # bail out on error
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status)
+            raise NotmuchError(status=status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -638,7 +638,7 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         status = nmlib.notmuch_message_freeze(self._msg)
 
@@ -646,7 +646,7 @@ class Message(object):
             # return on success
             return status
 
-        raise NotmuchError(status)
+        raise NotmuchError(status=status)
 
     def thaw(self):
         """Thaws the current 'message'
@@ -673,7 +673,7 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         status = nmlib.notmuch_message_thaw(self._msg)
 
@@ -681,7 +681,7 @@ class Message(object):
             # return on success
             return status
 
-        raise NotmuchError(status)
+        raise NotmuchError(status=status)
 
     def is_match(self):
         """(Not implemented)"""
@@ -709,7 +709,7 @@ class Message(object):
         :returns: a :class:`STATUS`. In short, you want to see
             notmuch.STATUS.SUCCESS here. See there for details."""
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         status = Message._tags_to_maildir_flags(self._msg)
 
     def maildir_flags_to_tags(self):
@@ -736,7 +736,7 @@ class Message(object):
         :returns: a :class:`STATUS`. In short, you want to see
             notmuch.STATUS.SUCCESS here. See there for details."""
         if self._msg is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         status = Message._tags_to_maildir_flags(self._msg)
 
     def __repr__(self):
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index 50e3686..9ca871a 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -70,7 +70,7 @@ class Tags(object):
                cache the tags in the Python object(?)
         """
         if tags_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         self._tags = tags_p
         #save reference to parent object so we keep it alive
@@ -82,7 +82,7 @@ class Tags(object):
 
     def next(self):
         if self._tags is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         if not nmlib.notmuch_tags_valid(self._tags):
             self._tags = None
             raise StopIteration
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 5e08eb3..93089d0 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -95,7 +95,7 @@ class Threads(object):
                the Python object.(?)
         """
         if threads_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         self._threads = threads_p
         #store parent, so we keep them alive as long as self  is alive
@@ -107,7 +107,7 @@ class Threads(object):
 
     def next(self):
         if self._threads is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         if not nmlib.notmuch_threads_valid(self._threads):
             self._threads = None
@@ -126,11 +126,11 @@ class Threads(object):
                  #THIS FAILS
                  threads = Database().create_query('').search_threads()
                  if len(threads) > 0:              #this 'exhausts' threads
-                     # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!!
+                     # next line raises NotmuchError(status=STATUS.NOT_INITIALIZED)!!!
                      for thread in threads: print thread
         """
         if self._threads is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         i = 0
         # returns 'bool'. On out-of-memory it returns None
@@ -206,7 +206,7 @@ class Thread(object):
               objects are dead.
         """
         if thread_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         self._thread = thread_p
         #keep reference to parent, so we keep it alive
         self._parent = parent
@@ -222,7 +222,7 @@ class Thread(object):
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Thread._get_thread_id(self._thread)
 
     def get_total_messages(self):
@@ -235,7 +235,7 @@ class Thread(object):
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return nmlib.notmuch_thread_get_total_messages(self._thread)
 
     def get_toplevel_messages(self):
@@ -258,12 +258,12 @@ class Thread(object):
                       * STATUS.NULL_POINTER if search_messages failed
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         msgs_p = Thread._get_toplevel_messages(self._thread)
 
         if msgs_p is None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
 
         return Messages(msgs_p, self)
 
@@ -277,7 +277,7 @@ class Thread(object):
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return nmlib.notmuch_thread_get_matched_messages(self._thread)
 
     def get_authors(self):
@@ -291,7 +291,7 @@ class Thread(object):
         as long as this Thread() is not deleted.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         authors = Thread._get_authors(self._thread)
         if authors is None:
             return None
@@ -304,7 +304,7 @@ class Thread(object):
         as long as this Thread() is not deleted.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         subject = Thread._get_subject(self._thread)
         if subject is None:
             return None
@@ -319,7 +319,7 @@ class Thread(object):
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Thread._get_newest_date(self._thread)
 
     def get_oldest_date(self):
@@ -331,7 +331,7 @@ class Thread(object):
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
         return Thread._get_oldest_date(self._thread)
 
     def get_tags(self):
@@ -354,11 +354,11 @@ class Thread(object):
                       * STATUS.NULL_POINTER, on error
         """
         if self._thread is None:
-            raise NotmuchError(STATUS.NOT_INITIALIZED)
+            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
 
         tags_p = Thread._get_tags(self._thread)
         if tags_p == None:
-            raise NotmuchError(STATUS.NULL_POINTER)
+            raise NotmuchError(status=STATUS.NULL_POINTER)
         return Tags(tags_p, self)
 
     def __str__(self):
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/9] python: fix NotmuchError.__str__ if status == None
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
  2011-09-26  1:05 ` [PATCH 2/9] python: add status and message attributes to NotmuchError Justus Winter
  2011-09-26  1:05 ` [PATCH 3/9] python: reorder the arguments of NotmuchError.__init__() Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 5/9] python: rename _verify_initialized_db to _assert_db_is_initialized Justus Winter
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Passing None to STATUS.status2str raises an ArgumentError. Add a
check for this case and provide a generic message.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/globals.py |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index dd0c858..8b73f91 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -97,8 +97,10 @@ class NotmuchError(Exception):
     def __str__(self):
         if self.message is not None:
             return self.message
-        else:
+        elif self.status is not None:
             return STATUS.status2str(self.status)
+        else:
+            return 'Unknown error'
 
 def _str(value):
     """Ensure a nicely utf-8 encoded string to pass to libnotmuch
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/9] python: rename _verify_initialized_db to _assert_db_is_initialized
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (2 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 4/9] python: fix NotmuchError.__str__ if status == None Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 6/9] python: rename _verify_dir_initialized to _assert_dir_is_initialized Justus Winter
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Rename the function to clarify its effect and remove all the comments
accompanying each call to the function.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/database.py |   32 +++++++++++---------------------
 1 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index e174f55..ecc5c17 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -105,7 +105,7 @@ class Database(object):
         else:
             self.create(path)
 
-    def _verify_initialized_db(self):
+    def _assert_db_is_initialized(self):
         """Raises a NotmuchError in case self._db is still None"""
         if self._db is None:
             raise NotmuchError(status=STATUS.NOT_INITIALIZED)
@@ -161,8 +161,7 @@ class Database(object):
         """Returns the file path of an open database
 
         Wraps *notmuch_database_get_path*."""
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         return Database._get_path(self._db).decode('utf-8')
 
@@ -173,8 +172,7 @@ class Database(object):
         :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
                     the database was not intitialized.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         return Database._get_version(self._db)
 
@@ -190,8 +188,7 @@ class Database(object):
         :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
                     the database was not intitialized.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         return nmlib.notmuch_database_needs_upgrade(self._db)
 
@@ -210,8 +207,7 @@ class Database(object):
 
         :TODO: catch exceptions, document return values and etc...
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         status = Database._upgrade(self._db, None, None)
         #TODO: catch exceptions, document return values and etc
@@ -239,8 +235,7 @@ class Database(object):
                     components same as database.
 
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         # sanity checking if path is valid, and make path absolute
         if path[0] == os.sep:
@@ -310,8 +305,7 @@ class Database(object):
               STATUS.NOT_INITIALIZED
                       The database has not been initialized.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         msg_p = c_void_p()
         status = nmlib.notmuch_database_add_message(self._db,
@@ -357,8 +351,7 @@ class Database(object):
              STATUS.NOT_INITIALIZED
                The database has not been initialized.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         return nmlib.notmuch_database_remove_message(self._db,
                                                        filename)
@@ -381,8 +374,7 @@ class Database(object):
         :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
                   the database was not intitialized.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         msg_p = Database._find_message(self._db, _str(msgid))
         return msg_p and Message(msg_p, self) or None
@@ -393,8 +385,7 @@ class Database(object):
         :returns: :class:`Tags`
         :execption: :exc:`NotmuchError` with STATUS.NULL_POINTER on error
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         tags_p = Database._get_all_tags(self._db)
         if tags_p == None:
@@ -419,8 +410,7 @@ class Database(object):
 
         This function is a python extension and not in the underlying C API.
         """
-        # Raise a NotmuchError if not initialized
-        self._verify_initialized_db()
+        self._assert_db_is_initialized()
 
         return Query(self, querystring)
 
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/9] python: rename _verify_dir_initialized to _assert_dir_is_initialized
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (3 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 5/9] python: rename _verify_initialized_db to _assert_db_is_initialized Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 7/9] python: provide more exception classes Justus Winter
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Rename the function to clarify its effect and remove all the comments
accompanying each call to the function.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/database.py |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index ecc5c17..edde70e 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -648,7 +648,7 @@ class Directory(object):
     _get_child_directories = nmlib.notmuch_directory_get_child_directories
     _get_child_directories.restype = c_void_p
 
-    def _verify_dir_initialized(self):
+    def _assert_dir_is_initialized(self):
         """Raises a NotmuchError(status=STATUS.NOT_INITIALIZED) if dir_p is None"""
         if self._dir_p is None:
             raise NotmuchError(status=STATUS.NOT_INITIALIZED)
@@ -703,8 +703,7 @@ class Directory(object):
                         STATUS.NOT_INITIALIZED
                           The directory has not been initialized
         """
-        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if the dir_p is None
-        self._verify_dir_initialized()
+        self._assert_dir_is_initialized()
 
         #TODO: make sure, we convert the mtime parameter to a 'c_long'
         status = Directory._set_mtime(self._dir_p, mtime)
@@ -727,8 +726,7 @@ class Directory(object):
                         STATUS.NOT_INITIALIZED
                           The directory has not been initialized
         """
-        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self.dir_p is None
-        self._verify_dir_initialized()
+        self._assert_dir_is_initialized()
 
         return Directory._get_mtime(self._dir_p)
 
@@ -746,8 +744,7 @@ class Directory(object):
         The returned filenames will be the basename-entries only (not
         complete paths.
         """
-        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self._dir_p is None
-        self._verify_dir_initialized()
+        self._assert_dir_is_initialized()
 
         files_p = Directory._get_child_files(self._dir_p)
         return Filenames(files_p, self)
@@ -759,8 +756,7 @@ class Directory(object):
         The returned filenames will be the basename-entries only (not
         complete paths.
         """
-        #Raise a NotmuchError(status=STATUS.NOT_INITIALIZED) if self._dir_p is None
-        self._verify_dir_initialized()
+        self._assert_dir_is_initialized()
 
         files_p = Directory._get_child_directories(self._dir_p)
         return Filenames(files_p, self)
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/9] python: provide more exception classes
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (4 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 6/9] python: rename _verify_dir_initialized to _assert_dir_is_initialized Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-30 12:00   ` Sebastian Spaeth
  2011-09-26  1:05 ` [PATCH 8/9] python: use the new exception classes and update the documentation Justus Winter
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

To make the exception handling more effective in code using the
python bindings it is necessary to differentiate between the
different kind of failures.

Add an exception class for each status code and add a decode
classmethod to the NotmuchError class that acts as a factory.

Import the new classes in __init__.py so they can be easily
imported by anyone.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/__init__.py |   16 ++++++++++++++-
 bindings/python/notmuch/globals.py  |   37 +++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 1 deletions(-)

diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py
index a7b558f..7e6a68c 100644
--- a/bindings/python/notmuch/__init__.py
+++ b/bindings/python/notmuch/__init__.py
@@ -56,7 +56,21 @@ from notmuch.database import Database, Query
 from notmuch.message import Messages, Message
 from notmuch.thread import Threads, Thread
 from notmuch.tag import Tags
-from notmuch.globals import nmlib, STATUS, NotmuchError
+from notmuch.globals import (
+    nmlib,
+    STATUS,
+    NotmuchError,
+    OutOfMemoryError,
+    ReadOnlyDatabaseError,
+    XapianError,
+    FileError,
+    FileNotEmailError,
+    DuplicateMessageIdError,
+    NullPointerError,
+    TagTooLongError,
+    UnbalancedFreezeThawError,
+    NotInitializedError
+)
 from notmuch.version import __VERSION__
 __LICENSE__ = "GPL v3+"
 __AUTHOR__ = 'Sebastian Spaeth <Sebastian@SSpaeth.de>'
diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index 8b73f91..e454384 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -102,6 +102,43 @@ class NotmuchError(Exception):
         else:
             return 'Unknown error'
 
+    @classmethod
+    def decode(cls, status, message=None):
+        assert 0 < status <= 10
+        return [
+            OutOfMemoryError,
+            ReadOnlyDatabaseError,
+            XapianError,
+            FileError,
+            FileNotEmailError,
+            DuplicateMessageIdError,
+            NullPointerError,
+            TagTooLongError,
+            UnbalancedFreezeThawError,
+            NotInitializedError
+        ][status - 1](message)
+
+class OutOfMemoryError(NotmuchError):
+    status = 1
+class ReadOnlyDatabaseError(NotmuchError):
+    status = 2
+class XapianError(NotmuchError):
+    status = 3
+class FileError(NotmuchError):
+    status = 4
+class FileNotEmailError(NotmuchError):
+    status = 5
+class DuplicateMessageIdError(NotmuchError):
+    status = 6
+class NullPointerError(NotmuchError):
+    status = 7
+class TagTooLongError(NotmuchError):
+    status = 8
+class UnbalancedFreezeThawError(NotmuchError):
+    status = 9
+class NotInitializedError(NotmuchError):
+    status = 10
+
 def _str(value):
     """Ensure a nicely utf-8 encoded string to pass to libnotmuch
 
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/9] python: use the new exception classes and update the documentation
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (5 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 7/9] python: provide more exception classes Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-26  1:05 ` [PATCH 9/9] python: raise a more specific error in Messages.print_messages Justus Winter
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/database.py |  138 +++++++++++++++++++++--------------
 bindings/python/notmuch/filename.py |    9 +-
 bindings/python/notmuch/message.py  |   79 ++++++++++----------
 bindings/python/notmuch/tag.py      |   10 ++-
 bindings/python/notmuch/thread.py   |   47 ++++++------
 5 files changed, 158 insertions(+), 125 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index edde70e..8df7c2f 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -19,7 +19,9 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 
 import os
 from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref
-from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str
+from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str, \
+                            NotInitializedError, FileError, \
+                            NullPointerError
 from notmuch.thread import Threads
 from notmuch.message import Messages, Message
 from notmuch.tag import Tags
@@ -106,9 +108,9 @@ class Database(object):
             self.create(path)
 
     def _assert_db_is_initialized(self):
-        """Raises a NotmuchError in case self._db is still None"""
+        """Raises a :exc:`NotInitializedError` in case self._db is still None"""
         if self._db is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
     def create(self, path):
         """Creates a new notmuch database
@@ -160,7 +162,12 @@ class Database(object):
     def get_path(self):
         """Returns the file path of an open database
 
-        Wraps *notmuch_database_get_path*."""
+        Wraps *notmuch_database_get_path*.
+
+        :returns: The path to the database as string
+        :exception: :exc:`NotInitializedError` if
+                    the database was not intitialized.
+        """
         self._assert_db_is_initialized()
 
         return Database._get_path(self._db).decode('utf-8')
@@ -169,7 +176,7 @@ class Database(object):
         """Returns the database format version
 
         :returns: The database version as positive integer
-        :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
+        :exception: :exc:`NotInitializedError` if
                     the database was not intitialized.
         """
         self._assert_db_is_initialized()
@@ -185,7 +192,7 @@ class Database(object):
         etc.) will work unless :meth:`upgrade` is called successfully first.
 
         :returns: `True` or `False`
-        :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
+        :exception: :exc:`NotInitializedError` if
                     the database was not intitialized.
         """
         self._assert_db_is_initialized()
@@ -206,6 +213,9 @@ class Database(object):
         indicating the progress made so far in the upgrade process.
 
         :TODO: catch exceptions, document return values and etc...
+
+        :exception: :exc:`NotInitializedError` if
+                    the database was not intitialized.
         """
         self._assert_db_is_initialized()
 
@@ -225,15 +235,14 @@ class Database(object):
               of database (see :meth:`get_path`), or else should be an absolute path
               with initial components that match the path of 'database'.
         :returns: :class:`Directory` or raises an exception.
-        :exception: :exc:`NotmuchError`
+        :exception: :exc:`NotInitializedError` or :exc:`FileError`
 
-                  STATUS.NOT_INITIALIZED
+                  :exc:`NotInitializedError`
                     If the database was not intitialized.
 
-                  STATUS.FILE_ERROR
+                  :exc:`FileError`
                     If path is not relative database or absolute with initial
                     components same as database.
-
         """
         self._assert_db_is_initialized()
 
@@ -242,9 +251,8 @@ class Database(object):
             # we got an absolute path
             if not path.startswith(self.get_path()):
                 # but its initial components are not equal to the db path
-                raise NotmuchError(message="Database().get_directory() called "
-                                           "with a wrong absolute path.",
-                                   status=STATUS.FILE_ERROR)
+                raise FileError("Database().get_directory() called "
+                                "with a wrong absolute path.")
             abs_dirpath = path
         else:
             #we got a relative path, make it absolute
@@ -293,16 +301,16 @@ class Database(object):
         :exception: Raises a :exc:`NotmuchError` with the following meaning.
               If such an exception occurs, nothing was added to the database.
 
-              STATUS.FILE_ERROR
+              :exc:`FileError`
                       An error occurred trying to open the file, (such as
                       permission denied, or file not found, etc.).
-              STATUS.FILE_NOT_EMAIL
+              :exc:`FileNotEmail`
                       The contents of filename don't look like an email
                       message.
-              STATUS.READ_ONLY_DATABASE
+              :exc:`ReadOnlyDatabaseError`
                       Database was opened in read-only mode so no message can
                       be added.
-              STATUS.NOT_INITIALIZED
+              :exc:`NotInitializedError`
                       The database has not been initialized.
         """
         self._assert_db_is_initialized()
@@ -313,7 +321,7 @@ class Database(object):
                                                   byref(msg_p))
 
         if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:
-            raise NotmuchError(status=status)
+            raise NotmuchError.decode(status)
 
         #construct Message() and return
         msg = Message(msg_p, self)
@@ -345,10 +353,10 @@ class Database(object):
              If such an exception occurs, nothing was removed from the
              database.
 
-             STATUS.READ_ONLY_DATABASE
+             :exc:`ReadOnlyDatabaseError`
                Database was opened in read-only mode so no message can be
                removed.
-             STATUS.NOT_INITIALIZED
+             :exc:`NotInitializedError`
                The database has not been initialized.
         """
         self._assert_db_is_initialized()
@@ -371,7 +379,7 @@ class Database(object):
                   another program in the meantime. A return value of
                   `None` is therefore no guarantee that the message
                   does not exist.
-        :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if
+        :exception: :exc:`NotInitializedError` if
                   the database was not intitialized.
         """
         self._assert_db_is_initialized()
@@ -383,13 +391,13 @@ class Database(object):
         """Returns :class:`Tags` with a list of all tags found in the database
 
         :returns: :class:`Tags`
-        :execption: :exc:`NotmuchError` with STATUS.NULL_POINTER on error
+        :execption: :exc:`NullPointerError` on error
         """
         self._assert_db_is_initialized()
 
         tags_p = Database._get_all_tags(self._db)
         if tags_p == None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         return Tags(tags_p, self)
 
     def create_query(self, querystring):
@@ -409,6 +417,9 @@ class Database(object):
           q  = Query(db,'from:"Biene Maja"')
 
         This function is a python extension and not in the underlying C API.
+
+        :exception: :exc:`NotInitializedError` if
+                  the database was not intitialized.
         """
         self._assert_db_is_initialized()
 
@@ -425,7 +436,8 @@ class Database(object):
     def _get_user_default_db(self):
         """ Reads a user's notmuch config and returns his db location
 
-        Throws a NotmuchError if it cannot find it"""
+        :exception: :exc:`NotMuchError` if it cannot find it
+        """
         from ConfigParser import SafeConfigParser
         config = SafeConfigParser()
         conf_f = os.getenv('NOTMUCH_CONFIG',
@@ -507,20 +519,20 @@ class Query(object):
         :param querystr: The query string
         :type querystr: utf-8 encoded str or unicode
         :returns: Nothing
-        :exception: :exc:`NotmuchError`
+        :exception: :exc:`NotInitializedError` or :exc:`NullPointerError`
 
-                      * STATUS.NOT_INITIALIZED if db is not inited
-                      * STATUS.NULL_POINTER if the query creation failed
+                      :exc:`NotInitializedError` if db is not initialized
+                      :exc:`NullPointerError` if the query creation failed
                         (too little memory)
         """
         if db.db_p is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         # create reference to parent db to keep it alive
         self._db = db
         # create query, return None if too little mem available
         query_p = Query._create(db.db_p, _str(querystr))
         if query_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         self._query = query_p
 
     def set_sort(self, sort):
@@ -530,11 +542,11 @@ class Query(object):
 
         :param sort: Sort order (see :attr:`Query.SORT`)
         :returns: Nothing
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if query has not
+        :exception: :exc:`NotInitializedError` if query has not
                     been initialized.
         """
         if self._query is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         self.sort = sort
         nmlib.notmuch_query_set_sort(self._query, sort)
@@ -554,18 +566,18 @@ class Query(object):
         *notmuch_query_search_threads* function.
 
         :returns: :class:`Threads`
-        :exception: :exc:`NotmuchError`
+        :exception: :exc:`NotInitializedError` or :exc:`NullPointerError`
 
-                      * STATUS.NOT_INITIALIZED if query is not inited
-                      * STATUS.NULL_POINTER if search_threads failed
+                      :exc:`NotInitializedError` if query is not initialized
+                      :exc:`NullPointerError` if the search_threads failed
         """
         if self._query is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         threads_p = Query._search_threads(self._query)
 
         if threads_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         return Threads(threads_p, self)
 
@@ -577,18 +589,18 @@ class Query(object):
         *notmuch_query_search_messages* function.
 
         :returns: :class:`Messages`
-        :exception: :exc:`NotmuchError`
+        :exception: :exc:`NotInitializedError` or :exc:`NullPointerError`
 
-                      * STATUS.NOT_INITIALIZED if query is not inited
-                      * STATUS.NULL_POINTER if search_messages failed
+                      :exc:`NotInitializedError` if query is not initialized
+                      :exc:`NullPointerError` if the search_messages failed
         """
         if self._query is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         msgs_p = Query._search_messages(self._query)
 
         if msgs_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         return Messages(msgs_p, self)
 
@@ -603,12 +615,12 @@ class Query(object):
         *notmuch_query_count_messages* function.
 
         :returns: :class:`Messages`
-        :exception: :exc:`NotmuchError`
+        :exception: :exc:`NotInitializedError`
 
-                      * STATUS.NOT_INITIALIZED if query is not inited
+                      :exc:`NotInitializedError` if query is not initialized
         """
         if self._query is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         return Query._count_messages(self._query)
 
@@ -651,7 +663,7 @@ class Directory(object):
     def _assert_dir_is_initialized(self):
         """Raises a NotmuchError(status=STATUS.NOT_INITIALIZED) if dir_p is None"""
         if self._dir_p is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
     def __init__(self, path, dir_p, parent):
         """
@@ -693,14 +705,15 @@ class Directory(object):
 
           :param mtime: A (time_t) timestamp
           :returns: Nothing on success, raising an exception on failure.
-          :exception: :exc:`NotmuchError`:
+          :exception: :exc:`NotInitializedError`, :exc:`XapianError` or
+                      :exc:`ReadOnlyDatabaseError`
 
-                        STATUS.XAPIAN_EXCEPTION
+                        :exc:`XapianError`
                           A Xapian exception occurred, mtime not stored.
-                        STATUS.READ_ONLY_DATABASE
+                        :exc:`ReadOnlyDatabaseError`
                           Database was opened in read-only mode so directory
                           mtime cannot be modified.
-                        STATUS.NOT_INITIALIZED
+                        :exc:`NotInitializedError`
                           The directory has not been initialized
         """
         self._assert_dir_is_initialized()
@@ -712,7 +725,7 @@ class Directory(object):
         if status == STATUS.SUCCESS:
             return
         #fail with Exception otherwise
-        raise NotmuchError(status=status)
+        raise NotmuchError.decode(status)
 
     def get_mtime(self):
         """Gets the mtime value of this directory in the database
@@ -721,9 +734,9 @@ class Directory(object):
 
         :param mtime: A (time_t) timestamp
         :returns: Nothing on success, raising an exception on failure.
-        :exception: :exc:`NotmuchError`:
+        :exception: :exc:`NotInitializedError`
 
-                        STATUS.NOT_INITIALIZED
+                        :exc:`NotInitializedError`
                           The directory has not been initialized
         """
         self._assert_dir_is_initialized()
@@ -743,6 +756,11 @@ class Directory(object):
 
         The returned filenames will be the basename-entries only (not
         complete paths.
+
+        :exception: :exc:`NotInitializedError`
+
+                        :exc:`NotInitializedError`
+                          The directory has not been initialized
         """
         self._assert_dir_is_initialized()
 
@@ -755,6 +773,11 @@ class Directory(object):
 
         The returned filenames will be the basename-entries only (not
         complete paths.
+
+        :exception: :exc:`NotInitializedError`
+
+                        :exc:`NotInitializedError`
+                          The directory has not been initialized
         """
         self._assert_dir_is_initialized()
 
@@ -801,7 +824,7 @@ class Filenames(object):
 
     def next(self):
         if self._files_p is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         if not nmlib.notmuch_filenames_valid(self._files_p):
             self._files_p = None
@@ -820,11 +843,16 @@ class Filenames(object):
                  #THIS FAILS
                  files = Database().get_directory('').get_child_files()
                  if len(files) > 0:              #this 'exhausts' msgs
-                     # next line raises NotmuchError(status=STATUS.NOT_INITIALIZED)!!!
+                     # next line raises NotInitializedError()!!!
                      for file in files: print file
+
+        :exception: :exc:`NotInitializedError`
+
+                        :exc:`NotInitializedError`
+                          If self._files_p is None
         """
         if self._files_p is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         i = 0
         while nmlib.notmuch_filenames_valid(self._files_p):
diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py
index c5dfd94..ddfd494 100644
--- a/bindings/python/notmuch/filename.py
+++ b/bindings/python/notmuch/filename.py
@@ -17,7 +17,8 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
 from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError
+from notmuch.globals import nmlib, STATUS, NotmuchError, \
+                            NullPointerError, NotInitializedError
 
 
 class Filenames(object):
@@ -68,7 +69,7 @@ class Filenames(object):
              once all derived objects are dead.
         """
         if files_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         self._files = files_p
         #save reference to parent object so we keep it alive
@@ -80,7 +81,7 @@ class Filenames(object):
         This is the main function that will usually be used by the
         user."""
         if self._files is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         if not nmlib.notmuch_filenames_valid(self._files):
             self._files = None
@@ -96,7 +97,7 @@ class Filenames(object):
         .. note:: As this iterates over the filenames, we will not be
                able to iterate over them again (as in retrieve them)! If
                the tags have been exhausted already, this will raise a
-               :exc:`NotmuchError` STATUS.NOT_INITIALIZED on subsequent
+               :exc:`NotInitializedError` on subsequent
                attempts. However, you can use
                :meth:`Message.get_filenames` repeatedly to perform
                various actions on filenames.
diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index 5cc3175..ac708ec 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -21,7 +21,8 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 
 from ctypes import c_char_p, c_void_p, c_long, c_uint, c_int
 from datetime import date
-from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str
+from notmuch.globals import nmlib, STATUS, Enum, _str, NotmuchError, \
+                            NullPointerError, NotInitializedError
 from notmuch.tag import Tags
 from notmuch.filename import Filenames
 import sys
@@ -42,7 +43,7 @@ class Messages(object):
     only provides a one-time iterator (it cannot reset the iterator to
     the start). Thus iterating over the function will "exhaust" the list
     of messages, and a subsequent iteration attempt will raise a
-    :exc:`NotmuchError` STATUS.NOT_INITIALIZED. If you need to
+    :exc:`NotInitializedError`. If you need to
     re-iterate over a list of messages you will need to retrieve a new
     :class:`Messages` object or cache your :class:`Message`\s in a list
     via::
@@ -115,7 +116,7 @@ class Messages(object):
                the Python object.(?)
         """
         if msgs_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         self._msgs = msgs_p
         #store parent, so we keep them alive as long as self  is alive
@@ -125,13 +126,13 @@ class Messages(object):
         """Return the unique :class:`Tags` in the contained messages
 
         :returns: :class:`Tags`
-        :exceptions: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if not inited
+        :exceptions: :exc:`NotInitializedError` if not inited
 
         .. note:: :meth:`collect_tags` will iterate over the messages and
           therefore will not allow further iterations.
         """
         if self._msgs is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         # collect all tags (returns NULL on error)
         tags_p = Messages._collect_tags(self._msgs)
@@ -139,7 +140,7 @@ class Messages(object):
         self._msgs = None
 
         if tags_p == None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         return Tags(tags_p, self)
 
     def __iter__(self):
@@ -148,7 +149,7 @@ class Messages(object):
 
     def next(self):
         if self._msgs is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         if not nmlib.notmuch_messages_valid(self._msgs):
             self._msgs = None
@@ -292,7 +293,7 @@ class Message(object):
               objects are dead.
         """
         if msg_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         self._msg = msg_p
         #keep reference to parent, so we keep it alive
         self._parent = parent
@@ -301,11 +302,11 @@ class Message(object):
         """Returns the message ID
 
         :returns: String with a message ID
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Message._get_message_id(self._msg)
 
     def get_thread_id(self):
@@ -318,11 +319,11 @@ class Message(object):
         message belongs to a single thread.
 
         :returns: String with a thread ID
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         return Message._get_thread_id(self._msg)
 
@@ -341,11 +342,11 @@ class Message(object):
 
         :returns: :class:`Messages` or `None` if there are no replies to
             this message.
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         msgs_p = Message._get_replies(self._msg)
 
@@ -363,11 +364,11 @@ class Message(object):
 
         :returns: A time_t timestamp.
         :rtype: c_unit64
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Message._get_date(self._msg)
 
     def get_header(self, header):
@@ -389,23 +390,23 @@ class Message(object):
                     * STATUS.NULL_POINTER, if no header was found
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         #Returns NULL if any error occurs.
         header = Message._get_header(self._msg, header)
         if header == None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         return header.decode('UTF-8')
 
     def get_filename(self):
         """Returns the file path of the message file
 
         :returns: Absolute file path & name of the message file
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Message._get_filename(self._msg)
 
     def get_filenames(self):
@@ -415,7 +416,7 @@ class Message(object):
         messages recorded to have the same Message-ID. These files must
         not necessarily have identical content."""
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         files_p = Message._get_filenames(self._msg)
 
@@ -431,11 +432,11 @@ class Message(object):
         :param flag: One of the :attr:`Message.FLAG` values (currently only
                      *Message.FLAG.MATCH*
         :returns: An unsigned int (0/1), indicating whether the flag is set.
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Message._get_flag(self._msg, flag)
 
     def set_flag(self, flag, value):
@@ -446,11 +447,11 @@ class Message(object):
         :param value: A bool indicating whether to set or unset the flag.
 
         :returns: Nothing
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
               is not initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         nmlib.notmuch_message_set_flag(self._msg, flag, value)
 
     def get_tags(self):
@@ -464,11 +465,11 @@ class Message(object):
                       * STATUS.NULL_POINTER, on error
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         tags_p = Message._get_tags(self._msg)
         if tags_p == None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         return Tags(tags_p, self)
 
     def add_tag(self, tag, sync_maildir_flags=False):
@@ -503,13 +504,13 @@ class Message(object):
                      The message has not been initialized.
        """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         status = nmlib.notmuch_message_add_tag(self._msg, _str(tag))
 
         # bail out on failure
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status=status)
+            raise NotmuchError.decode(status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -547,12 +548,12 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         status = nmlib.notmuch_message_remove_tag(self._msg, _str(tag))
         # bail out on error
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status=status)
+            raise NotmuchError.decode(status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -584,13 +585,13 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         status = nmlib.notmuch_message_remove_all_tags(self._msg)
 
         # bail out on error
         if status != STATUS.SUCCESS:
-            raise NotmuchError(status=status)
+            raise NotmuchError.decode(status)
 
         if sync_maildir_flags:
             self.tags_to_maildir_flags()
@@ -638,7 +639,7 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         status = nmlib.notmuch_message_freeze(self._msg)
 
@@ -646,7 +647,7 @@ class Message(object):
             # return on success
             return status
 
-        raise NotmuchError(status=status)
+        raise NotmuchError.decode(status)
 
     def thaw(self):
         """Thaws the current 'message'
@@ -673,7 +674,7 @@ class Message(object):
                      The message has not been initialized.
         """
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         status = nmlib.notmuch_message_thaw(self._msg)
 
@@ -681,7 +682,7 @@ class Message(object):
             # return on success
             return status
 
-        raise NotmuchError(status=status)
+        raise NotmuchError.decode(status)
 
     def is_match(self):
         """(Not implemented)"""
@@ -709,7 +710,7 @@ class Message(object):
         :returns: a :class:`STATUS`. In short, you want to see
             notmuch.STATUS.SUCCESS here. See there for details."""
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         status = Message._tags_to_maildir_flags(self._msg)
 
     def maildir_flags_to_tags(self):
@@ -736,7 +737,7 @@ class Message(object):
         :returns: a :class:`STATUS`. In short, you want to see
             notmuch.STATUS.SUCCESS here. See there for details."""
         if self._msg is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         status = Message._tags_to_maildir_flags(self._msg)
 
     def __repr__(self):
diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py
index 9ca871a..b903864 100644
--- a/bindings/python/notmuch/tag.py
+++ b/bindings/python/notmuch/tag.py
@@ -17,7 +17,9 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
 from ctypes import c_char_p
-from notmuch.globals import nmlib, STATUS, NotmuchError
+from notmuch.globals import nmlib, STATUS, NotmuchError, \
+                            NullPointerError, NotInitializedError
+
 
 
 class Tags(object):
@@ -70,7 +72,7 @@ class Tags(object):
                cache the tags in the Python object(?)
         """
         if tags_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         self._tags = tags_p
         #save reference to parent object so we keep it alive
@@ -82,7 +84,7 @@ class Tags(object):
 
     def next(self):
         if self._tags is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         if not nmlib.notmuch_tags_valid(self._tags):
             self._tags = None
             raise StopIteration
@@ -107,7 +109,7 @@ class Tags(object):
         .. note:: As this iterates over the tags, we will not be able
                to iterate over them again (as in retrieve them)! If
                the tags have been exhausted already, this will raise a
-               :exc:`NotmuchError` STATUS.NOT_INITIALIZED on
+               :exc:`NotInitializedError` on
                subsequent attempts.
         """
         return " ".join(self)
diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py
index 93089d0..e9d1185 100644
--- a/bindings/python/notmuch/thread.py
+++ b/bindings/python/notmuch/thread.py
@@ -18,7 +18,8 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
 
 from ctypes import c_char_p, c_void_p, c_long
-from notmuch.globals import nmlib, STATUS, NotmuchError
+from notmuch.globals import nmlib, STATUS, NotmuchError, \
+                            NullPointerError, NotInitializedError
 from notmuch.message import Messages
 from notmuch.tag import Tags
 from datetime import date
@@ -33,7 +34,7 @@ class Threads(object):
     library only provides a one-time iterator (it cannot reset the
     iterator to the start). Thus iterating over the function will
     "exhaust" the list of threads, and a subsequent iteration attempt
-    will raise a :exc:`NotmuchError` STATUS.NOT_INITIALIZED. Also
+    will raise a :exc:`NotInitializedError`. Also
     note, that any function that uses iteration will also
     exhaust the messages. So both::
 
@@ -95,7 +96,7 @@ class Threads(object):
                the Python object.(?)
         """
         if threads_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         self._threads = threads_p
         #store parent, so we keep them alive as long as self  is alive
@@ -107,7 +108,7 @@ class Threads(object):
 
     def next(self):
         if self._threads is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         if not nmlib.notmuch_threads_valid(self._threads):
             self._threads = None
@@ -126,11 +127,11 @@ class Threads(object):
                  #THIS FAILS
                  threads = Database().create_query('').search_threads()
                  if len(threads) > 0:              #this 'exhausts' threads
-                     # next line raises NotmuchError(status=STATUS.NOT_INITIALIZED)!!!
+                     # next line raises NotInitializedError()!!!
                      for thread in threads: print thread
         """
         if self._threads is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         i = 0
         # returns 'bool'. On out-of-memory it returns None
@@ -206,7 +207,7 @@ class Thread(object):
               objects are dead.
         """
         if thread_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         self._thread = thread_p
         #keep reference to parent, so we keep it alive
         self._parent = parent
@@ -218,11 +219,11 @@ class Thread(object):
         for as long as the thread is valid.
 
         :returns: String with a message ID
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
+        :exception: :exc:`NotInitializedError` if the thread
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Thread._get_thread_id(self._thread)
 
     def get_total_messages(self):
@@ -231,11 +232,11 @@ class Thread(object):
         :returns: The number of all messages in the database
                   belonging to this thread. Contrast with
                   :meth:`get_matched_messages`.
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
+        :exception: :exc:`NotInitializedError` if the thread
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return nmlib.notmuch_thread_get_total_messages(self._thread)
 
     def get_toplevel_messages(self):
@@ -258,12 +259,12 @@ class Thread(object):
                       * STATUS.NULL_POINTER if search_messages failed
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         msgs_p = Thread._get_toplevel_messages(self._thread)
 
         if msgs_p is None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
 
         return Messages(msgs_p, self)
 
@@ -273,11 +274,11 @@ class Thread(object):
         :returns: The number of all messages belonging to this thread that
                   matched the :class:`Query`from which this thread was created.
                   Contrast with :meth:`get_total_messages`.
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread
+        :exception: :exc:`NotInitializedError` if the thread
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return nmlib.notmuch_thread_get_matched_messages(self._thread)
 
     def get_authors(self):
@@ -291,7 +292,7 @@ class Thread(object):
         as long as this Thread() is not deleted.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         authors = Thread._get_authors(self._thread)
         if authors is None:
             return None
@@ -304,7 +305,7 @@ class Thread(object):
         as long as this Thread() is not deleted.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         subject = Thread._get_subject(self._thread)
         if subject is None:
             return None
@@ -315,11 +316,11 @@ class Thread(object):
 
         :returns: A time_t timestamp.
         :rtype: c_unit64
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Thread._get_newest_date(self._thread)
 
     def get_oldest_date(self):
@@ -327,11 +328,11 @@ class Thread(object):
 
         :returns: A time_t timestamp.
         :rtype: c_unit64
-        :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message
+        :exception: :exc:`NotInitializedError` if the message
                     is not initialized.
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
         return Thread._get_oldest_date(self._thread)
 
     def get_tags(self):
@@ -354,11 +355,11 @@ class Thread(object):
                       * STATUS.NULL_POINTER, on error
         """
         if self._thread is None:
-            raise NotmuchError(status=STATUS.NOT_INITIALIZED)
+            raise NotInitializedError()
 
         tags_p = Thread._get_tags(self._thread)
         if tags_p == None:
-            raise NotmuchError(status=STATUS.NULL_POINTER)
+            raise NullPointerError()
         return Tags(tags_p, self)
 
     def __str__(self):
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 9/9] python: raise a more specific error in Messages.print_messages
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (6 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 8/9] python: use the new exception classes and update the documentation Justus Winter
@ 2011-09-26  1:05 ` Justus Winter
  2011-09-29  7:45 ` [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Sebastian Spaeth
  2011-09-29  7:47 ` Sebastian Spaeth
  9 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-26  1:05 UTC (permalink / raw)
  To: notmuch; +Cc: Justus Winter

Raising Exception is considered bad since the only way to catch
it is to do 'except Exception'. Raising a TypeError is more
appropriate.

Since the format parameter has already been validated, checking
it again is not necessary. Simplify this conditional.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/message.py |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py
index ac708ec..a40932a 100644
--- a/bindings/python/notmuch/message.py
+++ b/bindings/python/notmuch/message.py
@@ -188,7 +188,7 @@ class Messages(object):
             set_end = "]"
             set_sep = ", "
         else:
-            raise Exception
+            raise TypeError("format must be either 'text' or 'json'")
 
         first_set = True
 
@@ -209,10 +209,8 @@ class Messages(object):
             if (match or entire_thread):
                 if format.lower() == "text":
                     sys.stdout.write(msg.format_message_as_text(indent))
-                elif format.lower() == "json":
-                    sys.stdout.write(msg.format_message_as_json(indent))
                 else:
-                    raise NotmuchError
+                    sys.stdout.write(msg.format_message_as_json(indent))
                 next_indent = indent + 1
 
             # get replies and print them also out (if there are any)
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] python: add a .gitignore file and refine the toplevel one
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (7 preceding siblings ...)
  2011-09-26  1:05 ` [PATCH 9/9] python: raise a more specific error in Messages.print_messages Justus Winter
@ 2011-09-29  7:45 ` Sebastian Spaeth
  2011-09-30  0:41   ` Justus Winter
  2011-09-29  7:47 ` Sebastian Spaeth
  9 siblings, 1 reply; 15+ messages in thread
From: Sebastian Spaeth @ 2011-09-29  7:45 UTC (permalink / raw)
  To: Justus Winter, notmuch

[-- Attachment #1: Type: text/plain, Size: 2258 bytes --]

On Mon, 26 Sep 2011 03:05:29 +0200, Justus Winter wrote:

#1) APPLIED
#2) APPLIED
#3) reorder the arguments of NotmuchError.__init__(): NOT APPLIED

The python tutorial gives an example of custom TransitionError with
three arguments, a custom message as the third. In addition, a STATUS
value is always expected to be given, while the additional explanatory
msg is optional, so STATUS makes for a more logical 1st parameter IMHO.
Even if it were the case, it makes for lots of code churn, longer code
(status=foo) to all Exceptions, and existing third party code would be
broken. Overall, I think there is more potential for trouble than
cleanup.

#4) APPLIED
status is always expected to be existing, but bullet proofing never hurts,
so this patch makes sense.

#5&#6) APPLIED
Modified the patches to apply again, as some changes had been made.

#7) NOT APPLIED, INPUT SOUGHT :)
I do see the value of more fine grained exceptions, but I am not sure,
we need this level of fine-grainedness. It would also make things more
tricky (the API is still actively evolving, and e.g. 4 days ago, a new
error status was added), so users of the bindings would now have
 +    NotmuchError,
 +    OutOfMemoryError,
 +    ReadOnlyDatabaseError,
 +    XapianError,
 +    FileError,
 +    FileNotEmailError,
 +    DuplicateMessageIdError,
 +    NullPointerError,
 +    TagTooLongError,
 +    UnbalancedFreezeThawError,
 +    UnbalancedAtomicError,
 +    NotInitializedError

to check where e.g. Xapian could also hide an Out of Memory. Do people
really want to catch, say UnbalancedAtomic errors specifically, rather
than testing whether an operation succeeded, and check the status code
if not? I could see the case for NotInitializedError, as that is a bit
specific to the python bindings and users might want to catch it separately.

Also, not all "status" are an error, e.g. DuplicateMessageId denotes
success rather than failure, it just communicates a status.

What do people (&user of the bindings) think would make sense here?
I am not opposed, but want more discussion and input before such a
change is made.

#8) Not merged, as it depends on #7

#9) APPLIED

Thanks for the patches, most of them are quite nice. For 7&8, I'd like
to hear more opinions.

Sebastian

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] python: add a .gitignore file and refine the toplevel one
  2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
                   ` (8 preceding siblings ...)
  2011-09-29  7:45 ` [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Sebastian Spaeth
@ 2011-09-29  7:47 ` Sebastian Spaeth
  9 siblings, 0 replies; 15+ messages in thread
From: Sebastian Spaeth @ 2011-09-29  7:47 UTC (permalink / raw)
  To: Justus Winter, notmuch

[-- Attachment #1: Type: text/plain, Size: 263 bytes --]

On Mon, 26 Sep 2011 03:05:29 +0200, Justus Winter wrote:

P.S. I don't use the bindings myself, and I don't see me using them in
the near future. If you are volunteering to take over the binding
maintainership, I'd be happy to hand the reign over :-).

Sebastian

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] python: add a .gitignore file and refine the toplevel one
  2011-09-29  7:45 ` [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Sebastian Spaeth
@ 2011-09-30  0:41   ` Justus Winter
  2011-09-30  9:14     ` Sebastian Spaeth
  0 siblings, 1 reply; 15+ messages in thread
From: Justus Winter @ 2011-09-30  0:41 UTC (permalink / raw)
  To: Sebastian Spaeth, notmuch

[-- Attachment #1: Type: text/plain, Size: 550 bytes --]


Hi Sebastian,

Quoting Sebastian Spaeth (2011-09-29 09:45:38)
>Also, not all "status" are an error, e.g. DuplicateMessageId denotes
>success rather than failure, it just communicates a status.

I just stumbled upon the following comment in notmuch.h:

/* Status codes used for the return values of most functions.
 *
 * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
 * completed without error. Any other value indicates an error as
 * follows:
[...]

Now I'm confused, could you clarify this?

Thanks,
Justus

[-- Attachment #2: .signature --]
[-- Type: application/octet-stream, Size: 17 bytes --]

love u alot @,@


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/9] python: add a .gitignore file and refine the toplevel one
  2011-09-30  0:41   ` Justus Winter
@ 2011-09-30  9:14     ` Sebastian Spaeth
  0 siblings, 0 replies; 15+ messages in thread
From: Sebastian Spaeth @ 2011-09-30  9:14 UTC (permalink / raw)
  To: Justus Winter, notmuch

[-- Attachment #1: Type: text/plain, Size: 1599 bytes --]

On Fri, 30 Sep 2011 02:41:02 +0200, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
Non-text part: multipart/mixed
> Quoting Sebastian Spaeth (2011-09-29 09:45:38)
> >Also, not all "status" are an error, e.g. DuplicateMessageId denotes
> >success rather than failure, it just communicates a status.
> 
> I just stumbled upon the following comment in notmuch.h:
> 
> /* Status codes used for the return values of most functions.
>  *
>  * A zero value (NOTMUCH_STATUS_SUCCESS) indicates that the function
>  * completed without error. Any other value indicates an error as
>  * follows:
> [...]

That sounds like notmuch.h doesn't know what it wants :-). The "error"
can occur on add_message or remove_message and notmuch.h has to say:

on add_message:
 * If 'message' is not NULL, then, on successful return
 * (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message'
 * will be initialized to a message object that can be used for things
 * such as adding tags to the just-added message. The user should call
 * notmuch_message_destroy when done with the message. ... On any failure
 * '*message' will be set to NULL.

So DUPLICATE_MESSAGE_ID is definitely a successful return here, filling in the
Message object.

on remove_message:
 * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but
 *	the message persists in the database with at least one other
 *	filename.

Similarly, the operation succeeded, it's just that there are other
messages with that ID still around. One could argue whether this is an
error or not.

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/9] python: provide more exception classes
  2011-09-26  1:05 ` [PATCH 7/9] python: provide more exception classes Justus Winter
@ 2011-09-30 12:00   ` Sebastian Spaeth
  2011-09-30 12:23     ` Justus Winter
  0 siblings, 1 reply; 15+ messages in thread
From: Sebastian Spaeth @ 2011-09-30 12:00 UTC (permalink / raw)
  To: Justus Winter, notmuch

[-- Attachment #1: Type: text/plain, Size: 622 bytes --]

On Mon, 26 Sep 2011 03:05:35 +0200, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
> To make the exception handling more effective in code using the
> python bindings it is necessary to differentiate between the
> different kind of failures.

[master b6a0173] python: provide more exception classes

Hi, I have taken your patch and used it as a template, modifying things
slightly. I also converted database.py to make use of the new
subclasses. Documentation will have to follow, but as users can use the
code, just as they had done before, there is no urgency.

Justus is that what you had in mind?

Sebastian

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/9] python: provide more exception classes
  2011-09-30 12:00   ` Sebastian Spaeth
@ 2011-09-30 12:23     ` Justus Winter
  0 siblings, 0 replies; 15+ messages in thread
From: Justus Winter @ 2011-09-30 12:23 UTC (permalink / raw)
  To: Sebastian Spaeth, notmuch

[-- Attachment #1: Type: text/plain, Size: 726 bytes --]


Quoting Sebastian Spaeth (2011-09-30 14:00:36)
>On Mon, 26 Sep 2011 03:05:35 +0200, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
>> To make the exception handling more effective in code using the
>> python bindings it is necessary to differentiate between the
>> different kind of failures.
>
>[master b6a0173] python: provide more exception classes
>
>Hi, I have taken your patch and used it as a template, modifying things
>slightly. I also converted database.py to make use of the new
>subclasses. Documentation will have to follow, but as users can use the
>code, just as they had done before, there is no urgency.
>
>Justus is that what you had in mind?

Yes, very nice. Thanks :)

Justus

[-- Attachment #2: .signature --]
[-- Type: application/octet-stream, Size: 17 bytes --]

love u alot @,@


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-09-30 12:23 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-26  1:05 [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Justus Winter
2011-09-26  1:05 ` [PATCH 2/9] python: add status and message attributes to NotmuchError Justus Winter
2011-09-26  1:05 ` [PATCH 3/9] python: reorder the arguments of NotmuchError.__init__() Justus Winter
2011-09-26  1:05 ` [PATCH 4/9] python: fix NotmuchError.__str__ if status == None Justus Winter
2011-09-26  1:05 ` [PATCH 5/9] python: rename _verify_initialized_db to _assert_db_is_initialized Justus Winter
2011-09-26  1:05 ` [PATCH 6/9] python: rename _verify_dir_initialized to _assert_dir_is_initialized Justus Winter
2011-09-26  1:05 ` [PATCH 7/9] python: provide more exception classes Justus Winter
2011-09-30 12:00   ` Sebastian Spaeth
2011-09-30 12:23     ` Justus Winter
2011-09-26  1:05 ` [PATCH 8/9] python: use the new exception classes and update the documentation Justus Winter
2011-09-26  1:05 ` [PATCH 9/9] python: raise a more specific error in Messages.print_messages Justus Winter
2011-09-29  7:45 ` [PATCH 1/9] python: add a .gitignore file and refine the toplevel one Sebastian Spaeth
2011-09-30  0:41   ` Justus Winter
2011-09-30  9:14     ` Sebastian Spaeth
2011-09-29  7:47 ` Sebastian Spaeth

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).