[PATCH 8/9] python: use the new exception classes and update the documentation
authorJustus Winter <4winter@informatik.uni-hamburg.de>
Mon, 26 Sep 2011 01:05:36 +0000 (03:05 +0200)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:39:29 +0000 (09:39 -0800)
a6/a6eb3fc53a726c4b4d721df274f88d8783ec1c [new file with mode: 0644]

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