[PATCH 2/2] python: annotate all calls into libnotmuch with types
authorJustus Winter <4winter@informatik.uni-hamburg.de>
Sun, 9 Oct 2011 22:12:54 +0000 (00:12 +0200)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:39:38 +0000 (09:39 -0800)
ab/2ad867f139112094b0c49c9b043f13ace38ac8 [new file with mode: 0644]

diff --git a/ab/2ad867f139112094b0c49c9b043f13ace38ac8 b/ab/2ad867f139112094b0c49c9b043f13ace38ac8
new file mode 100644 (file)
index 0000000..8052e50
--- /dev/null
@@ -0,0 +1,999 @@
+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 C0C7E429E25\r
+       for <notmuch@notmuchmail.org>; Sun,  9 Oct 2011 15:13:45 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.001\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.001 tagged_above=-999 required=5\r
+       tests=[UNPARSEABLE_RELAY=0.001] 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 KcPOLsTVLwUh for <notmuch@notmuchmail.org>;\r
+       Sun,  9 Oct 2011 15:13:43 -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 344A8431FB6\r
+       for <notmuch@notmuchmail.org>; Sun,  9 Oct 2011 15:13:43 -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 E1747509367\r
+       for <notmuch@notmuchmail.org>; Mon, 10 Oct 2011 00:13:41 +0200 (CEST)\r
+Received: by mail.jade-hamburg.de (Postfix, from userid 401)\r
+       id 60011DF2A1; Mon, 10 Oct 2011 00:13:41 +0200 (CEST)\r
+Received: from thinkbox.jade-hamburg.de (unknown\r
+       [IPv6:fe80::216:d3ff:fe3e:5058%br0])\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 680C2DF29F;\r
+       Mon, 10 Oct 2011 00:13:22 +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 1RD1cX-0000HM-JH; Mon, 10 Oct 2011 00:13:21 +0200\r
+From: Justus Winter <4winter@informatik.uni-hamburg.de>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH 2/2] python: annotate all calls into libnotmuch with types\r
+Date: Mon, 10 Oct 2011 00:12:54 +0200\r
+Message-Id:\r
+ <1318198374-926-2-git-send-email-4winter@informatik.uni-hamburg.de>\r
+X-Mailer: git-send-email 1.7.6.3\r
+In-Reply-To:\r
+ <1318198374-926-1-git-send-email-4winter@informatik.uni-hamburg.de>\r
+References:\r
+ <1318198374-926-1-git-send-email-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: Sun, 09 Oct 2011 22:13:45 -0000\r
+\r
+Add type information to the ctypes._FuncPtr wrappers and\r
+use the wrapper classes instead of c_void_p for pointers\r
+to notmuch_*_t.\r
+\r
+This enables the ctypes library to type check parameters\r
+being handed to functions from the notmuch library.\r
+\r
+Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>\r
+---\r
+ bindings/python/notmuch/database.py |  127 ++++++++++++++++++++++++++--------\r
+ bindings/python/notmuch/filename.py |   22 +++++-\r
+ bindings/python/notmuch/message.py  |   91 ++++++++++++++++++++-----\r
+ bindings/python/notmuch/tag.py      |   23 +++++--\r
+ bindings/python/notmuch/thread.py   |   63 +++++++++++++----\r
+ 5 files changed, 255 insertions(+), 71 deletions(-)\r
+\r
+diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py\r
+index f4bc53e..25b4b1b 100644\r
+--- a/bindings/python/notmuch/database.py\r
++++ b/bindings/python/notmuch/database.py\r
+@@ -18,9 +18,11 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ """\r
\r
+ import os\r
+-from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref\r
++from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref, POINTER\r
+ from notmuch.globals import (nmlib, STATUS, NotmuchError, NotInitializedError,\r
+-     NullPointerError, OutOfMemoryError, XapianError, Enum, _str)\r
++     NullPointerError, OutOfMemoryError, XapianError, Enum, _str,\r
++     NotmuchDatabaseP, NotmuchDirectoryP, NotmuchMessageP, NotmuchTagsP,\r
++     NotmuchQueryP, NotmuchMessagesP, NotmuchThreadsP, NotmuchFilenamesP)\r
+ from notmuch.thread import Threads\r
+ from notmuch.message import Messages, Message\r
+ from notmuch.tag import Tags\r
+@@ -56,37 +58,48 @@ class Database(object):\r
\r
+     """notmuch_database_get_directory"""\r
+     _get_directory = nmlib.notmuch_database_get_directory\r
+-    _get_directory.restype = c_void_p\r
++    _get_directory.argtypes = [NotmuchDatabaseP, c_char_p]\r
++    _get_directory.restype = NotmuchDirectoryP\r
\r
+     """notmuch_database_get_path"""\r
+     _get_path = nmlib.notmuch_database_get_path\r
++    _get_path.argtypes = [NotmuchDatabaseP]\r
+     _get_path.restype = c_char_p\r
\r
+     """notmuch_database_get_version"""\r
+     _get_version = nmlib.notmuch_database_get_version\r
++    _get_version.argtypes = [NotmuchDatabaseP]\r
+     _get_version.restype = c_uint\r
\r
+     """notmuch_database_open"""\r
+     _open = nmlib.notmuch_database_open\r
+-    _open.restype = c_void_p\r
++    _open.argtypes = [c_char_p, c_uint]\r
++    _open.restype = NotmuchDatabaseP\r
\r
+     """notmuch_database_upgrade"""\r
+     _upgrade = nmlib.notmuch_database_upgrade\r
+-    _upgrade.argtypes = [c_void_p, c_void_p, c_void_p]\r
++    _upgrade.argtypes = [NotmuchDatabaseP, c_void_p, c_void_p]\r
++    _upgrade.restype = c_uint\r
\r
+     """ notmuch_database_find_message"""\r
+     _find_message = nmlib.notmuch_database_find_message\r
++    _find_message.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++    _find_message.restype = c_uint\r
\r
+     """notmuch_database_find_message_by_filename"""\r
+     _find_message_by_filename = nmlib.notmuch_database_find_message_by_filename\r
++    _find_message_by_filename.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++    _find_message_by_filename.restype = c_uint\r
\r
+     """notmuch_database_get_all_tags"""\r
+     _get_all_tags = nmlib.notmuch_database_get_all_tags\r
+-    _get_all_tags.restype = c_void_p\r
++    _get_all_tags.argtypes = [NotmuchDatabaseP]\r
++    _get_all_tags.restype = NotmuchTagsP\r
\r
+     """notmuch_database_create"""\r
+     _create = nmlib.notmuch_database_create\r
+-    _create.restype = c_void_p\r
++    _create.argtypes = [c_char_p]\r
++    _create.restype = NotmuchDatabaseP\r
\r
+     def __init__(self, path=None, create=False, mode=0):\r
+         """If *path* is `None`, we will try to read a users notmuch\r
+@@ -186,6 +199,10 @@ class Database(object):\r
+         self._assert_db_is_initialized()\r
+         return Database._get_version(self._db)\r
\r
++    _needs_upgrade = nmlib.notmuch_database_needs_upgrade\r
++    _needs_upgrade.argtypes = [NotmuchDatabaseP]\r
++    _needs_upgrade.restype = bool\r
++\r
+     def needs_upgrade(self):\r
+         """Does this database need to be upgraded before writing to it?\r
\r
+@@ -197,7 +214,7 @@ class Database(object):\r
+         :returns: `True` or `False`\r
+         """\r
+         self._assert_db_is_initialized()\r
+-        return nmlib.notmuch_database_needs_upgrade(self._db)\r
++        return self._needs_upgrade(self._db)\r
\r
+     def upgrade(self):\r
+         """Upgrades the current database\r
+@@ -219,6 +236,10 @@ class Database(object):\r
+         #TODO: catch exceptions, document return values and etc\r
+         return status\r
\r
++    _begin_atomic = nmlib.notmuch_database_begin_atomic\r
++    _begin_atomic.argtypes = [NotmuchDatabaseP]\r
++    _begin_atomic.restype = c_uint\r
++\r
+     def begin_atomic(self):\r
+         """Begin an atomic database operation\r
\r
+@@ -236,11 +257,15 @@ class Database(object):\r
\r
+         *Added in notmuch 0.9*"""\r
+         self._assert_db_is_initialized()\r
+-        status = nmlib.notmuch_database_begin_atomic(self._db)\r
++        status = self._begin_atomic(self._db)\r
+         if status != STATUS.SUCCESS:\r
+             raise NotmuchError(status)\r
+         return status\r
\r
++    _end_atomic = nmlib.notmuch_database_end_atomic\r
++    _end_atomic.argtypes = [NotmuchDatabaseP]\r
++    _end_atomic.restype = c_uint\r
++\r
+     def end_atomic(self):\r
+         """Indicate the end of an atomic database operation\r
\r
+@@ -258,7 +283,7 @@ class Database(object):\r
\r
+         *Added in notmuch 0.9*"""\r
+         self._assert_db_is_initialized()\r
+-        status = nmlib.notmuch_database_end_atomic(self._db)\r
++        status = self._end_atomic(self._db)\r
+         if status != STATUS.SUCCESS:\r
+             raise NotmuchError(status)\r
+         return status\r
+@@ -299,6 +324,10 @@ class Database(object):\r
+         # return the Directory, init it with the absolute path\r
+         return Directory(_str(abs_dirpath), dir_p, self)\r
\r
++    _add_message = nmlib.notmuch_database_add_message\r
++    _add_message.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++    _add_message.restype = c_uint\r
++\r
+     def add_message(self, filename, sync_maildir_flags=False):\r
+         """Adds a new message to the database\r
\r
+@@ -350,9 +379,7 @@ class Database(object):\r
+         """\r
+         self._assert_db_is_initialized()\r
+         msg_p = c_void_p()\r
+-        status = nmlib.notmuch_database_add_message(self._db,\r
+-                                                  _str(filename),\r
+-                                                  byref(msg_p))\r
++        status = self._add_message(self._db, _str(filename), byref(msg_p))\r
\r
+         if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:\r
+             raise NotmuchError(status)\r
+@@ -364,6 +391,10 @@ class Database(object):\r
+             msg.maildir_flags_to_tags()\r
+         return (msg, status)\r
\r
++    _remove_message = nmlib.notmuch_database_remove_message\r
++    _remove_message.argtypes = [NotmuchDatabaseP, c_char_p]\r
++    _remove_message.restype = c_uint\r
++\r
+     def remove_message(self, filename):\r
+         """Removes a message (filename) from the given notmuch database\r
\r
+@@ -392,8 +423,7 @@ class Database(object):\r
+                removed.\r
+         """\r
+         self._assert_db_is_initialized()\r
+-        return nmlib.notmuch_database_remove_message(self._db,\r
+-                                                       filename)\r
++        return self._remove_message(self._db, filename)\r
\r
+     def find_message(self, msgid):\r
+         """Returns a :class:`Message` as identified by its message ID\r
+@@ -491,10 +521,14 @@ class Database(object):\r
+     def __repr__(self):\r
+         return "'Notmuch DB " + self.get_path() + "'"\r
\r
++    _close = nmlib.notmuch_database_close\r
++    _close.argtypes = [NotmuchDatabaseP]\r
++    _close.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the notmuch database if needed"""\r
+         if self._db is not None:\r
+-            nmlib.notmuch_database_close(self._db)\r
++            self._close(self._db)\r
\r
+     def _get_user_default_db(self):\r
+         """ Reads a user's notmuch config and returns his db location\r
+@@ -545,18 +579,22 @@ class Query(object):\r
\r
+     """notmuch_query_create"""\r
+     _create = nmlib.notmuch_query_create\r
+-    _create.restype = c_void_p\r
++    _create.argtypes = [NotmuchDatabaseP, c_char_p]\r
++    _create.restype = NotmuchQueryP\r
\r
+     """notmuch_query_search_threads"""\r
+     _search_threads = nmlib.notmuch_query_search_threads\r
+-    _search_threads.restype = c_void_p\r
++    _search_threads.argtypes = [NotmuchQueryP]\r
++    _search_threads.restype = NotmuchThreadsP\r
\r
+     """notmuch_query_search_messages"""\r
+     _search_messages = nmlib.notmuch_query_search_messages\r
+-    _search_messages.restype = c_void_p\r
++    _search_messages.argtypes = [NotmuchQueryP]\r
++    _search_messages.restype = NotmuchMessagesP\r
\r
+     """notmuch_query_count_messages"""\r
+     _count_messages = nmlib.notmuch_query_count_messages\r
++    _count_messages.argtypes = [NotmuchQueryP]\r
+     _count_messages.restype = c_uint\r
\r
+     def __init__(self, db, querystr):\r
+@@ -602,6 +640,10 @@ class Query(object):\r
+             raise NullPointerError\r
+         self._query = query_p\r
\r
++    _set_sort = nmlib.notmuch_query_set_sort\r
++    _set_sort.argtypes = [NotmuchQueryP, c_uint]\r
++    _set_sort.argtypes = None\r
++\r
+     def set_sort(self, sort):\r
+         """Set the sort order future results will be delivered in\r
\r
+@@ -609,7 +651,7 @@ class Query(object):\r
+         """\r
+         self._assert_query_is_initialized()\r
+         self.sort = sort\r
+-        nmlib.notmuch_query_set_sort(self._query, sort)\r
++        self._set_sort(self._query, sort)\r
\r
+     def search_threads(self):\r
+         """Execute a query for threads\r
+@@ -661,10 +703,14 @@ class Query(object):\r
+         self._assert_query_is_initialized()\r
+         return Query._count_messages(self._query)\r
\r
++    _destroy = nmlib.notmuch_query_destroy\r
++    _destroy.argtypes = [NotmuchQueryP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the Query"""\r
+         if self._query is not None:\r
+-            nmlib.notmuch_query_destroy(self._query)\r
++            self._destroy(self._query)\r
\r
\r
+ class Directory(object):\r
+@@ -683,19 +729,23 @@ class Directory(object):\r
\r
+     """notmuch_directory_get_mtime"""\r
+     _get_mtime = nmlib.notmuch_directory_get_mtime\r
++    _get_mtime.argtypes = [NotmuchDirectoryP]\r
+     _get_mtime.restype = c_long\r
\r
+     """notmuch_directory_set_mtime"""\r
+     _set_mtime = nmlib.notmuch_directory_set_mtime\r
+-    _set_mtime.argtypes = [c_char_p, c_long]\r
++    _set_mtime.argtypes = [NotmuchDirectoryP, c_long]\r
++    _set_mtime.restype = c_uint\r
\r
+     """notmuch_directory_get_child_files"""\r
+     _get_child_files = nmlib.notmuch_directory_get_child_files\r
+-    _get_child_files.restype = c_void_p\r
++    _get_child_files.argtypes = [NotmuchDirectoryP]\r
++    _get_child_files.restype = NotmuchFilenamesP\r
\r
+     """notmuch_directory_get_child_directories"""\r
+     _get_child_directories = nmlib.notmuch_directory_get_child_directories\r
+-    _get_child_directories.restype = c_void_p\r
++    _get_child_directories.argtypes = [NotmuchDirectoryP]\r
++    _get_child_directories.restype = NotmuchFilenamesP\r
\r
+     def _assert_dir_is_initialized(self):\r
+         """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None"""\r
+@@ -815,10 +865,14 @@ class Directory(object):\r
+         """Object representation"""\r
+         return "<notmuch Directory object '%s'>" % self._path\r
\r
++    _destroy = nmlib.notmuch_directory_destroy\r
++    _destroy.argtypes = [NotmuchDirectoryP]\r
++    _destroy.argtypes = None\r
++\r
+     def __del__(self):\r
+         """Close and free the Directory"""\r
+         if self._dir_p is not None:\r
+-            nmlib.notmuch_directory_destroy(self._dir_p)\r
++            self._destroy(self._dir_p)\r
\r
\r
+ class Filenames(object):\r
+@@ -826,6 +880,7 @@ class Filenames(object):\r
\r
+     #notmuch_filenames_get\r
+     _get = nmlib.notmuch_filenames_get\r
++    _get.argtypes = [NotmuchFilenamesP]\r
+     _get.restype = c_char_p\r
\r
+     def __init__(self, files_p, parent):\r
+@@ -844,16 +899,24 @@ class Filenames(object):\r
+         """ Make Filenames an iterator """\r
+         return self\r
\r
++    _valid = nmlib.notmuch_filenames_valid\r
++    _valid.argtypes = [NotmuchFilenamesP]\r
++    _valid.restype = bool\r
++\r
++    _move_to_next = nmlib.notmuch_filenames_move_to_next\r
++    _move_to_next.argtypes = [NotmuchFilenamesP]\r
++    _move_to_next.restype = None\r
++\r
+     def next(self):\r
+         if self._files_p is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        if not nmlib.notmuch_filenames_valid(self._files_p):\r
++        if not self._valid(self._files_p):\r
+             self._files_p = None\r
+             raise StopIteration\r
\r
+         file = Filenames._get(self._files_p)\r
+-        nmlib.notmuch_filenames_move_to_next(self._files_p)\r
++        self._move_to_next(self._files_p)\r
+         return file\r
\r
+     def __len__(self):\r
+@@ -872,13 +935,17 @@ class Filenames(object):\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+         i = 0\r
+-        while nmlib.notmuch_filenames_valid(self._files_p):\r
+-            nmlib.notmuch_filenames_move_to_next(self._files_p)\r
++        while self._valid(self._files_p):\r
++            self._move_to_next(self._files_p)\r
+             i += 1\r
+         self._files_p = None\r
+         return i\r
\r
++    _destroy = nmlib.notmuch_filenames_destroy\r
++    _destroy.argtypes = [NotmuchFilenamesP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free Filenames"""\r
+         if self._files_p is not None:\r
+-            nmlib.notmuch_filenames_destroy(self._files_p)\r
++            self._destroy(self._files_p)\r
+diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py\r
+index de4d785..077754e 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
++    NotmuchFilenamesP, NotmuchMessagesP, NotmuchMessageP)\r
\r
\r
+ class Filenames(object):\r
+@@ -50,6 +51,7 @@ class Filenames(object):\r
\r
+     #notmuch_filenames_get\r
+     _get = nmlib.notmuch_filenames_get\r
++    _get.argtypes = [NotmuchFilenamesP]\r
+     _get.restype = c_char_p\r
\r
+     def __init__(self, files_p, parent):\r
+@@ -74,6 +76,14 @@ class Filenames(object):\r
+         #save reference to parent object so we keep it alive\r
+         self._parent = parent\r
\r
++    _valid = nmlib.notmuch_filenames_valid\r
++    _valid.argtypes = [NotmuchFilenamesP]\r
++    _valid.restype = bool\r
++\r
++    _move_to_next = nmlib.notmuch_filenames_move_to_next\r
++    _move_to_next.argtypes = [NotmuchFilenamesP]\r
++    _move_to_next.restype = None\r
++\r
+     def as_generator(self):\r
+         """Return generator of Filenames\r
\r
+@@ -82,9 +92,9 @@ class Filenames(object):\r
+         if self._files is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        while nmlib.notmuch_filenames_valid(self._files):\r
++        while self._valid(self._files):\r
+             yield Filenames._get(self._files)\r
+-            nmlib.notmuch_filenames_move_to_next(self._files)\r
++            self._move_to_next(self._files)\r
\r
+         self._files = None\r
\r
+@@ -101,7 +111,11 @@ class Filenames(object):\r
+         """\r
+         return "\n".join(self)\r
\r
++    _destroy = nmlib.notmuch_filenames_destroy\r
++    _destroy.argtypes = [NotmuchMessageP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the notmuch filenames"""\r
+         if self._files is not None:\r
+-            nmlib.notmuch_filenames_destroy(self._files)\r
++            self._destroy(self._files)\r
+diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py\r
+index 4bf90c2..e0c7eda 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, NotmuchError, Enum, _str,\r
++    NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP)\r
+ from notmuch.tag import Tags\r
+ from notmuch.filename import Filenames\r
+ import sys\r
+@@ -92,10 +93,12 @@ class Messages(object):\r
\r
+     #notmuch_messages_get\r
+     _get = nmlib.notmuch_messages_get\r
+-    _get.restype = c_void_p\r
++    _get.argtypes = [NotmuchMessagesP]\r
++    _get.restype = NotmuchMessageP\r
\r
+     _collect_tags = nmlib.notmuch_messages_collect_tags\r
+-    _collect_tags.restype = c_void_p\r
++    _collect_tags.argtypes = [NotmuchMessagesP]\r
++    _collect_tags.restype = NotmuchTagsP\r
\r
+     def __init__(self, msgs_p, parent=None):\r
+         """\r
+@@ -146,16 +149,24 @@ class Messages(object):\r
+         """ Make Messages an iterator """\r
+         return self\r
\r
++    _valid = nmlib.notmuch_messages_valid\r
++    _valid.argtypes = [NotmuchMessagesP]\r
++    _valid.restype = bool\r
++\r
++    _move_to_next = nmlib.notmuch_messages_move_to_next\r
++    _move_to_next.argtypes = [NotmuchMessagesP]\r
++    _move_to_next.restype = None\r
++\r
+     def next(self):\r
+         if self._msgs is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        if not nmlib.notmuch_messages_valid(self._msgs):\r
++        if not self._valid(self._msgs):\r
+             self._msgs = None\r
+             raise StopIteration\r
\r
+         msg = Message(Messages._get(self._msgs), self)\r
+-        nmlib.notmuch_messages_move_to_next(self._msgs)\r
++        self._move_to_next(self._msgs)\r
+         return msg\r
\r
+     def __nonzero__(self):\r
+@@ -163,12 +174,16 @@ class Messages(object):\r
+         :return: True if there is at least one more thread in the\r
+             Iterator, False if not."""\r
+         return self._msgs is not None and \\r
+-            nmlib.notmuch_messages_valid(self._msgs) > 0\r
++            self._valid(self._msgs) > 0\r
++\r
++    _destroy = nmlib.notmuch_messages_destroy\r
++    _destroy.argtypes = [NotmuchMessagesP]\r
++    _destroy.restype = None\r
\r
+     def __del__(self):\r
+         """Close and free the notmuch Messages"""\r
+         if self._msgs is not None:\r
+-            nmlib.notmuch_messages_destroy(self._msgs)\r
++            self._destroy(self._msgs)\r
\r
+     def print_messages(self, format, indent=0, entire_thread=False):\r
+         """Outputs messages as needed for 'notmuch show' to sys.stdout\r
+@@ -235,44 +250,60 @@ class Message(object):\r
\r
+     """notmuch_message_get_filename (notmuch_message_t *message)"""\r
+     _get_filename = nmlib.notmuch_message_get_filename\r
++    _get_filename.argtypes = [NotmuchMessageP]\r
+     _get_filename.restype = c_char_p\r
\r
+     """return all filenames for a message"""\r
+     _get_filenames = nmlib.notmuch_message_get_filenames\r
+-    _get_filenames.restype = c_void_p\r
++    _get_filenames.argtypes = [NotmuchMessageP]\r
++    _get_filenames.restype = NotmuchFilenamesP\r
\r
+     """notmuch_message_get_flag"""\r
+     _get_flag = nmlib.notmuch_message_get_flag\r
+-    _get_flag.restype = c_uint\r
++    _get_flag.argtypes = [NotmuchMessageP, c_uint]\r
++    _get_flag.restype = bool\r
++\r
++    """notmuch_message_set_flag"""\r
++    _set_flag = nmlib.notmuch_message_set_flag\r
++    _set_flag.argtypes = [NotmuchMessageP, c_uint, c_int]\r
++    _set_flag.restype = None\r
\r
+     """notmuch_message_get_message_id (notmuch_message_t *message)"""\r
+     _get_message_id = nmlib.notmuch_message_get_message_id\r
++    _get_message_id.argtypes = [NotmuchMessageP]\r
+     _get_message_id.restype = c_char_p\r
\r
+     """notmuch_message_get_thread_id"""\r
+     _get_thread_id = nmlib.notmuch_message_get_thread_id\r
++    _get_thread_id.argtypes = [NotmuchMessageP]\r
+     _get_thread_id.restype = c_char_p\r
\r
+     """notmuch_message_get_replies"""\r
+     _get_replies = nmlib.notmuch_message_get_replies\r
+-    _get_replies.restype = c_void_p\r
++    _get_replies.argtypes = [NotmuchMessageP]\r
++    _get_replies.restype = NotmuchMessagesP\r
\r
+     """notmuch_message_get_tags (notmuch_message_t *message)"""\r
+     _get_tags = nmlib.notmuch_message_get_tags\r
+-    _get_tags.restype = c_void_p\r
++    _get_tags.argtypes = [NotmuchMessageP]\r
++    _get_tags.restype = NotmuchTagsP\r
\r
+     _get_date = nmlib.notmuch_message_get_date\r
++    _get_date.argtypes = [NotmuchMessageP]\r
+     _get_date.restype = c_long\r
\r
+     _get_header = nmlib.notmuch_message_get_header\r
++    _get_header.argtypes = [NotmuchMessageP, c_char_p]\r
+     _get_header.restype = c_char_p\r
\r
+     """notmuch_status_t ..._maildir_flags_to_tags (notmuch_message_t *)"""\r
+     _tags_to_maildir_flags = nmlib.notmuch_message_tags_to_maildir_flags\r
++    _tags_to_maildir_flags.argtypes = [NotmuchMessageP]\r
+     _tags_to_maildir_flags.restype = c_int\r
\r
+     """notmuch_status_t ..._tags_to_maildir_flags (notmuch_message_t *)"""\r
+     _maildir_flags_to_tags = nmlib.notmuch_message_maildir_flags_to_tags\r
++    _maildir_flags_to_tags.argtypes = [NotmuchMessageP]\r
+     _maildir_flags_to_tags.restype = c_int\r
\r
+     #Constants: Flags that can be set/get with set_flag\r
+@@ -450,7 +481,7 @@ class Message(object):\r
+         """\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+-        nmlib.notmuch_message_set_flag(self._msg, flag, value)\r
++        self._set_flag(self._msg, flag, value)\r
\r
+     def get_tags(self):\r
+         """Returns the message tags\r
+@@ -470,6 +501,10 @@ class Message(object):\r
+             raise NotmuchError(STATUS.NULL_POINTER)\r
+         return Tags(tags_p, self)\r
\r
++    _add_tag = nmlib.notmuch_message_add_tag\r
++    _add_tag.argtypes = [NotmuchMessageP, c_char_p]\r
++    _add_tag.restype = c_uint\r
++\r
+     def add_tag(self, tag, sync_maildir_flags=False):\r
+         """Adds a tag to the given message\r
\r
+@@ -504,7 +539,7 @@ class Message(object):\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        status = nmlib.notmuch_message_add_tag(self._msg, _str(tag))\r
++        status = self._add_tag(self._msg, _str(tag))\r
\r
+         # bail out on failure\r
+         if status != STATUS.SUCCESS:\r
+@@ -514,6 +549,10 @@ class Message(object):\r
+             self.tags_to_maildir_flags()\r
+         return STATUS.SUCCESS\r
\r
++    _remove_tag = nmlib.notmuch_message_remove_tag\r
++    _remove_tag.argtypes = [NotmuchMessageP, c_char_p]\r
++    _remove_tag.restype = c_uint\r
++\r
+     def remove_tag(self, tag, sync_maildir_flags=False):\r
+         """Removes a tag from the given message\r
\r
+@@ -548,7 +587,7 @@ class Message(object):\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        status = nmlib.notmuch_message_remove_tag(self._msg, _str(tag))\r
++        status = self._remove_tag(self._msg, _str(tag))\r
+         # bail out on error\r
+         if status != STATUS.SUCCESS:\r
+             raise NotmuchError(status)\r
+@@ -557,6 +596,10 @@ class Message(object):\r
+             self.tags_to_maildir_flags()\r
+         return STATUS.SUCCESS\r
\r
++    _remove_all_tags = nmlib.notmuch_message_remove_all_tags\r
++    _remove_all_tags.argtypes = [NotmuchMessageP]\r
++    _remove_all_tags.restype = c_uint\r
++\r
+     def remove_all_tags(self, sync_maildir_flags=False):\r
+         """Removes all tags from the given message.\r
\r
+@@ -585,7 +628,7 @@ class Message(object):\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        status = nmlib.notmuch_message_remove_all_tags(self._msg)\r
++        status = self._remove_all_tags(self._msg)\r
\r
+         # bail out on error\r
+         if status != STATUS.SUCCESS:\r
+@@ -595,6 +638,10 @@ class Message(object):\r
+             self.tags_to_maildir_flags()\r
+         return STATUS.SUCCESS\r
\r
++    _freeze = nmlib.notmuch_message_freeze\r
++    _freeze.argtypes = [NotmuchMessageP]\r
++    _freeze.restype = c_uint\r
++\r
+     def freeze(self):\r
+         """Freezes the current state of 'message' within the database\r
\r
+@@ -639,7 +686,7 @@ class Message(object):\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        status = nmlib.notmuch_message_freeze(self._msg)\r
++        status = self._freeze(self._msg)\r
\r
+         if STATUS.SUCCESS == status:\r
+             # return on success\r
+@@ -647,6 +694,10 @@ class Message(object):\r
\r
+         raise NotmuchError(status)\r
\r
++    _thaw = nmlib.notmuch_message_thaw\r
++    _thaw.argtypes = [NotmuchMessageP]\r
++    _thaw.restype = c_uint\r
++\r
+     def thaw(self):\r
+         """Thaws the current 'message'\r
\r
+@@ -674,7 +725,7 @@ class Message(object):\r
+         if self._msg is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        status = nmlib.notmuch_message_thaw(self._msg)\r
++        status = self._thaw(self._msg)\r
\r
+         if STATUS.SUCCESS == status:\r
+             # return on success\r
+@@ -896,7 +947,11 @@ class Message(object):\r
+             res = cmp(list(self.get_filenames()), list(other.get_filenames()))\r
+         return res\r
\r
++    _destroy = nmlib.notmuch_message_destroy\r
++    _destroy.argtypes = [NotmuchMessageP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the notmuch Message"""\r
+         if self._msg is not None:\r
+-            nmlib.notmuch_message_destroy(self._msg)\r
++            self._destroy(self._msg)\r
+diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py\r
+index 50e3686..f3a3d27 100644\r
+--- a/bindings/python/notmuch/tag.py\r
++++ b/bindings/python/notmuch/tag.py\r
+@@ -17,7 +17,7 @@ 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, NotmuchTagsP\r
\r
\r
+ class Tags(object):\r
+@@ -50,6 +50,7 @@ class Tags(object):\r
\r
+     #notmuch_tags_get\r
+     _get = nmlib.notmuch_tags_get\r
++    _get.argtypes = [NotmuchTagsP]\r
+     _get.restype = c_char_p\r
\r
+     def __init__(self, tags_p, parent=None):\r
+@@ -80,14 +81,22 @@ class Tags(object):\r
+         """ Make Tags an iterator """\r
+         return self\r
\r
++    _valid = nmlib.notmuch_tags_valid\r
++    _valid.argtypes = [NotmuchTagsP]\r
++    _valid.restype = bool\r
++\r
++    _move_to_next = nmlib.notmuch_tags_move_to_next\r
++    _move_to_next.argtypes = [NotmuchTagsP]\r
++    _move_to_next.restype = None\r
++\r
+     def next(self):\r
+         if self._tags is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+-        if not nmlib.notmuch_tags_valid(self._tags):\r
++        if not self._valid(self._tags):\r
+             self._tags = None\r
+             raise StopIteration\r
+         tag = Tags._get(self._tags).decode('UTF-8')\r
+-        nmlib.notmuch_tags_move_to_next(self._tags)\r
++        self._move_to_next(self._tags)\r
+         return tag\r
\r
+     def __nonzero__(self):\r
+@@ -99,7 +108,7 @@ class Tags(object):\r
\r
+         :returns: True if the Tags() iterator has at least one more Tag\r
+             left."""\r
+-        return nmlib.notmuch_tags_valid(self._tags) > 0\r
++        return self._valid(self._tags) > 0\r
\r
+     def __str__(self):\r
+         """The str() representation of Tags() is a space separated list of tags\r
+@@ -112,7 +121,11 @@ class Tags(object):\r
+         """\r
+         return " ".join(self)\r
\r
++    _destroy = nmlib.notmuch_tags_destroy\r
++    _destroy.argtypes = [NotmuchTagsP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the notmuch tags"""\r
+         if self._tags is not None:\r
+-            nmlib.notmuch_tags_destroy(self._tags)\r
++            self._destroy(self._tags)\r
+diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py\r
+index 5e08eb3..d903c76 100644\r
+--- a/bindings/python/notmuch/thread.py\r
++++ b/bindings/python/notmuch/thread.py\r
+@@ -17,8 +17,10 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.\r
+ 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 ctypes import c_char_p, c_void_p, c_long, c_int\r
++from notmuch.globals import (nmlib, STATUS,\r
++    NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP,\r
++    NotmuchTagsP,)\r
+ from notmuch.message import Messages\r
+ from notmuch.tag import Tags\r
+ from datetime import date\r
+@@ -75,7 +77,8 @@ class Threads(object):\r
\r
+     #notmuch_threads_get\r
+     _get = nmlib.notmuch_threads_get\r
+-    _get.restype = c_void_p\r
++    _get.argtypes = [NotmuchThreadsP]\r
++    _get.restype = NotmuchThreadP\r
\r
+     def __init__(self, threads_p, parent=None):\r
+         """\r
+@@ -105,16 +108,24 @@ class Threads(object):\r
+         """ Make Threads an iterator """\r
+         return self\r
\r
++    _valid = nmlib.notmuch_threads_valid\r
++    _valid.argtypes = [NotmuchThreadsP]\r
++    _valid.restype = bool\r
++\r
++    _move_to_next = nmlib.notmuch_threads_move_to_next\r
++    _move_to_next.argtypes = [NotmuchThreadsP]\r
++    _move_to_next.restype = None\r
++\r
+     def next(self):\r
+         if self._threads is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
\r
+-        if not nmlib.notmuch_threads_valid(self._threads):\r
++        if not self._valid(self._threads):\r
+             self._threads = None\r
+             raise StopIteration\r
\r
+         thread = Thread(Threads._get(self._threads), self)\r
+-        nmlib.notmuch_threads_move_to_next(self._threads)\r
++        self._move_to_next(self._threads)\r
+         return thread\r
\r
+     def __len__(self):\r
+@@ -134,8 +145,8 @@ class Threads(object):\r
\r
+         i = 0\r
+         # returns 'bool'. On out-of-memory it returns None\r
+-        while nmlib.notmuch_threads_valid(self._threads):\r
+-            nmlib.notmuch_threads_move_to_next(self._threads)\r
++        while self._valid(self._threads):\r
++            self._move_to_next(self._threads)\r
+             i += 1\r
+         # reset self._threads to mark as "exhausted"\r
+         self._threads = None\r
+@@ -153,12 +164,16 @@ class Threads(object):\r
+            Iterator, False if not. None on a "Out-of-memory" error.\r
+         """\r
+         return self._threads is not None and \\r
+-            nmlib.notmuch_threads_valid(self._threads) > 0\r
++            self._valid(self._threads) > 0\r
++\r
++    _destroy = nmlib.notmuch_threads_destroy\r
++    _destroy.argtypes = [NotmuchThreadsP]\r
++    _destroy.argtypes = None\r
\r
+     def __del__(self):\r
+         """Close and free the notmuch Threads"""\r
+         if self._threads is not None:\r
+-            nmlib.notmuch_messages_destroy(self._threads)\r
++            self._destroy(self._threads)\r
\r
\r
+ class Thread(object):\r
+@@ -166,29 +181,36 @@ class Thread(object):\r
\r
+     """notmuch_thread_get_thread_id"""\r
+     _get_thread_id = nmlib.notmuch_thread_get_thread_id\r
++    _get_thread_id.argtypes = [NotmuchThreadP]\r
+     _get_thread_id.restype = c_char_p\r
\r
+     """notmuch_thread_get_authors"""\r
+     _get_authors = nmlib.notmuch_thread_get_authors\r
++    _get_authors.argtypes = [NotmuchThreadP]\r
+     _get_authors.restype = c_char_p\r
\r
+     """notmuch_thread_get_subject"""\r
+     _get_subject = nmlib.notmuch_thread_get_subject\r
++    _get_subject.argtypes = [NotmuchThreadP]\r
+     _get_subject.restype = c_char_p\r
\r
+     """notmuch_thread_get_toplevel_messages"""\r
+     _get_toplevel_messages = nmlib.notmuch_thread_get_toplevel_messages\r
+-    _get_toplevel_messages.restype = c_void_p\r
++    _get_toplevel_messages.argtypes = [NotmuchThreadP]\r
++    _get_toplevel_messages.restype = NotmuchMessagesP\r
\r
+     _get_newest_date = nmlib.notmuch_thread_get_newest_date\r
++    _get_newest_date.argtypes = [NotmuchThreadP]\r
+     _get_newest_date.restype = c_long\r
\r
+     _get_oldest_date = nmlib.notmuch_thread_get_oldest_date\r
++    _get_oldest_date.argtypes = [NotmuchThreadP]\r
+     _get_oldest_date.restype = c_long\r
\r
+     """notmuch_thread_get_tags"""\r
+     _get_tags = nmlib.notmuch_thread_get_tags\r
+-    _get_tags.restype = c_void_p\r
++    _get_tags.argtypes = [NotmuchThreadP]\r
++    _get_tags.restype = NotmuchTagsP\r
\r
+     def __init__(self, thread_p, parent=None):\r
+         """\r
+@@ -225,6 +247,11 @@ class Thread(object):\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+         return Thread._get_thread_id(self._thread)\r
\r
++\r
++    _get_total_messages = nmlib.notmuch_thread_get_total_messages\r
++    _get_total_messages.argtypes = [NotmuchThreadP]\r
++    _get_total_messages.restype = c_int\r
++\r
+     def get_total_messages(self):\r
+         """Get the total number of messages in 'thread'\r
\r
+@@ -236,7 +263,7 @@ class Thread(object):\r
+         """\r
+         if self._thread is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+-        return nmlib.notmuch_thread_get_total_messages(self._thread)\r
++        return self._get_total_messages(self._thread)\r
\r
+     def get_toplevel_messages(self):\r
+         """Returns a :class:`Messages` iterator for the top-level messages in\r
+@@ -267,6 +294,10 @@ class Thread(object):\r
\r
+         return Messages(msgs_p, self)\r
\r
++    _get_matched_messages = nmlib.notmuch_thread_get_matched_messages\r
++    _get_matched_messages.argtypes = [NotmuchThreadP]\r
++    _get_matched_messages.restype = c_int\r
++\r
+     def get_matched_messages(self):\r
+         """Returns the number of messages in 'thread' that matched the query\r
\r
+@@ -278,7 +309,7 @@ class Thread(object):\r
+         """\r
+         if self._thread is None:\r
+             raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+-        return nmlib.notmuch_thread_get_matched_messages(self._thread)\r
++        return self._get_matched_messages(self._thread)\r
\r
+     def get_authors(self):\r
+         """Returns the authors of 'thread'\r
+@@ -387,7 +418,11 @@ class Thread(object):\r
+                                                        thread['subject'],\r
+                                                        thread['tags'])\r
\r
++    _destroy = nmlib.notmuch_thread_destroy\r
++    _destroy.argtypes = [NotmuchThreadP]\r
++    _destroy.restype = None\r
++\r
+     def __del__(self):\r
+         """Close and free the notmuch Thread"""\r
+         if self._thread is not None:\r
+-            nmlib.notmuch_thread_destroy(self._thread)\r
++            self._destroy(self._thread)\r
+-- \r
+1.7.6.3\r
+\r