unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
@ 2011-10-09 22:12 Justus Winter
  2011-10-09 22:12 ` [PATCH 2/2] python: annotate all calls into libnotmuch with types Justus Winter
  2011-11-02  7:25 ` [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Sebastian Spaeth
  0 siblings, 2 replies; 23+ messages in thread
From: Justus Winter @ 2011-10-09 22:12 UTC (permalink / raw)
  To: notmuch

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

diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py
index de1db16..36354fc 100644
--- a/bindings/python/notmuch/globals.py
+++ b/bindings/python/notmuch/globals.py
@@ -17,7 +17,7 @@ along with notmuch.  If not, see <http://www.gnu.org/licenses/>.
 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'
 """
 
-from ctypes import CDLL, c_char_p, c_int
+from ctypes import CDLL, c_char_p, c_int, Structure, POINTER
 from ctypes.util import find_library
 
 #-----------------------------------------------------------------------------
@@ -182,3 +182,39 @@ def _str(value):
         return value.encode('UTF-8')
     return value
 
+
+class NotmuchDatabaseS(Structure):
+    pass
+NotmuchDatabaseP = POINTER(NotmuchDatabaseS)
+
+class NotmuchQueryS(Structure):
+    pass
+NotmuchQueryP = POINTER(NotmuchQueryS)
+
+class NotmuchThreadsS(Structure):
+    pass
+NotmuchThreadsP = POINTER(NotmuchThreadsS)
+
+class NotmuchThreadS(Structure):
+    pass
+NotmuchThreadP = POINTER(NotmuchThreadS)
+
+class NotmuchMessagesS(Structure):
+    pass
+NotmuchMessagesP = POINTER(NotmuchMessagesS)
+
+class NotmuchMessageS(Structure):
+    pass
+NotmuchMessageP = POINTER(NotmuchMessageS)
+
+class NotmuchTagsS(Structure):
+    pass
+NotmuchTagsP = POINTER(NotmuchTagsS)
+
+class NotmuchDirectoryS(Structure):
+    pass
+NotmuchDirectoryP = POINTER(NotmuchDirectoryS)
+
+class NotmuchFilenamesS(Structure):
+    pass
+NotmuchFilenamesP = POINTER(NotmuchFilenamesS)
-- 
1.7.6.3

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

* [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-10-09 22:12 [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Justus Winter
@ 2011-10-09 22:12 ` Justus Winter
  2011-12-06 10:46   ` Patrick Totzke
  2011-11-02  7:25 ` [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Sebastian Spaeth
  1 sibling, 1 reply; 23+ messages in thread
From: Justus Winter @ 2011-10-09 22:12 UTC (permalink / raw)
  To: notmuch

Add type information to the ctypes._FuncPtr wrappers and
use the wrapper classes instead of c_void_p for pointers
to notmuch_*_t.

This enables the ctypes library to type check parameters
being handed to functions from the notmuch library.

Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
---
 bindings/python/notmuch/database.py |  127 ++++++++++++++++++++++++++--------
 bindings/python/notmuch/filename.py |   22 +++++-
 bindings/python/notmuch/message.py  |   91 ++++++++++++++++++++-----
 bindings/python/notmuch/tag.py      |   23 +++++--
 bindings/python/notmuch/thread.py   |   63 +++++++++++++----
 5 files changed, 255 insertions(+), 71 deletions(-)

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

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-10-09 22:12 [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Justus Winter
  2011-10-09 22:12 ` [PATCH 2/2] python: annotate all calls into libnotmuch with types Justus Winter
@ 2011-11-02  7:25 ` Sebastian Spaeth
  2011-11-28 12:36   ` Justus Winter
  1 sibling, 1 reply; 23+ messages in thread
From: Sebastian Spaeth @ 2011-11-02  7:25 UTC (permalink / raw)
  To: Justus Winter, notmuch

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

On Mon, 10 Oct 2011 00:12:53 +0200, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
> Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
> ---
>  bindings/python/notmuch/globals.py |   38 +++++++++++++++++++++++++++++++++++-

Hi there, catching up on email, sorry for the delay.
I am not opposed to the change, but I fail to see any justification for
a whole lot more complexity either. What was wrong with the previous
approach?

Sebastian

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

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-11-02  7:25 ` [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Sebastian Spaeth
@ 2011-11-28 12:36   ` Justus Winter
  2011-12-01 21:25     ` Sebastian Spaeth
  0 siblings, 1 reply; 23+ messages in thread
From: Justus Winter @ 2011-11-28 12:36 UTC (permalink / raw)
  To: Sebastian Spaeth, notmuch

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

Quoting Sebastian Spaeth (2011-11-02 08:25:53)
>On Mon, 10 Oct 2011 00:12:53 +0200, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
>> Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>
>> ---
>>  bindings/python/notmuch/globals.py |   38 +++++++++++++++++++++++++++++++++++-
>
>Hi there, catching up on email, sorry for the delay.
>I am not opposed to the change, but I fail to see any justification for
>a whole lot more complexity either. What was wrong with the previous
>approach?

Well, quoting my commit message:

> Add type information to the ctypes._FuncPtr wrappers and
> use the wrapper classes instead of c_void_p for pointers
> to notmuch_*_t.
>
> This enables the ctypes library to type check parameters
> being handed to functions from the notmuch library.

Justus

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

love u alot @,@


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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-11-28 12:36   ` Justus Winter
@ 2011-12-01 21:25     ` Sebastian Spaeth
  2011-12-01 23:32       ` James Westby
  0 siblings, 1 reply; 23+ messages in thread
From: Sebastian Spaeth @ 2011-12-01 21:25 UTC (permalink / raw)
  To: Justus Winter, notmuch

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

On Mon, 28 Nov 2011 13:36:44 +0100, Justus Winter wrote:
> Well, quoting my commit message:
> 
> > Add type information to the ctypes._FuncPtr wrappers and
> > use the wrapper classes instead of c_void_p for pointers
> > to notmuch_*_t.
> >
> > This enables the ctypes library to type check parameters
> > being handed to functions from the notmuch library.


This strikes me as a rather good thing, so the patches went in.

Sebastian

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

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-12-01 21:25     ` Sebastian Spaeth
@ 2011-12-01 23:32       ` James Westby
  2011-12-02 12:35         ` Justus Winter
  0 siblings, 1 reply; 23+ messages in thread
From: James Westby @ 2011-12-01 23:32 UTC (permalink / raw)
  To: Sebastian Spaeth, Justus Winter, notmuch

On Thu, 01 Dec 2011 22:25:41 +0100, Sebastian Spaeth <Sebastian@SSpaeth.de> wrote:
> This strikes me as a rather good thing, so the patches went in.

Hah, I've just seen this, and I'm going to guess that it fixes my
problems too.

...

I've tested and it seems to work, so my patch is unneeded witht his one.

Thanks,

James

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-12-01 23:32       ` James Westby
@ 2011-12-02 12:35         ` Justus Winter
  2011-12-02 14:20           ` James Westby
  0 siblings, 1 reply; 23+ messages in thread
From: Justus Winter @ 2011-12-02 12:35 UTC (permalink / raw)
  To: James Westby, Sebastian Spaeth, notmuch

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

Quoting James Westby (2011-12-02 00:32:30)
>On Thu, 01 Dec 2011 22:25:41 +0100, Sebastian Spaeth <Sebastian@SSpaeth.de> wrote:
>> This strikes me as a rather good thing, so the patches went in.
>
>Hah, I've just seen this, and I'm going to guess that it fixes my
>problems too.
>
>...
>
>I've tested and it seems to work, so my patch is unneeded witht his one.

Huh, strange. My patch isn't supposed to change anything, it just
enables the ctypes package to check whether the functions from
libnotmuch are called with the right parameters, thus preventing
mistakes when changing the python bindings in the future.

Cheers,
Justus

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

love u alot @,@


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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-12-02 12:35         ` Justus Winter
@ 2011-12-02 14:20           ` James Westby
  2011-12-02 23:24             ` James Westby
  0 siblings, 1 reply; 23+ messages in thread
From: James Westby @ 2011-12-02 14:20 UTC (permalink / raw)
  To: Justus Winter, Sebastian Spaeth, notmuch

On Fri, 02 Dec 2011 13:35:11 +0100, Justus Winter <4winter@informatik.uni-hamburg.de> wrote:
> Huh, strange. My patch isn't supposed to change anything, it just
> enables the ctypes package to check whether the functions from
> libnotmuch are called with the right parameters, thus preventing
> mistakes when changing the python bindings in the future.

Where .restype is set to c_void_p ctypes spots this and returns it as
int32. Where it's set to another callable (e.g. your custom types) it
actually wraps the value by passing it to the callable and returning the
result.

Then, because your custom types are pointers, it stores them in an
appropriate value, and also stops the storage being reused.

I'll test again to make sure that I have this correct, but my tests
yesterday certainly suggested that your patches fixed this.

Thanks,

James

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-12-02 14:20           ` James Westby
@ 2011-12-02 23:24             ` James Westby
  2011-12-03  2:11               ` Justus Winter
  0 siblings, 1 reply; 23+ messages in thread
From: James Westby @ 2011-12-02 23:24 UTC (permalink / raw)
  To: Justus Winter, Sebastian Spaeth, notmuch

On Fri, 02 Dec 2011 09:20:35 -0500, James Westby <jw+debian@jameswestby.net> wrote:
> I'll test again to make sure that I have this correct, but my tests
> yesterday certainly suggested that your patches fixed this.

Yep, segfaults a plenty dropping your second patch that go away again
when it is applied once more.

Thanks,

James

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

* Re: [PATCH 1/2] python: add classes to wrap all notmuch_*_t types
  2011-12-02 23:24             ` James Westby
@ 2011-12-03  2:11               ` Justus Winter
  0 siblings, 0 replies; 23+ messages in thread
From: Justus Winter @ 2011-12-03  2:11 UTC (permalink / raw)
  To: James Westby, Sebastian Spaeth, notmuch

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

Quoting James Westby (2011-12-03 00:24:18)
>On Fri, 02 Dec 2011 09:20:35 -0500, James Westby <jw+debian@jameswestby.net> wrote:
>> I'll test again to make sure that I have this correct, but my tests
>> yesterday certainly suggested that your patches fixed this.
>
>Yep, segfaults a plenty dropping your second patch that go away again
>when it is applied once more.

Happy to hear that :)

Justus

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

love u alot @,@


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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-10-09 22:12 ` [PATCH 2/2] python: annotate all calls into libnotmuch with types Justus Winter
@ 2011-12-06 10:46   ` Patrick Totzke
  2011-12-06 11:12     ` Sebastian Spaeth
                       ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Patrick Totzke @ 2011-12-06 10:46 UTC (permalink / raw)
  To: Justus Winter, notmuch

This commit breaks raising XapianErrors for me.

If I lock the index with some `notmuch tag +test '*'`
and try to write to it in alot, i get a segfault and
the following on stderr:

Xapian exception occurred opening database: Unable to get write lock on
/home/pazz/mail/.notmuch/xapian: already locked

/p

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-12-06 10:46   ` Patrick Totzke
@ 2011-12-06 11:12     ` Sebastian Spaeth
  2011-12-06 11:44       ` Patrick Totzke
  2011-12-06 12:05     ` Sebastian Spaeth
  2014-01-24 13:25     ` [PATCH 2/2] python: annotate all calls into libnotmuch with types David Bremner
  2 siblings, 1 reply; 23+ messages in thread
From: Sebastian Spaeth @ 2011-12-06 11:12 UTC (permalink / raw)
  To: Patrick Totzke, Justus Winter, notmuch

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

On Tue, 06 Dec 2011 10:46:31 +0000, Patrick Totzke <patricktotzke@googlemail.com> wrote:
> This commit breaks raising XapianErrors for me.
> 
> If I lock the index with some `notmuch tag +test '*'`
> and try to write to it in alot, i get a segfault and
> the following on stderr:
> 
> Xapian exception occurred opening database: Unable to get write lock on
> /home/pazz/mail/.notmuch/xapian: already locked

Can you confirm that this only occurs with this patch and not without?
To be honest, I don't see how the patch would change things in a way
that make it throw XapianErrors that would not also occur before this
patch.

Sebastian

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

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-12-06 11:12     ` Sebastian Spaeth
@ 2011-12-06 11:44       ` Patrick Totzke
  0 siblings, 0 replies; 23+ messages in thread
From: Patrick Totzke @ 2011-12-06 11:44 UTC (permalink / raw)
  To: Sebastian Spaeth, Justus Winter, notmuch

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

yes, i can. here's how to reproduce it on master:

fire a `notmuch tag +TEST1 '*'`, which should block the db for a while.
Then use the attached script to write to the index (this could make a nice
second testcase for the bindings in case the test body is large enough).

On master, the script fails like this:

A Xapian exception occurred opening database: Unable to get write lock on
/home/pazz/mail/.notmuch/xapian: already locked
Segmentation fault

When you reset using `git reset e92b438f46a3a` (to 4winters first patch), the script
fails like this, which is the intended behaviour:

A Xapian exception occurred opening database: Unable to get write lock on /home/pazz/mail/.notmuch/xapian: already locked
Traceback (most recent call last):
  File "./p.py", line 3, in <module>
    db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
  File "/usr/local/lib/python2.7/dist-packages/notmuch/database.py", line 121, in __init__
    self.open(path, mode)
  File "/usr/local/lib/python2.7/dist-packages/notmuch/database.py", line 173, in open
    raise NotmuchError(message="Could not open the specified database")
notmuch.globals.NotmuchError: Could not open the specified database


best,
/p


Quoting Sebastian Spaeth (2011-12-06 11:12:42)
>On Tue, 06 Dec 2011 10:46:31 +0000, Patrick Totzke <patricktotzke@googlemail.com> wrote:
>> This commit breaks raising XapianErrors for me.
>> 
>> If I lock the index with some `notmuch tag +test '*'`
>> and try to write to it in alot, i get a segfault and
>> the following on stderr:
>> 
>> Xapian exception occurred opening database: Unable to get write lock on
>> /home/pazz/mail/.notmuch/xapian: already locked
>
>Can you confirm that this only occurs with this patch and not without?
>To be honest, I don't see how the patch would change things in a way
>that make it throw XapianErrors that would not also occur before this
>patch.
>
>Sebastian

[-- Attachment #2: exceptiontest.py --]
[-- Type: text/x-python, Size: 181 bytes --]

#!/usr/bin/python
import notmuch
db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
q_new = notmuch.Query(db, '*')
for m in q_new.search_messages():
    m.add_tag('TEST')

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-12-06 10:46   ` Patrick Totzke
  2011-12-06 11:12     ` Sebastian Spaeth
@ 2011-12-06 12:05     ` Sebastian Spaeth
       [not found]       ` <notmuch-sha1-f155d93e11888b35377531dd556b03fd493b7590>
  2014-01-24 13:25     ` [PATCH 2/2] python: annotate all calls into libnotmuch with types David Bremner
  2 siblings, 1 reply; 23+ messages in thread
From: Sebastian Spaeth @ 2011-12-06 12:05 UTC (permalink / raw)
  To: Patrick Totzke, Justus Winter, notmuch

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

On Tue, 06 Dec 2011 10:46:31 +0000, Patrick Totzke <patricktotzke@googlemail.com> wrote:
> This commit breaks raising XapianErrors for me.
> 
> If I lock the index with some `notmuch tag +test '*'`
> and try to write to it in alot, i get a segfault and
> the following on stderr:
> 
> Xapian exception occurred opening database: Unable to get write lock on
> /home/pazz/mail/.notmuch/xapian: already locked

Hi Justus,
I can confirm that this patch breaks as Totzke has described it:

http://git.notmuchmail.org/git/notmuch/commitdiff/3434d194026ff65217d9342ffe511f67fd71e79f

This change makes python segfault with a Xapianerror on stdout rather
than the python exception that we were seeing before this patch.

-     _open.restype = c_void_p
+     _open.restype = NotmuchDatabaseP


As the patch obviously fixed other crashers I would like to not revert
it. Can you have a look and see if you find a cause of that?

Sebastian

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

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
       [not found]       ` <notmuch-sha1-f155d93e11888b35377531dd556b03fd493b7590>
@ 2011-12-07 18:49         ` Justus Winter
       [not found]         ` <notmuch-sha1-c3821ec5e6ef2f83665b03ba10fdfff871f70c2b>
  1 sibling, 0 replies; 23+ messages in thread
From: Justus Winter @ 2011-12-07 18:49 UTC (permalink / raw)
  To: Sebastian Spaeth, notmuch

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

Quoting Justus Winter (2011-12-06 13:51:08)
>Quoting Sebastian Spaeth (2011-12-06 13:05:53)
>>On Tue, 06 Dec 2011 10:46:31 +0000, Patrick Totzke <patricktotzke@googlemail.com> wrote:
>>> This commit breaks raising XapianErrors for me.
>>> 
>>> If I lock the index with some `notmuch tag +test '*'`
>>> and try to write to it in alot, i get a segfault and
>>> the following on stderr:
>>> 
>>> Xapian exception occurred opening database: Unable to get write lock on
>>> /home/pazz/mail/.notmuch/xapian: already locked
>>
>>Hi Justus,
>>I can confirm that this patch breaks as Totzke has described it:
>>
>>http://git.notmuchmail.org/git/notmuch/commitdiff/3434d194026ff65217d9342ffe511f67fd71e79f
>>
>>This change makes python segfault with a Xapianerror on stdout rather
>>than the python exception that we were seeing before this patch.
>>
>>-     _open.restype = c_void_p
>>+     _open.restype = NotmuchDatabaseP
>>
>>
>>As the patch obviously fixed other crashers I would like to not revert
>>it. Can you have a look and see if you find a cause of that?
>
>Yes, I've seen that one as well and could not figure out what causes
>it since I thought that I wasn't changing the semantic of the binding.
>
>I began running alot in gdb since I get segfaults within libnotmuch
>from time to time and managed to get a stack trace pointing to
>notmuch_database_begin_atomic, but I couldn't figure out what caused
>it.

#0  0x00007f5f25e30f71 in notmuch_database_begin_atomic () from /home/teythoon/.local/lib/libnotmuch.so.2
#1  0x00007f5f2605ef70 in ffi_call_unix64 () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#2  0x00007f5f2605e9eb in ffi_call () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#3  0x00007f5f260529c7 in _call_function_pointer (argcount=1, resmem=0x7fff57659500, restype=<optimized out>, 
    atypes=<optimized out>, avalues=0x7fff576594e0, pProc=0x7f5f25e30f70 <notmuch_database_begin_atomic>, 
    flags=4353) at /home/packages/python/2.7/python2.7-2.7.2/Modules/_ctypes/callproc.c:827

with stderr saying:

A Xapian exception occurred opening database: Unable to get write lock on /home/teythoon/Maildir/.notmuch/xapian: already locked

Justus

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

love u alot @,@


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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
       [not found]         ` <notmuch-sha1-c3821ec5e6ef2f83665b03ba10fdfff871f70c2b>
@ 2011-12-07 19:05           ` Justus Winter
  2014-01-24 13:17             ` David Bremner
  0 siblings, 1 reply; 23+ messages in thread
From: Justus Winter @ 2011-12-07 19:05 UTC (permalink / raw)
  To: Justus Winter, Sebastian Spaeth, notmuch

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

Quoting Justus Winter (2011-12-07 19:49:31)
>Quoting Justus Winter (2011-12-06 13:51:08)
>>I began running alot in gdb since I get segfaults within libnotmuch
>>from time to time and managed to get a stack trace pointing to
>>notmuch_database_begin_atomic, but I couldn't figure out what caused
>>it.

And another one:

Reading symbols from /usr/bin/python...Reading symbols from /usr/lib/debug/usr/bin/python2.7...done.
done.
[New LWP 15188]
[Thread debugging using libthread_db enabled]
Core was generated by `/usr/bin/python /home/teythoon/.local/bin/afew -v --tag --new'.
Program terminated with signal 6, Aborted.
#0  0x00007f72f2cce405 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
	in ../nptl/sysdeps/unix/sysv/linux/raise.c
(gdb) bt
#0  0x00007f72f2cce405 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007f72f2cd1680 in *__GI_abort () at abort.c:92
#2  0x00007f72f1380bfd in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007f72f137eda6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007f72f137edd3 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007f72f137eece in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007f72f16b792e in ChertTable::set_overwritten() const () from /usr/lib/libxapian.so.22
#7  0x00007f72f16ba7a6 in ChertTable::block_to_cursor(Cursor*, int, unsigned int) const () from /usr/lib/libxapian.so.22
#8  0x00007f72f16bcc35 in ChertTable::find(Cursor*) const () from /usr/lib/libxapian.so.22
#9  0x00007f72f1697431 in ChertCursor::find_entry(std::string const&) () from /usr/lib/libxapian.so.22
#10 0x00007f72f16c0858 in ?? () from /usr/lib/libxapian.so.22
#11 0x00007f72f16c0c69 in ?? () from /usr/lib/libxapian.so.22
#12 0x00007f72f16a649a in ?? () from /usr/lib/libxapian.so.22
#13 0x00007f72f1621001 in Xapian::Document::Internal::get_value(unsigned int) const () from /usr/lib/libxapian.so.22
#14 0x00007f72f162103c in Xapian::Document::get_value(unsigned int) const () from /usr/lib/libxapian.so.22
#15 0x00007f72f238ef23 in notmuch_message_get_header () from /home/teythoon/.local/lib/libnotmuch.so.2
#16 0x00007f72f25b7f70 in ffi_call_unix64 () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#17 0x00007f72f25b79eb in ffi_call () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#18 0x00007f72f25ab9c7 in _call_function_pointer (argcount=2, resmem=0x7fffc13a0310, restype=<optimized out>, atypes=<optimized out>, avalues=0x7fffc13a02f0, 
    pProc=0x7f72f238ee50 <notmuch_message_get_header>, flags=4353) at /home/packages/python/2.7/python2.7-2.7.2/Modules/_ctypes/callproc.c:827
#19 _ctypes_callproc (pProc=0x7f72f238ee50 <notmuch_message_get_header>, argtuple=0x0, flags=4353, argtypes=<optimized out>, restype=
    <_ctypes.PyCSimpleType at remote 0xd17c30>, checker=0x0) at /home/packages/python/2.7/python2.7-2.7.2/Modules/_ctypes/callproc.c:1174
#20 0x00007f72f25a3257 in PyCFuncPtr_call (self=<optimized out>, inargs=<optimized out>, kwds=0x0)
    at /home/packages/python/2.7/python2.7-2.7.2/Modules/_ctypes/_ctypes.c:3913
#21 0x000000000041d35a in PyObject_Call (func=<_FuncPtr(__name__='notmuch_message_get_header') at remote 0xe02530>, arg=<optimized out>, kw=<optimized out>)
    at ../Objects/abstract.c:2529
#22 0x00000000004b9b4e in do_call (nk=<optimized out>, na=<optimized out>, pp_stack=0x7fffc13a05f0, func=
    <_FuncPtr(__name__='notmuch_message_get_header') at remote 0xe02530>) at ../Python/ceval.c:4239
#23 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a05f0) at ../Python/ceval.c:4044
#24 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#25 0x00000000004b9d27 in fast_function (nk=<optimized out>, na=<optimized out>, n=<optimized out>, pp_stack=0x7fffc13a0730, func=<function at remote 0xdfef50>)
    at ../Python/ceval.c:4107
#26 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a0730) at ../Python/ceval.c:4042
#27 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#28 0x00000000004bfc9d in PyEval_EvalCodeEx (co=0xcd28b0, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, 
    kws=<optimized out>, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:3253
#29 0x000000000044b36f in function_call (func=<function at remote 0xe03758>, arg=
    (<Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>,), kw=0x0) at ../Objects/funcobject.c:526
#30 0x000000000041d35a in PyObject_Call (func=<function at remote 0xe03758>, arg=<optimized out>, kw=<optimized out>) at ../Objects/abstract.c:2529
#31 0x0000000000432bdb in instancemethod_call (func=<function at remote 0xe03758>, arg=
    (<Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>,), kw=0x0) at ../Objects/classobject.c:2578
#32 0x000000000042668c in PyObject_Call (func=<instancemethod at remote 0x1192f00>, arg=<optimized out>, kw=0x0) at ../Objects/abstract.c:2529
#33 0x00000000004299fc in PyObject_CallFunctionObjArgs (callable=<instancemethod at remote 0x1192f00>) at ../Objects/abstract.c:2760
#34 0x0000000000466ebb in PyObject_Unicode (v=
    <Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>) at ../Objects/object.c:509
#35 0x0000000000494443 in unicode_new (type=0x853200, args=<optimized out>, kwds=<optimized out>) at ../Objects/unicodeobject.c:8722
#36 0x000000000047ef15 in type_call (type=0x853200, args=
    (<Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>,), kwds=0x0) at ../Objects/typeobject.c:721
#37 0x000000000041d35a in PyObject_Call (func=<type at remote 0x853200>, arg=<optimized out>, kw=<optimized out>) at ../Objects/abstract.c:2529
#38 0x00000000004b9b4e in do_call (nk=<optimized out>, na=<optimized out>, pp_stack=0x7fffc13a0e50, func=<type at remote 0x853200>) at ../Python/ceval.c:4239
#39 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a0e50) at ../Python/ceval.c:4044
#40 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#41 0x00000000004bfc9d in PyEval_EvalCodeEx (co=0xcd2830, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, 
    kws=<optimized out>, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:3253
#42 0x000000000044b36f in function_call (func=<function at remote 0xe036e0>, arg=
    (<Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>,), kw=0x0) at ../Objects/funcobject.c:526
#43 0x000000000041d35a in PyObject_Call (func=<function at remote 0xe036e0>, arg=<optimized out>, kw=<optimized out>) at ../Objects/abstract.c:2529
#44 0x0000000000432bdb in instancemethod_call (func=<function at remote 0xe036e0>, arg=
    (<Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>,), kw=0x0) at ../Objects/classobject.c:2578
#45 0x000000000041d35a in PyObject_Call (func=<instancemethod at remote 0xe710a0>, arg=<optimized out>, kw=<optimized out>) at ../Objects/abstract.c:2529
#46 0x00000000004b8cb6 in PyEval_CallObjectWithKeywords (func=<instancemethod at remote 0xe710a0>, arg=(), kw=<optimized out>) at ../Python/ceval.c:3890
#47 0x00000000004837c9 in slot_tp_str (self=
    <Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>) at ../Objects/typeobject.c:5341
#48 0x0000000000466848 in _PyObject_Str (v=
    <Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>) at ../Objects/object.c:430
#49 0x0000000000471ce9 in PyString_Format (format='Adding tags %s to %s', args=
    ('juggling', <Message(_parent=<Messages(_parent=<Query(sort=None, _db=<Database(_db=<LP_NotmuchDatabaseS at remote 0xdf8e60>) at remote 0xe6c9d0>, _query=<LP_NotmuchQueryS at remote 0xdf8f80>) at remote 0xe6ca50>, _msgs=<LP_NotmuchMessagesS at remote 0xe770e0>) at remote 0xe6c990>, _msg=<LP_NotmuchMessageS at remote 0xe77200>) at remote 0x11a1b10>)) at ../Objects/stringobject.c:4435
#50 0x00000000004bad8d in PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:1308
#51 0x00000000004bfc9d in PyEval_EvalCodeEx (co=0xbdf930, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, 
    kws=<optimized out>, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:3253
#52 0x00000000004b9a03 in fast_function (nk=<optimized out>, na=3, n=<optimized out>, pp_stack=0x7fffc13a17c0, func=<function at remote 0xe3b9b0>)
    at ../Python/ceval.c:4117
#53 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a17c0) at ../Python/ceval.c:4042
#54 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#55 0x00000000004b9d27 in fast_function (nk=<optimized out>, na=<optimized out>, n=<optimized out>, pp_stack=0x7fffc13a1900, func=<function at remote 0xe65f50>)
    at ../Python/ceval.c:4107
#56 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a1900) at ../Python/ceval.c:4042
#57 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#58 0x00000000004b9d27 in fast_function (nk=<optimized out>, na=<optimized out>, n=<optimized out>, pp_stack=0x7fffc13a1a40, func=<function at remote 0xe3b8c0>)
    at ../Python/ceval.c:4107
#59 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a1a40) at ../Python/ceval.c:4042
#60 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#61 0x00000000004c0295 in PyEval_EvalCodeEx (co=0xe44730, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, 
    kws=<optimized out>, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:3253
#62 0x00000000004b9a03 in fast_function (nk=<optimized out>, na=2, n=<optimized out>, pp_stack=0x7fffc13a1c30, func=<function at remote 0xe70aa0>)
    at ../Python/ceval.c:4117
#63 call_function (oparg=<optimized out>, pp_stack=0x7fffc13a1c30) at ../Python/ceval.c:4042
#64 PyEval_EvalFrameEx (f=<optimized out>, throwflag=<optimized out>) at ../Python/ceval.c:2666
#65 0x00000000004bfc9d in PyEval_EvalCodeEx (co=0xb4a8b0, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, 
    kws=<optimized out>, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python/ceval.c:3253
#66 0x00000000004c0772 in PyEval_EvalCode (co=<optimized out>, globals=<optimized out>, locals=<optimized out>) at ../Python/ceval.c:667
#67 0x00000000004dfa22 in run_mod (mod=<optimized out>, filename=<optimized out>, globals=
    {'no_actions': 1, 'configured_filter_chain': [<SpamFilter(_remove_tags={}, _tag_blacklist=set([]), spam_tag='spam', _flush_tags=[], _tags_to_remove=[], _add_tags={}, _tags_to_add=[], db_path='/home/teythoon/Maildir') at remote 0xe6c6d0>, <ClassifyingFilter(_remove_tags={}, _tag_blacklist=set([]), _flush_tags=[], _tags_to_remove=[], _add_tags={'003f01ccb4fb$902a6430$b07f2c90$@gmx.de': set([u'juggling']), '20111203042836.GI27538@rzssh1.informatik.uni-hamburg.de': set([u'juggling']), '4ED62052.4000109@informatik.uni-hamburg.de': set([u'juggling']), 'A106C811-6B91-4E70-938A-403C22F24DB4@mex21.net': set([u'juggling']), '4EDE321F.4040708@ramdrive.org': set([u'juggling']), 'CAC2-jLG5wauWYVhFwxX8Rh1sbexx4OT2sks7EbZRAWn9=hPs3w@mail.gmail.com': set([u'juggling']), '4ED65C2C.9070805@informatik.uni-hamburg.de': set([u'juggling']), '4EDCC624.3020509@informatik.uni-hamburg.de': set([u'juggling']), 'D51F629D-9742-4F0A-807E-A7CF8102C9BD@robert-marquardt.com': set([u'juggling']), '005601ccb50a$91845110$b48cf330$@gmx.de': set(...(truncated), locals=
    {'no_actions': 1, 'configured_filter_chain': [<SpamFilter(_remove_tags={}, _tag_blacklist=set([]), spam_tag='spam', _flush_tags=[], _tags_to_remove=[], _add_tags={}, _tags_to_add=[], db_path='/home/teythoon/Maildir') at remote 0xe6c6d0>, <ClassifyingFilter(_remove_tags={}, _tag_blacklist=set([]), _flush_tags=[], _tags_to_remove=[], _add_tags={'003f01ccb4fb$902a6430$b07f2c90$@gmx.de': set([u'juggling']), '20111203042836.GI27538@rzssh1.informatik.uni-hamburg.de': set([u'juggling']), '4ED62052.4000109@informatik.uni-hamburg.de': set([u'juggling']), 'A106C811-6B91-4E70-938A-403C22F24DB4@mex21.net': set([u'juggling']), '4EDE321F.4040708@ramdrive.org': set([u'juggling']), 'CAC2-jLG5wauWYVhFwxX8Rh1sbexx4OT2sks7EbZRAWn9=hPs3w@mail.gmail.com': set([u'juggling']), '4ED65C2C.9070805@informatik.uni-hamburg.de': set([u'juggling']), '4EDCC624.3020509@informatik.uni-hamburg.de': set([u'juggling']), 'D51F629D-9742-4F0A-807E-A7CF8102C9BD@robert-marquardt.com': set([u'juggling']), '005601ccb50a$91845110$b48cf330$@gmx.de': set(...(truncated), flags=<optimized out>, arena=<optimized out>) at ../Python/pythonrun.c:1346
#68 0x00000000004e05b4 in PyRun_FileExFlags (fp=0xb99c10, filename=0x7fffc13a3346 "/home/teythoon/.local/bin/afew", start=<optimized out>, globals=
    {'no_actions': 1, 'configured_filter_chain': [<SpamFilter(_remove_tags={}, _tag_blacklist=set([]), spam_tag='spam', _flush_tags=[], _tags_to_remove=[], _add_tags={}, _tags_to_add=[], db_path='/home/teythoon/Maildir') at remote 0xe6c6d0>, <ClassifyingFilter(_remove_tags={}, _tag_blacklist=set([]), _flush_tags=[], _tags_to_remove=[], _add_tags={'003f01ccb4fb$902a6430$b07f2c90$@gmx.de': set([u'juggling']), '20111203042836.GI27538@rzssh1.informatik.uni-hamburg.de': set([u'juggling']), '4ED62052.4000109@informatik.uni-hamburg.de': set([u'juggling']), 'A106C811-6B91-4E70-938A-403C22F24DB4@mex21.net': set([u'juggling']), '4EDE321F.4040708@ramdrive.org': set([u'juggling']), 'CAC2-jLG5wauWYVhFwxX8Rh1sbexx4OT2sks7EbZRAWn9=hPs3w@mail.gmail.com': set([u'juggling']), '4ED65C2C.9070805@informatik.uni-hamburg.de': set([u'juggling']), '4EDCC624.3020509@informatik.uni-hamburg.de': set([u'juggling']), 'D51F629D-9742-4F0A-807E-A7CF8102C9BD@robert-marquardt.com': set([u'juggling']), '005601ccb50a$91845110$b48cf330$@gmx.de': set(...(truncated), locals=
    {'no_actions': 1, 'configured_filter_chain': [<SpamFilter(_remove_tags={}, _tag_blacklist=set([]), spam_tag='spam', _flush_tags=[], _tags_to_remove=[], _add_tags={}, _tags_to_add=[], db_path='/home/teythoon/Maildir') at remote 0xe6c6d0>, <ClassifyingFilter(_remove_tags={}, _tag_blacklist=set([]), _flush_tags=[], _tags_to_remove=[], _add_tags={'003f01ccb4fb$902a6430$b07f2c90$@gmx.de': set([u'juggling']), '20111203042836.GI27538@rzssh1.informatik.uni-hamburg.de': set([u'juggling']), '4ED62052.4000109@informatik.uni-hamburg.de': set([u'juggling']), 'A106C811-6B91-4E70-938A-403C22F24DB4@mex21.net': set([u'juggling']), '4EDE321F.4040708@ramdrive.org': set([u'juggling']), 'CAC2-jLG5wauWYVhFwxX8Rh1sbexx4OT2sks7EbZRAWn9=hPs3w@mail.gmail.com': set([u'juggling']), '4ED65C2C.9070805@informatik.uni-hamburg.de': set([u'juggling']), '4EDCC624.3020509@informatik.uni-hamburg.de': set([u'juggling']), 'D51F629D-9742-4F0A-807E-A7CF8102C9BD@robert-marquardt.com': set([u'juggling']), '005601ccb50a$91845110$b48cf330$@gmx.de': set(...(truncated), closeit=1, flags=0x7fffc13a1f60) at ../Python/pythonrun.c:1332
#69 0x00000000004e10be in PyRun_SimpleFileExFlags (fp=0xb99c10, filename=<optimized out>, closeit=1, flags=0x7fffc13a1f60) at ../Python/pythonrun.c:936
#70 0x00000000004f10fd in Py_Main (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:599
#71 0x00007f72f2cbaead in __libc_start_main (main=<optimized out>, argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>, fini=<optimized out>, 
    rtld_fini=<optimized out>, stack_end=0x7fffc13a2078) at libc-start.c:228
#72 0x000000000041f199 in _start ()
(gdb) q

with stderr saying:

terminate called after throwing an instance of 'Xapian::DatabaseModifiedError'
Aborted (core dumped)

This is an uncought c++ exception, right? If so I think it has to be
cought somewhere in libnotmuch and turned into the appropriate error
code (hm, there is only the generic XAPIAN_EXCEPTION, I thought there
was a way to indicate that the db has been modified?).

Justus

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

love u alot @,@


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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-12-07 19:05           ` Justus Winter
@ 2014-01-24 13:17             ` David Bremner
  2014-01-24 16:33               ` Justus Winter
  0 siblings, 1 reply; 23+ messages in thread
From: David Bremner @ 2014-01-24 13:17 UTC (permalink / raw)
  To: Justus Winter, notmuch

Justus Winter <4winter@informatik.uni-hamburg.de> writes:

> Quoting Justus Winter (2011-12-07 19:49:31)

> And another one:
[stack trace snipped]
> #69 0x00000000004e10be in PyRun_SimpleFileExFlags (fp=0xb99c10, filename=<optimized out>, closeit=1, flags=0x7fffc13a1f60) at ../Python/pythonrun.c:936
> #70 0x00000000004f10fd in Py_Main (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:599
> #71 0x00007f72f2cbaead in __libc_start_main (main=<optimized out>, argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>, fini=<optimized out>, 
>     rtld_fini=<optimized out>, stack_end=0x7fffc13a2078) at libc-start.c:228
> #72 0x000000000041f199 in _start ()
> (gdb) q
>
> with stderr saying:
>
> terminate called after throwing an instance of 'Xapian::DatabaseModifiedError'
> Aborted (core dumped)
>
> This is an uncought c++ exception, right? If so I think it has to be
> cought somewhere in libnotmuch and turned into the appropriate error
> code (hm, there is only the generic XAPIAN_EXCEPTION, I thought there
> was a way to indicate that the db has been modified?).

Can you still reproduce this bug?  If so, a small test case (python is
fine, but ideally not requiring afew) would be helpful.

d

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2011-12-06 10:46   ` Patrick Totzke
  2011-12-06 11:12     ` Sebastian Spaeth
  2011-12-06 12:05     ` Sebastian Spaeth
@ 2014-01-24 13:25     ` David Bremner
  2 siblings, 0 replies; 23+ messages in thread
From: David Bremner @ 2014-01-24 13:25 UTC (permalink / raw)
  To: Patrick Totzke, Justus Winter, notmuch

Patrick Totzke <patricktotzke@googlemail.com> writes:

> This commit breaks raising XapianErrors for me.
>
> If I lock the index with some `notmuch tag +test '*'`
> and try to write to it in alot, i get a segfault and
> the following on stderr:
>
> Xapian exception occurred opening database: Unable to get write lock on
> /home/pazz/mail/.notmuch/xapian: already locked
>
> /p

Is is this bug still reproducible with git master? If so, can you
reproduce it purely with the CLI?  It would be nice to narrow down if
this a bug in the lib or in the bindings.

d

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2014-01-24 13:17             ` David Bremner
@ 2014-01-24 16:33               ` Justus Winter
  2014-01-25  1:40                 ` David Bremner
  0 siblings, 1 reply; 23+ messages in thread
From: Justus Winter @ 2014-01-24 16:33 UTC (permalink / raw)
  To: David Bremner, notmuch

Hi :)

Quoting David Bremner (2014-01-24 14:17:27)
> Justus Winter <4winter@informatik.uni-hamburg.de> writes:
> 
> > Quoting Justus Winter (2011-12-07 19:49:31)
> 
> > And another one:
> [stack trace snipped]
> > #69 0x00000000004e10be in PyRun_SimpleFileExFlags (fp=0xb99c10, filename=<optimized out>, closeit=1, flags=0x7fffc13a1f60) at ../Python/pythonrun.c:936
> > #70 0x00000000004f10fd in Py_Main (argc=<optimized out>, argv=<optimized out>) at ../Modules/main.c:599
> > #71 0x00007f72f2cbaead in __libc_start_main (main=<optimized out>, argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>, fini=<optimized out>, 
> >     rtld_fini=<optimized out>, stack_end=0x7fffc13a2078) at libc-start.c:228
> > #72 0x000000000041f199 in _start ()
> > (gdb) q
> >
> > with stderr saying:
> >
> > terminate called after throwing an instance of 'Xapian::DatabaseModifiedError'
> > Aborted (core dumped)
> >
> > This is an uncought c++ exception, right? If so I think it has to be
> > cought somewhere in libnotmuch and turned into the appropriate error
> > code (hm, there is only the generic XAPIAN_EXCEPTION, I thought there
> > was a way to indicate that the db has been modified?).
> 
> Can you still reproduce this bug?  If so, a small test case (python is
> fine, but ideally not requiring afew) would be helpful.

I'm sorry, I've no idea how to reproduce this. I have, however, some
more test cases that crash libnotmuch, like this one:

~~~ snap ~~~
import os
import notmuch

db_path = os.path.expanduser('~/Maildir')

db = notmuch.Database(db_path, mode=notmuch.Database.MODE.READ_WRITE)
directory = db.get_directory(os.path.join(db_path, 'cur'))
db._destroy(db._db)

try:
    directory.get_child_files()
except notmuch.errors.NotInitializedError as e:
    print('yeah')
else:
    assert False, "Hey, where's my exception?"
~~~ snap ~~~

% python destroy_minimal.py
[2]    3907 abort (core dumped)  python destroy_minimal.py

Program terminated with signal 6, Aborted.
#0  0x00007f996ad021d5 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007f996ad021d5 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007f996ad05388 in __GI_abort () at abort.c:90
#2  0x00007f99699d4486 in talloc_abort (reason=0x7f99699db648 "Bad talloc magic value - access after free") at ../talloc.c:317
#3  0x00007f99699d8097 in talloc_abort_access_after_free () at ../talloc.c:336
#4  talloc_chunk_from_ptr (ptr=0x23e6f20) at ../talloc.c:357
#5  talloc_chunk_from_ptr (ptr=0x23e6f20) at ../talloc.c:2064
#6  __talloc (size=17, context=0x23e6f20) at ../talloc.c:555
#7  talloc_vasprintf (t=<optimized out>, fmt=0x7f996a3a56ef "%s%u:", ap=0x7fffb612bff8) at ../talloc.c:2079
#8  0x00007f99699d8167 in talloc_asprintf (t=<optimized out>, fmt=<optimized out>) at ../talloc.c:2101
#9  0x00007f996a39c02e in notmuch_directory_get_child_files () from /home/teythoon/.local/lib/libnotmuch.so.3
#10 0x00007f996a5b1cfc in ffi_call_unix64 () from /usr/lib/x86_64-linux-gnu/libffi.so.6
#11 0x00007f996a5b162c in ffi_call () from /usr/lib/x86_64-linux-gnu/libffi.so.6
#12 0x00007f996a7c86d0 in _ctypes_callproc () from /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
#13 0x00007f996a7ca08e in PyCFuncPtr_call.3149.2622 () from /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so
#14 0x000000000055f47a in PyEval_EvalFrameEx () at ../Objects/abstract.c:2529
#15 0x000000000055f7ba in PyEval_EvalFrameEx () at ../Python/ceval.c:4107
#16 0x0000000000566bfb in PyEval_EvalCode () at ../Python/ceval.c:3253
#17 0x0000000000469499 in run_mod.42569 () at ../Python/pythonrun.c:1370
#18 0x0000000000469819 in PyRun_FileExFlags () at ../Python/pythonrun.c:1356
#19 0x0000000000469d52 in PyRun_SimpleFileExFlags () at ../Python/pythonrun.c:948
#20 0x000000000046b65f in Py_Main () at ../Modules/main.c:640
#21 0x00007f996acee995 in __libc_start_main (main=0x46b71d <main>, argc=2, ubp_av=0x7fffb612ca58, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
    stack_end=0x7fffb612ca48) at libc-start.c:276
#22 0x0000000000573f2e in _start ()

This is a bit contrived b/c I'm destroying the db object by
hand. Never the less libnotmuch calls abort, and there is no way to
contain something like this in the python bindings.

I've seen your recent proposal to improve the error reporting for
libnotmuch functions. I think it's awesome, albeit a little late.

I've no idea how other frontends deal with libnotmuch, but alot has
moved libnotmuch to it's own process to contain any crashes (or
libnotmuch calling exit(3)), and to prevent libnotmuch from writing to
stderr destroying alots curses gui. I've always felt like libnotmuch
users were second-class citizens, the primary target of libnotmuch
being the notmuch binary.

Justus

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

* Re: [PATCH 2/2] python: annotate all calls into libnotmuch with types
  2014-01-24 16:33               ` Justus Winter
@ 2014-01-25  1:40                 ` David Bremner
  2014-01-25  3:07                   ` [PATCH] lib: update documentation for notmuch_database_get_directory David Bremner
  0 siblings, 1 reply; 23+ messages in thread
From: David Bremner @ 2014-01-25  1:40 UTC (permalink / raw)
  To: Justus Winter, notmuch

Justus Winter <4winter@informatik.uni-hamburg.de> writes:

> #0  0x00007f996ad021d5 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
> 56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
> (gdb) bt
> #0  0x00007f996ad021d5 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
> #1  0x00007f996ad05388 in __GI_abort () at abort.c:90
> #2  0x00007f99699d4486 in talloc_abort (reason=0x7f99699db648 "Bad talloc magic value - access after free") at ../talloc.c:317
> #3  0x00007f99699d8097 in talloc_abort_access_after_free () at ../talloc.c:336

> This is a bit contrived b/c I'm destroying the db object by
> hand. Never the less libnotmuch calls abort, and there is no way to
> contain something like this in the python bindings.

FWIW libnotmuch is not directly calling abort here, talloc is, because
it is detecting illegal memory access patterns. So there could well be a
libnotmuch bug here, but it isn't really related to error handling.

As far as I can tell, the underlying reason for the crash is that that
talloc is a hierarchical memory allocator, and the directory is a child
of the database.  This "ownership" should probably be documented in the
header for notmuch_database_get_directory. This won't fix your crash, of
course ;).

d

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

* [PATCH] lib: update documentation for notmuch_database_get_directory
  2014-01-25  1:40                 ` David Bremner
@ 2014-01-25  3:07                   ` David Bremner
  2014-01-25 11:46                     ` Tomi Ollila
  2014-01-26 14:02                     ` David Bremner
  0 siblings, 2 replies; 23+ messages in thread
From: David Bremner @ 2014-01-25  3:07 UTC (permalink / raw)
  To: notmuch

Clarify that using the directory after destroying the corresponding
database is not permitted.

This is implicit in the description of notmuch_database_destroy, but
it doesn't hurt to be explicit, and we do express similar "ownership"
relationships at other places in the docs.
---
 lib/notmuch.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/notmuch.h b/lib/notmuch.h
index 68896ae..3df1ade 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -415,6 +415,10 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
  * If this directory object does not exist in the database, this
  * returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL.
  *
+ * Otherwise the returned directory object is owned by the database
+ * and as such, will only be valid until notmuch_database_destroy is
+ * called.
+ *
  * Return value:
  *
  * NOTMUCH_STATUS_SUCCESS: Successfully retrieved directory.
-- 
1.8.5.2

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

* Re: [PATCH] lib: update documentation for notmuch_database_get_directory
  2014-01-25  3:07                   ` [PATCH] lib: update documentation for notmuch_database_get_directory David Bremner
@ 2014-01-25 11:46                     ` Tomi Ollila
  2014-01-26 14:02                     ` David Bremner
  1 sibling, 0 replies; 23+ messages in thread
From: Tomi Ollila @ 2014-01-25 11:46 UTC (permalink / raw)
  To: David Bremner, notmuch

On Sat, Jan 25 2014, David Bremner <david@tethera.net> wrote:

> Clarify that using the directory after destroying the corresponding
> database is not permitted.
>
> This is implicit in the description of notmuch_database_destroy, but
> it doesn't hurt to be explicit, and we do express similar "ownership"
> relationships at other places in the docs.
> ---

LGTM.

Tomi


>  lib/notmuch.h | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index 68896ae..3df1ade 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -415,6 +415,10 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
>   * If this directory object does not exist in the database, this
>   * returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL.
>   *
> + * Otherwise the returned directory object is owned by the database
> + * and as such, will only be valid until notmuch_database_destroy is
> + * called.
> + *
>   * Return value:
>   *
>   * NOTMUCH_STATUS_SUCCESS: Successfully retrieved directory.
> -- 
> 1.8.5.2
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

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

* Re: [PATCH] lib: update documentation for notmuch_database_get_directory
  2014-01-25  3:07                   ` [PATCH] lib: update documentation for notmuch_database_get_directory David Bremner
  2014-01-25 11:46                     ` Tomi Ollila
@ 2014-01-26 14:02                     ` David Bremner
  1 sibling, 0 replies; 23+ messages in thread
From: David Bremner @ 2014-01-26 14:02 UTC (permalink / raw)
  To: notmuch

David Bremner <david@tethera.net> writes:

> Clarify that using the directory after destroying the corresponding
> database is not permitted.
>
> This is implicit in the description of notmuch_database_destroy, but
> it doesn't hurt to be explicit, and we do express similar "ownership"
> relationships at other places in the docs.

pushed,

d

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

end of thread, other threads:[~2014-01-26 14:03 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-09 22:12 [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Justus Winter
2011-10-09 22:12 ` [PATCH 2/2] python: annotate all calls into libnotmuch with types Justus Winter
2011-12-06 10:46   ` Patrick Totzke
2011-12-06 11:12     ` Sebastian Spaeth
2011-12-06 11:44       ` Patrick Totzke
2011-12-06 12:05     ` Sebastian Spaeth
     [not found]       ` <notmuch-sha1-f155d93e11888b35377531dd556b03fd493b7590>
2011-12-07 18:49         ` Justus Winter
     [not found]         ` <notmuch-sha1-c3821ec5e6ef2f83665b03ba10fdfff871f70c2b>
2011-12-07 19:05           ` Justus Winter
2014-01-24 13:17             ` David Bremner
2014-01-24 16:33               ` Justus Winter
2014-01-25  1:40                 ` David Bremner
2014-01-25  3:07                   ` [PATCH] lib: update documentation for notmuch_database_get_directory David Bremner
2014-01-25 11:46                     ` Tomi Ollila
2014-01-26 14:02                     ` David Bremner
2014-01-24 13:25     ` [PATCH 2/2] python: annotate all calls into libnotmuch with types David Bremner
2011-11-02  7:25 ` [PATCH 1/2] python: add classes to wrap all notmuch_*_t types Sebastian Spaeth
2011-11-28 12:36   ` Justus Winter
2011-12-01 21:25     ` Sebastian Spaeth
2011-12-01 23:32       ` James Westby
2011-12-02 12:35         ` Justus Winter
2011-12-02 14:20           ` James Westby
2011-12-02 23:24             ` James Westby
2011-12-03  2:11               ` Justus Winter

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).