From 7ddd849015759a329bf8fef8c8b5a93359408962 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 16 Jan 2012 13:39:41 +0100 Subject: py3k: add a specialized version of _str for python3 All strings are unicode strings in python 3 and the basestring and unicode types are removed hence the need for a specialized version. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/globals.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index 32ed9ae..4138460 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -31,12 +31,34 @@ if sys.version_info[0] == 2: class Python3StringMixIn(object): def __str__(self): return unicode(self).encode('utf-8') + + + def _str(value): + """Ensure a nicely utf-8 encoded string to pass to libnotmuch + + C++ code expects strings to be well formatted and + unicode strings to have no null bytes.""" + if not isinstance(value, basestring): + raise TypeError("Expected str or unicode, got %s" % type(value)) + if isinstance(value, unicode): + return value.encode('UTF-8') + return value else: class Python3StringMixIn(object): def __str__(self): return self.__unicode__() + def _str(value): + """Ensure a nicely utf-8 encoded string to pass to libnotmuch + + C++ code expects strings to be well formatted and + unicode strings to have no null bytes.""" + if not isinstance(value, str): + raise TypeError("Expected str, got %s" % type(value)) + return value.encode('UTF-8') + + class Enum(object): """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc...""" def __init__(self, names): @@ -202,18 +224,6 @@ class NotInitializedError(NotmuchError): status = STATUS.NOT_INITIALIZED -def _str(value): - """Ensure a nicely utf-8 encoded string to pass to libnotmuch - - C++ code expects strings to be well formatted and - unicode strings to have no null bytes.""" - if not isinstance(value, basestring): - raise TypeError("Expected str or unicode, got %s" % str(type(value))) - if isinstance(value, unicode): - return value.encode('UTF-8') - return value - - class NotmuchDatabaseS(Structure): pass NotmuchDatabaseP = POINTER(NotmuchDatabaseS) -- cgit v1.2.3 From 8015cbff263606f009b5750d23b28ee332c25db8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 22 Jan 2012 06:14:57 +0100 Subject: python: fix error handling Before 3434d1940 the return values of libnotmuch functions were declared as c_void_p and the code checking for errors compared the returned value to None, which is the ctypes equivalent of a NULL pointer. But said commit wrapped all the data types in python classes and the semantic changed in a subtle way. If a function returns NULL, the wrapped python value is falsish, but no longer equal to None. --- bindings/python/notmuch/database.py | 16 ++++++++-------- bindings/python/notmuch/filename.py | 2 +- bindings/python/notmuch/message.py | 6 +++--- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 24da8e9..6238b28 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -168,7 +168,7 @@ class Database(object): res = Database._create(_str(path), Database.MODE.READ_WRITE) - if res is None: + if not res: raise NotmuchError( message="Could not create the specified database") self._db = res @@ -188,7 +188,7 @@ class Database(object): """ res = Database._open(_str(path), mode) - if res is None: + if not res: raise NotmuchError(message="Could not open the specified database") self._db = res @@ -651,7 +651,7 @@ class Query(object): self._db = db # create query, return None if too little mem available query_p = Query._create(db.db_p, _str(querystr)) - if query_p is None: + if not query_p: raise NullPointerError self._query = query_p @@ -685,7 +685,7 @@ class Query(object): self._assert_query_is_initialized() threads_p = Query._search_threads(self._query) - if threads_p is None: + if not threads_p: raise NullPointerError return Threads(threads_p, self) @@ -699,7 +699,7 @@ class Query(object): self._assert_query_is_initialized() msgs_p = Query._search_messages(self._query) - if msgs_p is None: + if not msgs_p: raise NullPointerError return Messages(msgs_p, self) @@ -765,7 +765,7 @@ class Directory(object): def _assert_dir_is_initialized(self): """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None""" - if self._dir_p is None: + if not self._dir_p: raise NotmuchError(STATUS.NOT_INITIALIZED) def __init__(self, path, dir_p, parent): @@ -926,7 +926,7 @@ class Filenames(object): _move_to_next.restype = None def __next__(self): - if self._files_p is None: + if not self._files_p: raise NotmuchError(STATUS.NOT_INITIALIZED) if not self._valid(self._files_p): @@ -953,7 +953,7 @@ class Filenames(object): # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) for file in files: print file """ - if self._files_p is None: + if not self._files_p: raise NotmuchError(STATUS.NOT_INITIALIZED) i = 0 diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index 51dae20..3f54104 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -69,7 +69,7 @@ class Filenames(Python3StringMixIn): reference to it, so we can automatically delete the db object once all derived objects are dead. """ - if files_p is None: + if not files_p: raise NotmuchError(STATUS.NULL_POINTER) self._files = files_p diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index d40a575..883ed23 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -117,7 +117,7 @@ class Messages(object): :TODO: Make the iterator work more than once and cache the tags in the Python object.(?) """ - if msgs_p is None: + if not msgs_p: raise NotmuchError(STATUS.NULL_POINTER) self._msgs = msgs_p @@ -349,7 +349,7 @@ class Message(Python3StringMixIn): automatically delete the parent object once all derived objects are dead. """ - if msg_p is None: + if not msg_p: raise NotmuchError(STATUS.NULL_POINTER) self._msg = msg_p #keep reference to parent, so we keep it alive @@ -407,7 +407,7 @@ class Message(Python3StringMixIn): msgs_p = Message._get_replies(self._msg) - if msgs_p is None: + if not msgs_p: return EmptyMessagesResult(self) return Messages(msgs_p, self) diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index ceb7244..71d81dd 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -70,7 +70,7 @@ class Tags(Python3StringMixIn): :TODO: Make the iterator optionally work more than once by cache the tags in the Python object(?) """ - if tags_p is None: + if not tags_p: raise NotmuchError(STATUS.NULL_POINTER) self._tags = tags_p diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index e81ff1b..104710c 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -97,7 +97,7 @@ class Threads(Python3StringMixIn): :TODO: Make the iterator work more than once and cache the tags in the Python object.(?) """ - if threads_p is None: + if not threads_p: raise NotmuchError(STATUS.NULL_POINTER) self._threads = threads_p @@ -228,7 +228,7 @@ class Thread(object): automatically delete the parent object once all derived objects are dead. """ - if thread_p is None: + if not thread_p: raise NotmuchError(STATUS.NULL_POINTER) self._thread = thread_p #keep reference to parent, so we keep it alive @@ -289,7 +289,7 @@ class Thread(object): msgs_p = Thread._get_toplevel_messages(self._thread) - if msgs_p is None: + if not msgs_p: raise NotmuchError(STATUS.NULL_POINTER) return Messages(msgs_p, self) -- cgit v1.2.3 From 221c7e0b38177f5f1dbf0561580c15e8aaa49004 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 22 Jan 2012 14:09:35 +0100 Subject: python: fix error handling Before 3434d1940 the return values of libnotmuch functions were declared as c_void_p and the code checking for errors compared the returned value to None, which is the ctypes equivalent of a NULL pointer. But said commit wrapped all the data types in python classes and the semantic changed in a subtle way. If a function returns NULL, the wrapped python value is falsish, but no longer equal to None. Backported from master to 0.11. --- bindings/python/notmuch/database.py | 16 ++++++++-------- bindings/python/notmuch/filename.py | 2 +- bindings/python/notmuch/message.py | 6 +++--- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 7923f76..0074ba3 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -168,7 +168,7 @@ class Database(object): res = Database._create(_str(path), Database.MODE.READ_WRITE) - if res is None: + if not res: raise NotmuchError( message="Could not create the specified database") self._db = res @@ -188,7 +188,7 @@ class Database(object): """ res = Database._open(_str(path), mode) - if res is None: + if not res: raise NotmuchError(message="Could not open the specified database") self._db = res @@ -645,7 +645,7 @@ class Query(object): self._db = db # create query, return None if too little mem available query_p = Query._create(db.db_p, _str(querystr)) - if query_p is None: + if not query_p: raise NullPointerError self._query = query_p @@ -679,7 +679,7 @@ class Query(object): self._assert_query_is_initialized() threads_p = Query._search_threads(self._query) - if threads_p is None: + if not threads_p: raise NullPointerError return Threads(threads_p, self) @@ -693,7 +693,7 @@ class Query(object): self._assert_query_is_initialized() msgs_p = Query._search_messages(self._query) - if msgs_p is None: + if not msgs_p: raise NullPointerError return Messages(msgs_p, self) @@ -759,7 +759,7 @@ class Directory(object): def _assert_dir_is_initialized(self): """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None""" - if self._dir_p is None: + if not self._dir_p: raise NotmuchError(STATUS.NOT_INITIALIZED) def __init__(self, path, dir_p, parent): @@ -920,7 +920,7 @@ class Filenames(object): _move_to_next.restype = None def next(self): - if self._files_p is None: + if not self._files_p: raise NotmuchError(STATUS.NOT_INITIALIZED) if not self._valid(self._files_p): @@ -946,7 +946,7 @@ class Filenames(object): # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) for file in files: print file """ - if self._files_p is None: + if not self._files_p: raise NotmuchError(STATUS.NOT_INITIALIZED) i = 0 diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index a7cd7e6..f7313ec 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -69,7 +69,7 @@ class Filenames(object): reference to it, so we can automatically delete the db object once all derived objects are dead. """ - if files_p is None: + if not files_p: raise NotmuchError(STATUS.NULL_POINTER) self._files = files_p diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index ce8e718..5540df3 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -116,7 +116,7 @@ class Messages(object): :TODO: Make the iterator work more than once and cache the tags in the Python object.(?) """ - if msgs_p is None: + if not msgs_p: raise NotmuchError(STATUS.NULL_POINTER) self._msgs = msgs_p @@ -321,7 +321,7 @@ class Message(object): automatically delete the parent object once all derived objects are dead. """ - if msg_p is None: + if not msg_p: raise NotmuchError(STATUS.NULL_POINTER) self._msg = msg_p #keep reference to parent, so we keep it alive @@ -380,7 +380,7 @@ class Message(object): msgs_p = Message._get_replies(self._msg) - if msgs_p is None: + if not msgs_p: return None return Messages(msgs_p, self) diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 2fb7d32..4881db9 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -70,7 +70,7 @@ class Tags(object): :TODO: Make the iterator optionally work more than once by cache the tags in the Python object(?) """ - if tags_p is None: + if not tags_p: raise NotmuchError(STATUS.NULL_POINTER) self._tags = tags_p diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 5058846..594fa52 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -97,7 +97,7 @@ class Threads(object): :TODO: Make the iterator work more than once and cache the tags in the Python object.(?) """ - if threads_p is None: + if not threads_p: raise NotmuchError(STATUS.NULL_POINTER) self._threads = threads_p @@ -227,7 +227,7 @@ class Thread(object): automatically delete the parent object once all derived objects are dead. """ - if thread_p is None: + if not thread_p: raise NotmuchError(STATUS.NULL_POINTER) self._thread = thread_p #keep reference to parent, so we keep it alive @@ -288,7 +288,7 @@ class Thread(object): msgs_p = Thread._get_toplevel_messages(self._thread) - if msgs_p is None: + if not msgs_p: raise NotmuchError(STATUS.NULL_POINTER) return Messages(msgs_p, self) -- cgit v1.2.3 From c10b780b44128983c56253e46fa2e5f8553f2e0e Mon Sep 17 00:00:00 2001 From: David Bremner Date: Fri, 3 Feb 2012 08:32:49 -0400 Subject: version: bump to 0.11.1 also semi-automatically update man page and python bindings versions. --- bindings/python/notmuch/version.py | 2 +- notmuch.1 | 2 +- version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index 59c396f..ed40e7f 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.11' +__VERSION__ = '0.11.1' diff --git a/notmuch.1 b/notmuch.1 index a5828bc..7ab2947 100644 --- a/notmuch.1 +++ b/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-01-13 "Notmuch 0.11" +.TH NOTMUCH 1 2012-02-03 "Notmuch 0.11.1" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/version b/version index 51176c7..af88ba8 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.11 +0.11.1 -- cgit v1.2.3 From 8c5be7d12dc5e48faf4008209327d34c04961616 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 10 Feb 2012 18:52:19 +0100 Subject: python: Add a Mock class to the sphinx config that can be used to mock modules Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/conf.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'bindings') diff --git a/bindings/python/docs/source/conf.py b/bindings/python/docs/source/conf.py index e0ee39c..c7b9518 100644 --- a/bindings/python/docs/source/conf.py +++ b/bindings/python/docs/source/conf.py @@ -18,6 +18,23 @@ import sys, os # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0,os.path.abspath('../..')) +class Mock(object): + def __init__(self, *args, **kwargs): + pass + + def __call__(self, *args, **kwargs): + return Mock() + + @classmethod + def __getattr__(self, name): + return Mock() if name not in ('__file__', '__path__') else '/dev/null' + +MOCK_MODULES = [ +] +for mod_name in MOCK_MODULES: + sys.modules[mod_name] = Mock() + + from notmuch import __VERSION__,__AUTHOR__ # -- General configuration ----------------------------------------------------- -- cgit v1.2.3 From ae376c774ee8d8f45bae002261c425e1bc0a243a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 10 Feb 2012 18:53:04 +0100 Subject: python: mock out the ctypes library This allows rtfd.org to build the documentation without libnotmuch. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/conf.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bindings') diff --git a/bindings/python/docs/source/conf.py b/bindings/python/docs/source/conf.py index c7b9518..76610b7 100644 --- a/bindings/python/docs/source/conf.py +++ b/bindings/python/docs/source/conf.py @@ -30,6 +30,7 @@ class Mock(object): return Mock() if name not in ('__file__', '__path__') else '/dev/null' MOCK_MODULES = [ + 'ctypes', ] for mod_name in MOCK_MODULES: sys.modules[mod_name] = Mock() -- cgit v1.2.3 From bb514d7862aa38f6628ef1c8cb69ed5ec72098fd Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 10 Feb 2012 22:34:47 +0100 Subject: py3k: Fix decoding of default database name in Database._get_user_default_db Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 6238b28..36b65ec 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -18,6 +18,7 @@ Copyright 2010 Sebastian Spaeth ' """ import os +import codecs from ctypes import c_char_p, c_void_p, c_uint, c_long, byref, POINTER from notmuch.globals import (nmlib, STATUS, NotmuchError, NotInitializedError, NullPointerError, Enum, _str, @@ -553,11 +554,11 @@ class Database(object): config = SafeConfigParser() conf_f = os.getenv('NOTMUCH_CONFIG', os.path.expanduser('~/.notmuch-config')) - config.read(conf_f) + config.readfp(codecs.open(conf_f, 'r', 'utf-8')) if not config.has_option('database', 'path'): raise NotmuchError(message="No DB path specified" " and no user default found") - return config.get('database', 'path').decode('utf-8') + return config.get('database', 'path') @property def db_p(self): -- cgit v1.2.3 From b2734519db78fdec76eeafc5fe8f5631a6436cf6 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 15 Feb 2012 22:25:13 +0100 Subject: python: provide a Database.close function Rename Database.__del__ to Database.close, move it just below the open function and call close() in a newly created destructor just below the constructor. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 36b65ec..d0e38dd 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -142,6 +142,9 @@ class Database(object): else: self.create(path) + def __del__(self): + self.close() + def _assert_db_is_initialized(self): """Raises :exc:`NotInitializedError` if self._db is `None`""" if self._db is None: @@ -193,6 +196,16 @@ class Database(object): raise NotmuchError(message="Could not open the specified database") self._db = res + _close = nmlib.notmuch_database_close + _close.argtypes = [NotmuchDatabaseP] + _close.restype = None + + def close(self): + """Close and free the notmuch database if needed""" + if self._db is not None: + self._close(self._db) + self._db = None + def get_path(self): """Returns the file path of an open database""" self._assert_db_is_initialized() @@ -531,15 +544,6 @@ 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: - self._close(self._db) - def _get_user_default_db(self): """ Reads a user's notmuch config and returns his db location -- cgit v1.2.3 From 36ce7e3c989f6f66a4b250483de3b45e902d68d1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 15 Feb 2012 22:41:16 +0100 Subject: python: implement the context manager protocol for database objects Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index d0e38dd..533948c 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -41,6 +41,10 @@ class Database(object): :exc:`XapianError` as the underlying database has been modified. Close and reopen the database to continue working with it. + :class:`Database` objects implement the context manager protocol + so you can use the :keyword:`with` statement to ensure that the + database is properly closed. + .. note:: Any function in this class can and will throw an @@ -206,6 +210,18 @@ class Database(object): self._close(self._db) self._db = None + def __enter__(self): + ''' + Implements the context manager protocol. + ''' + return self + + def __exit__(self, exc_type, exc_value, traceback): + ''' + Implements the context manager protocol. + ''' + self.close() + def get_path(self): """Returns the file path of an open database""" self._assert_db_is_initialized() -- cgit v1.2.3 From c471d448379b13d8133dfc73b7bbec43964f26d2 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 00:57:59 +0100 Subject: python: remove unused but imported symbol Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/filename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index 3f54104..469b6a5 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -18,7 +18,7 @@ Copyright 2010 Sebastian Spaeth ' """ from ctypes import c_char_p from notmuch.globals import (nmlib, STATUS, NotmuchError, - NotmuchFilenamesP, NotmuchMessageP, _str, Python3StringMixIn) + NotmuchFilenamesP, NotmuchMessageP, Python3StringMixIn) class Filenames(Python3StringMixIn): -- cgit v1.2.3 From ff287531ca765f39def6941cd13eb77aa36c14fa Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:01:33 +0100 Subject: python: remove unused but imported symbol Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/tag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 71d81dd..d2dc498 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -17,7 +17,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth ' """ from ctypes import c_char_p -from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, _str, Python3StringMixIn +from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, Python3StringMixIn class Tags(Python3StringMixIn): -- cgit v1.2.3 From 5d69d272c3025f537de0e9995dee394c75ed1005 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:10:45 +0100 Subject: python: move Query class to its own file Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 181 +++------------------------------ bindings/python/notmuch/query.py | 192 ++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 166 deletions(-) create mode 100644 bindings/python/notmuch/query.py (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 533948c..0958ce0 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -20,14 +20,22 @@ Copyright 2010 Sebastian Spaeth ' import os import codecs from ctypes import c_char_p, c_void_p, c_uint, c_long, byref, POINTER -from notmuch.globals import (nmlib, STATUS, NotmuchError, NotInitializedError, - NullPointerError, Enum, _str, - NotmuchDatabaseP, NotmuchDirectoryP, NotmuchMessageP, NotmuchTagsP, - NotmuchQueryP, NotmuchMessagesP, NotmuchThreadsP, NotmuchFilenamesP) -from notmuch.thread import Threads -from notmuch.message import Messages, Message +from notmuch.globals import ( + nmlib, + STATUS, + NotmuchError, + NotInitializedError, + Enum, + _str, + NotmuchDatabaseP, + NotmuchDirectoryP, + NotmuchMessageP, + NotmuchTagsP, + NotmuchFilenamesP +) +from notmuch.message import Message from notmuch.tag import Tags - +from .query import Query class Database(object): """The :class:`Database` is the highest-level object that notmuch @@ -590,165 +598,6 @@ class Database(object): return self._db -class Query(object): - """Represents a search query on an opened :class:`Database`. - - A query selects and filters a subset of messages from the notmuch - database we derive from. - - :class:`Query` provides an instance attribute :attr:`sort`, which - contains the sort order (if specified via :meth:`set_sort`) or - `None`. - - Any function in this class may throw an :exc:`NotInitializedError` - in case the underlying query object was not set up correctly. - - .. note:: Do remember that as soon as we tear down this object, - all underlying derived objects such as threads, - messages, tags etc will be freed by the underlying library - as well. Accessing these objects will lead to segfaults and - other unexpected behavior. See above for more details. - """ - # constants - SORT = Enum(['OLDEST_FIRST', 'NEWEST_FIRST', 'MESSAGE_ID', 'UNSORTED']) - """Constants: Sort order in which to return results""" - - """notmuch_query_create""" - _create = nmlib.notmuch_query_create - _create.argtypes = [NotmuchDatabaseP, c_char_p] - _create.restype = NotmuchQueryP - - """notmuch_query_search_threads""" - _search_threads = nmlib.notmuch_query_search_threads - _search_threads.argtypes = [NotmuchQueryP] - _search_threads.restype = NotmuchThreadsP - - """notmuch_query_search_messages""" - _search_messages = nmlib.notmuch_query_search_messages - _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): - """ - :param db: An open database which we derive the Query from. - :type db: :class:`Database` - :param querystr: The query string for the message. - :type querystr: utf-8 encoded str or unicode - """ - self._db = None - self._query = None - self.sort = None - self.create(db, querystr) - - def _assert_query_is_initialized(self): - """Raises :exc:`NotInitializedError` if self._query is `None`""" - if self._query is None: - raise NotInitializedError() - - def create(self, db, querystr): - """Creates a new query derived from a Database - - This function is utilized by __init__() and usually does not need to - be called directly. - - :param db: Database to create the query from. - :type db: :class:`Database` - :param querystr: The query string - :type querystr: utf-8 encoded str or unicode - :returns: Nothing - :exception: - :exc:`NullPointerError` if the query creation failed - (e.g. too little memory). - :exc:`NotInitializedError` if the underlying db was not - intitialized. - """ - db._assert_db_is_initialized() - # create reference to parent db to keep it alive - self._db = db - # create query, return None if too little mem available - query_p = Query._create(db.db_p, _str(querystr)) - if not query_p: - 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 - - :param sort: Sort order (see :attr:`Query.SORT`) - """ - self._assert_query_is_initialized() - self.sort = sort - self._set_sort(self._query, sort) - - def search_threads(self): - """Execute a query for threads - - Execute a query for threads, returning a :class:`Threads` iterator. - The returned threads are owned by the query and as such, will only be - valid until the Query is deleted. - - The method sets :attr:`Message.FLAG`\.MATCH for those messages that - match the query. The method :meth:`Message.get_flag` allows us - to get the value of this flag. - - :returns: :class:`Threads` - :exception: :exc:`NullPointerError` if search_threads failed - """ - self._assert_query_is_initialized() - threads_p = Query._search_threads(self._query) - - if not threads_p: - raise NullPointerError - return Threads(threads_p, self) - - def search_messages(self): - """Filter messages according to the query and return - :class:`Messages` in the defined sort order - - :returns: :class:`Messages` - :exception: :exc:`NullPointerError` if search_messages failed - """ - self._assert_query_is_initialized() - msgs_p = Query._search_messages(self._query) - - if not msgs_p: - raise NullPointerError - return Messages(msgs_p, self) - - def count_messages(self): - """Estimate the number of messages matching the query - - This function performs a search and returns Xapian's best - guess as to the number of matching messages. It is much faster - than performing :meth:`search_messages` and counting the - result with `len()` (although it always returned the same - result in my tests). Technically, it wraps the underlying - *notmuch_query_count_messages* function. - - :returns: :class:`Messages` - """ - 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: - self._destroy(self._query) - - class Directory(object): """Represents a directory entry in the notmuch directory diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py new file mode 100644 index 0000000..bab5c3e --- /dev/null +++ b/bindings/python/notmuch/query.py @@ -0,0 +1,192 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth ' +""" + +from ctypes import c_char_p, c_uint +from notmuch.globals import ( + nmlib, + Enum, + _str, + NotmuchQueryP, + NotmuchThreadsP, + NotmuchDatabaseP, + NotmuchMessagesP, + NullPointerError, + NotInitializedError, +) +from notmuch.thread import Threads +from notmuch.message import Messages + + +class Query(object): + """Represents a search query on an opened :class:`Database`. + + A query selects and filters a subset of messages from the notmuch + database we derive from. + + :class:`Query` provides an instance attribute :attr:`sort`, which + contains the sort order (if specified via :meth:`set_sort`) or + `None`. + + Any function in this class may throw an :exc:`NotInitializedError` + in case the underlying query object was not set up correctly. + + .. note:: Do remember that as soon as we tear down this object, + all underlying derived objects such as threads, + messages, tags etc will be freed by the underlying library + as well. Accessing these objects will lead to segfaults and + other unexpected behavior. See above for more details. + """ + # constants + SORT = Enum(['OLDEST_FIRST', 'NEWEST_FIRST', 'MESSAGE_ID', 'UNSORTED']) + """Constants: Sort order in which to return results""" + + """notmuch_query_create""" + _create = nmlib.notmuch_query_create + _create.argtypes = [NotmuchDatabaseP, c_char_p] + _create.restype = NotmuchQueryP + + """notmuch_query_search_threads""" + _search_threads = nmlib.notmuch_query_search_threads + _search_threads.argtypes = [NotmuchQueryP] + _search_threads.restype = NotmuchThreadsP + + """notmuch_query_search_messages""" + _search_messages = nmlib.notmuch_query_search_messages + _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): + """ + :param db: An open database which we derive the Query from. + :type db: :class:`Database` + :param querystr: The query string for the message. + :type querystr: utf-8 encoded str or unicode + """ + self._db = None + self._query = None + self.sort = None + self.create(db, querystr) + + def _assert_query_is_initialized(self): + """Raises :exc:`NotInitializedError` if self._query is `None`""" + if self._query is None: + raise NotInitializedError() + + def create(self, db, querystr): + """Creates a new query derived from a Database + + This function is utilized by __init__() and usually does not need to + be called directly. + + :param db: Database to create the query from. + :type db: :class:`Database` + :param querystr: The query string + :type querystr: utf-8 encoded str or unicode + :returns: Nothing + :exception: + :exc:`NullPointerError` if the query creation failed + (e.g. too little memory). + :exc:`NotInitializedError` if the underlying db was not + intitialized. + """ + db._assert_db_is_initialized() + # create reference to parent db to keep it alive + self._db = db + # create query, return None if too little mem available + query_p = Query._create(db.db_p, _str(querystr)) + if not query_p: + 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 + + :param sort: Sort order (see :attr:`Query.SORT`) + """ + self._assert_query_is_initialized() + self.sort = sort + self._set_sort(self._query, sort) + + def search_threads(self): + """Execute a query for threads + + Execute a query for threads, returning a :class:`Threads` iterator. + The returned threads are owned by the query and as such, will only be + valid until the Query is deleted. + + The method sets :attr:`Message.FLAG`\.MATCH for those messages that + match the query. The method :meth:`Message.get_flag` allows us + to get the value of this flag. + + :returns: :class:`Threads` + :exception: :exc:`NullPointerError` if search_threads failed + """ + self._assert_query_is_initialized() + threads_p = Query._search_threads(self._query) + + if not threads_p: + raise NullPointerError + return Threads(threads_p, self) + + def search_messages(self): + """Filter messages according to the query and return + :class:`Messages` in the defined sort order + + :returns: :class:`Messages` + :exception: :exc:`NullPointerError` if search_messages failed + """ + self._assert_query_is_initialized() + msgs_p = Query._search_messages(self._query) + + if not msgs_p: + raise NullPointerError + return Messages(msgs_p, self) + + def count_messages(self): + """Estimate the number of messages matching the query + + This function performs a search and returns Xapian's best + guess as to the number of matching messages. It is much faster + than performing :meth:`search_messages` and counting the + result with `len()` (although it always returned the same + result in my tests). Technically, it wraps the underlying + *notmuch_query_count_messages* function. + + :returns: :class:`Messages` + """ + 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: + self._destroy(self._query) -- cgit v1.2.3 From 4315ac015a1ba329880031805f4706731b3c1ef4 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:13:06 +0100 Subject: python: refactor Query class Put each libnotmuch function reference right in front of the corresponding python wrapper. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/query.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index bab5c3e..d4a93d5 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -56,26 +56,6 @@ class Query(object): SORT = Enum(['OLDEST_FIRST', 'NEWEST_FIRST', 'MESSAGE_ID', 'UNSORTED']) """Constants: Sort order in which to return results""" - """notmuch_query_create""" - _create = nmlib.notmuch_query_create - _create.argtypes = [NotmuchDatabaseP, c_char_p] - _create.restype = NotmuchQueryP - - """notmuch_query_search_threads""" - _search_threads = nmlib.notmuch_query_search_threads - _search_threads.argtypes = [NotmuchQueryP] - _search_threads.restype = NotmuchThreadsP - - """notmuch_query_search_messages""" - _search_messages = nmlib.notmuch_query_search_messages - _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): """ :param db: An open database which we derive the Query from. @@ -93,6 +73,11 @@ class Query(object): if self._query is None: raise NotInitializedError() + """notmuch_query_create""" + _create = nmlib.notmuch_query_create + _create.argtypes = [NotmuchDatabaseP, c_char_p] + _create.restype = NotmuchQueryP + def create(self, db, querystr): """Creates a new query derived from a Database @@ -132,6 +117,11 @@ class Query(object): self.sort = sort self._set_sort(self._query, sort) + """notmuch_query_search_threads""" + _search_threads = nmlib.notmuch_query_search_threads + _search_threads.argtypes = [NotmuchQueryP] + _search_threads.restype = NotmuchThreadsP + def search_threads(self): """Execute a query for threads @@ -153,6 +143,11 @@ class Query(object): raise NullPointerError return Threads(threads_p, self) + """notmuch_query_search_messages""" + _search_messages = nmlib.notmuch_query_search_messages + _search_messages.argtypes = [NotmuchQueryP] + _search_messages.restype = NotmuchMessagesP + def search_messages(self): """Filter messages according to the query and return :class:`Messages` in the defined sort order @@ -167,6 +162,11 @@ class Query(object): raise NullPointerError return Messages(msgs_p, self) + """notmuch_query_count_messages""" + _count_messages = nmlib.notmuch_query_count_messages + _count_messages.argtypes = [NotmuchQueryP] + _count_messages.restype = c_uint + def count_messages(self): """Estimate the number of messages matching the query -- cgit v1.2.3 From ff8f864245c3ac54cc23aa47af09c95cde484abb Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:32:21 +0100 Subject: python: wrap notmuch_query_count_threads as Query.count_threads Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 2 ++ bindings/python/notmuch/query.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index f7d3d60..5405de8 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -128,6 +128,8 @@ More information on specific topics can be found on the following pages: .. automethod:: count_messages + .. automethod:: count_threads + :class:`Messages` -- A bunch of messages ---------------------------------------- diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index d4a93d5..14c00cd 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -182,6 +182,25 @@ class Query(object): self._assert_query_is_initialized() return Query._count_messages(self._query) + _count_threads = nmlib.notmuch_query_count_threads + _count_threads.argtypes = [NotmuchQueryP] + _count_threads.restype = c_uint + + def count_threads(self): + ''' + This function performs a search and returns the number of + unique thread IDs in the matching messages. This is the same + as number of threads matching a search. + + Note that this is a significantly heavier operation than + meth:`Query.count_messages`. + + :returns: the number of threads returned by this query + :rtype: int + ''' + self._assert_query_is_initialized() + return Query._count_threads(self._query) + _destroy = nmlib.notmuch_query_destroy _destroy.argtypes = [NotmuchQueryP] _destroy.restype = None -- cgit v1.2.3 From bf6039e34eca52ccf7fe1db51e1b5c843a9828f3 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:38:19 +0100 Subject: python: improve Query.count_messages docstring Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/query.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 14c00cd..0c08aa9 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -162,23 +162,18 @@ class Query(object): raise NullPointerError return Messages(msgs_p, self) - """notmuch_query_count_messages""" _count_messages = nmlib.notmuch_query_count_messages _count_messages.argtypes = [NotmuchQueryP] _count_messages.restype = c_uint def count_messages(self): - """Estimate the number of messages matching the query - + ''' This function performs a search and returns Xapian's best - guess as to the number of matching messages. It is much faster - than performing :meth:`search_messages` and counting the - result with `len()` (although it always returned the same - result in my tests). Technically, it wraps the underlying - *notmuch_query_count_messages* function. + guess as to the number of matching messages. - :returns: :class:`Messages` - """ + :returns: the estimated number of messages matching this query + :rtype: int + ''' self._assert_query_is_initialized() return Query._count_messages(self._query) -- cgit v1.2.3 From ab2f9fd828058d281480e9947ea346e382a7f3c8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sat, 18 Feb 2012 01:41:23 +0100 Subject: python: remove trailing whitespace within the documentation source files Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 14 +++++++------- bindings/python/docs/source/notmuch.rst | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index 5405de8..25eb146 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -13,7 +13,7 @@ Within :mod:`notmuch`, the classes :class:`Database`, :class:`Query` provide mos :License: This module is covered under the GNU GPL v3 (or later). -This page contains the main API overview of notmuch |release|. +This page contains the main API overview of notmuch |release|. Notmuch can be imported as:: @@ -35,7 +35,7 @@ More information on specific topics can be found on the following pages: :maxdepth: 1 status_and_errors - notmuch + notmuch :mod:`notmuch` -- The Notmuch interface ================================================= @@ -111,8 +111,8 @@ More information on specific topics can be found on the following pages: Sort by email message ID. SORT.UNSORTED - Do not apply a special sort order (returns results in document id - order). + Do not apply a special sort order (returns results in document id + order). .. automethod:: set_sort @@ -141,7 +141,7 @@ More information on specific topics can be found on the following pages: .. method:: __len__() .. warning:: - + :meth:`__len__` was removed in version 0.6 as it exhausted the iterator and broke list(Messages()). Use the :meth:`Query.count_messages` function or use `len(list(msgs))`. @@ -162,7 +162,7 @@ More information on specific topics can be found on the following pages: .. attribute:: FLAG - FLAG.MATCH + FLAG.MATCH This flag is automatically set by a Query.search_threads on those messages that match the query. This allows us to distinguish matches from the rest @@ -171,7 +171,7 @@ More information on specific topics can be found on the following pages: .. automethod:: get_flag .. automethod:: set_flag - + .. automethod:: get_date .. automethod:: get_header diff --git a/bindings/python/docs/source/notmuch.rst b/bindings/python/docs/source/notmuch.rst index 32e1783..bf68f33 100644 --- a/bindings/python/docs/source/notmuch.rst +++ b/bindings/python/docs/source/notmuch.rst @@ -29,7 +29,7 @@ Where and [args...] are as follows: **show** [...] Show all messages matching the search terms. - This has been partially implemented, we show a stub for each + This has been partially implemented, we show a stub for each found message, but do not output the full message body yet. **count** [...] -- cgit v1.2.3 From be851ad39de11f38e1cd4f7f15f1fa952232efe2 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 19 Feb 2012 00:36:15 +0100 Subject: python: more error handling fixes This is a follow up commit to 221c7e0b38177f5f1dbf0561580c15e8aaa49004 fixing more NULL pointer checks. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 2 +- bindings/python/notmuch/filename.py | 2 +- bindings/python/notmuch/message.py | 40 ++++++++++++++++++------------------- bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 26 ++++++++++++------------ 6 files changed, 37 insertions(+), 37 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 0958ce0..6edb18b 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -159,7 +159,7 @@ class Database(object): def _assert_db_is_initialized(self): """Raises :exc:`NotInitializedError` if self._db is `None`""" - if self._db is None: + if not self._db: raise NotInitializedError() def create(self, path): diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index 469b6a5..322e6bf 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -89,7 +89,7 @@ class Filenames(Python3StringMixIn): This is the main function that will usually be used by the user.""" - if self._files is None: + if not self._files: raise NotmuchError(STATUS.NOT_INITIALIZED) while self._valid(self._files): diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 883ed23..28723c1 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -135,7 +135,7 @@ class Messages(object): :meth:`collect_tags` will iterate over the messages and therefore will not allow further iterations. """ - if self._msgs is None: + if not self._msgs: raise NotmuchError(STATUS.NOT_INITIALIZED) # collect all tags (returns NULL on error) @@ -160,7 +160,7 @@ class Messages(object): _move_to_next.restype = None def __next__(self): - if self._msgs is None: + if not self._msgs: raise NotmuchError(STATUS.NOT_INITIALIZED) if not self._valid(self._msgs): @@ -362,7 +362,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._get_message_id(self._msg).decode('utf-8', 'ignore') @@ -379,7 +379,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._get_thread_id(self._msg).decode('utf-8', 'ignore') @@ -402,7 +402,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) msgs_p = Message._get_replies(self._msg) @@ -424,7 +424,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._get_date(self._msg) @@ -447,7 +447,7 @@ class Message(Python3StringMixIn): is not initialized. * STATUS.NULL_POINTER if any error occured. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) #Returns NULL if any error occurs. @@ -463,7 +463,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._get_filename(self._msg).decode('utf-8', 'ignore') @@ -473,7 +473,7 @@ class Message(Python3StringMixIn): Returns a Filenames() generator with all absolute filepaths for messages recorded to have the same Message-ID. These files must not necessarily have identical content.""" - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) files_p = Message._get_filenames(self._msg) @@ -493,7 +493,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._get_flag(self._msg, flag) @@ -508,7 +508,7 @@ class Message(Python3StringMixIn): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) self._set_flag(self._msg, flag, value) @@ -522,7 +522,7 @@ class Message(Python3StringMixIn): is not initialized. * STATUS.NULL_POINTER, on error """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) tags_p = Message._get_tags(self._msg) @@ -565,7 +565,7 @@ class Message(Python3StringMixIn): STATUS.NOT_INITIALIZED The message has not been initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) status = self._add_tag(self._msg, _str(tag)) @@ -613,7 +613,7 @@ class Message(Python3StringMixIn): STATUS.NOT_INITIALIZED The message has not been initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) status = self._remove_tag(self._msg, _str(tag)) @@ -654,7 +654,7 @@ class Message(Python3StringMixIn): STATUS.NOT_INITIALIZED The message has not been initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) status = self._remove_all_tags(self._msg) @@ -712,7 +712,7 @@ class Message(Python3StringMixIn): STATUS.NOT_INITIALIZED The message has not been initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) status = self._freeze(self._msg) @@ -751,7 +751,7 @@ class Message(Python3StringMixIn): STATUS.NOT_INITIALIZED The message has not been initialized. """ - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) status = self._thaw(self._msg) @@ -787,7 +787,7 @@ class Message(Python3StringMixIn): :returns: a :class:`STATUS` value. In short, you want to see notmuch.STATUS.SUCCESS here. See there for details.""" - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._tags_to_maildir_flags(self._msg) @@ -814,7 +814,7 @@ class Message(Python3StringMixIn): :returns: a :class:`STATUS`. In short, you want to see notmuch.STATUS.SUCCESS here. See there for details.""" - if self._msg is None: + if not self._msg: raise NotmuchError(STATUS.NOT_INITIALIZED) return Message._tags_to_maildir_flags(self._msg) @@ -957,7 +957,7 @@ class Message(Python3StringMixIn): def __hash__(self): """Implement hash(), so we can use Message() sets""" file = self.get_filename() - if file is None: + if not file: return None return hash(file) diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 0c08aa9..6132ca0 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -70,7 +70,7 @@ class Query(object): def _assert_query_is_initialized(self): """Raises :exc:`NotInitializedError` if self._query is `None`""" - if self._query is None: + if not self._query: raise NotInitializedError() """notmuch_query_create""" diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index d2dc498..d0f7bb4 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -90,7 +90,7 @@ class Tags(Python3StringMixIn): _move_to_next.restype = None def __next__(self): - if self._tags is None: + if not self._tags: raise NotmuchError(STATUS.NOT_INITIALIZED) if not self._valid(self._tags): self._tags = None diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 104710c..c2347fe 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -117,7 +117,7 @@ class Threads(Python3StringMixIn): _move_to_next.restype = None def __next__(self): - if self._threads is None: + if not self._threads: raise NotmuchError(STATUS.NOT_INITIALIZED) if not self._valid(self._threads): @@ -141,7 +141,7 @@ class Threads(Python3StringMixIn): # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!! for thread in threads: print thread """ - if self._threads is None: + if not self._threads: raise NotmuchError(STATUS.NOT_INITIALIZED) i = 0 @@ -244,7 +244,7 @@ class Thread(object): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread is not initialized. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) return Thread._get_thread_id(self._thread).decode('utf-8', 'ignore') @@ -261,7 +261,7 @@ class Thread(object): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread is not initialized. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) return self._get_total_messages(self._thread) @@ -284,7 +284,7 @@ class Thread(object): * STATUS.NOT_INITIALIZED if query is not inited * STATUS.NULL_POINTER if search_messages failed """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) msgs_p = Thread._get_toplevel_messages(self._thread) @@ -307,7 +307,7 @@ class Thread(object): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread is not initialized. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) return self._get_matched_messages(self._thread) @@ -321,10 +321,10 @@ class Thread(object): The returned string belongs to 'thread' and will only be valid for as long as this Thread() is not deleted. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) authors = Thread._get_authors(self._thread) - if authors is None: + if not authors: return None return authors.decode('UTF-8', 'ignore') @@ -334,10 +334,10 @@ class Thread(object): The returned string belongs to 'thread' and will only be valid for as long as this Thread() is not deleted. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) subject = Thread._get_subject(self._thread) - if subject is None: + if not subject: return None return subject.decode('UTF-8', 'ignore') @@ -349,7 +349,7 @@ class Thread(object): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) return Thread._get_newest_date(self._thread) @@ -361,7 +361,7 @@ class Thread(object): :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message is not initialized. """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) return Thread._get_oldest_date(self._thread) @@ -384,7 +384,7 @@ class Thread(object): is not initialized. * STATUS.NULL_POINTER, on error """ - if self._thread is None: + if not self._thread: raise NotmuchError(STATUS.NOT_INITIALIZED) tags_p = Thread._get_tags(self._thread) -- cgit v1.2.3 From 4bb9f59ff6da456392ffaf9871941203e4cf9b53 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 20 Feb 2012 21:48:35 +0100 Subject: python: fix the projects name and update years of the copyright notice in the sphinx docs Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/conf.py b/bindings/python/docs/source/conf.py index 76610b7..9db377f 100644 --- a/bindings/python/docs/source/conf.py +++ b/bindings/python/docs/source/conf.py @@ -57,8 +57,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'cnotmuch' -copyright = u'2010, ' + __AUTHOR__ +project = u'notmuch' +copyright = u'2010-2012, ' + __AUTHOR__ # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the -- cgit v1.2.3 From a1442952d4d7fad8b7612502802ee346ac8fd349 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 20 Feb 2012 23:49:07 +0100 Subject: python: refactor the error handling machinery Raise specific error classes instead of a generic NotmuchError with an magic status value (e.g. NotmuchError(STATUS.NULL_POINTER) -> NullPointerError()), update the documentation accordingly. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 15 +-- bindings/python/notmuch/filename.py | 26 ++++-- bindings/python/notmuch/message.py | 181 +++++++++++++++++------------------- bindings/python/notmuch/tag.py | 26 ++++-- bindings/python/notmuch/thread.py | 78 ++++++++-------- 5 files changed, 165 insertions(+), 161 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 6edb18b..3de0f2b 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -23,7 +23,9 @@ from ctypes import c_char_p, c_void_p, c_uint, c_long, byref, POINTER from notmuch.globals import ( nmlib, STATUS, + FileError, NotmuchError, + NullPointerError, NotInitializedError, Enum, _str, @@ -355,9 +357,8 @@ class Database(object): # we got an absolute path if not path.startswith(self.get_path()): # but its initial components are not equal to the db path - raise NotmuchError(STATUS.FILE_ERROR, - message="Database().get_directory() called " - "with a wrong absolute path.") + raise FileError('Database().get_directory() called ' + 'with a wrong absolute path') abs_dirpath = path else: #we got a relative path, make it absolute @@ -542,7 +543,7 @@ class Database(object): self._assert_db_is_initialized() tags_p = Database._get_all_tags(self._db) if tags_p == None: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return Tags(tags_p, self) def create_query(self, querystring): @@ -636,7 +637,7 @@ class Directory(object): """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None""" if not self._dir_p: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() def __init__(self, path, dir_p, parent): """ @@ -797,7 +798,7 @@ class Filenames(object): def __next__(self): if not self._files_p: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() if not self._valid(self._files_p): self._files_p = None @@ -824,7 +825,7 @@ class Filenames(object): for file in files: print file """ if not self._files_p: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() i = 0 while self._valid(self._files_p): diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index 322e6bf..353eb76 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -17,8 +17,14 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth ' """ from ctypes import c_char_p -from notmuch.globals import (nmlib, STATUS, NotmuchError, - NotmuchFilenamesP, NotmuchMessageP, Python3StringMixIn) +from notmuch.globals import ( + nmlib, + NullPointerError, + NotInitializedError, + NotmuchMessageP, + NotmuchFilenamesP, + Python3StringMixIn, +) class Filenames(Python3StringMixIn): @@ -29,9 +35,9 @@ class Filenames(Python3StringMixIn): iterator over a list of notmuch filenames. Do note that the underlying library only provides a one-time iterator (it cannot reset the iterator to the start). Thus iterating over the function will "exhaust" the list of - tags, and a subsequent iteration attempt will raise a :exc:`NotmuchError` - STATUS.NOT_INITIALIZED. Also note, that any function that uses iteration - (nearly all) will also exhaust the tags. So both:: + tags, and a subsequent iteration attempt will raise a + :exc:`NotInitializedError`. Also note, that any function that uses + iteration (nearly all) will also exhaust the tags. So both:: for name in filenames: print name @@ -61,8 +67,8 @@ class Filenames(Python3StringMixIn): will almost never instantiate a :class:`Tags` object herself. They are usually handed back as a result, e.g. in :meth:`Database.get_all_tags`. *tags_p* must be - valid, we will raise an :exc:`NotmuchError` - (STATUS.NULL_POINTER) if it is `None`. + valid, we will raise an :exc:`NullPointerError` + if it is `None`. :type files_p: :class:`ctypes.c_void_p` :param parent: The parent object (ie :class:`Message` these filenames are derived from, and saves a @@ -70,7 +76,7 @@ class Filenames(Python3StringMixIn): once all derived objects are dead. """ if not files_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._files = files_p #save reference to parent object so we keep it alive @@ -90,7 +96,7 @@ class Filenames(Python3StringMixIn): This is the main function that will usually be used by the user.""" if not self._files: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() while self._valid(self._files): yield Filenames._get(self._files).decode('utf-8', 'ignore') @@ -104,7 +110,7 @@ class Filenames(Python3StringMixIn): .. note:: As this iterates over the filenames, we will not be able to iterate over them again (as in retrieve them)! If the tags have been exhausted already, this will raise a - :exc:`NotmuchError` STATUS.NOT_INITIALIZED on subsequent + :exc:`NotInitializedError` on subsequent attempts. However, you can use :meth:`Message.get_filenames` repeatedly to perform various actions on filenames. diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 28723c1..b291f9f 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -22,8 +22,19 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p, c_long, c_uint, c_int from datetime import date from notmuch.globals import ( - nmlib, STATUS, NotmuchError, Enum, _str, Python3StringMixIn, - NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP) + nmlib, + Enum, + _str, + Python3StringMixIn, + STATUS, + NotmuchError, + NullPointerError, + NotInitializedError, + NotmuchTagsP, + NotmuchMessageP, + NotmuchMessagesP, + NotmuchFilenamesP, +) from notmuch.tag import Tags from notmuch.filename import Filenames import sys @@ -43,7 +54,7 @@ class Messages(object): only provides a one-time iterator (it cannot reset the iterator to the start). Thus iterating over the function will "exhaust" the list of messages, and a subsequent iteration attempt will raise a - :exc:`NotmuchError` STATUS.NOT_INITIALIZED. If you need to + :exc:`NotInitializedError`. If you need to re-iterate over a list of messages you will need to retrieve a new :class:`Messages` object or cache your :class:`Message`\s in a list via:: @@ -107,8 +118,8 @@ class Messages(object): will almost never instantiate a :class:`Messages` object herself. They are usually handed back as a result, e.g. in :meth:`Query.search_messages`. *msgs_p* must be - valid, we will raise an :exc:`NotmuchError` - (STATUS.NULL_POINTER) if it is `None`. + valid, we will raise an :exc:`NullPointerError` if it is + `None`. :type msgs_p: :class:`ctypes.c_void_p` :param parent: The parent object (ie :class:`Query`) these tags are derived from. It saves @@ -118,7 +129,7 @@ class Messages(object): the Python object.(?) """ if not msgs_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._msgs = msgs_p #store parent, so we keep them alive as long as self is alive @@ -128,7 +139,7 @@ class Messages(object): """Return the unique :class:`Tags` in the contained messages :returns: :class:`Tags` - :exceptions: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if not init'ed + :exceptions: :exc:`NotInitializedError` if not init'ed .. note:: @@ -136,7 +147,7 @@ class Messages(object): will not allow further iterations. """ if not self._msgs: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() # collect all tags (returns NULL on error) tags_p = Messages._collect_tags(self._msgs) @@ -144,7 +155,7 @@ class Messages(object): self._msgs = None if tags_p == None: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return Tags(tags_p, self) def __iter__(self): @@ -161,7 +172,7 @@ class Messages(object): def __next__(self): if not self._msgs: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() if not self._valid(self._msgs): self._msgs = None @@ -341,8 +352,8 @@ class Message(Python3StringMixIn): def __init__(self, msg_p, parent=None): """ :param msg_p: A pointer to an internal notmuch_message_t - Structure. If it is `None`, we will raise an :exc:`NotmuchError` - STATUS.NULL_POINTER. + Structure. If it is `None`, we will raise an + :exc:`NullPointerError`. :param parent: A 'parent' object is passed which this message is derived from. We save a reference to it, so we can @@ -350,7 +361,7 @@ class Message(Python3StringMixIn): objects are dead. """ if not msg_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._msg = msg_p #keep reference to parent, so we keep it alive self._parent = parent @@ -359,11 +370,11 @@ class Message(Python3StringMixIn): """Returns the message ID :returns: String with a message ID - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._get_message_id(self._msg).decode('utf-8', 'ignore') def get_thread_id(self): @@ -376,11 +387,11 @@ class Message(Python3StringMixIn): message belongs to a single thread. :returns: String with a thread ID - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._get_thread_id(self._msg).decode('utf-8', 'ignore') @@ -399,11 +410,11 @@ class Message(Python3StringMixIn): an empty Messages iterator. :returns: :class:`Messages`. - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() msgs_p = Message._get_replies(self._msg) @@ -421,11 +432,11 @@ class Message(Python3StringMixIn): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._get_date(self._msg) def get_header(self, header): @@ -441,30 +452,28 @@ class Message(Python3StringMixIn): It is not case-sensitive. :type header: str :returns: The header value as string - :exception: :exc:`NotmuchError` - - * STATUS.NOT_INITIALIZED if the message - is not initialized. - * STATUS.NULL_POINTER if any error occured. + :raises: :exc:`NotInitializedError` if the message is not + initialized + :raises: :exc:`NullPointerError` if any error occured """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() #Returns NULL if any error occurs. header = Message._get_header(self._msg, _str(header)) if header == None: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return header.decode('UTF-8', 'ignore') def get_filename(self): """Returns the file path of the message file :returns: Absolute file path & name of the message file - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._get_filename(self._msg).decode('utf-8', 'ignore') def get_filenames(self): @@ -474,7 +483,7 @@ class Message(Python3StringMixIn): messages recorded to have the same Message-ID. These files must not necessarily have identical content.""" if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() files_p = Message._get_filenames(self._msg) @@ -490,11 +499,11 @@ class Message(Python3StringMixIn): :param flag: One of the :attr:`Message.FLAG` values (currently only *Message.FLAG.MATCH* :returns: An unsigned int (0/1), indicating whether the flag is set. - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._get_flag(self._msg, flag) def set_flag(self, flag, value): @@ -505,29 +514,27 @@ class Message(Python3StringMixIn): :param value: A bool indicating whether to set or unset the flag. :returns: Nothing - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() self._set_flag(self._msg, flag, value) def get_tags(self): """Returns the message tags :returns: A :class:`Tags` iterator. - :exception: :exc:`NotmuchError` - - * STATUS.NOT_INITIALIZED if the message - is not initialized. - * STATUS.NULL_POINTER, on error + :raises: :exc:`NotInitializedError` if the message is not + initialized + :raises: :exc:`NullPointerError` if any error occured """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() tags_p = Message._get_tags(self._msg) if tags_p == None: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return Tags(tags_p, self) _add_tag = nmlib.notmuch_message_add_tag @@ -552,21 +559,16 @@ class Message(Python3StringMixIn): :returns: STATUS.SUCCESS if the tag was successfully added. Raises an exception otherwise. - :exception: :exc:`NotmuchError`. They have the following meaning: - - STATUS.NULL_POINTER - The 'tag' argument is NULL - STATUS.TAG_TOO_LONG - The length of 'tag' is too long - (exceeds Message.NOTMUCH_TAG_MAX) - STATUS.READ_ONLY_DATABASE - Database was opened in read-only mode so message cannot be - modified. - STATUS.NOT_INITIALIZED - The message has not been initialized. - """ + :raises: :exc:`NullPointerError` if the `tag` argument is NULL + :raises: :exc:`TagTooLongError` if the length of `tag` exceeds + Message.NOTMUCH_TAG_MAX) + :raises: :exc:`ReadOnlyDatabaseError` if the database was opened + in read-only mode so message cannot be modified + :raises: :exc:`NotInitializedError` if message has not been + initialized + """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() status = self._add_tag(self._msg, _str(tag)) @@ -600,21 +602,16 @@ class Message(Python3StringMixIn): :returns: STATUS.SUCCESS if the tag was successfully removed or if the message had no such tag. Raises an exception otherwise. - :exception: :exc:`NotmuchError`. They have the following meaning: - - STATUS.NULL_POINTER - The 'tag' argument is NULL - STATUS.TAG_TOO_LONG - The length of 'tag' is too long - (exceeds NOTMUCH_TAG_MAX) - STATUS.READ_ONLY_DATABASE - Database was opened in read-only mode so message cannot - be modified. - STATUS.NOT_INITIALIZED - The message has not been initialized. + :raises: :exc:`NullPointerError` if the `tag` argument is NULL + :raises: :exc:`TagTooLongError` if the length of `tag` exceeds + Message.NOTMUCH_TAG_MAX) + :raises: :exc:`ReadOnlyDatabaseError` if the database was opened + in read-only mode so message cannot be modified + :raises: :exc:`NotInitializedError` if message has not been + initialized """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() status = self._remove_tag(self._msg, _str(tag)) # bail out on error @@ -646,16 +643,13 @@ class Message(Python3StringMixIn): :returns: STATUS.SUCCESS if the tags were successfully removed. Raises an exception otherwise. - :exception: :exc:`NotmuchError`. They have the following meaning: - - STATUS.READ_ONLY_DATABASE - Database was opened in read-only mode so message cannot - be modified. - STATUS.NOT_INITIALIZED - The message has not been initialized. + :raises: :exc:`ReadOnlyDatabaseError` if the database was opened + in read-only mode so message cannot be modified + :raises: :exc:`NotInitializedError` if message has not been + initialized """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() status = self._remove_all_tags(self._msg) @@ -704,16 +698,13 @@ class Message(Python3StringMixIn): :returns: STATUS.SUCCESS if the message was successfully frozen. Raises an exception otherwise. - :exception: :exc:`NotmuchError`. They have the following meaning: - - STATUS.READ_ONLY_DATABASE - Database was opened in read-only mode so message cannot - be modified. - STATUS.NOT_INITIALIZED - The message has not been initialized. + :raises: :exc:`ReadOnlyDatabaseError` if the database was opened + in read-only mode so message cannot be modified + :raises: :exc:`NotInitializedError` if message has not been + initialized """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() status = self._freeze(self._msg) @@ -742,17 +733,15 @@ class Message(Python3StringMixIn): :returns: STATUS.SUCCESS if the message was successfully frozen. Raises an exception otherwise. - :exception: :exc:`NotmuchError`. They have the following meaning: - - STATUS.UNBALANCED_FREEZE_THAW - An attempt was made to thaw an unfrozen message. - That is, there have been an unbalanced number of calls - to :meth:`freeze` and :meth:`thaw`. - STATUS.NOT_INITIALIZED - The message has not been initialized. + :raises: :exc:`UnbalancedFreezeThawError` if an attempt was made + to thaw an unfrozen message. That is, there have been + an unbalanced number of calls to :meth:`freeze` and + :meth:`thaw`. + :raises: :exc:`NotInitializedError` if message has not been + initialized """ if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() status = self._thaw(self._msg) @@ -788,7 +777,7 @@ class Message(Python3StringMixIn): :returns: a :class:`STATUS` value. In short, you want to see notmuch.STATUS.SUCCESS here. See there for details.""" if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._tags_to_maildir_flags(self._msg) def maildir_flags_to_tags(self): @@ -815,7 +804,7 @@ class Message(Python3StringMixIn): :returns: a :class:`STATUS`. In short, you want to see notmuch.STATUS.SUCCESS here. See there for details.""" if not self._msg: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Message._tags_to_maildir_flags(self._msg) def __repr__(self): diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index d0f7bb4..526e51c 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -17,7 +17,13 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth ' """ from ctypes import c_char_p -from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP, Python3StringMixIn +from notmuch.globals import ( + nmlib, + Python3StringMixIn, + NullPointerError, + NotInitializedError, + NotmuchTagsP, +) class Tags(Python3StringMixIn): @@ -29,9 +35,9 @@ class Tags(Python3StringMixIn): Do note that the underlying library only provides a one-time iterator (it cannot reset the iterator to the start). Thus iterating over the function will "exhaust" the list of tags, and a subsequent - iteration attempt will raise a :exc:`NotmuchError` - STATUS.NOT_INITIALIZED. Also note, that any function that uses - iteration (nearly all) will also exhaust the tags. So both:: + iteration attempt will raise a :exc:`NotInitializedError`. + Also note, that any function that uses iteration (nearly all) will + also exhaust the tags. So both:: for tag in tags: print tag @@ -60,8 +66,8 @@ class Tags(Python3StringMixIn): will almost never instantiate a :class:`Tags` object herself. They are usually handed back as a result, e.g. in :meth:`Database.get_all_tags`. *tags_p* must be - valid, we will raise an :exc:`NotmuchError` - (STATUS.NULL_POINTER) if it is `None`. + valid, we will raise an :exc:`NullPointerError` if it is + `None`. :type tags_p: :class:`ctypes.c_void_p` :param parent: The parent object (ie :class:`Database` or :class:`Message` these tags are derived from, and saves a @@ -71,7 +77,7 @@ class Tags(Python3StringMixIn): cache the tags in the Python object(?) """ if not tags_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._tags = tags_p #save reference to parent object so we keep it alive @@ -91,7 +97,7 @@ class Tags(Python3StringMixIn): def __next__(self): if not self._tags: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() if not self._valid(self._tags): self._tags = None raise StopIteration @@ -118,8 +124,8 @@ class Tags(Python3StringMixIn): As this iterates over the tags, we will not be able to iterate over them again (as in retrieve them)! If the tags have been exhausted - already, this will raise a :exc:`NotmuchError` - STATUS.NOT_INITIALIZED on subsequent attempts. + already, this will raise a :exc:`NotInitializedError`on subsequent + attempts. """ return " ".join(self) diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index c2347fe..5c58028 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -18,9 +18,16 @@ Copyright 2010 Sebastian Spaeth ' """ from ctypes import c_char_p, c_long, c_int -from notmuch.globals import (nmlib, STATUS, - NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP, - NotmuchTagsP, Python3StringMixIn) +from notmuch.globals import ( + nmlib, + Python3StringMixIn, + NullPointerError, + NotInitializedError, + NotmuchThreadP, + NotmuchThreadsP, + NotmuchMessagesP, + NotmuchTagsP, +) from notmuch.message import Messages from notmuch.tag import Tags from datetime import date @@ -35,7 +42,7 @@ class Threads(Python3StringMixIn): library only provides a one-time iterator (it cannot reset the iterator to the start). Thus iterating over the function will "exhaust" the list of threads, and a subsequent iteration attempt - will raise a :exc:`NotmuchError` STATUS.NOT_INITIALIZED. Also + will raise a :exc:`NotInitializedError`. Also note, that any function that uses iteration will also exhaust the messages. So both:: @@ -87,8 +94,8 @@ class Threads(Python3StringMixIn): will almost never instantiate a :class:`Threads` object herself. They are usually handed back as a result, e.g. in :meth:`Query.search_threads`. *threads_p* must be - valid, we will raise an :exc:`NotmuchError` - (STATUS.NULL_POINTER) if it is `None`. + valid, we will raise an :exc:`NullPointerError` if it is + `None`. :type threads_p: :class:`ctypes.c_void_p` :param parent: The parent object (ie :class:`Query`) these tags are derived from. It saves @@ -98,7 +105,7 @@ class Threads(Python3StringMixIn): the Python object.(?) """ if not threads_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._threads = threads_p #store parent, so we keep them alive as long as self is alive @@ -118,7 +125,7 @@ class Threads(Python3StringMixIn): def __next__(self): if not self._threads: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() if not self._valid(self._threads): self._threads = None @@ -138,11 +145,11 @@ class Threads(Python3StringMixIn): #THIS FAILS threads = Database().create_query('').search_threads() if len(threads) > 0: #this 'exhausts' threads - # next line raises NotmuchError(STATUS.NOT_INITIALIZED)!!! + # next line raises :exc:`NotInitializedError`!!! for thread in threads: print thread """ if not self._threads: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() i = 0 # returns 'bool'. On out-of-memory it returns None @@ -220,8 +227,8 @@ class Thread(object): will almost never instantiate a :class:`Thread` object herself. They are usually handed back as a result, e.g. when iterating through :class:`Threads`. *thread_p* - must be valid, we will raise an :exc:`NotmuchError` - (STATUS.NULL_POINTER) if it is `None`. + must be valid, we will raise an :exc:`NullPointerError` + if it is `None`. :param parent: A 'parent' object is passed which this message is derived from. We save a reference to it, so we can @@ -229,7 +236,7 @@ class Thread(object): objects are dead. """ if not thread_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() self._thread = thread_p #keep reference to parent, so we keep it alive self._parent = parent @@ -241,11 +248,11 @@ class Thread(object): for as long as the thread is valid. :returns: String with a message ID - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread + :exception: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Thread._get_thread_id(self._thread).decode('utf-8', 'ignore') _get_total_messages = nmlib.notmuch_thread_get_total_messages @@ -258,11 +265,11 @@ class Thread(object): :returns: The number of all messages in the database belonging to this thread. Contrast with :meth:`get_matched_messages`. - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread + :exception: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return self._get_total_messages(self._thread) def get_toplevel_messages(self): @@ -279,18 +286,16 @@ class Thread(object): messages, etc.). :returns: :class:`Messages` - :exception: :exc:`NotmuchError` - - * STATUS.NOT_INITIALIZED if query is not inited - * STATUS.NULL_POINTER if search_messages failed + :raises: :exc:`NotInitializedError` if query is not initialized + :raises: :exc:`NullPointerError` if search_messages failed """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() msgs_p = Thread._get_toplevel_messages(self._thread) if not msgs_p: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return Messages(msgs_p, self) @@ -304,11 +309,11 @@ class Thread(object): :returns: The number of all messages belonging to this thread that matched the :class:`Query`from which this thread was created. Contrast with :meth:`get_total_messages`. - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the thread + :exception: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return self._get_matched_messages(self._thread) def get_authors(self): @@ -322,7 +327,7 @@ class Thread(object): as long as this Thread() is not deleted. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() authors = Thread._get_authors(self._thread) if not authors: return None @@ -335,7 +340,7 @@ class Thread(object): as long as this Thread() is not deleted. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() subject = Thread._get_subject(self._thread) if not subject: return None @@ -346,11 +351,11 @@ class Thread(object): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Thread._get_newest_date(self._thread) def get_oldest_date(self): @@ -358,11 +363,11 @@ class Thread(object): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotmuchError` STATUS.NOT_INITIALIZED if the message + :exception: :exc:`NotInitializedError` if the message is not initialized. """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() return Thread._get_oldest_date(self._thread) def get_tags(self): @@ -378,18 +383,15 @@ class Thread(object): query from which it derived is explicitely deleted). :returns: A :class:`Tags` iterator. - :exception: :exc:`NotmuchError` - - * STATUS.NOT_INITIALIZED if the thread - is not initialized. - * STATUS.NULL_POINTER, on error + :raises: :exc:`NotInitializedError` if query is not initialized + :raises: :exc:`NullPointerError` if search_messages failed """ if not self._thread: - raise NotmuchError(STATUS.NOT_INITIALIZED) + raise NotInitializedError() tags_p = Thread._get_tags(self._thread) if tags_p == None: - raise NotmuchError(STATUS.NULL_POINTER) + raise NullPointerError() return Tags(tags_p, self) def __unicode__(self): -- cgit v1.2.3 From 798b74e859734d12c953390bca0753f8e5e1d67c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 21 Feb 2012 00:01:23 +0100 Subject: python: harmonize the sphinx keyword for exceptions Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 24 ++++++++++++------------ bindings/python/notmuch/message.py | 14 +++++++------- bindings/python/notmuch/query.py | 6 +++--- bindings/python/notmuch/thread.py | 10 +++++----- 4 files changed, 27 insertions(+), 27 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 3de0f2b..42a4442 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -140,7 +140,7 @@ class Database(object): :param mode: Mode to open a database in. Is always :attr:`MODE`.READ_WRITE when creating a new one. :type mode: :attr:`MODE` - :exception: :exc:`NotmuchError` or derived exception in case of + :raises: :exc:`NotmuchError` or derived exception in case of failure. """ self._db = None @@ -177,7 +177,7 @@ class Database(object): :param path: A directory in which we should create the database. :type path: str :returns: Nothing - :exception: :exc:`NotmuchError` in case of any failure + :raises: :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ if self._db is not None: @@ -201,7 +201,7 @@ class Database(object): :param status: Open the database in read-only or read-write mode :type status: :attr:`MODE` :returns: Nothing - :exception: Raises :exc:`NotmuchError` in case of any failure + :raises: Raises :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ res = Database._open(_str(path), mode) @@ -296,7 +296,7 @@ class Database(object): neither begin nor end necessarily flush modifications to disk. :returns: :attr:`STATUS`.SUCCESS or raises - :exception: :exc:`NotmuchError`: :attr:`STATUS`.XAPIAN_EXCEPTION + :raises: :exc:`NotmuchError`: :attr:`STATUS`.XAPIAN_EXCEPTION Xapian exception occurred; atomic section not entered. *Added in notmuch 0.9*""" @@ -317,7 +317,7 @@ class Database(object): :returns: :attr:`STATUS`.SUCCESS or raises - :exception: + :raises: :exc:`NotmuchError`: :attr:`STATUS`.XAPIAN_EXCEPTION A Xapian exception occurred; atomic section not @@ -346,7 +346,7 @@ class Database(object): of database (see :meth:`get_path`), or else should be an absolute path with initial components that match the path of 'database'. :returns: :class:`Directory` or raises an exception. - :exception: + :raises: :exc:`NotmuchError` with :attr:`STATUS`.FILE_ERROR If path is not relative database or absolute with initial components same as database. @@ -410,7 +410,7 @@ class Database(object): :rtype: 2-tuple(:class:`Message`, :attr:`STATUS`) - :exception: Raises a :exc:`NotmuchError` with the following meaning. + :raises: Raises a :exc:`NotmuchError` with the following meaning. If such an exception occurs, nothing was added to the database. :attr:`STATUS`.FILE_ERROR @@ -460,7 +460,7 @@ class Database(object): This filename was removed but the message persists in the database with at least one other filename. - :exception: Raises a :exc:`NotmuchError` with the following meaning. + :raises: Raises a :exc:`NotmuchError` with the following meaning. If such an exception occurs, nothing was removed from the database. @@ -479,7 +479,7 @@ class Database(object): :param msgid: The message ID :type msgid: unicode or str :returns: :class:`Message` or `None` if no message is found. - :exception: + :raises: :exc:`OutOfMemoryError` If an Out-of-memory occured while constructing the message. :exc:`XapianError` @@ -512,7 +512,7 @@ class Database(object): function returns None if no message is found with the given filename. - :exception: + :raises: :exc:`OutOfMemoryError` If an Out-of-memory occured while constructing the message. :exc:`XapianError` @@ -681,7 +681,7 @@ class Directory(object): :param mtime: A (time_t) timestamp :returns: Nothing on success, raising an exception on failure. - :exception: :exc:`NotmuchError`: + :raises: :exc:`NotmuchError`: :attr:`STATUS`.XAPIAN_EXCEPTION A Xapian exception occurred, mtime not stored. @@ -708,7 +708,7 @@ class Directory(object): :param mtime: A (time_t) timestamp :returns: Nothing on success, raising an exception on failure. - :exception: :exc:`NotmuchError`: + :raises: :exc:`NotmuchError`: :attr:`STATUS`.NOT_INITIALIZED The directory has not been initialized diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index b291f9f..ce7cb88 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -370,7 +370,7 @@ class Message(Python3StringMixIn): """Returns the message ID :returns: String with a message ID - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -387,7 +387,7 @@ class Message(Python3StringMixIn): message belongs to a single thread. :returns: String with a thread ID - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -410,7 +410,7 @@ class Message(Python3StringMixIn): an empty Messages iterator. :returns: :class:`Messages`. - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -432,7 +432,7 @@ class Message(Python3StringMixIn): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -469,7 +469,7 @@ class Message(Python3StringMixIn): """Returns the file path of the message file :returns: Absolute file path & name of the message file - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -499,7 +499,7 @@ class Message(Python3StringMixIn): :param flag: One of the :attr:`Message.FLAG` values (currently only *Message.FLAG.MATCH* :returns: An unsigned int (0/1), indicating whether the flag is set. - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: @@ -514,7 +514,7 @@ class Message(Python3StringMixIn): :param value: A bool indicating whether to set or unset the flag. :returns: Nothing - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._msg: diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 6132ca0..25b9e78 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -89,7 +89,7 @@ class Query(object): :param querystr: The query string :type querystr: utf-8 encoded str or unicode :returns: Nothing - :exception: + :raises: :exc:`NullPointerError` if the query creation failed (e.g. too little memory). :exc:`NotInitializedError` if the underlying db was not @@ -134,7 +134,7 @@ class Query(object): to get the value of this flag. :returns: :class:`Threads` - :exception: :exc:`NullPointerError` if search_threads failed + :raises: :exc:`NullPointerError` if search_threads failed """ self._assert_query_is_initialized() threads_p = Query._search_threads(self._query) @@ -153,7 +153,7 @@ class Query(object): :class:`Messages` in the defined sort order :returns: :class:`Messages` - :exception: :exc:`NullPointerError` if search_messages failed + :raises: :exc:`NullPointerError` if search_messages failed """ self._assert_query_is_initialized() msgs_p = Query._search_messages(self._query) diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 5c58028..d1ba3e5 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -248,7 +248,7 @@ class Thread(object): for as long as the thread is valid. :returns: String with a message ID - :exception: :exc:`NotInitializedError` if the thread + :raises: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: @@ -265,7 +265,7 @@ class Thread(object): :returns: The number of all messages in the database belonging to this thread. Contrast with :meth:`get_matched_messages`. - :exception: :exc:`NotInitializedError` if the thread + :raises: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: @@ -309,7 +309,7 @@ class Thread(object): :returns: The number of all messages belonging to this thread that matched the :class:`Query`from which this thread was created. Contrast with :meth:`get_total_messages`. - :exception: :exc:`NotInitializedError` if the thread + :raises: :exc:`NotInitializedError` if the thread is not initialized. """ if not self._thread: @@ -351,7 +351,7 @@ class Thread(object): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._thread: @@ -363,7 +363,7 @@ class Thread(object): :returns: A time_t timestamp. :rtype: c_unit64 - :exception: :exc:`NotInitializedError` if the message + :raises: :exc:`NotInitializedError` if the message is not initialized. """ if not self._thread: -- cgit v1.2.3 From 1737ff5290a8ce1f66b4a7aeb6a16146dbc3517c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 21 Feb 2012 00:13:20 +0100 Subject: python: rework Directory.set_mtime Fix the indentation within the docstring, remove useless remarks, do some trivial refactoring. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 42a4442..9f6b380 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -679,27 +679,19 @@ class Directory(object): don't store a timestamp of 0 unless you are comfortable with that. - :param mtime: A (time_t) timestamp - :returns: Nothing on success, raising an exception on failure. - :raises: :exc:`NotmuchError`: - - :attr:`STATUS`.XAPIAN_EXCEPTION - A Xapian exception occurred, mtime not stored. - :attr:`STATUS`.READ_ONLY_DATABASE - Database was opened in read-only mode so directory - mtime cannot be modified. - :attr:`STATUS`.NOT_INITIALIZED - The directory has not been initialized + :param mtime: A (time_t) timestamp + :raises: :exc:`XapianError` a Xapian exception occurred, mtime + not stored + :raises: :exc:`ReadOnlyDatabaseError` the database was opened + in read-only mode so directory mtime cannot be modified + :raises: :exc:`NotInitializedError` the directory object has not + been initialized """ self._assert_dir_is_initialized() - #TODO: make sure, we convert the mtime parameter to a 'c_long' status = Directory._set_mtime(self._dir_p, mtime) - #return on success - if status == STATUS.SUCCESS: - return - #fail with Exception otherwise - raise NotmuchError(status) + if status != STATUS.SUCCESS: + raise NotmuchError(status) def get_mtime(self): """Gets the mtime value of this directory in the database -- cgit v1.2.3 From 786f9882e8b408e6ad4c6b7abfef1ac54144be15 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 21 Feb 2012 00:15:59 +0100 Subject: python: remove :returns: keywords from functions returning nothing Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 3 --- bindings/python/notmuch/message.py | 1 - bindings/python/notmuch/query.py | 1 - 3 files changed, 5 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 9f6b380..d841367 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -176,7 +176,6 @@ class Database(object): :param path: A directory in which we should create the database. :type path: str - :returns: Nothing :raises: :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ @@ -200,7 +199,6 @@ class Database(object): :param status: Open the database in read-only or read-write mode :type status: :attr:`MODE` - :returns: Nothing :raises: Raises :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ @@ -699,7 +697,6 @@ class Directory(object): Retrieves a previously stored mtime for this directory. :param mtime: A (time_t) timestamp - :returns: Nothing on success, raising an exception on failure. :raises: :exc:`NotmuchError`: :attr:`STATUS`.NOT_INITIALIZED diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index ce7cb88..9ebb53d 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -513,7 +513,6 @@ class Message(Python3StringMixIn): *Message.FLAG.MATCH* :param value: A bool indicating whether to set or unset the flag. - :returns: Nothing :raises: :exc:`NotInitializedError` if the message is not initialized. """ diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 25b9e78..15ed153 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -88,7 +88,6 @@ class Query(object): :type db: :class:`Database` :param querystr: The query string :type querystr: utf-8 encoded str or unicode - :returns: Nothing :raises: :exc:`NullPointerError` if the query creation failed (e.g. too little memory). -- cgit v1.2.3 From c1094bc2d767159b5478cd0399d37a4813d0de05 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 21 Feb 2012 00:56:07 +0100 Subject: python: allow an empty path as parameter to Database.get_directory Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index d841367..ab3cdec 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -351,7 +351,7 @@ class Database(object): """ self._assert_db_is_initialized() # sanity checking if path is valid, and make path absolute - if path[0] == os.sep: + if path and path[0] == os.sep: # we got an absolute path if not path.startswith(self.get_path()): # but its initial components are not equal to the db path -- cgit v1.2.3 From 0b2ff308ece7e45a32a9e5a98d400b268278071a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Tue, 21 Feb 2012 01:06:15 +0100 Subject: python: fix the type nonsense of the first parameter of class Directory Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index ab3cdec..504bb88 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -365,7 +365,7 @@ class Database(object): dir_p = Database._get_directory(self._db, _str(path)) # return the Directory, init it with the absolute path - return Directory(_str(abs_dirpath), dir_p, self) + return Directory(abs_dirpath, dir_p, self) _add_message = nmlib.notmuch_database_add_message _add_message.argtypes = [NotmuchDatabaseP, c_char_p, @@ -639,7 +639,7 @@ class Directory(object): def __init__(self, path, dir_p, parent): """ - :param path: The absolute path of the directory object as unicode. + :param path: The absolute path of the directory object. :param dir_p: The pointer to an internal notmuch_directory_t object. :param parent: The object this Directory is derived from (usually a :class:`Database`). We do not directly use @@ -647,7 +647,6 @@ class Directory(object): this Directory object lives. This keeps the parent object alive. """ - assert isinstance(path, unicode), "Path needs to be an UNICODE object" self._path = path self._dir_p = dir_p self._parent = parent -- cgit v1.2.3 From 92983dd14e3c9d767bb8ef6e9b85ef76b293cdd4 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 21:01:24 +0100 Subject: python: avoid using a magic value for database mode in Database.__init__ Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 504bb88..c905395 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -122,7 +122,8 @@ class Database(object): _create.argtypes = [c_char_p] _create.restype = NotmuchDatabaseP - def __init__(self, path=None, create=False, mode=0): + def __init__(self, path = None, create = False, + mode = MODE.READ_ONLY): """If *path* is `None`, we will try to read a users notmuch configuration and use his configured database. The location of the configuration file can be specified through the environment variable -- cgit v1.2.3 From 35ceaf496fe2d2a1324a8462e629e618ed20037a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 20:46:42 +0100 Subject: python: Improve the docstring of Database.get_directory Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index c905395..bef9720 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -345,10 +345,8 @@ class Database(object): of database (see :meth:`get_path`), or else should be an absolute path with initial components that match the path of 'database'. :returns: :class:`Directory` or raises an exception. - :raises: - :exc:`NotmuchError` with :attr:`STATUS`.FILE_ERROR - If path is not relative database or absolute with initial - components same as database. + :raises: :exc:`FileError` if path is not relative database or absolute + with initial components same as database. """ self._assert_db_is_initialized() # sanity checking if path is valid, and make path absolute -- cgit v1.2.3 From fcf19ad029913e88558a21135feb0b5e1b33cef3 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 20:58:44 +0100 Subject: python: work around libnotmuch calling exit(3) in Database.get_directory Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index bef9720..82cb803 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -27,6 +27,7 @@ from notmuch.globals import ( NotmuchError, NullPointerError, NotInitializedError, + ReadOnlyDatabaseError, Enum, _str, NotmuchDatabaseP, @@ -145,6 +146,7 @@ class Database(object): failure. """ self._db = None + self.mode = mode if path is None: # no path specified. use a user's default database if Database._std_db_path is None: @@ -335,20 +337,24 @@ class Database(object): """Returns a :class:`Directory` of path, (creating it if it does not exist(?)) - .. warning:: - - This call needs a writeable database in - :attr:`Database.MODE`.READ_WRITE mode. The underlying library will - exit the program if this method is used on a read-only database! - :param path: An unicode string containing the path relative to the path of database (see :meth:`get_path`), or else should be an absolute path with initial components that match the path of 'database'. :returns: :class:`Directory` or raises an exception. :raises: :exc:`FileError` if path is not relative database or absolute with initial components same as database. + :raises: :exc:`ReadOnlyDatabaseError` if the database has not been + opened in read-write mode """ self._assert_db_is_initialized() + + # work around libnotmuch calling exit(3), see + # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de + # TODO: remove once this issue is resolved + if self.mode != Database.MODE.READ_WRITE: + raise ReadOnlyDatabaseError('The database has to be opened in ' + 'read-write mode for get_directory') + # sanity checking if path is valid, and make path absolute if path and path[0] == os.sep: # we got an absolute path -- cgit v1.2.3 From 05cdb3d7b7c007364fe9fa38ff36488feaf698b7 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 21:07:18 +0100 Subject: python: improve the docstring of Database.find_message_by_filename Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 82cb803..ebb8f20 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -515,17 +515,16 @@ class Database(object): function returns None if no message is found with the given filename. - :raises: - :exc:`OutOfMemoryError` - If an Out-of-memory occured while constructing the message. - :exc:`XapianError` - In case of a Xapian Exception. These exceptions - include "Database modified" situations, e.g. when the - notmuch database has been modified by another program - in the meantime. In this case, you should close and - reopen the database and retry. - :exc:`NotInitializedError` if - the database was not intitialized. + :raises: :exc:`OutOfMemoryError` if an Out-of-memory occured while + constructing the message. + :raises: :exc:`XapianError` in case of a Xapian Exception. + These exceptions include "Database modified" + situations, e.g. when the notmuch database has been + modified by another program in the meantime. In this + case, you should close and reopen the database and + retry. + :raises: :exc:`NotInitializedError` if the database was not + intitialized. *Added in notmuch 0.9*""" self._assert_db_is_initialized() -- cgit v1.2.3 From 1736488ecfd9b18a380ce04ac2df0303c0ea3c80 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 21:14:13 +0100 Subject: python: work around libnotmuch calling exit(3) in Database.find_message_by_filename Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index ebb8f20..a054be7 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -504,12 +504,6 @@ class Database(object): def find_message_by_filename(self, filename): """Find a message with the given filename - .. warning:: - - This call needs a writeable database in - :attr:`Database.MODE`.READ_WRITE mode. The underlying library will - exit the program if this method is used on a read-only database! - :returns: If the database contains a message with the given filename, then a class:`Message:` is returned. This function returns None if no message is found with the given @@ -525,9 +519,19 @@ class Database(object): retry. :raises: :exc:`NotInitializedError` if the database was not intitialized. + :raises: :exc:`ReadOnlyDatabaseError` if the database has not been + opened in read-write mode *Added in notmuch 0.9*""" self._assert_db_is_initialized() + + # work around libnotmuch calling exit(3), see + # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de + # TODO: remove once this issue is resolved + if self.mode != Database.MODE.READ_WRITE: + raise ReadOnlyDatabaseError('The database has to be opened in ' + 'read-write mode for get_directory') + msg_p = NotmuchMessageP() status = Database._find_message_by_filename(self._db, _str(filename), byref(msg_p)) -- cgit v1.2.3 From ba95980cf1a5e2b32104611ccdf2e9c43bf3305a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 21:55:59 +0100 Subject: python: refactor the python bindings Move the Directory class into its own file, merge the two Filenames classes into one, deprecate Filenames.as_iterator, update the documentation accordingly. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 20 +-- bindings/python/notmuch/__init__.py | 15 ++- bindings/python/notmuch/database.py | 239 +--------------------------------- bindings/python/notmuch/directory.py | 183 ++++++++++++++++++++++++++ bindings/python/notmuch/filename.py | 62 +++++++-- 5 files changed, 256 insertions(+), 263 deletions(-) create mode 100644 bindings/python/notmuch/directory.py (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index 25eb146..e87a865 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -254,26 +254,28 @@ More information on specific topics can be found on the following pages: :class:`Filenames` -- An iterator over filenames ------------------------------------------------ -.. autoclass:: notmuch.database.Filenames +.. autoclass:: notmuch.Filenames - .. automethod:: notmuch.database.Filenames.__len__ + .. automethod:: notmuch.Filenames.__len__ + + .. automethod:: notmuch.Filenames.as_generator :class:`notmuch.database.Directoy` -- A directory entry in the database ------------------------------------------------------------------------ -.. autoclass:: notmuch.database.Directory +.. autoclass:: notmuch.Directory - .. automethod:: notmuch.database.Directory.get_child_files + .. automethod:: notmuch.Directory.get_child_files - .. automethod:: notmuch.database.Directory.get_child_directories + .. automethod:: notmuch.Directory.get_child_directories - .. automethod:: notmuch.database.Directory.get_mtime + .. automethod:: notmuch.Directory.get_mtime - .. automethod:: notmuch.database.Directory.set_mtime + .. automethod:: notmuch.Directory.set_mtime - .. autoattribute:: notmuch.database.Directory.mtime + .. autoattribute:: notmuch.Directory.mtime - .. autoattribute:: notmuch.database.Directory.path + .. autoattribute:: notmuch.Directory.path The `next page `_ contains information on possible Status and Error values. diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index f3ff987..8de73d5 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -51,11 +51,14 @@ along with notmuch. If not, see . Copyright 2010-2011 Sebastian Spaeth """ -from notmuch.database import Database, Query -from notmuch.message import Messages, Message -from notmuch.thread import Threads, Thread -from notmuch.tag import Tags -from notmuch.globals import ( +from .database import Database +from .directory import Directory +from .filename import Filenames +from .message import Messages, Message +from .query import Query +from .tag import Tags +from .thread import Threads, Thread +from .globals import ( nmlib, STATUS, NotmuchError, @@ -71,6 +74,6 @@ from notmuch.globals import ( UnbalancedAtomicError, NotInitializedError, ) -from notmuch.version import __VERSION__ +from .version import __VERSION__ __LICENSE__ = "GPL v3+" __AUTHOR__ = 'Sebastian Spaeth ' diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index a054be7..800264b 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -19,7 +19,7 @@ Copyright 2010 Sebastian Spaeth ' import os import codecs -from ctypes import c_char_p, c_void_p, c_uint, c_long, byref, POINTER +from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER from notmuch.globals import ( nmlib, STATUS, @@ -34,11 +34,11 @@ from notmuch.globals import ( NotmuchDirectoryP, NotmuchMessageP, NotmuchTagsP, - NotmuchFilenamesP ) from notmuch.message import Message from notmuch.tag import Tags from .query import Query +from .directory import Directory class Database(object): """The :class:`Database` is the highest-level object that notmuch @@ -603,238 +603,3 @@ class Database(object): guaranteed to remain stable in future versions). """ return self._db - - -class Directory(object): - """Represents a directory entry in the notmuch directory - - Modifying attributes of this object will modify the - database, not the real directory attributes. - - The Directory object is usually derived from another object - e.g. via :meth:`Database.get_directory`, and will automatically be - become invalid whenever that parent is deleted. You should - therefore initialized this object handing it a reference to the - parent, preventing the parent from automatically being garbage - collected. - """ - - """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 = [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.argtypes = [NotmuchDirectoryP] - _get_child_files.restype = NotmuchFilenamesP - - """notmuch_directory_get_child_directories""" - _get_child_directories = nmlib.notmuch_directory_get_child_directories - _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""" - if not self._dir_p: - raise NotInitializedError() - - def __init__(self, path, dir_p, parent): - """ - :param path: The absolute path of the directory object. - :param dir_p: The pointer to an internal notmuch_directory_t object. - :param parent: The object this Directory is derived from - (usually a :class:`Database`). We do not directly use - this, but store a reference to it as long as - this Directory object lives. This keeps the - parent object alive. - """ - self._path = path - self._dir_p = dir_p - self._parent = parent - - def set_mtime(self, mtime): - """Sets the mtime value of this directory in the database - - The intention is for the caller to use the mtime to allow efficient - identification of new messages to be added to the database. The - recommended usage is as follows: - - * Read the mtime of a directory from the filesystem - - * Call :meth:`Database.add_message` for all mail files in - the directory - - * Call notmuch_directory_set_mtime with the mtime read from the - filesystem. Then, when wanting to check for updates to the - directory in the future, the client can call :meth:`get_mtime` - and know that it only needs to add files if the mtime of the - directory and files are newer than the stored timestamp. - - .. note:: - - :meth:`get_mtime` function does not allow the caller to - distinguish a timestamp of 0 from a non-existent timestamp. So - don't store a timestamp of 0 unless you are comfortable with - that. - - :param mtime: A (time_t) timestamp - :raises: :exc:`XapianError` a Xapian exception occurred, mtime - not stored - :raises: :exc:`ReadOnlyDatabaseError` the database was opened - in read-only mode so directory mtime cannot be modified - :raises: :exc:`NotInitializedError` the directory object has not - been initialized - """ - self._assert_dir_is_initialized() - status = Directory._set_mtime(self._dir_p, mtime) - - if status != STATUS.SUCCESS: - raise NotmuchError(status) - - def get_mtime(self): - """Gets the mtime value of this directory in the database - - Retrieves a previously stored mtime for this directory. - - :param mtime: A (time_t) timestamp - :raises: :exc:`NotmuchError`: - - :attr:`STATUS`.NOT_INITIALIZED - The directory has not been initialized - """ - self._assert_dir_is_initialized() - return Directory._get_mtime(self._dir_p) - - # Make mtime attribute a property of Directory() - mtime = property(get_mtime, set_mtime, doc="""Property that allows getting - and setting of the Directory *mtime* (read-write) - - See :meth:`get_mtime` and :meth:`set_mtime` for usage and - possible exceptions.""") - - def get_child_files(self): - """Gets a Filenames iterator listing all the filenames of - messages in the database within the given directory. - - The returned filenames will be the basename-entries only (not - complete paths. - """ - self._assert_dir_is_initialized() - files_p = Directory._get_child_files(self._dir_p) - return Filenames(files_p, self) - - def get_child_directories(self): - """Gets a :class:`Filenames` iterator listing all the filenames of - sub-directories in the database within the given directory - - The returned filenames will be the basename-entries only (not - complete paths. - """ - self._assert_dir_is_initialized() - files_p = Directory._get_child_directories(self._dir_p) - return Filenames(files_p, self) - - @property - def path(self): - """Returns the absolute path of this Directory (read-only)""" - return self._path - - def __repr__(self): - """Object representation""" - return "" % 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: - self._destroy(self._dir_p) - - -class Filenames(object): - """An iterator over File- or Directory names stored in the database""" - - #notmuch_filenames_get - _get = nmlib.notmuch_filenames_get - _get.argtypes = [NotmuchFilenamesP] - _get.restype = c_char_p - - def __init__(self, files_p, parent): - """ - :param files_p: The pointer to an internal notmuch_filenames_t object. - :param parent: The object this Directory is derived from - (usually a Directory()). We do not directly use - this, but store a reference to it as long as - this Directory object lives. This keeps the - parent object alive. - """ - self._files_p = files_p - self._parent = parent - - def __iter__(self): - """ 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 not self._files_p: - raise NotInitializedError() - - if not self._valid(self._files_p): - self._files_p = None - raise StopIteration - - file_ = Filenames._get(self._files_p) - self._move_to_next(self._files_p) - return file_.decode('utf-8', 'ignore') - next = __next__ # python2.x iterator protocol compatibility - - def __len__(self): - """len(:class:`Filenames`) returns the number of contained files - - .. note:: - - As this iterates over the files, we will not be able to - iterate over them again! So this will fail:: - - #THIS FAILS - files = Database().get_directory('').get_child_files() - if len(files) > 0: # this 'exhausts' msgs - # next line raises - # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) - for file in files: print file - """ - if not self._files_p: - raise NotInitializedError() - - i = 0 - 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: - self._destroy(self._files_p) diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py new file mode 100644 index 0000000..3e0763f --- /dev/null +++ b/bindings/python/notmuch/directory.py @@ -0,0 +1,183 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth ' +""" + +from ctypes import c_uint, c_long +from notmuch.globals import ( + nmlib, + STATUS, + NotmuchError, + NotInitializedError, + NotmuchDirectoryP, + NotmuchFilenamesP +) +from .filename import Filenames + +class Directory(object): + """Represents a directory entry in the notmuch directory + + Modifying attributes of this object will modify the + database, not the real directory attributes. + + The Directory object is usually derived from another object + e.g. via :meth:`Database.get_directory`, and will automatically be + become invalid whenever that parent is deleted. You should + therefore initialized this object handing it a reference to the + parent, preventing the parent from automatically being garbage + collected. + """ + + """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 = [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.argtypes = [NotmuchDirectoryP] + _get_child_files.restype = NotmuchFilenamesP + + """notmuch_directory_get_child_directories""" + _get_child_directories = nmlib.notmuch_directory_get_child_directories + _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""" + if not self._dir_p: + raise NotInitializedError() + + def __init__(self, path, dir_p, parent): + """ + :param path: The absolute path of the directory object. + :param dir_p: The pointer to an internal notmuch_directory_t object. + :param parent: The object this Directory is derived from + (usually a :class:`Database`). We do not directly use + this, but store a reference to it as long as + this Directory object lives. This keeps the + parent object alive. + """ + self._path = path + self._dir_p = dir_p + self._parent = parent + + def set_mtime(self, mtime): + """Sets the mtime value of this directory in the database + + The intention is for the caller to use the mtime to allow efficient + identification of new messages to be added to the database. The + recommended usage is as follows: + + * Read the mtime of a directory from the filesystem + + * Call :meth:`Database.add_message` for all mail files in + the directory + + * Call notmuch_directory_set_mtime with the mtime read from the + filesystem. Then, when wanting to check for updates to the + directory in the future, the client can call :meth:`get_mtime` + and know that it only needs to add files if the mtime of the + directory and files are newer than the stored timestamp. + + .. note:: + + :meth:`get_mtime` function does not allow the caller to + distinguish a timestamp of 0 from a non-existent timestamp. So + don't store a timestamp of 0 unless you are comfortable with + that. + + :param mtime: A (time_t) timestamp + :raises: :exc:`XapianError` a Xapian exception occurred, mtime + not stored + :raises: :exc:`ReadOnlyDatabaseError` the database was opened + in read-only mode so directory mtime cannot be modified + :raises: :exc:`NotInitializedError` the directory object has not + been initialized + """ + self._assert_dir_is_initialized() + status = Directory._set_mtime(self._dir_p, mtime) + + if status != STATUS.SUCCESS: + raise NotmuchError(status) + + def get_mtime(self): + """Gets the mtime value of this directory in the database + + Retrieves a previously stored mtime for this directory. + + :param mtime: A (time_t) timestamp + :raises: :exc:`NotmuchError`: + + :attr:`STATUS`.NOT_INITIALIZED + The directory has not been initialized + """ + self._assert_dir_is_initialized() + return Directory._get_mtime(self._dir_p) + + # Make mtime attribute a property of Directory() + mtime = property(get_mtime, set_mtime, doc="""Property that allows getting + and setting of the Directory *mtime* (read-write) + + See :meth:`get_mtime` and :meth:`set_mtime` for usage and + possible exceptions.""") + + def get_child_files(self): + """Gets a Filenames iterator listing all the filenames of + messages in the database within the given directory. + + The returned filenames will be the basename-entries only (not + complete paths. + """ + self._assert_dir_is_initialized() + files_p = Directory._get_child_files(self._dir_p) + return Filenames(files_p, self) + + def get_child_directories(self): + """Gets a :class:`Filenames` iterator listing all the filenames of + sub-directories in the database within the given directory + + The returned filenames will be the basename-entries only (not + complete paths. + """ + self._assert_dir_is_initialized() + files_p = Directory._get_child_directories(self._dir_p) + return Filenames(files_p, self) + + @property + def path(self): + """Returns the absolute path of this Directory (read-only)""" + return self._path + + def __repr__(self): + """Object representation""" + return "" % 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: + self._destroy(self._dir_p) diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py index 353eb76..232a9ed 100644 --- a/bindings/python/notmuch/filename.py +++ b/bindings/python/notmuch/filename.py @@ -78,10 +78,14 @@ class Filenames(Python3StringMixIn): if not files_p: raise NullPointerError() - self._files = files_p + self._files_p = files_p #save reference to parent object so we keep it alive self._parent = parent + def __iter__(self): + """ Make Filenames an iterator """ + return self + _valid = nmlib.notmuch_filenames_valid _valid.argtypes = [NotmuchFilenamesP] _valid.restype = bool @@ -90,19 +94,30 @@ class Filenames(Python3StringMixIn): _move_to_next.argtypes = [NotmuchFilenamesP] _move_to_next.restype = None + def __next__(self): + if not self._files_p: + raise NotInitializedError() + + if not self._valid(self._files_p): + self._files_p = None + raise StopIteration + + file_ = Filenames._get(self._files_p) + self._move_to_next(self._files_p) + return file_.decode('utf-8', 'ignore') + next = __next__ # python2.x iterator protocol compatibility + def as_generator(self): """Return generator of Filenames This is the main function that will usually be used by the - user.""" - if not self._files: - raise NotInitializedError() + user. - while self._valid(self._files): - yield Filenames._get(self._files).decode('utf-8', 'ignore') - self._move_to_next(self._files) - - self._files = None + .. deprecated:: 0.12 + :class:`Filenames` objects implement the + iterator protocol. + """ + return self def __unicode__(self): """Represent Filenames() as newline-separated list of full paths @@ -123,5 +138,30 @@ class Filenames(Python3StringMixIn): def __del__(self): """Close and free the notmuch filenames""" - if self._files is not None: - self._destroy(self._files) + if self._files_p is not None: + self._destroy(self._files_p) + + def __len__(self): + """len(:class:`Filenames`) returns the number of contained files + + .. note:: + + As this iterates over the files, we will not be able to + iterate over them again! So this will fail:: + + #THIS FAILS + files = Database().get_directory('').get_child_files() + if len(files) > 0: # this 'exhausts' msgs + # next line raises + # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) + for file in files: print file + """ + if not self._files_p: + raise NotInitializedError() + + i = 0 + while self._valid(self._files_p): + self._move_to_next(self._files_p) + i += 1 + self._files_p = None + return i -- cgit v1.2.3 From 69f077898a65c10453d08dd94bf4c94efc69b91b Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 22:34:40 +0100 Subject: python: move Messages class into its own file Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/__init__.py | 3 +- bindings/python/notmuch/message.py | 242 +-------------------------------- bindings/python/notmuch/messages.py | 262 ++++++++++++++++++++++++++++++++++++ bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/thread.py | 2 +- 5 files changed, 272 insertions(+), 239 deletions(-) create mode 100644 bindings/python/notmuch/messages.py (limited to 'bindings') diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index 8de73d5..b8f3610 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -54,7 +54,8 @@ Copyright 2010-2011 Sebastian Spaeth from .database import Database from .directory import Directory from .filename import Filenames -from .message import Messages, Message +from .message import Message +from .messages import Messages from .query import Query from .tag import Tags from .thread import Threads, Thread diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 9ebb53d..20ba9cb 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -21,7 +21,7 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p, c_long, c_uint, c_int from datetime import date -from notmuch.globals import ( +from .globals import ( nmlib, Enum, _str, @@ -35,9 +35,9 @@ from notmuch.globals import ( NotmuchMessagesP, NotmuchFilenamesP, ) -from notmuch.tag import Tags -from notmuch.filename import Filenames -import sys +from .tag import Tags +from .filename import Filenames + import email try: import simplejson as json @@ -45,238 +45,6 @@ except ImportError: import json -class Messages(object): - """Represents a list of notmuch messages - - This object provides an iterator over a list of notmuch messages - (Technically, it provides a wrapper for the underlying - *notmuch_messages_t* structure). Do note that the underlying library - only provides a one-time iterator (it cannot reset the iterator to - the start). Thus iterating over the function will "exhaust" the list - of messages, and a subsequent iteration attempt will raise a - :exc:`NotInitializedError`. If you need to - re-iterate over a list of messages you will need to retrieve a new - :class:`Messages` object or cache your :class:`Message`\s in a list - via:: - - msglist = list(msgs) - - You can store and reuse the single :class:`Message` objects as often - as you want as long as you keep the parent :class:`Messages` object - around. (Due to hierarchical memory allocation, all derived - :class:`Message` objects will be invalid when we delete the parent - :class:`Messages` object, even if it was already exhausted.) So - this works:: - - db = Database() - msgs = Query(db,'').search_messages() #get a Messages() object - msglist = list(msgs) - - # msgs is "exhausted" now and msgs.next() will raise an exception. - # However it will be kept alive until all retrieved Message() - # objects are also deleted. If you do e.g. an explicit del(msgs) - # here, the following lines would fail. - - # You can reiterate over *msglist* however as often as you want. - # It is simply a list with :class:`Message`s. - - print (msglist[0].get_filename()) - print (msglist[1].get_filename()) - print (msglist[0].get_message_id()) - - - As :class:`Message` implements both __hash__() and __cmp__(), it is - possible to make sets out of :class:`Messages` and use set - arithmetic (this happens in python and will of course be *much* - slower than redoing a proper query with the appropriate filters:: - - s1, s2 = set(msgs1), set(msgs2) - s.union(s2) - s1 -= s2 - ... - - Be careful when using set arithmetic between message sets derived - from different Databases (ie the same database reopened after - messages have changed). If messages have added or removed associated - files in the meantime, it is possible that the same message would be - considered as a different object (as it points to a different file). - """ - - #notmuch_messages_get - _get = nmlib.notmuch_messages_get - _get.argtypes = [NotmuchMessagesP] - _get.restype = NotmuchMessageP - - _collect_tags = nmlib.notmuch_messages_collect_tags - _collect_tags.argtypes = [NotmuchMessagesP] - _collect_tags.restype = NotmuchTagsP - - def __init__(self, msgs_p, parent=None): - """ - :param msgs_p: A pointer to an underlying *notmuch_messages_t* - structure. These are not publically exposed, so a user - will almost never instantiate a :class:`Messages` object - herself. They are usually handed back as a result, - e.g. in :meth:`Query.search_messages`. *msgs_p* must be - valid, we will raise an :exc:`NullPointerError` if it is - `None`. - :type msgs_p: :class:`ctypes.c_void_p` - :param parent: The parent object - (ie :class:`Query`) these tags are derived from. It saves - a reference to it, so we can automatically delete the db - object once all derived objects are dead. - :TODO: Make the iterator work more than once and cache the tags in - the Python object.(?) - """ - if not msgs_p: - raise NullPointerError() - - self._msgs = msgs_p - #store parent, so we keep them alive as long as self is alive - self._parent = parent - - def collect_tags(self): - """Return the unique :class:`Tags` in the contained messages - - :returns: :class:`Tags` - :exceptions: :exc:`NotInitializedError` if not init'ed - - .. note:: - - :meth:`collect_tags` will iterate over the messages and therefore - will not allow further iterations. - """ - if not self._msgs: - raise NotInitializedError() - - # collect all tags (returns NULL on error) - tags_p = Messages._collect_tags(self._msgs) - #reset _msgs as we iterated over it and can do so only once - self._msgs = None - - if tags_p == None: - raise NullPointerError() - return Tags(tags_p, self) - - def __iter__(self): - """ 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 not self._msgs: - raise NotInitializedError() - - if not self._valid(self._msgs): - self._msgs = None - raise StopIteration - - msg = Message(Messages._get(self._msgs), self) - self._move_to_next(self._msgs) - return msg - next = __next__ # python2.x iterator protocol compatibility - - def __nonzero__(self): - """ - :return: True if there is at least one more thread in the - Iterator, False if not.""" - return self._msgs is not None and \ - 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: - self._destroy(self._msgs) - - def format_messages(self, format, indent=0, entire_thread=False): - """Formats messages as needed for 'notmuch show'. - - :param format: A string of either 'text' or 'json'. - :param indent: A number indicating the reply depth of these messages. - :param entire_thread: A bool, indicating whether we want to output - whole threads or only the matching messages. - :return: a list of lines - """ - result = list() - - if format.lower() == "text": - set_start = "" - set_end = "" - set_sep = "" - elif format.lower() == "json": - set_start = "[" - set_end = "]" - set_sep = ", " - else: - raise TypeError("format must be either 'text' or 'json'") - - first_set = True - - result.append(set_start) - - # iterate through all toplevel messages in this thread - for msg in self: - # if not msg: - # break - if not first_set: - result.append(set_sep) - first_set = False - - result.append(set_start) - match = msg.is_match() - next_indent = indent - - if (match or entire_thread): - if format.lower() == "text": - result.append(msg.format_message_as_text(indent)) - else: - result.append(msg.format_message_as_json(indent)) - next_indent = indent + 1 - - # get replies and print them also out (if there are any) - replies = msg.get_replies().format_messages(format, next_indent, entire_thread) - if replies: - result.append(set_sep) - result.extend(replies) - - result.append(set_end) - result.append(set_end) - - return result - - def print_messages(self, format, indent=0, entire_thread=False, handle=sys.stdout): - """Outputs messages as needed for 'notmuch show' to a file like object. - - :param format: A string of either 'text' or 'json'. - :param handle: A file like object to print to (default is sys.stdout). - :param indent: A number indicating the reply depth of these messages. - :param entire_thread: A bool, indicating whether we want to output - whole threads or only the matching messages. - """ - handle.write(''.join(self.format_messages(format, indent, entire_thread))) - - -class EmptyMessagesResult(Messages): - def __init__(self, parent): - self._msgs = None - self._parent = parent - - def __next__(self): - raise StopIteration() - next = __next__ - - class Message(Python3StringMixIn): """Represents a single Email message @@ -418,6 +186,8 @@ class Message(Python3StringMixIn): msgs_p = Message._get_replies(self._msg) + from .messages import Messages, EmptyMessagesResult + if not msgs_p: return EmptyMessagesResult(self) diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py new file mode 100644 index 0000000..20d3632 --- /dev/null +++ b/bindings/python/notmuch/messages.py @@ -0,0 +1,262 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth ' + Jesse Rosenthal +""" + +from .globals import ( + nmlib, + NullPointerError, + NotInitializedError, + NotmuchTagsP, + NotmuchMessageP, + NotmuchMessagesP, +) +from .tag import Tags +from .message import Message + +import sys + +class Messages(object): + """Represents a list of notmuch messages + + This object provides an iterator over a list of notmuch messages + (Technically, it provides a wrapper for the underlying + *notmuch_messages_t* structure). Do note that the underlying library + only provides a one-time iterator (it cannot reset the iterator to + the start). Thus iterating over the function will "exhaust" the list + of messages, and a subsequent iteration attempt will raise a + :exc:`NotInitializedError`. If you need to + re-iterate over a list of messages you will need to retrieve a new + :class:`Messages` object or cache your :class:`Message`\s in a list + via:: + + msglist = list(msgs) + + You can store and reuse the single :class:`Message` objects as often + as you want as long as you keep the parent :class:`Messages` object + around. (Due to hierarchical memory allocation, all derived + :class:`Message` objects will be invalid when we delete the parent + :class:`Messages` object, even if it was already exhausted.) So + this works:: + + db = Database() + msgs = Query(db,'').search_messages() #get a Messages() object + msglist = list(msgs) + + # msgs is "exhausted" now and msgs.next() will raise an exception. + # However it will be kept alive until all retrieved Message() + # objects are also deleted. If you do e.g. an explicit del(msgs) + # here, the following lines would fail. + + # You can reiterate over *msglist* however as often as you want. + # It is simply a list with :class:`Message`s. + + print (msglist[0].get_filename()) + print (msglist[1].get_filename()) + print (msglist[0].get_message_id()) + + + As :class:`Message` implements both __hash__() and __cmp__(), it is + possible to make sets out of :class:`Messages` and use set + arithmetic (this happens in python and will of course be *much* + slower than redoing a proper query with the appropriate filters:: + + s1, s2 = set(msgs1), set(msgs2) + s.union(s2) + s1 -= s2 + ... + + Be careful when using set arithmetic between message sets derived + from different Databases (ie the same database reopened after + messages have changed). If messages have added or removed associated + files in the meantime, it is possible that the same message would be + considered as a different object (as it points to a different file). + """ + + #notmuch_messages_get + _get = nmlib.notmuch_messages_get + _get.argtypes = [NotmuchMessagesP] + _get.restype = NotmuchMessageP + + _collect_tags = nmlib.notmuch_messages_collect_tags + _collect_tags.argtypes = [NotmuchMessagesP] + _collect_tags.restype = NotmuchTagsP + + def __init__(self, msgs_p, parent=None): + """ + :param msgs_p: A pointer to an underlying *notmuch_messages_t* + structure. These are not publically exposed, so a user + will almost never instantiate a :class:`Messages` object + herself. They are usually handed back as a result, + e.g. in :meth:`Query.search_messages`. *msgs_p* must be + valid, we will raise an :exc:`NullPointerError` if it is + `None`. + :type msgs_p: :class:`ctypes.c_void_p` + :param parent: The parent object + (ie :class:`Query`) these tags are derived from. It saves + a reference to it, so we can automatically delete the db + object once all derived objects are dead. + :TODO: Make the iterator work more than once and cache the tags in + the Python object.(?) + """ + if not msgs_p: + raise NullPointerError() + + self._msgs = msgs_p + #store parent, so we keep them alive as long as self is alive + self._parent = parent + + def collect_tags(self): + """Return the unique :class:`Tags` in the contained messages + + :returns: :class:`Tags` + :exceptions: :exc:`NotInitializedError` if not init'ed + + .. note:: + + :meth:`collect_tags` will iterate over the messages and therefore + will not allow further iterations. + """ + if not self._msgs: + raise NotInitializedError() + + # collect all tags (returns NULL on error) + tags_p = Messages._collect_tags(self._msgs) + #reset _msgs as we iterated over it and can do so only once + self._msgs = None + + if tags_p == None: + raise NullPointerError() + return Tags(tags_p, self) + + def __iter__(self): + """ 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 not self._msgs: + raise NotInitializedError() + + if not self._valid(self._msgs): + self._msgs = None + raise StopIteration + + msg = Message(Messages._get(self._msgs), self) + self._move_to_next(self._msgs) + return msg + next = __next__ # python2.x iterator protocol compatibility + + def __nonzero__(self): + """ + :return: True if there is at least one more thread in the + Iterator, False if not.""" + return self._msgs is not None and \ + 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: + self._destroy(self._msgs) + + def format_messages(self, format, indent=0, entire_thread=False): + """Formats messages as needed for 'notmuch show'. + + :param format: A string of either 'text' or 'json'. + :param indent: A number indicating the reply depth of these messages. + :param entire_thread: A bool, indicating whether we want to output + whole threads or only the matching messages. + :return: a list of lines + """ + result = list() + + if format.lower() == "text": + set_start = "" + set_end = "" + set_sep = "" + elif format.lower() == "json": + set_start = "[" + set_end = "]" + set_sep = ", " + else: + raise TypeError("format must be either 'text' or 'json'") + + first_set = True + + result.append(set_start) + + # iterate through all toplevel messages in this thread + for msg in self: + # if not msg: + # break + if not first_set: + result.append(set_sep) + first_set = False + + result.append(set_start) + match = msg.is_match() + next_indent = indent + + if (match or entire_thread): + if format.lower() == "text": + result.append(msg.format_message_as_text(indent)) + else: + result.append(msg.format_message_as_json(indent)) + next_indent = indent + 1 + + # get replies and print them also out (if there are any) + replies = msg.get_replies().format_messages(format, next_indent, entire_thread) + if replies: + result.append(set_sep) + result.extend(replies) + + result.append(set_end) + result.append(set_end) + + return result + + def print_messages(self, format, indent=0, entire_thread=False, handle=sys.stdout): + """Outputs messages as needed for 'notmuch show' to a file like object. + + :param format: A string of either 'text' or 'json'. + :param handle: A file like object to print to (default is sys.stdout). + :param indent: A number indicating the reply depth of these messages. + :param entire_thread: A bool, indicating whether we want to output + whole threads or only the matching messages. + """ + handle.write(''.join(self.format_messages(format, indent, entire_thread))) + +class EmptyMessagesResult(Messages): + def __init__(self, parent): + self._msgs = None + self._parent = parent + + def __next__(self): + raise StopIteration() + next = __next__ diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 15ed153..b669a3e 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -30,7 +30,7 @@ from notmuch.globals import ( NotInitializedError, ) from notmuch.thread import Threads -from notmuch.message import Messages +from .messages import Messages class Query(object): diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index d1ba3e5..c599bcb 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -28,7 +28,7 @@ from notmuch.globals import ( NotmuchMessagesP, NotmuchTagsP, ) -from notmuch.message import Messages +from .messages import Messages from notmuch.tag import Tags from datetime import date -- cgit v1.2.3 From 76a2db3d7b92bc1a8be75f673dc384c46cf02fab Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 22:39:52 +0100 Subject: python: move Threads class into its own file Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/__init__.py | 3 +- bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/thread.py | 154 ------------------------------- bindings/python/notmuch/threads.py | 178 ++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 156 deletions(-) create mode 100644 bindings/python/notmuch/threads.py (limited to 'bindings') diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index b8f3610..89b9849 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -58,7 +58,8 @@ from .message import Message from .messages import Messages from .query import Query from .tag import Tags -from .thread import Threads, Thread +from .thread import Thread +from .threads import Threads from .globals import ( nmlib, STATUS, diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index b669a3e..fcd67e5 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -29,7 +29,7 @@ from notmuch.globals import ( NullPointerError, NotInitializedError, ) -from notmuch.thread import Threads +from .threads import Threads from .messages import Messages diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index c599bcb..0dac522 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -20,11 +20,9 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p, c_long, c_int from notmuch.globals import ( nmlib, - Python3StringMixIn, NullPointerError, NotInitializedError, NotmuchThreadP, - NotmuchThreadsP, NotmuchMessagesP, NotmuchTagsP, ) @@ -32,158 +30,6 @@ from .messages import Messages from notmuch.tag import Tags from datetime import date - -class Threads(Python3StringMixIn): - """Represents a list of notmuch threads - - This object provides an iterator over a list of notmuch threads - (Technically, it provides a wrapper for the underlying - *notmuch_threads_t* structure). Do note that the underlying - library only provides a one-time iterator (it cannot reset the - iterator to the start). Thus iterating over the function will - "exhaust" the list of threads, and a subsequent iteration attempt - will raise a :exc:`NotInitializedError`. Also - note, that any function that uses iteration will also - exhaust the messages. So both:: - - for thread in threads: print thread - - as well as:: - - number_of_msgs = len(threads) - - will "exhaust" the threads. If you need to re-iterate over a list of - messages you will need to retrieve a new :class:`Threads` object. - - Things are not as bad as it seems though, you can store and reuse - the single Thread objects as often as you want as long as you - keep the parent Threads object around. (Recall that due to - hierarchical memory allocation, all derived Threads objects will - be invalid when we delete the parent Threads() object, even if it - was already "exhausted".) So this works:: - - db = Database() - threads = Query(db,'').search_threads() #get a Threads() object - threadlist = [] - for thread in threads: - threadlist.append(thread) - - # threads is "exhausted" now and even len(threads) will raise an - # exception. - # However it will be kept around until all retrieved Thread() objects are - # also deleted. If you did e.g. an explicit del(threads) here, the - # following lines would fail. - - # You can reiterate over *threadlist* however as often as you want. - # It is simply a list with Thread objects. - - print (threadlist[0].get_thread_id()) - print (threadlist[1].get_thread_id()) - print (threadlist[0].get_total_messages()) - """ - - #notmuch_threads_get - _get = nmlib.notmuch_threads_get - _get.argtypes = [NotmuchThreadsP] - _get.restype = NotmuchThreadP - - def __init__(self, threads_p, parent=None): - """ - :param threads_p: A pointer to an underlying *notmuch_threads_t* - structure. These are not publically exposed, so a user - will almost never instantiate a :class:`Threads` object - herself. They are usually handed back as a result, - e.g. in :meth:`Query.search_threads`. *threads_p* must be - valid, we will raise an :exc:`NullPointerError` if it is - `None`. - :type threads_p: :class:`ctypes.c_void_p` - :param parent: The parent object - (ie :class:`Query`) these tags are derived from. It saves - a reference to it, so we can automatically delete the db - object once all derived objects are dead. - :TODO: Make the iterator work more than once and cache the tags in - the Python object.(?) - """ - if not threads_p: - raise NullPointerError() - - self._threads = threads_p - #store parent, so we keep them alive as long as self is alive - self._parent = parent - - def __iter__(self): - """ 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 not self._threads: - raise NotInitializedError() - - if not self._valid(self._threads): - self._threads = None - raise StopIteration - - thread = Thread(Threads._get(self._threads), self) - self._move_to_next(self._threads) - return thread - next = __next__ # python2.x iterator protocol compatibility - - def __len__(self): - """len(:class:`Threads`) returns the number of contained Threads - - .. note:: As this iterates over the threads, we will not be able to - iterate over them again! So this will fail:: - - #THIS FAILS - threads = Database().create_query('').search_threads() - if len(threads) > 0: #this 'exhausts' threads - # next line raises :exc:`NotInitializedError`!!! - for thread in threads: print thread - """ - if not self._threads: - raise NotInitializedError() - - i = 0 - # returns 'bool'. On out-of-memory it returns None - while self._valid(self._threads): - self._move_to_next(self._threads) - i += 1 - # reset self._threads to mark as "exhausted" - self._threads = None - return i - - def __nonzero__(self): - """Check if :class:`Threads` contains at least one more valid thread - - The existence of this function makes 'if Threads: foo' work, as - that will implicitely call len() exhausting the iterator if - __nonzero__ does not exist. This function makes `bool(Threads())` - work repeatedly. - - :return: True if there is at least one more thread in the - Iterator, False if not. None on a "Out-of-memory" error. - """ - return self._threads is not None and \ - 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: - self._destroy(self._threads) - - class Thread(object): """Represents a single message thread.""" diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py new file mode 100644 index 0000000..9d305e2 --- /dev/null +++ b/bindings/python/notmuch/threads.py @@ -0,0 +1,178 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth ' +""" + +from notmuch.globals import ( + nmlib, + Python3StringMixIn, + NullPointerError, + NotInitializedError, + NotmuchThreadP, + NotmuchThreadsP, +) +from .thread import Thread + +class Threads(Python3StringMixIn): + """Represents a list of notmuch threads + + This object provides an iterator over a list of notmuch threads + (Technically, it provides a wrapper for the underlying + *notmuch_threads_t* structure). Do note that the underlying + library only provides a one-time iterator (it cannot reset the + iterator to the start). Thus iterating over the function will + "exhaust" the list of threads, and a subsequent iteration attempt + will raise a :exc:`NotInitializedError`. Also + note, that any function that uses iteration will also + exhaust the messages. So both:: + + for thread in threads: print thread + + as well as:: + + number_of_msgs = len(threads) + + will "exhaust" the threads. If you need to re-iterate over a list of + messages you will need to retrieve a new :class:`Threads` object. + + Things are not as bad as it seems though, you can store and reuse + the single Thread objects as often as you want as long as you + keep the parent Threads object around. (Recall that due to + hierarchical memory allocation, all derived Threads objects will + be invalid when we delete the parent Threads() object, even if it + was already "exhausted".) So this works:: + + db = Database() + threads = Query(db,'').search_threads() #get a Threads() object + threadlist = [] + for thread in threads: + threadlist.append(thread) + + # threads is "exhausted" now and even len(threads) will raise an + # exception. + # However it will be kept around until all retrieved Thread() objects are + # also deleted. If you did e.g. an explicit del(threads) here, the + # following lines would fail. + + # You can reiterate over *threadlist* however as often as you want. + # It is simply a list with Thread objects. + + print (threadlist[0].get_thread_id()) + print (threadlist[1].get_thread_id()) + print (threadlist[0].get_total_messages()) + """ + + #notmuch_threads_get + _get = nmlib.notmuch_threads_get + _get.argtypes = [NotmuchThreadsP] + _get.restype = NotmuchThreadP + + def __init__(self, threads_p, parent=None): + """ + :param threads_p: A pointer to an underlying *notmuch_threads_t* + structure. These are not publically exposed, so a user + will almost never instantiate a :class:`Threads` object + herself. They are usually handed back as a result, + e.g. in :meth:`Query.search_threads`. *threads_p* must be + valid, we will raise an :exc:`NullPointerError` if it is + `None`. + :type threads_p: :class:`ctypes.c_void_p` + :param parent: The parent object + (ie :class:`Query`) these tags are derived from. It saves + a reference to it, so we can automatically delete the db + object once all derived objects are dead. + :TODO: Make the iterator work more than once and cache the tags in + the Python object.(?) + """ + if not threads_p: + raise NullPointerError() + + self._threads = threads_p + #store parent, so we keep them alive as long as self is alive + self._parent = parent + + def __iter__(self): + """ 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 not self._threads: + raise NotInitializedError() + + if not self._valid(self._threads): + self._threads = None + raise StopIteration + + thread = Thread(Threads._get(self._threads), self) + self._move_to_next(self._threads) + return thread + next = __next__ # python2.x iterator protocol compatibility + + def __len__(self): + """len(:class:`Threads`) returns the number of contained Threads + + .. note:: As this iterates over the threads, we will not be able to + iterate over them again! So this will fail:: + + #THIS FAILS + threads = Database().create_query('').search_threads() + if len(threads) > 0: #this 'exhausts' threads + # next line raises :exc:`NotInitializedError`!!! + for thread in threads: print thread + """ + if not self._threads: + raise NotInitializedError() + + i = 0 + # returns 'bool'. On out-of-memory it returns None + while self._valid(self._threads): + self._move_to_next(self._threads) + i += 1 + # reset self._threads to mark as "exhausted" + self._threads = None + return i + + def __nonzero__(self): + """Check if :class:`Threads` contains at least one more valid thread + + The existence of this function makes 'if Threads: foo' work, as + that will implicitely call len() exhausting the iterator if + __nonzero__ does not exist. This function makes `bool(Threads())` + work repeatedly. + + :return: True if there is at least one more thread in the + Iterator, False if not. None on a "Out-of-memory" error. + """ + return self._threads is not None and \ + 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: + self._destroy(self._threads) -- cgit v1.2.3 From df0e1cf7884f93bbbf70786d0bffc45824ae01c1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 22 Feb 2012 22:44:35 +0100 Subject: python: rename filename.py into filenames.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/__init__.py | 2 +- bindings/python/notmuch/directory.py | 2 +- bindings/python/notmuch/filename.py | 167 ----------------------------------- bindings/python/notmuch/filenames.py | 167 +++++++++++++++++++++++++++++++++++ bindings/python/notmuch/message.py | 2 +- 5 files changed, 170 insertions(+), 170 deletions(-) delete mode 100644 bindings/python/notmuch/filename.py create mode 100644 bindings/python/notmuch/filenames.py (limited to 'bindings') diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index 89b9849..fddc492 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -53,7 +53,7 @@ Copyright 2010-2011 Sebastian Spaeth """ from .database import Database from .directory import Directory -from .filename import Filenames +from .filenames import Filenames from .message import Message from .messages import Messages from .query import Query diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index 3e0763f..b679aa2 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -26,7 +26,7 @@ from notmuch.globals import ( NotmuchDirectoryP, NotmuchFilenamesP ) -from .filename import Filenames +from .filenames import Filenames class Directory(object): """Represents a directory entry in the notmuch directory diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py deleted file mode 100644 index 232a9ed..0000000 --- a/bindings/python/notmuch/filename.py +++ /dev/null @@ -1,167 +0,0 @@ -""" -This file is part of notmuch. - -Notmuch is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation, either version 3 of the License, or (at your -option) any later version. - -Notmuch is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with notmuch. If not, see . - -Copyright 2010 Sebastian Spaeth ' -""" -from ctypes import c_char_p -from notmuch.globals import ( - nmlib, - NullPointerError, - NotInitializedError, - NotmuchMessageP, - NotmuchFilenamesP, - Python3StringMixIn, -) - - -class Filenames(Python3StringMixIn): - """Represents a list of filenames as returned by notmuch - - This object contains the Filenames iterator. The main function is - as_generator() which will return a generator so we can do a Filenamesth an - iterator over a list of notmuch filenames. Do note that the underlying - library only provides a one-time iterator (it cannot reset the iterator to - the start). Thus iterating over the function will "exhaust" the list of - tags, and a subsequent iteration attempt will raise a - :exc:`NotInitializedError`. Also note, that any function that uses - iteration (nearly all) will also exhaust the tags. So both:: - - for name in filenames: print name - - as well as:: - - number_of_names = len(names) - - and even a simple:: - - #str() iterates over all tags to construct a space separated list - print(str(filenames)) - - will "exhaust" the Filenames. However, you can use - :meth:`Message.get_filenames` repeatedly to get fresh Filenames - objects to perform various actions on filenames. - """ - - #notmuch_filenames_get - _get = nmlib.notmuch_filenames_get - _get.argtypes = [NotmuchFilenamesP] - _get.restype = c_char_p - - def __init__(self, files_p, parent): - """ - :param files_p: A pointer to an underlying *notmuch_tags_t* - structure. These are not publically exposed, so a user - will almost never instantiate a :class:`Tags` object - herself. They are usually handed back as a result, - e.g. in :meth:`Database.get_all_tags`. *tags_p* must be - valid, we will raise an :exc:`NullPointerError` - if it is `None`. - :type files_p: :class:`ctypes.c_void_p` - :param parent: The parent object (ie :class:`Message` these - filenames are derived from, and saves a - reference to it, so we can automatically delete the db object - once all derived objects are dead. - """ - if not files_p: - raise NullPointerError() - - self._files_p = files_p - #save reference to parent object so we keep it alive - self._parent = parent - - def __iter__(self): - """ 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 not self._files_p: - raise NotInitializedError() - - if not self._valid(self._files_p): - self._files_p = None - raise StopIteration - - file_ = Filenames._get(self._files_p) - self._move_to_next(self._files_p) - return file_.decode('utf-8', 'ignore') - next = __next__ # python2.x iterator protocol compatibility - - def as_generator(self): - """Return generator of Filenames - - This is the main function that will usually be used by the - user. - - .. deprecated:: 0.12 - :class:`Filenames` objects implement the - iterator protocol. - """ - return self - - def __unicode__(self): - """Represent Filenames() as newline-separated list of full paths - - .. note:: As this iterates over the filenames, we will not be - able to iterate over them again (as in retrieve them)! If - the tags have been exhausted already, this will raise a - :exc:`NotInitializedError` on subsequent - attempts. However, you can use - :meth:`Message.get_filenames` repeatedly to perform - various actions on filenames. - """ - 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_p is not None: - self._destroy(self._files_p) - - def __len__(self): - """len(:class:`Filenames`) returns the number of contained files - - .. note:: - - As this iterates over the files, we will not be able to - iterate over them again! So this will fail:: - - #THIS FAILS - files = Database().get_directory('').get_child_files() - if len(files) > 0: # this 'exhausts' msgs - # next line raises - # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) - for file in files: print file - """ - if not self._files_p: - raise NotInitializedError() - - i = 0 - while self._valid(self._files_p): - self._move_to_next(self._files_p) - i += 1 - self._files_p = None - return i diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py new file mode 100644 index 0000000..232a9ed --- /dev/null +++ b/bindings/python/notmuch/filenames.py @@ -0,0 +1,167 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth ' +""" +from ctypes import c_char_p +from notmuch.globals import ( + nmlib, + NullPointerError, + NotInitializedError, + NotmuchMessageP, + NotmuchFilenamesP, + Python3StringMixIn, +) + + +class Filenames(Python3StringMixIn): + """Represents a list of filenames as returned by notmuch + + This object contains the Filenames iterator. The main function is + as_generator() which will return a generator so we can do a Filenamesth an + iterator over a list of notmuch filenames. Do note that the underlying + library only provides a one-time iterator (it cannot reset the iterator to + the start). Thus iterating over the function will "exhaust" the list of + tags, and a subsequent iteration attempt will raise a + :exc:`NotInitializedError`. Also note, that any function that uses + iteration (nearly all) will also exhaust the tags. So both:: + + for name in filenames: print name + + as well as:: + + number_of_names = len(names) + + and even a simple:: + + #str() iterates over all tags to construct a space separated list + print(str(filenames)) + + will "exhaust" the Filenames. However, you can use + :meth:`Message.get_filenames` repeatedly to get fresh Filenames + objects to perform various actions on filenames. + """ + + #notmuch_filenames_get + _get = nmlib.notmuch_filenames_get + _get.argtypes = [NotmuchFilenamesP] + _get.restype = c_char_p + + def __init__(self, files_p, parent): + """ + :param files_p: A pointer to an underlying *notmuch_tags_t* + structure. These are not publically exposed, so a user + will almost never instantiate a :class:`Tags` object + herself. They are usually handed back as a result, + e.g. in :meth:`Database.get_all_tags`. *tags_p* must be + valid, we will raise an :exc:`NullPointerError` + if it is `None`. + :type files_p: :class:`ctypes.c_void_p` + :param parent: The parent object (ie :class:`Message` these + filenames are derived from, and saves a + reference to it, so we can automatically delete the db object + once all derived objects are dead. + """ + if not files_p: + raise NullPointerError() + + self._files_p = files_p + #save reference to parent object so we keep it alive + self._parent = parent + + def __iter__(self): + """ 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 not self._files_p: + raise NotInitializedError() + + if not self._valid(self._files_p): + self._files_p = None + raise StopIteration + + file_ = Filenames._get(self._files_p) + self._move_to_next(self._files_p) + return file_.decode('utf-8', 'ignore') + next = __next__ # python2.x iterator protocol compatibility + + def as_generator(self): + """Return generator of Filenames + + This is the main function that will usually be used by the + user. + + .. deprecated:: 0.12 + :class:`Filenames` objects implement the + iterator protocol. + """ + return self + + def __unicode__(self): + """Represent Filenames() as newline-separated list of full paths + + .. note:: As this iterates over the filenames, we will not be + able to iterate over them again (as in retrieve them)! If + the tags have been exhausted already, this will raise a + :exc:`NotInitializedError` on subsequent + attempts. However, you can use + :meth:`Message.get_filenames` repeatedly to perform + various actions on filenames. + """ + 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_p is not None: + self._destroy(self._files_p) + + def __len__(self): + """len(:class:`Filenames`) returns the number of contained files + + .. note:: + + As this iterates over the files, we will not be able to + iterate over them again! So this will fail:: + + #THIS FAILS + files = Database().get_directory('').get_child_files() + if len(files) > 0: # this 'exhausts' msgs + # next line raises + # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) + for file in files: print file + """ + if not self._files_p: + raise NotInitializedError() + + i = 0 + while self._valid(self._files_p): + self._move_to_next(self._files_p) + i += 1 + self._files_p = None + return i diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 20ba9cb..d17b9bc 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -36,7 +36,7 @@ from .globals import ( NotmuchFilenamesP, ) from .tag import Tags -from .filename import Filenames +from .filenames import Filenames import email try: -- cgit v1.2.3 From a7561cc20b17669784c3259afcbcef98029f93e9 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 23 Feb 2012 00:11:22 +0100 Subject: python: move the exception classes into error.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/__init__.py | 4 +- bindings/python/notmuch/database.py | 14 +-- bindings/python/notmuch/directory.py | 6 +- bindings/python/notmuch/errors.py | 183 +++++++++++++++++++++++++++++++++++ bindings/python/notmuch/filenames.py | 6 +- bindings/python/notmuch/globals.py | 160 +----------------------------- bindings/python/notmuch/message.py | 10 +- bindings/python/notmuch/messages.py | 6 +- bindings/python/notmuch/query.py | 2 + bindings/python/notmuch/tag.py | 4 +- bindings/python/notmuch/thread.py | 6 +- bindings/python/notmuch/threads.py | 6 +- 12 files changed, 225 insertions(+), 182 deletions(-) create mode 100644 bindings/python/notmuch/errors.py (limited to 'bindings') diff --git a/bindings/python/notmuch/__init__.py b/bindings/python/notmuch/__init__.py index fddc492..5561624 100644 --- a/bindings/python/notmuch/__init__.py +++ b/bindings/python/notmuch/__init__.py @@ -60,8 +60,8 @@ from .query import Query from .tag import Tags from .thread import Thread from .threads import Threads -from .globals import ( - nmlib, +from .globals import nmlib +from .errors import ( STATUS, NotmuchError, OutOfMemoryError, diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 800264b..44d40fd 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -22,12 +22,6 @@ import codecs from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER from notmuch.globals import ( nmlib, - STATUS, - FileError, - NotmuchError, - NullPointerError, - NotInitializedError, - ReadOnlyDatabaseError, Enum, _str, NotmuchDatabaseP, @@ -35,6 +29,14 @@ from notmuch.globals import ( NotmuchMessageP, NotmuchTagsP, ) +from .errors import ( + STATUS, + FileError, + NotmuchError, + NullPointerError, + NotInitializedError, + ReadOnlyDatabaseError, +) from notmuch.message import Message from notmuch.tag import Tags from .query import Query diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index b679aa2..0c5e015 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -20,11 +20,13 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_uint, c_long from notmuch.globals import ( nmlib, + NotmuchDirectoryP, + NotmuchFilenamesP +) +from .errors import ( STATUS, NotmuchError, NotInitializedError, - NotmuchDirectoryP, - NotmuchFilenamesP ) from .filenames import Filenames diff --git a/bindings/python/notmuch/errors.py b/bindings/python/notmuch/errors.py new file mode 100644 index 0000000..f153a9c --- /dev/null +++ b/bindings/python/notmuch/errors.py @@ -0,0 +1,183 @@ +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth +""" + +from ctypes import c_char_p, c_int + +from .globals import ( + nmlib, + Enum, + Python3StringMixIn, +) + +class Status(Enum): + """Enum with a string representation of a notmuch_status_t value.""" + _status2str = nmlib.notmuch_status_to_string + _status2str.restype = c_char_p + _status2str.argtypes = [c_int] + + def __init__(self, statuslist): + """It is initialized with a list of strings that are available as + Status().string1 - Status().stringn attributes. + """ + super(Status, self).__init__(statuslist) + + @classmethod + def status2str(self, status): + """Get a (unicode) string representation of a notmuch_status_t value.""" + # define strings for custom error messages + if status == STATUS.NOT_INITIALIZED: + return "Operation on uninitialized object impossible." + return unicode(Status._status2str(status)) + +STATUS = Status(['SUCCESS', + 'OUT_OF_MEMORY', + 'READ_ONLY_DATABASE', + 'XAPIAN_EXCEPTION', + 'FILE_ERROR', + 'FILE_NOT_EMAIL', + 'DUPLICATE_MESSAGE_ID', + 'NULL_POINTER', + 'TAG_TOO_LONG', + 'UNBALANCED_FREEZE_THAW', + 'UNBALANCED_ATOMIC', + 'NOT_INITIALIZED']) +"""STATUS is a class, whose attributes provide constants that serve as return +indicators for notmuch functions. Currently the following ones are defined. For +possible return values and specific meaning for each method, see the method +description. + + * SUCCESS + * OUT_OF_MEMORY + * READ_ONLY_DATABASE + * XAPIAN_EXCEPTION + * FILE_ERROR + * FILE_NOT_EMAIL + * DUPLICATE_MESSAGE_ID + * NULL_POINTER + * TAG_TOO_LONG + * UNBALANCED_FREEZE_THAW + * UNBALANCED_ATOMIC + * NOT_INITIALIZED + +Invoke the class method `notmuch.STATUS.status2str` with a status value as +argument to receive a human readable string""" +STATUS.__name__ = 'STATUS' + + +class NotmuchError(Exception, Python3StringMixIn): + """Is initiated with a (notmuch.STATUS[, message=None]). It will not + return an instance of the class NotmuchError, but a derived instance + of a more specific Error Message, e.g. OutOfMemoryError. Each status + but SUCCESS has a corresponding subclassed Exception.""" + + @classmethod + def get_exc_subclass(cls, status): + """Returns a fine grained Exception() type, + detailing the error status""" + subclasses = { + STATUS.OUT_OF_MEMORY: OutOfMemoryError, + STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError, + STATUS.XAPIAN_EXCEPTION: XapianError, + STATUS.FILE_ERROR: FileError, + STATUS.FILE_NOT_EMAIL: FileNotEmailError, + STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError, + STATUS.NULL_POINTER: NullPointerError, + STATUS.TAG_TOO_LONG: TagTooLongError, + STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError, + STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError, + STATUS.NOT_INITIALIZED: NotInitializedError, + } + assert 0 < status <= len(subclasses) + return subclasses[status] + + def __new__(cls, *args, **kwargs): + """Return a correct subclass of NotmuchError if needed + + We return a NotmuchError instance if status is None (or 0) and a + subclass that inherits from NotmuchError depending on the + 'status' parameter otherwise.""" + # get 'status'. Passed in as arg or kwarg? + status = args[0] if len(args) else kwargs.get('status', None) + # no 'status' or cls is subclass already, return 'cls' instance + if not status or cls != NotmuchError: + return super(NotmuchError, cls).__new__(cls) + subclass = cls.get_exc_subclass(status) # which class to use? + return subclass.__new__(subclass, *args, **kwargs) + + def __init__(self, status=None, message=None): + self.status = status + self.message = message + + def __unicode__(self): + if self.message is not None: + return self.message + elif self.status is not None: + return STATUS.status2str(self.status) + else: + return 'Unknown error' + + +# List of Subclassed exceptions that correspond to STATUS values and are +# subclasses of NotmuchError. +class OutOfMemoryError(NotmuchError): + status = STATUS.OUT_OF_MEMORY + + +class ReadOnlyDatabaseError(NotmuchError): + status = STATUS.READ_ONLY_DATABASE + + +class XapianError(NotmuchError): + status = STATUS.XAPIAN_EXCEPTION + + +class FileError(NotmuchError): + status = STATUS.FILE_ERROR + + +class FileNotEmailError(NotmuchError): + status = STATUS.FILE_NOT_EMAIL + + +class DuplicateMessageIdError(NotmuchError): + status = STATUS.DUPLICATE_MESSAGE_ID + + +class NullPointerError(NotmuchError): + status = STATUS.NULL_POINTER + + +class TagTooLongError(NotmuchError): + status = STATUS.TAG_TOO_LONG + + +class UnbalancedFreezeThawError(NotmuchError): + status = STATUS.UNBALANCED_FREEZE_THAW + + +class UnbalancedAtomicError(NotmuchError): + status = STATUS.UNBALANCED_ATOMIC + + +class NotInitializedError(NotmuchError): + """Derived from NotmuchError, this occurs if the underlying data + structure (e.g. database is not initialized (yet) or an iterator has + been exhausted. You can test for NotmuchError with .status = + STATUS.NOT_INITIALIZED""" + status = STATUS.NOT_INITIALIZED diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index 232a9ed..12050df 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -19,12 +19,14 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p from notmuch.globals import ( nmlib, - NullPointerError, - NotInitializedError, NotmuchMessageP, NotmuchFilenamesP, Python3StringMixIn, ) +from .errors import ( + NullPointerError, + NotInitializedError, +) class Filenames(Python3StringMixIn): diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index 4138460..442f3e3 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -17,7 +17,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth ' """ import sys -from ctypes import CDLL, c_char_p, c_int, Structure, POINTER +from ctypes import CDLL, Structure, POINTER #----------------------------------------------------------------------------- #package-global instance of the notmuch library @@ -66,164 +66,6 @@ class Enum(object): setattr(self, name, number) -class Status(Enum): - """Enum with a string representation of a notmuch_status_t value.""" - _status2str = nmlib.notmuch_status_to_string - _status2str.restype = c_char_p - _status2str.argtypes = [c_int] - - def __init__(self, statuslist): - """It is initialized with a list of strings that are available as - Status().string1 - Status().stringn attributes. - """ - super(Status, self).__init__(statuslist) - - @classmethod - def status2str(self, status): - """Get a (unicode) string representation of a notmuch_status_t value.""" - # define strings for custom error messages - if status == STATUS.NOT_INITIALIZED: - return "Operation on uninitialized object impossible." - return unicode(Status._status2str(status)) - -STATUS = Status(['SUCCESS', - 'OUT_OF_MEMORY', - 'READ_ONLY_DATABASE', - 'XAPIAN_EXCEPTION', - 'FILE_ERROR', - 'FILE_NOT_EMAIL', - 'DUPLICATE_MESSAGE_ID', - 'NULL_POINTER', - 'TAG_TOO_LONG', - 'UNBALANCED_FREEZE_THAW', - 'UNBALANCED_ATOMIC', - 'NOT_INITIALIZED']) -"""STATUS is a class, whose attributes provide constants that serve as return -indicators for notmuch functions. Currently the following ones are defined. For -possible return values and specific meaning for each method, see the method -description. - - * SUCCESS - * OUT_OF_MEMORY - * READ_ONLY_DATABASE - * XAPIAN_EXCEPTION - * FILE_ERROR - * FILE_NOT_EMAIL - * DUPLICATE_MESSAGE_ID - * NULL_POINTER - * TAG_TOO_LONG - * UNBALANCED_FREEZE_THAW - * UNBALANCED_ATOMIC - * NOT_INITIALIZED - -Invoke the class method `notmuch.STATUS.status2str` with a status value as -argument to receive a human readable string""" -STATUS.__name__ = 'STATUS' - - -class NotmuchError(Exception, Python3StringMixIn): - """Is initiated with a (notmuch.STATUS[, message=None]). It will not - return an instance of the class NotmuchError, but a derived instance - of a more specific Error Message, e.g. OutOfMemoryError. Each status - but SUCCESS has a corresponding subclassed Exception.""" - - @classmethod - def get_exc_subclass(cls, status): - """Returns a fine grained Exception() type, - detailing the error status""" - subclasses = { - STATUS.OUT_OF_MEMORY: OutOfMemoryError, - STATUS.READ_ONLY_DATABASE: ReadOnlyDatabaseError, - STATUS.XAPIAN_EXCEPTION: XapianError, - STATUS.FILE_ERROR: FileError, - STATUS.FILE_NOT_EMAIL: FileNotEmailError, - STATUS.DUPLICATE_MESSAGE_ID: DuplicateMessageIdError, - STATUS.NULL_POINTER: NullPointerError, - STATUS.TAG_TOO_LONG: TagTooLongError, - STATUS.UNBALANCED_FREEZE_THAW: UnbalancedFreezeThawError, - STATUS.UNBALANCED_ATOMIC: UnbalancedAtomicError, - STATUS.NOT_INITIALIZED: NotInitializedError, - } - assert 0 < status <= len(subclasses) - return subclasses[status] - - def __new__(cls, *args, **kwargs): - """Return a correct subclass of NotmuchError if needed - - We return a NotmuchError instance if status is None (or 0) and a - subclass that inherits from NotmuchError depending on the - 'status' parameter otherwise.""" - # get 'status'. Passed in as arg or kwarg? - status = args[0] if len(args) else kwargs.get('status', None) - # no 'status' or cls is subclass already, return 'cls' instance - if not status or cls != NotmuchError: - return super(NotmuchError, cls).__new__(cls) - subclass = cls.get_exc_subclass(status) # which class to use? - return subclass.__new__(subclass, *args, **kwargs) - - def __init__(self, status=None, message=None): - self.status = status - self.message = message - - def __unicode__(self): - if self.message is not None: - return self.message - elif self.status is not None: - return STATUS.status2str(self.status) - else: - return 'Unknown error' - - -# List of Subclassed exceptions that correspond to STATUS values and are -# subclasses of NotmuchError. -class OutOfMemoryError(NotmuchError): - status = STATUS.OUT_OF_MEMORY - - -class ReadOnlyDatabaseError(NotmuchError): - status = STATUS.READ_ONLY_DATABASE - - -class XapianError(NotmuchError): - status = STATUS.XAPIAN_EXCEPTION - - -class FileError(NotmuchError): - status = STATUS.FILE_ERROR - - -class FileNotEmailError(NotmuchError): - status = STATUS.FILE_NOT_EMAIL - - -class DuplicateMessageIdError(NotmuchError): - status = STATUS.DUPLICATE_MESSAGE_ID - - -class NullPointerError(NotmuchError): - status = STATUS.NULL_POINTER - - -class TagTooLongError(NotmuchError): - status = STATUS.TAG_TOO_LONG - - -class UnbalancedFreezeThawError(NotmuchError): - status = STATUS.UNBALANCED_FREEZE_THAW - - -class UnbalancedAtomicError(NotmuchError): - status = STATUS.UNBALANCED_ATOMIC - - -class NotInitializedError(NotmuchError): - """Derived from NotmuchError, this occurs if the underlying data - structure (e.g. database is not initialized (yet) or an iterator has - been exhausted. You can test for NotmuchError with .status = - STATUS.NOT_INITIALIZED""" - status = STATUS.NOT_INITIALIZED - - class NotmuchDatabaseS(Structure): pass NotmuchDatabaseP = POINTER(NotmuchDatabaseS) diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index d17b9bc..9eb4fee 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -26,15 +26,17 @@ from .globals import ( Enum, _str, Python3StringMixIn, - STATUS, - NotmuchError, - NullPointerError, - NotInitializedError, NotmuchTagsP, NotmuchMessageP, NotmuchMessagesP, NotmuchFilenamesP, ) +from .errors import ( + STATUS, + NotmuchError, + NullPointerError, + NotInitializedError, +) from .tag import Tags from .filenames import Filenames diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index 20d3632..d94f91b 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -20,12 +20,14 @@ Copyright 2010 Sebastian Spaeth ' from .globals import ( nmlib, - NullPointerError, - NotInitializedError, NotmuchTagsP, NotmuchMessageP, NotmuchMessagesP, ) +from .errors import ( + NullPointerError, + NotInitializedError, +) from .tag import Tags from .message import Message diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index fcd67e5..ddaf8e0 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -26,6 +26,8 @@ from notmuch.globals import ( NotmuchThreadsP, NotmuchDatabaseP, NotmuchMessagesP, +) +from .errors import ( NullPointerError, NotInitializedError, ) diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 526e51c..711bf53 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -20,9 +20,11 @@ from ctypes import c_char_p from notmuch.globals import ( nmlib, Python3StringMixIn, + NotmuchTagsP, +) +from .errors import ( NullPointerError, NotInitializedError, - NotmuchTagsP, ) diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 0dac522..a759c90 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -20,12 +20,14 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p, c_long, c_int from notmuch.globals import ( nmlib, - NullPointerError, - NotInitializedError, NotmuchThreadP, NotmuchMessagesP, NotmuchTagsP, ) +from .errors import ( + NullPointerError, + NotInitializedError, +) from .messages import Messages from notmuch.tag import Tags from datetime import date diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index 9d305e2..690206e 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -20,11 +20,13 @@ Copyright 2010 Sebastian Spaeth ' from notmuch.globals import ( nmlib, Python3StringMixIn, - NullPointerError, - NotInitializedError, NotmuchThreadP, NotmuchThreadsP, ) +from .errors import ( + NullPointerError, + NotInitializedError, +) from .thread import Thread class Threads(Python3StringMixIn): -- cgit v1.2.3 From 90fb4e8334e043201dfb30f47c072ab9ebb662e1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 23 Feb 2012 00:14:59 +0100 Subject: python: mention the exception class refactoring in the docs Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/status_and_errors.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'bindings') diff --git a/bindings/python/docs/source/status_and_errors.rst b/bindings/python/docs/source/status_and_errors.rst index bc0d0d2..dd6e31f 100644 --- a/bindings/python/docs/source/status_and_errors.rst +++ b/bindings/python/docs/source/status_and_errors.rst @@ -5,6 +5,12 @@ Status and Errors Some methods return a status, indicating if an operation was successful and what the error was. Most of these status codes are expressed as a specific value, the :class:`notmuch.STATUS`. +.. note:: + + Prior to version 0.12 the exception classes and the enumeration + :class:`notmuch.STATUS` were defined in `notmuch.globals`. They + have since then been moved into `notmuch.errors`. + :class:`STATUS` -- Notmuch operation return value -------------------------------------------------- -- cgit v1.2.3 From fb52083bf7eff44f27b2f2fffcbfbcb4faaeda3c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 24 Feb 2012 00:38:47 +0100 Subject: python: strip module prefix in the sphinx documentation Remove the notmuch prefix from classes in the documentation. This change makes the table of contents look much nicer. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index e87a865..fc3179b 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -42,10 +42,10 @@ More information on specific topics can be found on the following pages: .. automodule:: notmuch -:class:`notmuch.Database` -- The underlying notmuch database +:class:`Database` -- The underlying notmuch database --------------------------------------------------------------------- -.. autoclass:: notmuch.Database([path=None[, create=False[, mode=MODE.READ_ONLY]]]) +.. autoclass:: Database([path=None[, create=False[, mode=MODE.READ_ONLY]]]) .. automethod:: create @@ -90,10 +90,10 @@ More information on specific topics can be found on the following pages: .. autoattribute:: db_p -:class:`notmuch.Query` -- A search query +:class:`Query` -- A search query ------------------------------------------------- -.. autoclass:: notmuch.Query +.. autoclass:: Query .. automethod:: create @@ -216,10 +216,10 @@ More information on specific topics can be found on the following pages: .. automethod:: __str__ -:class:`notmuch.Threads` -- Threads iterator +:class:`Threads` -- Threads iterator ----------------------------------------------------- -.. autoclass:: notmuch.Threads +.. autoclass:: Threads .. automethod:: __len__ @@ -254,28 +254,28 @@ More information on specific topics can be found on the following pages: :class:`Filenames` -- An iterator over filenames ------------------------------------------------ -.. autoclass:: notmuch.Filenames +.. autoclass:: Filenames - .. automethod:: notmuch.Filenames.__len__ + .. automethod:: Filenames.__len__ - .. automethod:: notmuch.Filenames.as_generator + .. automethod:: Filenames.as_generator -:class:`notmuch.database.Directoy` -- A directory entry in the database +:class:`Directoy` -- A directory entry in the database ------------------------------------------------------------------------ -.. autoclass:: notmuch.Directory +.. autoclass:: Directory - .. automethod:: notmuch.Directory.get_child_files + .. automethod:: Directory.get_child_files - .. automethod:: notmuch.Directory.get_child_directories + .. automethod:: Directory.get_child_directories - .. automethod:: notmuch.Directory.get_mtime + .. automethod:: Directory.get_mtime - .. automethod:: notmuch.Directory.set_mtime + .. automethod:: Directory.set_mtime - .. autoattribute:: notmuch.Directory.mtime + .. autoattribute:: Directory.mtime - .. autoattribute:: notmuch.Directory.path + .. autoattribute:: Directory.path The `next page `_ contains information on possible Status and Error values. -- cgit v1.2.3 From 8dfbba05fa43013e9c97d94246c167c3d64a9d50 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 24 Feb 2012 01:18:54 +0100 Subject: python: move the usage example to quickstart.rst Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 14 +------------- bindings/python/docs/source/quickstart.rst | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 bindings/python/docs/source/quickstart.rst (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index fc3179b..dec9697 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -15,25 +15,13 @@ Within :mod:`notmuch`, the classes :class:`Database`, :class:`Query` provide mos This page contains the main API overview of notmuch |release|. -Notmuch can be imported as:: - - import notmuch - -or:: - - from notmuch import Query, Database - - db = Database('path',create=True) - msgs = Query(db,'from:myself').search_messages() - - for msg in msgs: - print (msg) More information on specific topics can be found on the following pages: .. toctree:: :maxdepth: 1 + quickstart status_and_errors notmuch diff --git a/bindings/python/docs/source/quickstart.rst b/bindings/python/docs/source/quickstart.rst new file mode 100644 index 0000000..609f42e --- /dev/null +++ b/bindings/python/docs/source/quickstart.rst @@ -0,0 +1,19 @@ +Quickstart and examples +======================= + +.. todo:: write a nice introduction +.. todo:: improve the examples + +Notmuch can be imported as:: + + import notmuch + +or:: + + from notmuch import Query, Database + + db = Database('path', create=True) + msgs = Query(db, 'from:myself').search_messages() + + for msg in msgs: + print(msg) -- cgit v1.2.3 From 594dbb62432bd7f92d1e121145b80628eb8aad2a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 24 Feb 2012 01:30:04 +0100 Subject: python: move the notmuch module section to notes.rst Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 6 +----- bindings/python/docs/source/notes.rst | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 bindings/python/docs/source/notes.rst (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index dec9697..a2b42aa 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -22,14 +22,10 @@ More information on specific topics can be found on the following pages: :maxdepth: 1 quickstart + notes status_and_errors notmuch -:mod:`notmuch` -- The Notmuch interface -================================================= - -.. automodule:: notmuch - :class:`Database` -- The underlying notmuch database --------------------------------------------------------------------- diff --git a/bindings/python/docs/source/notes.rst b/bindings/python/docs/source/notes.rst new file mode 100644 index 0000000..a792748 --- /dev/null +++ b/bindings/python/docs/source/notes.rst @@ -0,0 +1,6 @@ +Interfacing with notmuch +======================== + +.. todo:: move the note about talloc out of the code + +.. automodule:: notmuch -- cgit v1.2.3 From d50171d1cc575a41bf620c55853ade65d0edfad8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 24 Feb 2012 01:34:15 +0100 Subject: python: split the documentation Move each classes documentation into its own file and thus into its own page in the generated documentation. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/database.rst | 48 ++++++ bindings/python/docs/source/filesystem.rst | 30 ++++ bindings/python/docs/source/index.rst | 267 ++--------------------------- bindings/python/docs/source/message.rst | 54 ++++++ bindings/python/docs/source/messages.rst | 15 ++ bindings/python/docs/source/query.rst | 41 +++++ bindings/python/docs/source/tags.rst | 17 ++ bindings/python/docs/source/thread.rst | 26 +++ bindings/python/docs/source/threads.rst | 10 ++ 9 files changed, 257 insertions(+), 251 deletions(-) create mode 100644 bindings/python/docs/source/database.rst create mode 100644 bindings/python/docs/source/filesystem.rst create mode 100644 bindings/python/docs/source/message.rst create mode 100644 bindings/python/docs/source/messages.rst create mode 100644 bindings/python/docs/source/query.rst create mode 100644 bindings/python/docs/source/tags.rst create mode 100644 bindings/python/docs/source/thread.rst create mode 100644 bindings/python/docs/source/threads.rst (limited to 'bindings') diff --git a/bindings/python/docs/source/database.rst b/bindings/python/docs/source/database.rst new file mode 100644 index 0000000..ee71085 --- /dev/null +++ b/bindings/python/docs/source/database.rst @@ -0,0 +1,48 @@ +:class:`Database` -- The underlying notmuch database +==================================================== + +.. currentmodule:: notmuch + +.. autoclass:: Database([path=None[, create=False[, mode=MODE.READ_ONLY]]]) + + .. automethod:: create + + .. automethod:: open(path, status=MODE.READ_ONLY) + + .. automethod:: get_path + + .. automethod:: get_version + + .. automethod:: needs_upgrade + + .. automethod:: upgrade + + .. automethod:: begin_atomic + + .. automethod:: end_atomic + + .. automethod:: get_directory + + .. automethod:: add_message + + .. automethod:: remove_message + + .. automethod:: find_message + + .. automethod:: find_message_by_filename + + .. automethod:: get_all_tags + + .. automethod:: create_query + + .. attribute:: Database.MODE + + Defines constants that are used as the mode in which to open a database. + + MODE.READ_ONLY + Open the database in read-only mode + + MODE.READ_WRITE + Open the database in read-write mode + + .. autoattribute:: db_p diff --git a/bindings/python/docs/source/filesystem.rst b/bindings/python/docs/source/filesystem.rst new file mode 100644 index 0000000..685dc4d --- /dev/null +++ b/bindings/python/docs/source/filesystem.rst @@ -0,0 +1,30 @@ +Files and directories +===================== + +.. currentmodule:: notmuch + +:class:`Filenames` -- An iterator over filenames +------------------------------------------------ + +.. autoclass:: Filenames + + .. automethod:: Filenames.__len__ + + .. automethod:: Filenames.as_generator + +:class:`Directoy` -- A directory entry in the database +------------------------------------------------------ + +.. autoclass:: Directory + + .. automethod:: Directory.get_child_files + + .. automethod:: Directory.get_child_directories + + .. automethod:: Directory.get_mtime + + .. automethod:: Directory.set_mtime + + .. autoattribute:: Directory.mtime + + .. autoattribute:: Directory.path diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index a2b42aa..9ad5fa9 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -1,272 +1,37 @@ -.. notmuch documentation master file, created by - sphinx-quickstart on Tue Feb 2 10:00:47 2010. +Welcome to :mod:`notmuch`'s documentation +========================================= .. currentmodule:: notmuch -Welcome to :mod:`notmuch`'s documentation -=========================================== - -The :mod:`notmuch` module provides an interface to the `notmuch `_ functionality, directly interfacing to a shared notmuch library. -Within :mod:`notmuch`, the classes :class:`Database`, :class:`Query` provide most of the core functionality, returning :class:`Threads`, :class:`Messages` and :class:`Tags`. +The :mod:`notmuch` module provides an interface to the `notmuch +`_ functionality, directly interfacing to a +shared notmuch library. Within :mod:`notmuch`, the classes +:class:`Database`, :class:`Query` provide most of the core +functionality, returning :class:`Threads`, :class:`Messages` and +:class:`Tags`. .. moduleauthor:: Sebastian Spaeth :License: This module is covered under the GNU GPL v3 (or later). -This page contains the main API overview of notmuch |release|. - - -More information on specific topics can be found on the following pages: - .. toctree:: :maxdepth: 1 quickstart notes status_and_errors + database + query + messages + message + tags + threads + thread + filesystem notmuch -:class:`Database` -- The underlying notmuch database ---------------------------------------------------------------------- - -.. autoclass:: Database([path=None[, create=False[, mode=MODE.READ_ONLY]]]) - - .. automethod:: create - - .. automethod:: open(path, status=MODE.READ_ONLY) - - .. automethod:: get_path - - .. automethod:: get_version - - .. automethod:: needs_upgrade - - .. automethod:: upgrade - - .. automethod:: begin_atomic - - .. automethod:: end_atomic - - .. automethod:: get_directory - - .. automethod:: add_message - - .. automethod:: remove_message - - .. automethod:: find_message - - .. automethod:: find_message_by_filename - - .. automethod:: get_all_tags - - .. automethod:: create_query - - .. attribute:: Database.MODE - - Defines constants that are used as the mode in which to open a database. - - MODE.READ_ONLY - Open the database in read-only mode - - MODE.READ_WRITE - Open the database in read-write mode - - .. autoattribute:: db_p - - -:class:`Query` -- A search query -------------------------------------------------- - -.. autoclass:: Query - - .. automethod:: create - - .. attribute:: Query.SORT - - Defines constants that are used as the mode in which to open a database. - - SORT.OLDEST_FIRST - Sort by message date, oldest first. - - SORT.NEWEST_FIRST - Sort by message date, newest first. - - SORT.MESSAGE_ID - Sort by email message ID. - - SORT.UNSORTED - Do not apply a special sort order (returns results in document id - order). - - .. automethod:: set_sort - - .. attribute:: sort - - Instance attribute :attr:`sort` contains the sort order (see - :attr:`Query.SORT`) if explicitely specified via - :meth:`set_sort`. By default it is set to `None`. - - .. automethod:: search_threads - - .. automethod:: search_messages - - .. automethod:: count_messages - - .. automethod:: count_threads - - -:class:`Messages` -- A bunch of messages ----------------------------------------- - -.. autoclass:: Messages - - .. automethod:: collect_tags - - .. method:: __len__() - - .. warning:: - - :meth:`__len__` was removed in version 0.6 as it exhausted the iterator and broke - list(Messages()). Use the :meth:`Query.count_messages` function or use `len(list(msgs))`. - -:class:`Message` -- A single message ----------------------------------------- - -.. autoclass:: Message - - .. automethod:: get_message_id - - .. automethod:: get_thread_id - - .. automethod:: get_replies - - .. automethod:: get_filename - - .. automethod:: get_filenames - - .. attribute:: FLAG - - FLAG.MATCH - This flag is automatically set by a - Query.search_threads on those messages that match the - query. This allows us to distinguish matches from the rest - of the messages in that thread. - - .. automethod:: get_flag - - .. automethod:: set_flag - - .. automethod:: get_date - - .. automethod:: get_header - - .. automethod:: get_tags - - .. automethod:: maildir_flags_to_tags - - .. automethod:: tags_to_maildir_flags - - .. automethod:: remove_tag - - .. automethod:: add_tag - - .. automethod:: remove_all_tags - - .. automethod:: freeze - - .. automethod:: thaw - - .. automethod:: format_message_as_json - - .. automethod:: format_message_as_text - - .. automethod:: __str__ - - -:class:`Tags` -- Notmuch tags ------------------------------ - -.. autoclass:: Tags - :members: - - .. method:: __len__ - - .. warning:: - - :meth:`__len__` was removed in version 0.6 as it exhausted the iterator and broke - list(Tags()). Use :meth:`len(list(msgs))` instead if you need to know the number of - tags. - - .. automethod:: __str__ - - -:class:`Threads` -- Threads iterator ------------------------------------------------------ - -.. autoclass:: Threads - - .. automethod:: __len__ - - .. automethod:: __str__ - -:class:`Thread` -- A single thread ------------------------------------- - -.. autoclass:: Thread - - .. automethod:: get_thread_id - - .. automethod:: get_total_messages - - .. automethod:: get_toplevel_messages - - .. automethod:: get_matched_messages - - .. automethod:: get_authors - - .. automethod:: get_subject - - .. automethod:: get_oldest_date - - .. automethod:: get_newest_date - - .. automethod:: get_tags - - .. automethod:: __str__ - - -:class:`Filenames` -- An iterator over filenames ------------------------------------------------- - -.. autoclass:: Filenames - - .. automethod:: Filenames.__len__ - - .. automethod:: Filenames.as_generator - -:class:`Directoy` -- A directory entry in the database ------------------------------------------------------------------------- - -.. autoclass:: Directory - - .. automethod:: Directory.get_child_files - - .. automethod:: Directory.get_child_directories - - .. automethod:: Directory.get_mtime - - .. automethod:: Directory.set_mtime - - .. autoattribute:: Directory.mtime - - .. autoattribute:: Directory.path - - -The `next page `_ contains information on possible Status and Error values. - Indices and tables ================== * :ref:`genindex` * :ref:`search` - diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst new file mode 100644 index 0000000..2ae280e --- /dev/null +++ b/bindings/python/docs/source/message.rst @@ -0,0 +1,54 @@ +:class:`Message` -- A single message +==================================== + +.. currentmodule:: notmuch + +.. autoclass:: Message + + .. automethod:: get_message_id + + .. automethod:: get_thread_id + + .. automethod:: get_replies + + .. automethod:: get_filename + + .. automethod:: get_filenames + + .. attribute:: FLAG + + FLAG.MATCH + This flag is automatically set by a + Query.search_threads on those messages that match the + query. This allows us to distinguish matches from the rest + of the messages in that thread. + + .. automethod:: get_flag + + .. automethod:: set_flag + + .. automethod:: get_date + + .. automethod:: get_header + + .. automethod:: get_tags + + .. automethod:: maildir_flags_to_tags + + .. automethod:: tags_to_maildir_flags + + .. automethod:: remove_tag + + .. automethod:: add_tag + + .. automethod:: remove_all_tags + + .. automethod:: freeze + + .. automethod:: thaw + + .. automethod:: format_message_as_json + + .. automethod:: format_message_as_text + + .. automethod:: __str__ diff --git a/bindings/python/docs/source/messages.rst b/bindings/python/docs/source/messages.rst new file mode 100644 index 0000000..3ccf505 --- /dev/null +++ b/bindings/python/docs/source/messages.rst @@ -0,0 +1,15 @@ +:class:`Messages` -- A bunch of messages +======================================== + +.. currentmodule:: notmuch + +.. autoclass:: Messages + + .. automethod:: collect_tags + + .. method:: __len__() + + .. warning:: + + :meth:`__len__` was removed in version 0.6 as it exhausted the iterator and broke + list(Messages()). Use the :meth:`Query.count_messages` function or use `len(list(msgs))`. diff --git a/bindings/python/docs/source/query.rst b/bindings/python/docs/source/query.rst new file mode 100644 index 0000000..ddfc348 --- /dev/null +++ b/bindings/python/docs/source/query.rst @@ -0,0 +1,41 @@ +:class:`Query` -- A search query +================================ + +.. currentmodule:: notmuch + +.. autoclass:: Query + + .. automethod:: create + + .. attribute:: Query.SORT + + Defines constants that are used as the mode in which to open a database. + + SORT.OLDEST_FIRST + Sort by message date, oldest first. + + SORT.NEWEST_FIRST + Sort by message date, newest first. + + SORT.MESSAGE_ID + Sort by email message ID. + + SORT.UNSORTED + Do not apply a special sort order (returns results in document id + order). + + .. automethod:: set_sort + + .. attribute:: sort + + Instance attribute :attr:`sort` contains the sort order (see + :attr:`Query.SORT`) if explicitely specified via + :meth:`set_sort`. By default it is set to `None`. + + .. automethod:: search_threads + + .. automethod:: search_messages + + .. automethod:: count_messages + + .. automethod:: count_threads diff --git a/bindings/python/docs/source/tags.rst b/bindings/python/docs/source/tags.rst new file mode 100644 index 0000000..31527d4 --- /dev/null +++ b/bindings/python/docs/source/tags.rst @@ -0,0 +1,17 @@ +:class:`Tags` -- Notmuch tags +----------------------------- + +.. currentmodule:: notmuch + +.. autoclass:: Tags + :members: + + .. method:: __len__ + + .. warning:: + + :meth:`__len__` was removed in version 0.6 as it exhausted the iterator and broke + list(Tags()). Use :meth:`len(list(msgs))` instead if you need to know the number of + tags. + + .. automethod:: __str__ diff --git a/bindings/python/docs/source/thread.rst b/bindings/python/docs/source/thread.rst new file mode 100644 index 0000000..4067872 --- /dev/null +++ b/bindings/python/docs/source/thread.rst @@ -0,0 +1,26 @@ +:class:`Thread` -- A single thread +================================== + +.. currentmodule:: notmuch + +.. autoclass:: Thread + + .. automethod:: get_thread_id + + .. automethod:: get_total_messages + + .. automethod:: get_toplevel_messages + + .. automethod:: get_matched_messages + + .. automethod:: get_authors + + .. automethod:: get_subject + + .. automethod:: get_oldest_date + + .. automethod:: get_newest_date + + .. automethod:: get_tags + + .. automethod:: __str__ diff --git a/bindings/python/docs/source/threads.rst b/bindings/python/docs/source/threads.rst new file mode 100644 index 0000000..e5a8c8a --- /dev/null +++ b/bindings/python/docs/source/threads.rst @@ -0,0 +1,10 @@ +:class:`Threads` -- Threads iterator +==================================== + +.. currentmodule:: notmuch + +.. autoclass:: Threads + + .. automethod:: __len__ + + .. automethod:: __str__ -- cgit v1.2.3 From 916aefc2de504a3f658145352c690c170504c8c1 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Thu, 1 Mar 2012 07:47:21 -0400 Subject: bump version to 0.12~rc1 As usual, only `version' is edited by hand. The rest of the changes I blame on the machine. --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index ed40e7f..e58a1b5 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.11.1' +__VERSION__ = '0.12~rc1' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index 3d69cc6..e62577c 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-CONFIG 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index 25fe329..0d0ab5d 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-COUNT 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index 9ccf35d..bd7e274 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-DUMP 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 76910a4..ccee738 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-NEW 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 5160ece..7ed7f0f 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-REPLY 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index ef27938..8bd59e4 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-RESTORE 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 0bc3f40..19d85df 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-SEARCH 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index b2301d8..4c5db94 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-SHOW 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 7281bb2..8e0bb5c 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-TAG 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 424ca36..3ab1af5 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH 1 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index 2c4e552..1e459c0 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-HOOKS 5 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index a53565b..09a699f 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2011-12-04 "Notmuch 0.10.2" +.TH NOTMUCH-SEARCH-TERMS 7 2012-02-29 "Notmuch 0.12~rc1" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index af88ba8..0d4c53f 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.11.1 +0.12~rc1 -- cgit v1.2.3 From 3a95f3fbc1602d612aec2b7f1095e40c95723aee Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 16 Mar 2012 13:56:32 +0100 Subject: python: fix signature of two wrapped libnotmuch functions Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/directory.py | 2 +- bindings/python/notmuch/threads.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index 0c5e015..284cbdc 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -177,7 +177,7 @@ class Directory(object): _destroy = nmlib.notmuch_directory_destroy _destroy.argtypes = [NotmuchDirectoryP] - _destroy.argtypes = None + _destroy.restype = None def __del__(self): """Close and free the Directory""" diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index 690206e..225f524 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -172,7 +172,7 @@ class Threads(Python3StringMixIn): _destroy = nmlib.notmuch_threads_destroy _destroy.argtypes = [NotmuchThreadsP] - _destroy.argtypes = None + _destroy.restype = None def __del__(self): """Close and free the notmuch Threads""" -- cgit v1.2.3 From d71cb5e45b2e27dea30bbca167af54f8403ff8a5 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Sun, 18 Mar 2012 08:07:00 -0300 Subject: bump version to 0.12~rc2 --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index e58a1b5..8f7eb87 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.12~rc1' +__VERSION__ = '0.12~rc2' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index 2205d28..fb023b8 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-CONFIG 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index 79dd6a5..383252e 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-COUNT 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index 4e24392..7cfe08e 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-DUMP 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 19cef3d..1158bb2 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-NEW 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 0fb68b4..deb3ae1 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-REPLY 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index bcb765c..333f488 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-RESTORE 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 72874d0..2cf830a 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-SEARCH 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index 27a06b7..48c7e0b 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-SHOW 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 9f62222..8a010e4 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-TAG 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 6fd20e0..3984314 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH 1 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index ab40443..2397c7e 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-HOOKS 5 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index 1d43042..a2dde70 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-02-29 "Notmuch 0.12~rc1" +.TH NOTMUCH-SEARCH-TERMS 7 2012-03-18 "Notmuch 0.12~rc2" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index 0d4c53f..d885035 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.12~rc1 +0.12~rc2 -- cgit v1.2.3 From c302bfa2f63fc1e59df6f842fe65d4d6ea258a33 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Mon, 19 Mar 2012 22:28:17 -0300 Subject: update version to 0.12 There may be a few NEWS changes after this, but no code (hopefully). --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index 8f7eb87..24e1d4c 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.12~rc2' +__VERSION__ = '0.12' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index fb023b8..a746895 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-CONFIG 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index 383252e..8de4345 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-COUNT 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index 7cfe08e..f479e8b 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-DUMP 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 1158bb2..613658d 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-NEW 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index deb3ae1..bd95b5f 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-REPLY 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index 333f488..db0b697 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-RESTORE 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 2cf830a..bf17220 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-SEARCH 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index 48c7e0b..d69834a 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-SHOW 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 8a010e4..aa4546e 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-TAG 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 3984314..2afcc77 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH 1 2012-03-19 "Notmuch 0.12" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index 2397c7e..9662bde 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-HOOKS 5 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index a2dde70..37ba9bb 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-03-18 "Notmuch 0.12~rc2" +.TH NOTMUCH-SEARCH-TERMS 7 2012-03-19 "Notmuch 0.12" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index d885035..c43e105 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.12~rc2 +0.12 -- cgit v1.2.3 From 22f73735c5d86cb10dc59ca536b9a73ade72eaea Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 22 Apr 2012 14:07:55 +0200 Subject: go: Use notmuch_database_destroy instead of notmuch_database_close Adapt the go bindings to the notmuch_database_close split. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/pkg/notmuch.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go index c6844ef..d32901d 100644 --- a/bindings/go/pkg/notmuch.go +++ b/bindings/go/pkg/notmuch.go @@ -114,7 +114,7 @@ func NewDatabase(path string) *Database { * An existing notmuch database can be identified by the presence of a * directory named ".notmuch" below 'path'. * - * The caller should call notmuch_database_close when finished with + * The caller should call notmuch_database_destroy when finished with * this database. * * In case of any failure, this function returns NULL, (after printing @@ -140,7 +140,7 @@ func OpenDatabase(path string, mode DatabaseMode) *Database { /* Close the given notmuch database, freeing all associated * resources. See notmuch_database_open. */ func (self *Database) Close() { - C.notmuch_database_close(self.db) + C.notmuch_database_destroy(self.db) } /* Return the database path of the given database. -- cgit v1.2.3 From 288feb7cdf1798408c708394fd935f05acf87985 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 22 Apr 2012 14:07:56 +0200 Subject: ruby: Use notmuch_database_destroy instead of notmuch_database_close Adapt the ruby bindings to the notmuch_database_close split. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/ruby/database.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index 982fd59..ba9a139 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -110,7 +110,7 @@ notmuch_rb_database_close (VALUE self) notmuch_database_t *db; Data_Get_Notmuch_Database (self, db); - notmuch_database_close (db); + notmuch_database_destroy (db); DATA_PTR (self) = NULL; return Qnil; -- cgit v1.2.3 From 7bfc4bf501af2207123135065b08bd4874446de8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 22 Apr 2012 14:07:57 +0200 Subject: python: wrap and use notmuch_database_destroy as destructor Adapt the python bindings to the notmuch_database_close split. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 44d40fd..268e952 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -161,8 +161,13 @@ class Database(object): else: self.create(path) + _destroy = nmlib.notmuch_database_destroy + _destroy.argtypes = [NotmuchDatabaseP] + _destroy.restype = None + def __del__(self): - self.close() + if self._db: + self._destroy(self._db) def _assert_db_is_initialized(self): """Raises :exc:`NotInitializedError` if self._db is `None`""" @@ -218,10 +223,11 @@ class Database(object): _close.restype = None def close(self): - """Close and free the notmuch database if needed""" - if self._db is not None: + ''' + Closes the notmuch database. + ''' + if self._db: self._close(self._db) - self._db = None def __enter__(self): ''' -- cgit v1.2.3 From 7190b0dbc289a451409886a9c535492bfa44eed8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:15:41 +0200 Subject: python: Remove unused import from setup.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 2e58dab..8a7a89c 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import re from distutils.core import setup # get the notmuch version number without importing the notmuch module -- cgit v1.2.3 From 61cf962df8f2000d7a9d4cbaf8c87970278d54f7 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:18:52 +0200 Subject: python: simplify a path expression in setup.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 8a7a89c..b46ac8d 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -4,7 +4,7 @@ import os from distutils.core import setup # get the notmuch version number without importing the notmuch module -version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), +version_file = os.path.join(os.path.dirname(__file__), 'notmuch', 'version.py') exec(compile(open(version_file).read(), version_file, 'exec')) assert __VERSION__, 'Failed to read the notmuch binding version number' -- cgit v1.2.3 From 99b4ae1a887f2e31246e5e8fe6ea874b1d4277a9 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:21:32 +0200 Subject: python: fix the test asserting that reading the version succeeded Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index b46ac8d..0b40724 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -7,7 +7,8 @@ from distutils.core import setup version_file = os.path.join(os.path.dirname(__file__), 'notmuch', 'version.py') exec(compile(open(version_file).read(), version_file, 'exec')) -assert __VERSION__, 'Failed to read the notmuch binding version number' +assert '__VERSION__' in globals(), \ + 'Failed to read the notmuch binding version number' setup(name='notmuch', version=__VERSION__, -- cgit v1.2.3 From 3ff39766d460446a1cd1f6731511baca9584ffa2 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:26:36 +0200 Subject: python: update the long description in setup.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 0b40724..97c284f 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -20,28 +20,16 @@ setup(name='notmuch', packages=['notmuch'], keywords = ["library", "email"], long_description="""Overview -============== +======== -The notmuch module provides an interface to the `notmuch `_ functionality, directly interfacing with a shared notmuch library. Notmuch provides a maildatabase that allows for extremely quick searching and filtering of your email according to various criteria. +The notmuch module provides an interface to the `notmuch +`_ functionality, directly interfacing with a +shared notmuch library. Notmuch provides a maildatabase that allows +for extremely quick searching and filtering of your email according to +various criteria. -The documentation for the latest cnotmuch release can be `viewed online `_. - -The classes notmuch.Database, notmuch.Query provide most of the core functionality, returning notmuch.Messages and notmuch.Tags. - -Installation and Deinstallation -------------------------------- - -notmuch is included in the upstream notmuch source repository and it is -packaged on http://pypi.python.org. This means you can do "easy_install -notmuch" (or using pip) on your linux box and it will get installed -into: - -/usr/local/lib/python2.x/dist-packages/ - -For uninstalling, you will need to remove the "notmuch-0.x-py2.x.egg" -directory and delete one entry refering to cnotmuch in the -"easy-install.pth" file in that directory. There should be no trace -left of cnotmuch then. +The documentation for the latest notmuch release can be `viewed +online `_. Requirements ------------ -- cgit v1.2.3 From 51e8e68649d97a2a4d672f9e8a1afd565589d682 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:28:50 +0200 Subject: python: stylistic and pep8 fixes in setup.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 97c284f..f4044f1 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -16,10 +16,10 @@ setup(name='notmuch', author='Sebastian Spaeth', author_email='Sebastian@SSpaeth.de', url='http://notmuchmail.org/', - download_url='http://notmuchmail.org/releases/notmuch-'+__VERSION__+'.tar.gz', + download_url='http://notmuchmail.org/releases/notmuch-%s.tar.gz' % __VERSION__, packages=['notmuch'], - keywords = ["library", "email"], - long_description="""Overview + keywords=['library', 'email'], + long_description='''Overview ======== The notmuch module provides an interface to the `notmuch @@ -37,7 +37,7 @@ Requirements You need to have notmuch installed (or rather libnotmuch.so.1). Also, notmuch makes use of the ctypes library, and has only been tested with python >= 2.5. It will not work on earlier python versions. -""", +''', classifiers=['Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', -- cgit v1.2.3 From 43ee25f7a9af2121b447eaa700560be4e0808c1a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:30:38 +0200 Subject: python: add copyright and licensing information to setup.py Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/setup.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'bindings') diff --git a/bindings/python/setup.py b/bindings/python/setup.py index f4044f1..f4c338e 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -1,5 +1,24 @@ #!/usr/bin/env python +""" +This file is part of notmuch. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth +""" + import os from distutils.core import setup -- cgit v1.2.3 From 1f08664a6b8f7cba63f63855833f877b66bbbe05 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 29 Apr 2012 16:33:06 +0200 Subject: python: strip superfluous single quote from copyright notices Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 2 +- bindings/python/notmuch/directory.py | 2 +- bindings/python/notmuch/filenames.py | 2 +- bindings/python/notmuch/globals.py | 2 +- bindings/python/notmuch/message.py | 2 +- bindings/python/notmuch/messages.py | 2 +- bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 2 +- bindings/python/notmuch/threads.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 268e952..0ac8b06 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ import os diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index 284cbdc..667d3a4 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from ctypes import c_uint, c_long diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index 12050df..f3d761d 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p from notmuch.globals import ( diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index 442f3e3..823c3e2 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ import sys from ctypes import CDLL, Structure, POINTER diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 9eb4fee..f1faf1d 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth Jesse Rosenthal """ diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index d94f91b..6b024cb 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth Jesse Rosenthal """ diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index ddaf8e0..27bc4df 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p, c_uint diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 711bf53..9b18160 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p from notmuch.globals import ( diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index a759c90..a47b209 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p, c_long, c_int diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index 225f524..fb053f9 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -14,7 +14,7 @@ for more details. You should have received a copy of the GNU General Public License along with notmuch. If not, see . -Copyright 2010 Sebastian Spaeth ' +Copyright 2010 Sebastian Spaeth """ from notmuch.globals import ( -- cgit v1.2.3 From e74b1f807bea9b8572a71757da9a3003e24a02b8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:13:31 +0200 Subject: python: remove the deprecated function Filenames.as_generator Remove the function Filenames.as_generator that has been marked as deprecated in 0.12. The class Filenames implements the iterator protocol so you can directly iterate over such objects instead. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/filenames.py | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index f3d761d..2079530 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -109,18 +109,6 @@ class Filenames(Python3StringMixIn): return file_.decode('utf-8', 'ignore') next = __next__ # python2.x iterator protocol compatibility - def as_generator(self): - """Return generator of Filenames - - This is the main function that will usually be used by the - user. - - .. deprecated:: 0.12 - :class:`Filenames` objects implement the - iterator protocol. - """ - return self - def __unicode__(self): """Represent Filenames() as newline-separated list of full paths -- cgit v1.2.3 From bbc38c5c11d76ec96a4648d33c0368584a11c748 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:27:15 +0200 Subject: python: fix Message.get_filenames Do not to use the removed function Filenames.as_iterator. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index f1faf1d..54c4e4b 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -259,7 +259,7 @@ class Message(Python3StringMixIn): files_p = Message._get_filenames(self._msg) - return Filenames(files_p, self).as_generator() + return Filenames(files_p, self) def get_flag(self, flag): """Checks whether a specific flag is set for this message -- cgit v1.2.3 From 60e512d84fd04291f552503f139ae6893b25018b Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:32:32 +0200 Subject: python: fix the documentation Remove the reference to Filenames.as_generator in the sphinx documentation. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/filesystem.rst | 2 -- 1 file changed, 2 deletions(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/filesystem.rst b/bindings/python/docs/source/filesystem.rst index 685dc4d..4eb7810 100644 --- a/bindings/python/docs/source/filesystem.rst +++ b/bindings/python/docs/source/filesystem.rst @@ -10,8 +10,6 @@ Files and directories .. automethod:: Filenames.__len__ - .. automethod:: Filenames.as_generator - :class:`Directoy` -- A directory entry in the database ------------------------------------------------------ -- cgit v1.2.3 From 0803603cdd0d2db0a0b073aba1ffd79077acba84 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:39:06 +0200 Subject: python: update the docstring of class Filenames Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/filenames.py | 37 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index 2079530..830618b 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -32,29 +32,32 @@ from .errors import ( class Filenames(Python3StringMixIn): """Represents a list of filenames as returned by notmuch - This object contains the Filenames iterator. The main function is - as_generator() which will return a generator so we can do a Filenamesth an - iterator over a list of notmuch filenames. Do note that the underlying - library only provides a one-time iterator (it cannot reset the iterator to - the start). Thus iterating over the function will "exhaust" the list of - tags, and a subsequent iteration attempt will raise a - :exc:`NotInitializedError`. Also note, that any function that uses - iteration (nearly all) will also exhaust the tags. So both:: + Objects of this class implement the iterator protocol. - for name in filenames: print name + .. note:: - as well as:: + The underlying library only provides a one-time iterator (it + cannot reset the iterator to the start). Thus iterating over + the function will "exhaust" the list of tags, and a subsequent + iteration attempt will raise a + :exc:`NotInitializedError`. Also note, that any function that + uses iteration (nearly all) will also exhaust the tags. So + both:: - number_of_names = len(names) + for name in filenames: print name - and even a simple:: + as well as:: - #str() iterates over all tags to construct a space separated list - print(str(filenames)) + number_of_names = len(names) - will "exhaust" the Filenames. However, you can use - :meth:`Message.get_filenames` repeatedly to get fresh Filenames - objects to perform various actions on filenames. + and even a simple:: + + #str() iterates over all tags to construct a space separated list + print(str(filenames)) + + will "exhaust" the Filenames. However, you can use + :meth:`Message.get_filenames` repeatedly to get fresh + Filenames objects to perform various actions on filenames. """ #notmuch_filenames_get -- cgit v1.2.3 From 09fdf2b283938da1cded87ec8621aabe917a8fa5 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:43:02 +0200 Subject: python: update the docstrings of Filenames.{__len__,__unicode} Formerly the documentation was overly verbose. Reword the comment and use the same for both functions. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/filenames.py | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index 830618b..d201ae2 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -115,13 +115,10 @@ class Filenames(Python3StringMixIn): def __unicode__(self): """Represent Filenames() as newline-separated list of full paths - .. note:: As this iterates over the filenames, we will not be - able to iterate over them again (as in retrieve them)! If - the tags have been exhausted already, this will raise a - :exc:`NotInitializedError` on subsequent - attempts. However, you can use - :meth:`Message.get_filenames` repeatedly to perform - various actions on filenames. + .. note:: + + This method exhausts the iterator object, so you will not be able to + iterate over them again. """ return "\n".join(self) @@ -139,15 +136,8 @@ class Filenames(Python3StringMixIn): .. note:: - As this iterates over the files, we will not be able to - iterate over them again! So this will fail:: - - #THIS FAILS - files = Database().get_directory('').get_child_files() - if len(files) > 0: # this 'exhausts' msgs - # next line raises - # NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) - for file in files: print file + This method exhausts the iterator object, so you will not be able to + iterate over them again. """ if not self._files_p: raise NotInitializedError() -- cgit v1.2.3 From 162687a99e412098729d639ed7bc27f01372cb84 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:52:35 +0200 Subject: python: fix NULL pointer tests Fix the NULL pointer tests in the destructors of all classes and Database.create. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 2 +- bindings/python/notmuch/directory.py | 2 +- bindings/python/notmuch/filenames.py | 2 +- bindings/python/notmuch/message.py | 2 +- bindings/python/notmuch/messages.py | 2 +- bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 2 +- bindings/python/notmuch/threads.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 0ac8b06..525f7c9 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -189,7 +189,7 @@ class Database(object): :raises: :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ - if self._db is not None: + if self._db: raise NotmuchError(message="Cannot create db, this Database() " "already has an open one.") diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index 667d3a4..ae115f8 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -181,5 +181,5 @@ class Directory(object): def __del__(self): """Close and free the Directory""" - if self._dir_p is not None: + if self._dir_p: self._destroy(self._dir_p) diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index d201ae2..a0b2956 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -128,7 +128,7 @@ class Filenames(Python3StringMixIn): def __del__(self): """Close and free the notmuch filenames""" - if self._files_p is not None: + if self._files_p: self._destroy(self._files_p) def __len__(self): diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 54c4e4b..4ec5147 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -741,5 +741,5 @@ class Message(Python3StringMixIn): def __del__(self): """Close and free the notmuch Message""" - if self._msg is not None: + if self._msg: self._destroy(self._msg) diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index 6b024cb..251fa3a 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -184,7 +184,7 @@ class Messages(object): def __del__(self): """Close and free the notmuch Messages""" - if self._msgs is not None: + if self._msgs: self._destroy(self._msgs) def format_messages(self, format, indent=0, entire_thread=False): diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 27bc4df..756e63b 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -203,5 +203,5 @@ class Query(object): def __del__(self): """Close and free the Query""" - if self._query is not None: + if self._query: self._destroy(self._query) diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 9b18160..e059813 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -137,5 +137,5 @@ class Tags(Python3StringMixIn): def __del__(self): """Close and free the notmuch tags""" - if self._tags is not None: + if self._tags: self._destroy(self._tags) diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index a47b209..2f60d49 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -260,5 +260,5 @@ class Thread(object): def __del__(self): """Close and free the notmuch Thread""" - if self._thread is not None: + if self._thread: self._destroy(self._thread) diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index fb053f9..a644164 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -176,5 +176,5 @@ class Threads(Python3StringMixIn): def __del__(self): """Close and free the notmuch Threads""" - if self._threads is not None: + if self._threads: self._destroy(self._threads) -- cgit v1.2.3 From 7f74a400d197dac5cdf36960f68f63ce3eeff486 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 19:12:36 +0200 Subject: python: cleanup the __nonzero__ implementations Cleanup the code, reword the docstring and use the same implementation in the Threads, Tags and Messages classes. __nonzero__ implements truth value testing. If __nonzero__ is not implemented, the python runtime would fall back to `len(..) > 0` thus exhausting the iterator. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/messages.py | 14 +++++++++----- bindings/python/notmuch/tag.py | 18 +++++++++--------- bindings/python/notmuch/threads.py | 21 +++++++++------------ 3 files changed, 27 insertions(+), 26 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index 251fa3a..59ef40a 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -172,11 +172,15 @@ class Messages(object): next = __next__ # python2.x iterator protocol compatibility def __nonzero__(self): - """ - :return: True if there is at least one more thread in the - Iterator, False if not.""" - return self._msgs is not None and \ - self._valid(self._msgs) > 0 + ''' + Implement truth value testing. If __nonzero__ is not + implemented, the python runtime would fall back to `len(..) > + 0` thus exhausting the iterator. + + :returns: True if the wrapped iterator has at least one more object + left. + ''' + return self._msgs and self._valid(self._msgs) _destroy = nmlib.notmuch_messages_destroy _destroy.argtypes = [NotmuchMessagesP] diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index e059813..363c348 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -109,15 +109,15 @@ class Tags(Python3StringMixIn): next = __next__ # python2.x iterator protocol compatibility def __nonzero__(self): - """Implement bool(Tags) check that can be repeatedly used - - If __nonzero__ is not implemented, "if Tags()" - will implicitly call __len__, using up our iterator, so it is - important that this function is defined. - - :returns: True if the Tags() iterator has at least one more Tag - left.""" - return self._valid(self._tags) > 0 + ''' + Implement truth value testing. If __nonzero__ is not + implemented, the python runtime would fall back to `len(..) > + 0` thus exhausting the iterator. + + :returns: True if the wrapped iterator has at least one more object + left. + ''' + return self._tags and self._valid(self._tags) def __unicode__(self): """string representation of :class:`Tags`: a space separated list of tags diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index a644164..d2e0a91 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -157,18 +157,15 @@ class Threads(Python3StringMixIn): return i def __nonzero__(self): - """Check if :class:`Threads` contains at least one more valid thread - - The existence of this function makes 'if Threads: foo' work, as - that will implicitely call len() exhausting the iterator if - __nonzero__ does not exist. This function makes `bool(Threads())` - work repeatedly. - - :return: True if there is at least one more thread in the - Iterator, False if not. None on a "Out-of-memory" error. - """ - return self._threads is not None and \ - self._valid(self._threads) > 0 + ''' + Implement truth value testing. If __nonzero__ is not + implemented, the python runtime would fall back to `len(..) > + 0` thus exhausting the iterator. + + :returns: True if the wrapped iterator has at least one more object + left. + ''' + return self._threads and self._valid(self._threads) _destroy = nmlib.notmuch_threads_destroy _destroy.argtypes = [NotmuchThreadsP] -- cgit v1.2.3 From e9bcbe7e70d0811f11e58466735b2bf7c8f0a3fc Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 18:48:29 +0200 Subject: python: deprecate code formatting messages as text and json This code adds functionality at the python level that is unlikely to be useful for anyone. Furthermore the python bindings strive to be a thin wrapper around libnotmuch, so this code will be removed in notmuch 0.14. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/message.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 4ec5147..0e65694 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -614,7 +614,15 @@ class Message(Python3StringMixIn): """Create an internal representation of the message parts, which can easily be output to json, text, or another output format. The argument match tells whether this matched a - query.""" + query. + + .. deprecated:: 0.13 + This code adds functionality at the python + level that is unlikely to be useful for + anyone. Furthermore the python bindings strive + to be a thin wrapper around libnotmuch, so + this code will be removed in notmuch 0.14. + """ output = {} output["id"] = self.get_message_id() output["match"] = self.is_match() @@ -660,12 +668,29 @@ class Message(Python3StringMixIn): def format_message_as_json(self, indent=0): """Outputs the message as json. This is essentially the same as python's dict format, but we run it through, just so we - don't have to worry about the details.""" + don't have to worry about the details. + + .. deprecated:: 0.13 + This code adds functionality at the python + level that is unlikely to be useful for + anyone. Furthermore the python bindings strive + to be a thin wrapper around libnotmuch, so + this code will be removed in notmuch 0.14. + """ return json.dumps(self.format_message_internal()) def format_message_as_text(self, indent=0): """Outputs it in the old-fashioned notmuch text form. Will be - easy to change to a new format when the format changes.""" + easy to change to a new format when the format changes. + + .. deprecated:: 0.13 + This code adds functionality at the python + level that is unlikely to be useful for + anyone. Furthermore the python bindings strive + to be a thin wrapper around libnotmuch, so + this code will be removed in notmuch 0.14. + """ + format = self.format_message_internal() output = "\fmessage{ id:%s depth:%d match:%d filename:%s" \ -- cgit v1.2.3 From ca1e232e5fa35c2fabe0ef4fcb78911bcffe67b8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 19:48:45 +0200 Subject: python: document the Database.close function Put a prominent warning into the docstring of Database.close, make the function show up in the sphinx doc and refer to the warning in the paragraph mentioning the context manager protocol. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/database.rst | 2 ++ bindings/python/notmuch/database.py | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/database.rst b/bindings/python/docs/source/database.rst index ee71085..2464bff 100644 --- a/bindings/python/docs/source/database.rst +++ b/bindings/python/docs/source/database.rst @@ -9,6 +9,8 @@ .. automethod:: open(path, status=MODE.READ_ONLY) + .. automethod:: close + .. automethod:: get_path .. automethod:: get_version diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 525f7c9..5c62d45 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -56,7 +56,8 @@ class Database(object): :class:`Database` objects implement the context manager protocol so you can use the :keyword:`with` statement to ensure that the - database is properly closed. + database is properly closed. See :meth:`close` for more + information. .. note:: @@ -225,6 +226,13 @@ class Database(object): def close(self): ''' Closes the notmuch database. + + .. warning:: + + This function closes the notmuch database. From that point + on every method invoked on any object ever derived from + the closed database may cease to function and raise a + NotmuchError. ''' if self._db: self._close(self._db) -- cgit v1.2.3 From fcfb619b44b0011ac6bc557e6cbe2d516bc58f8a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Mon, 30 Apr 2012 19:51:16 +0200 Subject: python: remove a note stating wrong things about the memory management Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 8 -------- 1 file changed, 8 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 5c62d45..1db332f 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -64,14 +64,6 @@ class Database(object): Any function in this class can and will throw an :exc:`NotInitializedError` if the database was not intitialized properly. - - .. note:: - - Do remember that as soon as we tear down (e.g. via `del db`) this - object, all underlying derived objects such as queries, threads, - messages, tags etc will be freed by the underlying library as well. - Accessing these objects will lead to segfaults and other unexpected - behavior. See above for more details. """ _std_db_path = None """Class attribute to cache user's default database""" -- cgit v1.2.3 From ce53850290e81ace34af5a1d418cc8941d0d3b8f Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sat, 28 Apr 2012 17:45:18 -0400 Subject: go: Update to the current notmuch_database_find_message API The signature of notmuch_database_find_message was changed in 02a30767 to report errors and the Go bindings were never updated. This brings the Go bindings in sync with that change and at least makes them compile with Go r60.3, the last release before Go 1. --- bindings/go/pkg/notmuch.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'bindings') diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go index d32901d..de9de23 100644 --- a/bindings/go/pkg/notmuch.go +++ b/bindings/go/pkg/notmuch.go @@ -306,20 +306,21 @@ func (self *Database) RemoveMessage(fname string) Status { * * An out-of-memory situation occurs * * A Xapian exception occurs */ -func (self *Database) FindMessage(message_id string) *Message { +func (self *Database) FindMessage(message_id string) (*Message, Status) { var c_msg_id *C.char = C.CString(message_id) defer C.free(unsafe.Pointer(c_msg_id)) if c_msg_id == nil { - return nil + return nil, STATUS_OUT_OF_MEMORY } - msg := C.notmuch_database_find_message(self.db, c_msg_id) - if msg == nil { - return nil + msg := &Message{message:nil} + st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message)) + if st != STATUS_SUCCESS { + return nil, st } - return &Message{message:msg} + return msg, st } /* Return a list of all tags found in the database. -- cgit v1.2.3 From 2e346b9e2adbca0e3dcd97bbf761a469068e91f9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 30 Apr 2012 12:25:35 -0400 Subject: go: Update Go bindings for new notmuch_database_{open, create} signatures This requires changing the return types of NewDatabase and OpenDatabase to follow the standard Go convention for returning errors. --- bindings/go/pkg/notmuch.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'bindings') diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go index de9de23..f9f86b5 100644 --- a/bindings/go/pkg/notmuch.go +++ b/bindings/go/pkg/notmuch.go @@ -86,21 +86,21 @@ const ( ) // Create a new, empty notmuch database located at 'path' -func NewDatabase(path string) *Database { +func NewDatabase(path string) (*Database, Status) { var c_path *C.char = C.CString(path) defer C.free(unsafe.Pointer(c_path)) if c_path == nil { - return nil + return nil, STATUS_OUT_OF_MEMORY } self := &Database{db:nil} - self.db = C.notmuch_database_create(c_path) - if self.db == nil { - return nil + st := Status(C.notmuch_database_create(c_path, &self.db)) + if st != STATUS_SUCCESS { + return nil, st } - return self + return self, st } /* Open an existing notmuch database located at 'path'. @@ -120,21 +120,21 @@ func NewDatabase(path string) *Database { * In case of any failure, this function returns NULL, (after printing * an error message on stderr). */ -func OpenDatabase(path string, mode DatabaseMode) *Database { +func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) { var c_path *C.char = C.CString(path) defer C.free(unsafe.Pointer(c_path)) if c_path == nil { - return nil + return nil, STATUS_OUT_OF_MEMORY } self := &Database{db:nil} - self.db = C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode)) - if self.db == nil { - return nil + st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db)) + if st != STATUS_SUCCESS { + return nil, st } - return self + return self, st } /* Close the given notmuch database, freeing all associated -- cgit v1.2.3 From 0a357fe4105b3ea936b41584cb40312e84a1e67a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 30 Apr 2012 12:25:36 -0400 Subject: python: Update Python bindings for new notmuch_database_{open, create} signatures --- bindings/python/notmuch/database.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 1db332f..1b1ddc3 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -88,8 +88,8 @@ class Database(object): """notmuch_database_open""" _open = nmlib.notmuch_database_open - _open.argtypes = [c_char_p, c_uint] - _open.restype = NotmuchDatabaseP + _open.argtypes = [c_char_p, c_uint, POINTER(NotmuchDatabaseP)] + _open.restype = c_uint """notmuch_database_upgrade""" _upgrade = nmlib.notmuch_database_upgrade @@ -115,8 +115,8 @@ class Database(object): """notmuch_database_create""" _create = nmlib.notmuch_database_create - _create.argtypes = [c_char_p] - _create.restype = NotmuchDatabaseP + _create.argtypes = [c_char_p, POINTER(NotmuchDatabaseP)] + _create.restype = c_uint def __init__(self, path = None, create = False, mode = MODE.READ_ONLY): @@ -186,12 +186,13 @@ class Database(object): raise NotmuchError(message="Cannot create db, this Database() " "already has an open one.") - res = Database._create(_str(path), Database.MODE.READ_WRITE) + db = NotmuchDatabaseP() + status = Database._create(_str(path), Database.MODE.READ_WRITE, byref(db)) - if not res: - raise NotmuchError( - message="Could not create the specified database") - self._db = res + if status != STATUS.SUCCESS: + raise NotmuchError(status) + self._db = db + return status def open(self, path, mode=0): """Opens an existing database @@ -205,11 +206,13 @@ class Database(object): :raises: Raises :exc:`NotmuchError` in case of any failure (possibly after printing an error message on stderr). """ - res = Database._open(_str(path), mode) + db = NotmuchDatabaseP() + status = Database._open(_str(path), mode, byref(db)) - if not res: - raise NotmuchError(message="Could not open the specified database") - self._db = res + if status != STATUS.SUCCESS: + raise NotmuchError(status) + self._db = db + return status _close = nmlib.notmuch_database_close _close.argtypes = [NotmuchDatabaseP] -- cgit v1.2.3 From 9721343e5b75e0e5a305ef32358fd83dcde650b4 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 30 Apr 2012 12:25:37 -0400 Subject: ruby: Update Ruby bindings for new notmuch_database_{open, create} signatures --- bindings/ruby/database.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index ba9a139..409d54f 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -42,6 +42,8 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self) int create, mode; VALUE pathv, hashv; VALUE modev; + notmuch_database_t *database; + notmuch_status_t ret; /* Check arguments */ rb_scan_args (argc, argv, "11", &pathv, &hashv); @@ -73,9 +75,13 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self) } Check_Type (self, T_DATA); - DATA_PTR (self) = create ? notmuch_database_create (path) : notmuch_database_open (path, mode); - if (!DATA_PTR (self)) - rb_raise (notmuch_rb_eDatabaseError, "Failed to open database"); + if (create) + ret = notmuch_database_create (path, &database); + else + ret = notmuch_database_open (path, mode, &database); + notmuch_rb_status_raise (ret); + + DATA_PTR (self) = database; return self; } -- cgit v1.2.3 From 7bf5be75ae8e3c2d4e8c06bba8b44f4fd495349b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sat, 28 Apr 2012 18:25:36 -0400 Subject: lib: Bump SO version from 2.0.0 to 3.0.0 We've changed the APIs of notmuch_database_open, notmuch_database_create, and notmuch_database_close. Amended by db: also bump string in bindings/python/notmuch/globals.py --- NEWS | 3 +++ bindings/python/notmuch/globals.py | 2 +- lib/Makefile.local | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/NEWS b/NEWS index c0cb3a2..9e32d56 100644 --- a/NEWS +++ b/NEWS @@ -81,6 +81,9 @@ contrib/ from now on. Library changes --------------- +The API changes detailed below break binary and source compatibility, +so libnotmuch has been bumped to version 3.0.0. + The function notmuch_database_close has been split into notmuch_database_close and notmuch_database_destroy diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index 823c3e2..f5fad72 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -22,7 +22,7 @@ from ctypes import CDLL, Structure, POINTER #----------------------------------------------------------------------------- #package-global instance of the notmuch library try: - nmlib = CDLL("libnotmuch.so.2") + nmlib = CDLL("libnotmuch.so.3") except: raise ImportError("Could not find shared 'notmuch' library.") diff --git a/lib/Makefile.local b/lib/Makefile.local index 54c4dea..8a9aa28 100644 --- a/lib/Makefile.local +++ b/lib/Makefile.local @@ -5,7 +5,7 @@ # the library interface, (such as the deletion of an API or a major # semantic change that breaks formerly functioning code). # -LIBNOTMUCH_VERSION_MAJOR = 2 +LIBNOTMUCH_VERSION_MAJOR = 3 # The minor version of the library interface. This should be incremented at # the time of release for any additions to the library interface, -- cgit v1.2.3 From d0000daab3f2b04b6b39210dd219de26fa2c8c13 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Mon, 7 May 2012 18:02:43 +0300 Subject: ruby: Add wrapper for notmuch_query_count_messages --- bindings/ruby/defs.h | 3 +++ bindings/ruby/init.c | 3 ++- bindings/ruby/query.c | 21 ++++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 81f652f..25222a6 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -222,6 +222,9 @@ notmuch_rb_query_search_threads (VALUE self); VALUE notmuch_rb_query_search_messages (VALUE self); +VALUE +notmuch_rb_query_count_messages (VALUE self); + /* threads.c */ VALUE notmuch_rb_threads_destroy (VALUE self); diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index 4405f19..7ad0ecf 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -1,6 +1,6 @@ /* The Ruby interface to the notmuch mail library * - * Copyright © 2010, 2011 Ali Polatel + * Copyright © 2010, 2011, 2012 Ali Polatel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -236,6 +236,7 @@ Init_notmuch (void) rb_define_method (notmuch_rb_cQuery, "to_s", notmuch_rb_query_get_string, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); /* in query.c */ + rb_define_method (notmuch_rb_cQuery, "count_messages", notmuch_rb_query_count_messages, 0); /* in query.c */ /* * Document-class: Notmuch::Threads diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c index 74fd585..02b7819 100644 --- a/bindings/ruby/query.c +++ b/bindings/ruby/query.c @@ -1,6 +1,6 @@ /* The Ruby interface to the notmuch mail library * - * Copyright © 2010, 2011 Ali Polatel + * Copyright © 2010, 2011, 2012 Ali Polatel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -127,3 +127,22 @@ notmuch_rb_query_search_messages (VALUE self) return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages); } + +/* + * call-seq: QUERY.count_messages => Fixnum + * + * Return an estimate of the number of messages matching a search + */ +VALUE +notmuch_rb_query_count_messages (VALUE self) +{ + notmuch_query_t *query; + + Data_Get_Notmuch_Query (self, query); + + /* Xapian exceptions are not handled properly. + * (function may return 0 after printing a message) + * Thus there is nothing we can do here... + */ + return UINT2FIX(notmuch_query_count_messages(query)); +} -- cgit v1.2.3 From 92680f12ebd276952ae51ff271526f4dd995a18a Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Mon, 7 May 2012 18:02:44 +0300 Subject: ruby: Add wrapper for notmuch_query_add_tag_exclude --- bindings/ruby/defs.h | 3 +++ bindings/ruby/init.c | 1 + bindings/ruby/query.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 25222a6..a41cf10 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -216,6 +216,9 @@ notmuch_rb_query_set_sort (VALUE self, VALUE sortv); VALUE notmuch_rb_query_get_string (VALUE self); +VALUE +notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv); + VALUE notmuch_rb_query_search_threads (VALUE self); diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index 7ad0ecf..edcf101 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -234,6 +234,7 @@ Init_notmuch (void) rb_define_method (notmuch_rb_cQuery, "sort", notmuch_rb_query_get_sort, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "to_s", notmuch_rb_query_get_string, 0); /* in query.c */ + rb_define_method (notmuch_rb_cQuery, "add_tag_exclude", notmuch_rb_query_add_tag_exclude, 1); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "count_messages", notmuch_rb_query_count_messages, 0); /* in query.c */ diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c index 02b7819..2a80008 100644 --- a/bindings/ruby/query.c +++ b/bindings/ruby/query.c @@ -88,6 +88,24 @@ notmuch_rb_query_get_string (VALUE self) return rb_str_new2 (notmuch_query_get_query_string (query)); } +/* + * call-seq: QUERY.add_tag_exclude(tag) => nil + * + * Add a tag that will be excluded from the query results by default. + */ +VALUE +notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv) +{ + notmuch_query_t *query; + const char *tag; + + Data_Get_Notmuch_Query (self, query); + tag = RSTRING_PTR(tagv); + + notmuch_query_add_tag_exclude(query, tag); + return Qnil; +} + /* * call-seq: QUERY.search_threads => THREADS * -- cgit v1.2.3 From 82b73ffd7380b85d259eeb91100dd6ac2d14223a Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Mon, 7 May 2012 18:02:45 +0300 Subject: ruby: Add workarounds to use in-tree build not the installed one - Make mkmf use the notmuch.h under ../../lib - Use libnotmuch.a instead of linking to the installed libnotmuch.so --- bindings/ruby/defs.h | 4 ++-- bindings/ruby/extconf.rb | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index a41cf10..6fe5787 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -1,6 +1,6 @@ /* The Ruby interface to the notmuch mail library * - * Copyright © 2010, 2011 Ali Polatel + * Copyright © 2010, 2011, 2012 Ali Polatel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,8 +21,8 @@ #ifndef DEFS_H #define DEFS_H -#include #include +#include "notmuch.h" VALUE notmuch_rb_cDatabase; VALUE notmuch_rb_cDirectory; diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb index ccac609..933f34a 100644 --- a/bindings/ruby/extconf.rb +++ b/bindings/ruby/extconf.rb @@ -1,13 +1,31 @@ #!/usr/bin/env ruby # coding: utf-8 -# Copyright 2010, 2011 Ali Polatel +# Copyright 2010, 2011, 2012 Ali Polatel # Distributed under the terms of the GNU General Public License v3 require 'mkmf' -# Notmuch Library -find_header('notmuch.h', '../../lib') -find_library('notmuch', 'notmuch_database_create', '../../lib') +NOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib')) +NOTHDR = File.join(NOTDIR, 'notmuch.h') +NOTLIB = File.join(NOTDIR, 'libnotmuch.a') + +unless File.exists? NOTHDR + $stderr.puts "notmuch.h is missing under #{NOTDIR}" + exit 1 +end + +unless File.exists? NOTLIB + $stderr.puts "libnotmuch.a is missing under #{NOTDIR}" + exit 1 +end + +# Small hack to build with in-tree version not the installed one. +# find_header() and friends use standard include/library paths first. +$stderr.puts "Added -I#{NOTDIR} to $INCFLAGS" +$INCFLAGS = "-I#{NOTDIR}".quote + " " + $INCFLAGS +find_header('notmuch.h', NOTDIR) + +$LOCAL_LIBS += NOTLIB # Create Makefile dir_config('notmuch') -- cgit v1.2.3 From a8e010962f257aaba0218392542cbfb1d14eddfd Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Mon, 7 May 2012 18:02:46 +0300 Subject: ruby: Add wrapper for notmuch_query_set_omit_excluded() --- bindings/ruby/defs.h | 3 +++ bindings/ruby/init.c | 7 +++++++ bindings/ruby/query.c | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 6fe5787..85d8205 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -219,6 +219,9 @@ notmuch_rb_query_get_string (VALUE self); VALUE notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv); +VALUE +notmuch_rb_query_set_omit_excluded (VALUE self, VALUE omitv); + VALUE notmuch_rb_query_search_threads (VALUE self); diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index edcf101..3fe60fb 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -95,6 +95,12 @@ Init_notmuch (void) * Message flag "match" */ rb_define_const (mod, "MESSAGE_FLAG_MATCH", INT2FIX (NOTMUCH_MESSAGE_FLAG_MATCH)); + /* + * Document-const: Notmuch::MESSAGE_FLAG_EXCLUDED + * + * Message flag "excluded" + */ + rb_define_const (mod, "MESSAGE_FLAG_EXCLUDED", INT2FIX (NOTMUCH_MESSAGE_FLAG_EXCLUDED)); /* * Document-const: Notmuch::TAG_MAX * @@ -235,6 +241,7 @@ Init_notmuch (void) rb_define_method (notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "to_s", notmuch_rb_query_get_string, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "add_tag_exclude", notmuch_rb_query_add_tag_exclude, 1); /* in query.c */ + rb_define_method (notmuch_rb_cQuery, "omit_excluded=", notmuch_rb_query_set_omit_excluded, 1); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); /* in query.c */ rb_define_method (notmuch_rb_cQuery, "count_messages", notmuch_rb_query_count_messages, 0); /* in query.c */ diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c index 2a80008..e5ba1b7 100644 --- a/bindings/ruby/query.c +++ b/bindings/ruby/query.c @@ -106,6 +106,24 @@ notmuch_rb_query_add_tag_exclude (VALUE self, VALUE tagv) return Qnil; } +/* + * call-seq: QUERY.omit_excluded=(boolean) => nil + * + * Specify whether to omit excluded results or simply flag them. + * By default, this is set to +true+. + */ +VALUE +notmuch_rb_query_set_omit_excluded (VALUE self, VALUE omitv) +{ + notmuch_query_t *query; + + Data_Get_Notmuch_Query (self, query); + + notmuch_query_set_omit_excluded (query, RTEST (omitv)); + + return Qnil; +} + /* * call-seq: QUERY.search_threads => THREADS * -- cgit v1.2.3 From a4b10675bfe6ee90d84b9880b59c4f5ff15eed3a Mon Sep 17 00:00:00 2001 From: David Bremner Date: Tue, 8 May 2012 14:49:08 -0300 Subject: bump version to 0.13~rc1 --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index 24e1d4c..25010f5 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.12' +__VERSION__ = '0.13~rc1' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index a55dbef..5c3b391 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-CONFIG 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index d6cbf07..0c87541 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-COUNT 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index f479e8b..50ec335 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-DUMP 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 613658d..b05d278 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-NEW 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 8666549..1f86b09 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-REPLY 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index db0b697..f393c04 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-RESTORE 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index ebb61fc..4b02f4e 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-SEARCH 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index 83cc575..14a2a5c 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-SHOW 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index aa4546e..55f79f8 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-TAG 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 2afcc77..f7ee528 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH 1 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index 9662bde..aa0839a 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-HOOKS 5 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index 37ba9bb..6af7a60 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-03-19 "Notmuch 0.12" +.TH NOTMUCH-SEARCH-TERMS 7 2012-05-08 "Notmuch 0.13~rc1" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index c43e105..80fa719 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.12 +0.13~rc1 -- cgit v1.2.3 From 9f5478637c925ec9996328671d9a8f26ac6a6ed4 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 12:23:06 +0200 Subject: go: update notmuch-addrlookup to the new API notmuch.OpenDatabase now returns a status indicating success or failure. Use this information to inform the user of any failures. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/cmds/notmuch-addrlookup.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/go/cmds/notmuch-addrlookup.go b/bindings/go/cmds/notmuch-addrlookup.go index 16958e5..03699fb 100644 --- a/bindings/go/cmds/notmuch-addrlookup.go +++ b/bindings/go/cmds/notmuch-addrlookup.go @@ -209,8 +209,12 @@ func (self *address_matcher) run(name string) { queries := [3]*notmuch.Query{} // open the database - self.db = notmuch.OpenDatabase(self.user_db_path, - notmuch.DATABASE_MODE_READ_ONLY) + if db, status := notmuch.OpenDatabase(self.user_db_path, + notmuch.DATABASE_MODE_READ_ONLY); status == notmuch.STATUS_SUCCESS { + self.db = db + } else { + log.Fatalf("Failed to open the database: %v\n", status) + } // pass 1: look at all from: addresses with the address book tag query := "tag:" + self.user_addrbook_tag -- cgit v1.2.3 From 0af7295faf56d5c469a9b47ad253ea5b146b0975 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 12:23:07 +0200 Subject: go: fix the notmuch status constants Formerly all the constants were set to zero since in golang constants are set to the previous value if no new value is specified. Use the iota operator that is incremented after each use to fix this issue. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/pkg/notmuch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go index f9f86b5..e065b54 100644 --- a/bindings/go/pkg/notmuch.go +++ b/bindings/go/pkg/notmuch.go @@ -14,7 +14,7 @@ import "unsafe" // Status codes used for the return values of most functions type Status C.notmuch_status_t const ( - STATUS_SUCCESS Status = 0 + STATUS_SUCCESS Status = iota STATUS_OUT_OF_MEMORY STATUS_READ_ONLY_DATABASE STATUS_XAPIAN_EXCEPTION -- cgit v1.2.3 From f83a5c6241db308393d9295aedbcfbeff43a53fd Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 12:23:08 +0200 Subject: go: define the constant STATUS_UNBALANCED_ATOMIC Add the constant STATUS_UNBALANCED_ATOMIC to the list of notmuch status codes. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/pkg/notmuch.go | 1 + 1 file changed, 1 insertion(+) (limited to 'bindings') diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go index e065b54..8faf3bb 100644 --- a/bindings/go/pkg/notmuch.go +++ b/bindings/go/pkg/notmuch.go @@ -24,6 +24,7 @@ const ( STATUS_NULL_POINTER STATUS_TAG_TOO_LONG STATUS_UNBALANCED_FREEZE_THAW + STATUS_UNBALANCED_ATOMIC STATUS_LAST_STATUS ) -- cgit v1.2.3 From 97565b77cdb4c7c2db82f0baa462eeabb17294dc Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 13:15:16 +0200 Subject: go: reorganize the go bindings go 1 introduced the "go" program that simplifies building of libraries and programs. This patch reorganizes the go code so it can be compiled using the new utility, it does not change any files. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/cmds/notmuch-addrlookup.go | 263 ----- bindings/go/pkg/notmuch.go | 1125 ---------------------- bindings/go/src/notmuch-addrlookup/addrlookup.go | 263 +++++ bindings/go/src/notmuch/notmuch.go | 1125 ++++++++++++++++++++++ 4 files changed, 1388 insertions(+), 1388 deletions(-) delete mode 100644 bindings/go/cmds/notmuch-addrlookup.go delete mode 100644 bindings/go/pkg/notmuch.go create mode 100644 bindings/go/src/notmuch-addrlookup/addrlookup.go create mode 100644 bindings/go/src/notmuch/notmuch.go (limited to 'bindings') diff --git a/bindings/go/cmds/notmuch-addrlookup.go b/bindings/go/cmds/notmuch-addrlookup.go deleted file mode 100644 index 03699fb..0000000 --- a/bindings/go/cmds/notmuch-addrlookup.go +++ /dev/null @@ -1,263 +0,0 @@ -package main - -// stdlib imports -import "os" -import "path" -import "log" -import "fmt" -import "regexp" -import "strings" -import "sort" - -// 3rd-party imports -import "notmuch" -import "github.com/kless/goconfig/config" - -type mail_addr_freq struct { - addr string - count [3]uint -} - -type frequencies map[string]uint - -/* Used to sort the email addresses from most to least used */ -func sort_by_freq(m1, m2 *mail_addr_freq) int { - if (m1.count[0] == m2.count[0] && - m1.count[1] == m2.count[1] && - m1.count[2] == m2.count[2]) { - return 0 - } - - if (m1.count[0] > m2.count[0] || - m1.count[0] == m2.count[0] && - m1.count[1] > m2.count[1] || - m1.count[0] == m2.count[0] && - m1.count[1] == m2.count[1] && - m1.count[2] > m2.count[2]) { - return -1 - } - - return 1 -} - -type maddresses []*mail_addr_freq - -func (self *maddresses) Len() int { - return len(*self) -} - -func (self *maddresses) Less(i,j int) bool { - m1 := (*self)[i] - m2 := (*self)[j] - v := sort_by_freq(m1, m2) - if v<=0 { - return true - } - return false -} - -func (self *maddresses) Swap(i,j int) { - (*self)[i], (*self)[j] = (*self)[j], (*self)[i] -} - -// find most frequent real name for each mail address -func frequent_fullname(freqs frequencies) string { - var maxfreq uint = 0 - fullname := "" - freqs_sz := len(freqs) - - for mail,freq := range freqs { - if (freq > maxfreq && mail != "") || freqs_sz == 1 { - // only use the entry if it has a real name - // or if this is the only entry - maxfreq = freq - fullname = mail - } - } - return fullname -} - -func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr_to_realname *map[string]*frequencies) *frequencies { - - freqs := make(frequencies) - - pattern := `\s*(("(\.|[^"])*"|[^,])*?)` - // pattern := "\\s*((\\\"(\\\\.|[^\\\\\"])*\\\"|[^,])*" + - // "\\b\\w+([-+.]\\w+)*\\@\\w+[-\\.\\w]*\\.([-\\.\\w]+)*\\w\\b)>?)" - pattern = `.*` + strings.ToLower(name) + `.*` - var re *regexp.Regexp = nil - var err os.Error = nil - if re,err = regexp.Compile(pattern); err != nil { - log.Printf("error: %v\n", err) - return &freqs - } - - headers := []string{"from"} - if pass == 1 { - headers = append(headers, "to", "cc", "bcc") - } - - for ;msgs.Valid();msgs.MoveToNext() { - msg := msgs.Get() - //println("==> msg [", msg.GetMessageId(), "]") - for _,header := range headers { - froms := strings.ToLower(msg.GetHeader(header)) - //println(" froms: ["+froms+"]") - for _,from := range strings.Split(froms, ",", -1) { - from = strings.Trim(from, " ") - match := re.FindString(from) - //println(" -> match: ["+match+"]") - occ,ok := freqs[match] - if !ok { - freqs[match] = 0 - occ = 0 - } - freqs[match] = occ+1 - } - } - } - return &freqs -} - -func search_address_passes(queries [3]*notmuch.Query, name string) []string { - var val []string - addr_freq := make(map[string]*mail_addr_freq) - addr_to_realname := make(map[string]*frequencies) - - var pass uint = 0 // 0-based - for _,query := range queries { - if query == nil { - //println("**warning: idx [",idx,"] contains a nil query") - continue - } - msgs := query.SearchMessages() - ht := addresses_by_frequency(msgs, name, pass, &addr_to_realname) - for addr, count := range *ht { - freq,ok := addr_freq[addr] - if !ok { - freq = &mail_addr_freq{addr:addr, count:[3]uint{0,0,0}} - } - freq.count[pass] = count - addr_freq[addr] = freq - } - msgs.Destroy() - pass += 1 - } - - addrs := make(maddresses, len(addr_freq)) - { - iaddr := 0 - for _, freq := range addr_freq { - addrs[iaddr] = freq - iaddr += 1 - } - } - sort.Sort(&addrs) - - for _,addr := range addrs { - freqs,ok := addr_to_realname[addr.addr] - if ok { - val = append(val, frequent_fullname(*freqs)) - } else { - val = append(val, addr.addr) - } - } - //println("val:",val) - return val -} - -type address_matcher struct { - // the notmuch database - db *notmuch.Database - // full path of the notmuch database - user_db_path string - // user primary email - user_primary_email string - // user tag to mark from addresses as in the address book - user_addrbook_tag string -} - -func new_address_matcher() *address_matcher { - var cfg *config.Config - var err os.Error - - // honor NOTMUCH_CONFIG - home := os.Getenv("NOTMUCH_CONFIG") - if home == "" { - home = os.Getenv("HOME") - } - - if cfg,err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil { - log.Fatalf("error loading config file:",err) - } - - db_path,_ := cfg.String("database", "path") - primary_email,_ := cfg.String("user", "primary_email") - addrbook_tag,err := cfg.String("user", "addrbook_tag") - if err != nil { - addrbook_tag = "addressbook" - } - - self := &address_matcher{db:nil, - user_db_path:db_path, - user_primary_email:primary_email, - user_addrbook_tag:addrbook_tag} - return self -} - -func (self *address_matcher) run(name string) { - queries := [3]*notmuch.Query{} - - // open the database - if db, status := notmuch.OpenDatabase(self.user_db_path, - notmuch.DATABASE_MODE_READ_ONLY); status == notmuch.STATUS_SUCCESS { - self.db = db - } else { - log.Fatalf("Failed to open the database: %v\n", status) - } - - // pass 1: look at all from: addresses with the address book tag - query := "tag:" + self.user_addrbook_tag - if name != "" { - query = query + " and from:" + name + "*" - } - queries[0] = self.db.CreateQuery(query) - - // pass 2: look at all to: addresses sent from our primary mail - query = "" - if name != "" { - query = "to:"+name+"*" - } - if self.user_primary_email != "" { - query = query + " from:" + self.user_primary_email - } - queries[1] = self.db.CreateQuery(query) - - // if that leads only to a few hits, we check every from too - if queries[0].CountMessages() + queries[1].CountMessages() < 10 { - query = "" - if name != "" { - query = "from:"+name+"*" - } - queries[2] = self.db.CreateQuery(query) - } - - // actually retrieve and sort addresses - results := search_address_passes(queries, name) - for _,v := range results { - if v != "" && v != "\n" { - fmt.Println(v) - } - } - return -} - -func main() { - //fmt.Println("args:",os.Args) - app := new_address_matcher() - name := "" - if len(os.Args) > 1 { - name = os.Args[1] - } - app.run(name) -} \ No newline at end of file diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go deleted file mode 100644 index 8faf3bb..0000000 --- a/bindings/go/pkg/notmuch.go +++ /dev/null @@ -1,1125 +0,0 @@ -// Wrapper around the notmuch library - -package notmuch - -/* -#include -#include -#include -#include "notmuch.h" -*/ -import "C" -import "unsafe" - -// Status codes used for the return values of most functions -type Status C.notmuch_status_t -const ( - STATUS_SUCCESS Status = iota - STATUS_OUT_OF_MEMORY - STATUS_READ_ONLY_DATABASE - STATUS_XAPIAN_EXCEPTION - STATUS_FILE_ERROR - STATUS_FILE_NOT_EMAIL - STATUS_DUPLICATE_MESSAGE_ID - STATUS_NULL_POINTER - STATUS_TAG_TOO_LONG - STATUS_UNBALANCED_FREEZE_THAW - STATUS_UNBALANCED_ATOMIC - - STATUS_LAST_STATUS -) - -func (self Status) String() string { - var p *C.char - - // p is read-only - p = C.notmuch_status_to_string(C.notmuch_status_t(self)) - if p != nil { - s := C.GoString(p) - return s - } - return "" -} - -/* Various opaque data types. For each notmuch__t see the various - * notmuch_ functions below. */ - -type Database struct { - db *C.notmuch_database_t -} - -type Query struct { - query *C.notmuch_query_t -} - -type Threads struct { - threads *C.notmuch_threads_t -} - -type Thread struct { - thread *C.notmuch_thread_t -} - -type Messages struct { - messages *C.notmuch_messages_t -} - -type Message struct { - message *C.notmuch_message_t -} - -type Tags struct { - tags *C.notmuch_tags_t -} - -type Directory struct { - dir *C.notmuch_directory_t -} - -type Filenames struct { - fnames *C.notmuch_filenames_t -} - -type DatabaseMode C.notmuch_database_mode_t -const ( - DATABASE_MODE_READ_ONLY DatabaseMode = 0 - DATABASE_MODE_READ_WRITE -) - -// Create a new, empty notmuch database located at 'path' -func NewDatabase(path string) (*Database, Status) { - - var c_path *C.char = C.CString(path) - defer C.free(unsafe.Pointer(c_path)) - - if c_path == nil { - return nil, STATUS_OUT_OF_MEMORY - } - - self := &Database{db:nil} - st := Status(C.notmuch_database_create(c_path, &self.db)) - if st != STATUS_SUCCESS { - return nil, st - } - return self, st -} - -/* Open an existing notmuch database located at 'path'. - * - * The database should have been created at some time in the past, - * (not necessarily by this process), by calling - * notmuch_database_create with 'path'. By default the database should be - * opened for reading only. In order to write to the database you need to - * pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode. - * - * An existing notmuch database can be identified by the presence of a - * directory named ".notmuch" below 'path'. - * - * The caller should call notmuch_database_destroy when finished with - * this database. - * - * In case of any failure, this function returns NULL, (after printing - * an error message on stderr). - */ -func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) { - - var c_path *C.char = C.CString(path) - defer C.free(unsafe.Pointer(c_path)) - - if c_path == nil { - return nil, STATUS_OUT_OF_MEMORY - } - - self := &Database{db:nil} - st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db)) - if st != STATUS_SUCCESS { - return nil, st - } - return self, st -} - -/* Close the given notmuch database, freeing all associated - * resources. See notmuch_database_open. */ -func (self *Database) Close() { - C.notmuch_database_destroy(self.db) -} - -/* Return the database path of the given database. - */ -func (self *Database) GetPath() string { - - /* The return value is a string owned by notmuch so should not be - * modified nor freed by the caller. */ - var p *C.char = C.notmuch_database_get_path(self.db) - if p != nil { - s := C.GoString(p) - return s - } - return "" -} - -/* Return the database format version of the given database. */ -func (self *Database) GetVersion() uint { - return uint(C.notmuch_database_get_version(self.db)) -} - -/* Does this database need to be upgraded before writing to it? - * - * If this function returns TRUE then no functions that modify the - * database (notmuch_database_add_message, notmuch_message_add_tag, - * notmuch_directory_set_mtime, etc.) will work unless the function - * notmuch_database_upgrade is called successfully first. */ -func (self *Database) NeedsUpgrade() bool { - do_upgrade := C.notmuch_database_needs_upgrade(self.db) - if do_upgrade == 0 { - return false - } - return true -} - -// TODO: notmuch_database_upgrade - - -/* Retrieve a directory object from the database for 'path'. - * - * Here, 'path' should be a path relative to the path of 'database' - * (see notmuch_database_get_path), or else should be an absolute path - * with initial components that match the path of 'database'. - * - * Can return NULL if a Xapian exception occurs. - */ -func (self *Database) GetDirectory(path string) *Directory { - var c_path *C.char = C.CString(path) - defer C.free(unsafe.Pointer(c_path)) - - if c_path == nil { - return nil - } - - c_dir := C.notmuch_database_get_directory(self.db, c_path) - if c_dir == nil { - return nil - } - return &Directory{dir:c_dir} -} - -/* Add a new message to the given notmuch database. - * - * Here,'filename' should be a path relative to the path of - * 'database' (see notmuch_database_get_path), or else should be an - * absolute filename with initial components that match the path of - * 'database'. - * - * The file should be a single mail message (not a multi-message mbox) - * that is expected to remain at its current location, (since the - * notmuch database will reference the filename, and will not copy the - * entire contents of the file. - * - * If 'message' is not NULL, then, on successful return '*message' - * will be initialized to a message object that can be used for things - * such as adding tags to the just-added message. The user should call - * notmuch_message_destroy when done with the message. On any failure - * '*message' will be set to NULL. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Message successfully added to database. - * - * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, - * message not added. - * - * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message - * ID as another message already in the database. The new - * filename was successfully added to the message in the database - * (if not already present). - * - * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the - * file, (such as permission denied, or file not found, - * etc.). Nothing added to the database. - * - * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look - * like an email message. Nothing added to the database. - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so no message can be added. - */ -func -(self *Database) AddMessage(fname string) (*Message, Status) { - var c_fname *C.char = C.CString(fname) - defer C.free(unsafe.Pointer(c_fname)) - - if c_fname == nil { - return nil, STATUS_OUT_OF_MEMORY - } - - var c_msg *C.notmuch_message_t = new(C.notmuch_message_t) - st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg)) - - return &Message{message:c_msg}, st -} - -/* Remove a message from the given notmuch database. - * - * Note that only this particular filename association is removed from - * the database. If the same message (as determined by the message ID) - * is still available via other filenames, then the message will - * persist in the database for those filenames. When the last filename - * is removed for a particular message, the database content for that - * message will be entirely removed. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: The last filename was removed and the - * message was removed from the database. - * - * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, - * message not removed. - * - * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but - * the message persists in the database with at least one other - * filename. - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so no message can be removed. - */ -func (self *Database) RemoveMessage(fname string) Status { - - var c_fname *C.char = C.CString(fname) - defer C.free(unsafe.Pointer(c_fname)) - - if c_fname == nil { - return STATUS_OUT_OF_MEMORY - } - - st := C.notmuch_database_remove_message(self.db, c_fname) - return Status(st) -} - -/* Find a message with the given message_id. - * - * If the database contains a message with the given message_id, then - * a new notmuch_message_t object is returned. The caller should call - * notmuch_message_destroy when done with the message. - * - * This function returns NULL in the following situations: - * - * * No message is found with the given message_id - * * An out-of-memory situation occurs - * * A Xapian exception occurs - */ -func (self *Database) FindMessage(message_id string) (*Message, Status) { - - var c_msg_id *C.char = C.CString(message_id) - defer C.free(unsafe.Pointer(c_msg_id)) - - if c_msg_id == nil { - return nil, STATUS_OUT_OF_MEMORY - } - - msg := &Message{message:nil} - st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message)) - if st != STATUS_SUCCESS { - return nil, st - } - return msg, st -} - -/* Return a list of all tags found in the database. - * - * This function creates a list of all tags found in the database. The - * resulting list contains all tags from all messages found in the database. - * - * On error this function returns NULL. - */ -func (self *Database) GetAllTags() *Tags { - tags := C.notmuch_database_get_all_tags(self.db) - if tags == nil { - return nil - } - return &Tags{tags:tags} -} - -/* Create a new query for 'database'. - * - * Here, 'database' should be an open database, (see - * notmuch_database_open and notmuch_database_create). - * - * For the query string, we'll document the syntax here more - * completely in the future, but it's likely to be a specialized - * version of the general Xapian query syntax: - * - * http://xapian.org/docs/queryparser.html - * - * As a special case, passing either a length-zero string, (that is ""), - * or a string consisting of a single asterisk (that is "*"), will - * result in a query that returns all messages in the database. - * - * See notmuch_query_set_sort for controlling the order of results. - * See notmuch_query_search_messages and notmuch_query_search_threads - * to actually execute the query. - * - * User should call notmuch_query_destroy when finished with this - * query. - * - * Will return NULL if insufficient memory is available. - */ -func (self *Database) CreateQuery(query string) *Query { - - var c_query *C.char = C.CString(query) - defer C.free(unsafe.Pointer(c_query)) - - if c_query == nil { - return nil - } - - q := C.notmuch_query_create(self.db, c_query) - if q == nil { - return nil - } - return &Query{query:q} -} - -/* Sort values for notmuch_query_set_sort */ -type Sort C.notmuch_sort_t -const ( - SORT_OLDEST_FIRST Sort = 0 - SORT_NEWEST_FIRST - SORT_MESSAGE_ID - SORT_UNSORTED -) - -/* Return the query_string of this query. See notmuch_query_create. */ -func (self *Query) String() string { - // FIXME: do we own 'q' or not ? - q := C.notmuch_query_get_query_string(self.query) - //defer C.free(unsafe.Pointer(q)) - - if q != nil { - s := C.GoString(q) - return s - } - - return "" -} - -/* Specify the sorting desired for this query. */ -func (self *Query) SetSort(sort Sort) { - C.notmuch_query_set_sort(self.query, C.notmuch_sort_t(sort)) -} - -/* Return the sort specified for this query. See notmuch_query_set_sort. */ -func (self *Query) GetSort() Sort { - return Sort(C.notmuch_query_get_sort(self.query)) -} - -/* Execute a query for threads, returning a notmuch_threads_t object - * which can be used to iterate over the results. The returned threads - * object is owned by the query and as such, will only be valid until - * notmuch_query_destroy. - * - * Typical usage might be: - * - * notmuch_query_t *query; - * notmuch_threads_t *threads; - * notmuch_thread_t *thread; - * - * query = notmuch_query_create (database, query_string); - * - * for (threads = notmuch_query_search_threads (query); - * notmuch_threads_valid (threads); - * notmuch_threads_move_to_next (threads)) - * { - * thread = notmuch_threads_get (threads); - * .... - * notmuch_thread_destroy (thread); - * } - * - * notmuch_query_destroy (query); - * - * Note: If you are finished with a thread before its containing - * query, you can call notmuch_thread_destroy to clean up some memory - * sooner (as in the above example). Otherwise, if your thread objects - * are long-lived, then you don't need to call notmuch_thread_destroy - * and all the memory will still be reclaimed when the query is - * destroyed. - * - * Note that there's no explicit destructor needed for the - * notmuch_threads_t object. (For consistency, we do provide a - * notmuch_threads_destroy function, but there's no good reason - * to call it if the query is about to be destroyed). - * - * If a Xapian exception occurs this function will return NULL. - */ -func (self *Query) SearchThreads() *Threads { - threads := C.notmuch_query_search_threads(self.query) - if threads == nil { - return nil - } - return &Threads{threads:threads} -} - -/* Execute a query for messages, returning a notmuch_messages_t object - * which can be used to iterate over the results. The returned - * messages object is owned by the query and as such, will only be - * valid until notmuch_query_destroy. - * - * Typical usage might be: - * - * notmuch_query_t *query; - * notmuch_messages_t *messages; - * notmuch_message_t *message; - * - * query = notmuch_query_create (database, query_string); - * - * for (messages = notmuch_query_search_messages (query); - * notmuch_messages_valid (messages); - * notmuch_messages_move_to_next (messages)) - * { - * message = notmuch_messages_get (messages); - * .... - * notmuch_message_destroy (message); - * } - * - * notmuch_query_destroy (query); - * - * Note: If you are finished with a message before its containing - * query, you can call notmuch_message_destroy to clean up some memory - * sooner (as in the above example). Otherwise, if your message - * objects are long-lived, then you don't need to call - * notmuch_message_destroy and all the memory will still be reclaimed - * when the query is destroyed. - * - * Note that there's no explicit destructor needed for the - * notmuch_messages_t object. (For consistency, we do provide a - * notmuch_messages_destroy function, but there's no good - * reason to call it if the query is about to be destroyed). - * - * If a Xapian exception occurs this function will return NULL. - */ -func (self *Query) SearchMessages() *Messages { - msgs := C.notmuch_query_search_messages(self.query) - if msgs == nil { - return nil - } - return &Messages{messages:msgs} -} - -/* Destroy a notmuch_query_t along with any associated resources. - * - * This will in turn destroy any notmuch_threads_t and - * notmuch_messages_t objects generated by this query, (and in - * turn any notmuch_thread_t and notmuch_message_t objects generated - * from those results, etc.), if such objects haven't already been - * destroyed. - */ -func (self *Query) Destroy() { - if self.query != nil { - C.notmuch_query_destroy(self.query) - } -} - -/* Return an estimate of the number of messages matching a search - * - * This function performs a search and returns Xapian's best - * guess as to number of matching messages. - * - * If a Xapian exception occurs, this function may return 0 (after - * printing a message). - */ -func (self *Query) CountMessages() uint { - return uint(C.notmuch_query_count_messages(self.query)) -} - -// TODO: wrap threads and thread - -/* Is the given 'threads' iterator pointing at a valid thread. - * - * When this function returns TRUE, notmuch_threads_get will return a - * valid object. Whereas when this function returns FALSE, - * notmuch_threads_get will return NULL. - * - * See the documentation of notmuch_query_search_threads for example - * code showing how to iterate over a notmuch_threads_t object. - */ -func (self *Threads) Valid() bool { - if self.threads == nil { - return false - } - valid := C.notmuch_threads_valid(self.threads) - if valid == 0 { - return false - } - return true -} - -/* Destroy a notmuch_threads_t object. - * - * It's not strictly necessary to call this function. All memory from - * the notmuch_threads_t object will be reclaimed when the - * containg query object is destroyed. - */ -func (self *Threads) Destroy() { - if self.threads != nil { - C.notmuch_threads_destroy(self.threads) - } -} - -/* Is the given 'messages' iterator pointing at a valid message. - * - * When this function returns TRUE, notmuch_messages_get will return a - * valid object. Whereas when this function returns FALSE, - * notmuch_messages_get will return NULL. - * - * See the documentation of notmuch_query_search_messages for example - * code showing how to iterate over a notmuch_messages_t object. - */ -func (self *Messages) Valid() bool { - if self.messages == nil { - return false - } - valid := C.notmuch_messages_valid(self.messages) - if valid == 0 { - return false - } - return true -} - -/* Get the current message from 'messages' as a notmuch_message_t. - * - * Note: The returned message belongs to 'messages' and has a lifetime - * identical to it (and the query to which it belongs). - * - * See the documentation of notmuch_query_search_messages for example - * code showing how to iterate over a notmuch_messages_t object. - * - * If an out-of-memory situation occurs, this function will return - * NULL. - */ -func (self *Messages) Get() *Message { - if self.messages == nil { - return nil - } - msg := C.notmuch_messages_get(self.messages) - if msg == nil { - return nil - } - return &Message{message:msg} -} - -/* Move the 'messages' iterator to the next message. - * - * If 'messages' is already pointing at the last message then the - * iterator will be moved to a point just beyond that last message, - * (where notmuch_messages_valid will return FALSE and - * notmuch_messages_get will return NULL). - * - * See the documentation of notmuch_query_search_messages for example - * code showing how to iterate over a notmuch_messages_t object. - */ -func (self *Messages) MoveToNext() { - if self.messages == nil { - return - } - C.notmuch_messages_move_to_next(self.messages) -} - -/* Destroy a notmuch_messages_t object. - * - * It's not strictly necessary to call this function. All memory from - * the notmuch_messages_t object will be reclaimed when the containing - * query object is destroyed. - */ -func (self *Messages) Destroy() { - if self.messages != nil { - C.notmuch_messages_destroy(self.messages) - } -} - -/* Return a list of tags from all messages. - * - * The resulting list is guaranteed not to contain duplicated tags. - * - * WARNING: You can no longer iterate over messages after calling this - * function, because the iterator will point at the end of the list. - * We do not have a function to reset the iterator yet and the only - * way how you can iterate over the list again is to recreate the - * message list. - * - * The function returns NULL on error. - */ -func (self *Messages) CollectTags() *Tags { - if self.messages == nil { - return nil - } - tags := C.notmuch_messages_collect_tags(self.messages) - if tags == nil { - return nil - } - return &Tags{tags:tags} -} - -/* Get the message ID of 'message'. - * - * The returned string belongs to 'message' and as such, should not be - * modified by the caller and will only be valid for as long as the - * message is valid, (which is until the query from which it derived - * is destroyed). - * - * This function will not return NULL since Notmuch ensures that every - * message has a unique message ID, (Notmuch will generate an ID for a - * message if the original file does not contain one). - */ -func (self *Message) GetMessageId() string { - - if self.message == nil { - return "" - } - id := C.notmuch_message_get_message_id(self.message) - // we dont own id - // defer C.free(unsafe.Pointer(id)) - if id == nil { - return "" - } - return C.GoString(id) -} - -/* Get the thread ID of 'message'. - * - * The returned string belongs to 'message' and as such, should not be - * modified by the caller and will only be valid for as long as the - * message is valid, (for example, until the user calls - * notmuch_message_destroy on 'message' or until a query from which it - * derived is destroyed). - * - * This function will not return NULL since Notmuch ensures that every - * message belongs to a single thread. - */ -func (self *Message) GetThreadId() string { - - if self.message == nil { - return "" - } - id := C.notmuch_message_get_thread_id(self.message) - // we dont own id - // defer C.free(unsafe.Pointer(id)) - - if id == nil { - return "" - } - - return C.GoString(id) -} - -/* Get a notmuch_messages_t iterator for all of the replies to - * 'message'. - * - * Note: This call only makes sense if 'message' was ultimately - * obtained from a notmuch_thread_t object, (such as by coming - * directly from the result of calling notmuch_thread_get_ - * toplevel_messages or by any number of subsequent - * calls to notmuch_message_get_replies). - * - * If 'message' was obtained through some non-thread means, (such as - * by a call to notmuch_query_search_messages), then this function - * will return NULL. - * - * If there are no replies to 'message', this function will return - * NULL. (Note that notmuch_messages_valid will accept that NULL - * value as legitimate, and simply return FALSE for it.) - */ -func (self *Message) GetReplies() *Messages { - if self.message == nil { - return nil - } - msgs := C.notmuch_message_get_replies(self.message) - if msgs == nil { - return nil - } - return &Messages{messages:msgs} -} - -/* Get a filename for the email corresponding to 'message'. - * - * The returned filename is an absolute filename, (the initial - * component will match notmuch_database_get_path() ). - * - * The returned string belongs to the message so should not be - * modified or freed by the caller (nor should it be referenced after - * the message is destroyed). - * - * Note: If this message corresponds to multiple files in the mail - * store, (that is, multiple files contain identical message IDs), - * this function will arbitrarily return a single one of those - * filenames. - */ -func (self *Message) GetFileName() string { - if self.message == nil { - return "" - } - fname := C.notmuch_message_get_filename(self.message) - // we dont own fname - // defer C.free(unsafe.Pointer(fname)) - - if fname == nil { - return "" - } - - return C.GoString(fname) -} - -type Flag C.notmuch_message_flag_t -const ( - MESSAGE_FLAG_MATCH Flag = 0 -) - -/* Get a value of a flag for the email corresponding to 'message'. */ -func (self *Message) GetFlag(flag Flag) bool { - if self.message == nil { - return false - } - v := C.notmuch_message_get_flag(self.message, C.notmuch_message_flag_t(flag)) - if v == 0 { - return false - } - return true -} - -/* Set a value of a flag for the email corresponding to 'message'. */ -func (self *Message) SetFlag(flag Flag, value bool) { - if self.message == nil { - return - } - var v C.notmuch_bool_t = 0 - if value { - v = 1 - } - C.notmuch_message_set_flag(self.message, C.notmuch_message_flag_t(flag), v) -} - -// TODO: wrap notmuch_message_get_date - -/* Get the value of the specified header from 'message'. - * - * The value will be read from the actual message file, not from the - * notmuch database. The header name is case insensitive. - * - * The returned string belongs to the message so should not be - * modified or freed by the caller (nor should it be referenced after - * the message is destroyed). - * - * Returns an empty string ("") if the message does not contain a - * header line matching 'header'. Returns NULL if any error occurs. - */ -func (self *Message) GetHeader(header string) string { - if self.message == nil { - return "" - } - - var c_header *C.char = C.CString(header) - defer C.free(unsafe.Pointer(c_header)) - - /* we dont own value */ - value := C.notmuch_message_get_header(self.message, c_header) - if value == nil { - return "" - } - - return C.GoString(value) -} - -/* Get the tags for 'message', returning a notmuch_tags_t object which - * can be used to iterate over all tags. - * - * The tags object is owned by the message and as such, will only be - * valid for as long as the message is valid, (which is until the - * query from which it derived is destroyed). - * - * Typical usage might be: - * - * notmuch_message_t *message; - * notmuch_tags_t *tags; - * const char *tag; - * - * message = notmuch_database_find_message (database, message_id); - * - * for (tags = notmuch_message_get_tags (message); - * notmuch_tags_valid (tags); - * notmuch_result_move_to_next (tags)) - * { - * tag = notmuch_tags_get (tags); - * .... - * } - * - * notmuch_message_destroy (message); - * - * Note that there's no explicit destructor needed for the - * notmuch_tags_t object. (For consistency, we do provide a - * notmuch_tags_destroy function, but there's no good reason to call - * it if the message is about to be destroyed). - */ -func (self *Message) GetTags() *Tags { - if self.message == nil { - return nil - } - tags := C.notmuch_message_get_tags(self.message) - if tags == nil { - return nil - } - return &Tags{tags:tags} -} - -/* The longest possible tag value. */ -const TAG_MAX = 200 - -/* Add a tag to the given message. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message - * - * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL - * - * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long - * (exceeds NOTMUCH_TAG_MAX) - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. - */ -func (self *Message) AddTag(tag string) Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - c_tag := C.CString(tag) - defer C.free(unsafe.Pointer(c_tag)) - - return Status(C.notmuch_message_add_tag(self.message, c_tag)) -} - -/* Remove a tag from the given message. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message - * - * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL - * - * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long - * (exceeds NOTMUCH_TAG_MAX) - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. - */ -func (self *Message) RemoveTag(tag string) Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - c_tag := C.CString(tag) - defer C.free(unsafe.Pointer(c_tag)) - - return Status(C.notmuch_message_remove_tag(self.message, c_tag)) -} - -/* Remove all tags from the given message. - * - * See notmuch_message_freeze for an example showing how to safely - * replace tag values. - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. - */ -func (self *Message) RemoveAllTags() Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - return Status(C.notmuch_message_remove_all_tags(self.message)) -} - -/* Freeze the current state of 'message' within the database. - * - * This means that changes to the message state, (via - * notmuch_message_add_tag, notmuch_message_remove_tag, and - * notmuch_message_remove_all_tags), will not be committed to the - * database until the message is thawed with notmuch_message_thaw. - * - * Multiple calls to freeze/thaw are valid and these calls will - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. - * - * The ability to do freeze/thaw allows for safe transactions to - * change tag values. For example, explicitly setting a message to - * have a given set of tags might look like this: - * - * notmuch_message_freeze (message); - * - * notmuch_message_remove_all_tags (message); - * - * for (i = 0; i < NUM_TAGS; i++) - * notmuch_message_add_tag (message, tags[i]); - * - * notmuch_message_thaw (message); - * - * With freeze/thaw used like this, the message in the database is - * guaranteed to have either the full set of original tag values, or - * the full set of new tag values, but nothing in between. - * - * Imagine the example above without freeze/thaw and the operation - * somehow getting interrupted. This could result in the message being - * left with no tags if the interruption happened after - * notmuch_message_remove_all_tags but before notmuch_message_add_tag. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Message successfully frozen. - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so message cannot be modified. - */ -func (self *Message) Freeze() Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - return Status(C.notmuch_message_freeze(self.message)) -} - -/* Thaw the current 'message', synchronizing any changes that may have - * occurred while 'message' was frozen into the notmuch database. - * - * See notmuch_message_freeze for an example of how to use this - * function to safely provide tag changes. - * - * Multiple calls to freeze/thaw are valid and these calls with - * "stack". That is there must be as many calls to thaw as to freeze - * before a message is actually thawed. - * - * Return value: - * - * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least - * its frozen count has successfully been reduced by 1). - * - * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw - * an unfrozen message. That is, there have been an unbalanced - * number of calls to notmuch_message_freeze and - * notmuch_message_thaw. - */ -func (self *Message) Thaw() Status { - if self.message == nil { - return STATUS_NULL_POINTER - } - - return Status(C.notmuch_message_thaw(self.message)) -} - -/* Destroy a notmuch_message_t object. - * - * It can be useful to call this function in the case of a single - * query object with many messages in the result, (such as iterating - * over the entire database). Otherwise, it's fine to never call this - * function and there will still be no memory leaks. (The memory from - * the messages get reclaimed when the containing query is destroyed.) - */ -func (self *Message) Destroy() { - if self.message == nil { - return - } - C.notmuch_message_destroy(self.message) -} - -/* Is the given 'tags' iterator pointing at a valid tag. - * - * When this function returns TRUE, notmuch_tags_get will return a - * valid string. Whereas when this function returns FALSE, - * notmuch_tags_get will return NULL. - * - * See the documentation of notmuch_message_get_tags for example code - * showing how to iterate over a notmuch_tags_t object. - */ -func (self *Tags) Valid() bool { - if self.tags == nil { - return false - } - v := C.notmuch_tags_valid(self.tags) - if v == 0 { - return false - } - return true -} - -/* Get the current tag from 'tags' as a string. - * - * Note: The returned string belongs to 'tags' and has a lifetime - * identical to it (and the query to which it ultimately belongs). - * - * See the documentation of notmuch_message_get_tags for example code - * showing how to iterate over a notmuch_tags_t object. - */ -func (self *Tags) Get() string { - if self.tags == nil { - return "" - } - s := C.notmuch_tags_get(self.tags) - // we dont own 's' - - return C.GoString(s) -} -func (self *Tags) String() string { - return self.Get() -} - -/* Move the 'tags' iterator to the next tag. - * - * If 'tags' is already pointing at the last tag then the iterator - * will be moved to a point just beyond that last tag, (where - * notmuch_tags_valid will return FALSE and notmuch_tags_get will - * return NULL). - * - * See the documentation of notmuch_message_get_tags for example code - * showing how to iterate over a notmuch_tags_t object. - */ -func (self *Tags) MoveToNext() { - if self.tags == nil { - return - } - C.notmuch_tags_move_to_next(self.tags) -} - -/* Destroy a notmuch_tags_t object. - * - * It's not strictly necessary to call this function. All memory from - * the notmuch_tags_t object will be reclaimed when the containing - * message or query objects are destroyed. - */ -func (self *Tags) Destroy() { - if self.tags == nil { - return - } - C.notmuch_tags_destroy(self.tags) -} - -// TODO: wrap notmuch_directory_ - -/* Destroy a notmuch_directory_t object. */ -func (self *Directory) Destroy() { - if self.dir == nil { - return - } - C.notmuch_directory_destroy(self.dir) -} - -// TODO: wrap notmuch_filenames_ - -/* Destroy a notmuch_filenames_t object. - * - * It's not strictly necessary to call this function. All memory from - * the notmuch_filenames_t object will be reclaimed when the - * containing directory object is destroyed. - * - * It is acceptable to pass NULL for 'filenames', in which case this - * function will do nothing. - */ -func (self *Filenames) Destroy() { - if self.fnames == nil { - return - } - C.notmuch_filenames_destroy(self.fnames) -} -/* EOF */ diff --git a/bindings/go/src/notmuch-addrlookup/addrlookup.go b/bindings/go/src/notmuch-addrlookup/addrlookup.go new file mode 100644 index 0000000..03699fb --- /dev/null +++ b/bindings/go/src/notmuch-addrlookup/addrlookup.go @@ -0,0 +1,263 @@ +package main + +// stdlib imports +import "os" +import "path" +import "log" +import "fmt" +import "regexp" +import "strings" +import "sort" + +// 3rd-party imports +import "notmuch" +import "github.com/kless/goconfig/config" + +type mail_addr_freq struct { + addr string + count [3]uint +} + +type frequencies map[string]uint + +/* Used to sort the email addresses from most to least used */ +func sort_by_freq(m1, m2 *mail_addr_freq) int { + if (m1.count[0] == m2.count[0] && + m1.count[1] == m2.count[1] && + m1.count[2] == m2.count[2]) { + return 0 + } + + if (m1.count[0] > m2.count[0] || + m1.count[0] == m2.count[0] && + m1.count[1] > m2.count[1] || + m1.count[0] == m2.count[0] && + m1.count[1] == m2.count[1] && + m1.count[2] > m2.count[2]) { + return -1 + } + + return 1 +} + +type maddresses []*mail_addr_freq + +func (self *maddresses) Len() int { + return len(*self) +} + +func (self *maddresses) Less(i,j int) bool { + m1 := (*self)[i] + m2 := (*self)[j] + v := sort_by_freq(m1, m2) + if v<=0 { + return true + } + return false +} + +func (self *maddresses) Swap(i,j int) { + (*self)[i], (*self)[j] = (*self)[j], (*self)[i] +} + +// find most frequent real name for each mail address +func frequent_fullname(freqs frequencies) string { + var maxfreq uint = 0 + fullname := "" + freqs_sz := len(freqs) + + for mail,freq := range freqs { + if (freq > maxfreq && mail != "") || freqs_sz == 1 { + // only use the entry if it has a real name + // or if this is the only entry + maxfreq = freq + fullname = mail + } + } + return fullname +} + +func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr_to_realname *map[string]*frequencies) *frequencies { + + freqs := make(frequencies) + + pattern := `\s*(("(\.|[^"])*"|[^,])*?)` + // pattern := "\\s*((\\\"(\\\\.|[^\\\\\"])*\\\"|[^,])*" + + // "\\b\\w+([-+.]\\w+)*\\@\\w+[-\\.\\w]*\\.([-\\.\\w]+)*\\w\\b)>?)" + pattern = `.*` + strings.ToLower(name) + `.*` + var re *regexp.Regexp = nil + var err os.Error = nil + if re,err = regexp.Compile(pattern); err != nil { + log.Printf("error: %v\n", err) + return &freqs + } + + headers := []string{"from"} + if pass == 1 { + headers = append(headers, "to", "cc", "bcc") + } + + for ;msgs.Valid();msgs.MoveToNext() { + msg := msgs.Get() + //println("==> msg [", msg.GetMessageId(), "]") + for _,header := range headers { + froms := strings.ToLower(msg.GetHeader(header)) + //println(" froms: ["+froms+"]") + for _,from := range strings.Split(froms, ",", -1) { + from = strings.Trim(from, " ") + match := re.FindString(from) + //println(" -> match: ["+match+"]") + occ,ok := freqs[match] + if !ok { + freqs[match] = 0 + occ = 0 + } + freqs[match] = occ+1 + } + } + } + return &freqs +} + +func search_address_passes(queries [3]*notmuch.Query, name string) []string { + var val []string + addr_freq := make(map[string]*mail_addr_freq) + addr_to_realname := make(map[string]*frequencies) + + var pass uint = 0 // 0-based + for _,query := range queries { + if query == nil { + //println("**warning: idx [",idx,"] contains a nil query") + continue + } + msgs := query.SearchMessages() + ht := addresses_by_frequency(msgs, name, pass, &addr_to_realname) + for addr, count := range *ht { + freq,ok := addr_freq[addr] + if !ok { + freq = &mail_addr_freq{addr:addr, count:[3]uint{0,0,0}} + } + freq.count[pass] = count + addr_freq[addr] = freq + } + msgs.Destroy() + pass += 1 + } + + addrs := make(maddresses, len(addr_freq)) + { + iaddr := 0 + for _, freq := range addr_freq { + addrs[iaddr] = freq + iaddr += 1 + } + } + sort.Sort(&addrs) + + for _,addr := range addrs { + freqs,ok := addr_to_realname[addr.addr] + if ok { + val = append(val, frequent_fullname(*freqs)) + } else { + val = append(val, addr.addr) + } + } + //println("val:",val) + return val +} + +type address_matcher struct { + // the notmuch database + db *notmuch.Database + // full path of the notmuch database + user_db_path string + // user primary email + user_primary_email string + // user tag to mark from addresses as in the address book + user_addrbook_tag string +} + +func new_address_matcher() *address_matcher { + var cfg *config.Config + var err os.Error + + // honor NOTMUCH_CONFIG + home := os.Getenv("NOTMUCH_CONFIG") + if home == "" { + home = os.Getenv("HOME") + } + + if cfg,err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil { + log.Fatalf("error loading config file:",err) + } + + db_path,_ := cfg.String("database", "path") + primary_email,_ := cfg.String("user", "primary_email") + addrbook_tag,err := cfg.String("user", "addrbook_tag") + if err != nil { + addrbook_tag = "addressbook" + } + + self := &address_matcher{db:nil, + user_db_path:db_path, + user_primary_email:primary_email, + user_addrbook_tag:addrbook_tag} + return self +} + +func (self *address_matcher) run(name string) { + queries := [3]*notmuch.Query{} + + // open the database + if db, status := notmuch.OpenDatabase(self.user_db_path, + notmuch.DATABASE_MODE_READ_ONLY); status == notmuch.STATUS_SUCCESS { + self.db = db + } else { + log.Fatalf("Failed to open the database: %v\n", status) + } + + // pass 1: look at all from: addresses with the address book tag + query := "tag:" + self.user_addrbook_tag + if name != "" { + query = query + " and from:" + name + "*" + } + queries[0] = self.db.CreateQuery(query) + + // pass 2: look at all to: addresses sent from our primary mail + query = "" + if name != "" { + query = "to:"+name+"*" + } + if self.user_primary_email != "" { + query = query + " from:" + self.user_primary_email + } + queries[1] = self.db.CreateQuery(query) + + // if that leads only to a few hits, we check every from too + if queries[0].CountMessages() + queries[1].CountMessages() < 10 { + query = "" + if name != "" { + query = "from:"+name+"*" + } + queries[2] = self.db.CreateQuery(query) + } + + // actually retrieve and sort addresses + results := search_address_passes(queries, name) + for _,v := range results { + if v != "" && v != "\n" { + fmt.Println(v) + } + } + return +} + +func main() { + //fmt.Println("args:",os.Args) + app := new_address_matcher() + name := "" + if len(os.Args) > 1 { + name = os.Args[1] + } + app.run(name) +} \ No newline at end of file diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go new file mode 100644 index 0000000..8faf3bb --- /dev/null +++ b/bindings/go/src/notmuch/notmuch.go @@ -0,0 +1,1125 @@ +// Wrapper around the notmuch library + +package notmuch + +/* +#include +#include +#include +#include "notmuch.h" +*/ +import "C" +import "unsafe" + +// Status codes used for the return values of most functions +type Status C.notmuch_status_t +const ( + STATUS_SUCCESS Status = iota + STATUS_OUT_OF_MEMORY + STATUS_READ_ONLY_DATABASE + STATUS_XAPIAN_EXCEPTION + STATUS_FILE_ERROR + STATUS_FILE_NOT_EMAIL + STATUS_DUPLICATE_MESSAGE_ID + STATUS_NULL_POINTER + STATUS_TAG_TOO_LONG + STATUS_UNBALANCED_FREEZE_THAW + STATUS_UNBALANCED_ATOMIC + + STATUS_LAST_STATUS +) + +func (self Status) String() string { + var p *C.char + + // p is read-only + p = C.notmuch_status_to_string(C.notmuch_status_t(self)) + if p != nil { + s := C.GoString(p) + return s + } + return "" +} + +/* Various opaque data types. For each notmuch__t see the various + * notmuch_ functions below. */ + +type Database struct { + db *C.notmuch_database_t +} + +type Query struct { + query *C.notmuch_query_t +} + +type Threads struct { + threads *C.notmuch_threads_t +} + +type Thread struct { + thread *C.notmuch_thread_t +} + +type Messages struct { + messages *C.notmuch_messages_t +} + +type Message struct { + message *C.notmuch_message_t +} + +type Tags struct { + tags *C.notmuch_tags_t +} + +type Directory struct { + dir *C.notmuch_directory_t +} + +type Filenames struct { + fnames *C.notmuch_filenames_t +} + +type DatabaseMode C.notmuch_database_mode_t +const ( + DATABASE_MODE_READ_ONLY DatabaseMode = 0 + DATABASE_MODE_READ_WRITE +) + +// Create a new, empty notmuch database located at 'path' +func NewDatabase(path string) (*Database, Status) { + + var c_path *C.char = C.CString(path) + defer C.free(unsafe.Pointer(c_path)) + + if c_path == nil { + return nil, STATUS_OUT_OF_MEMORY + } + + self := &Database{db:nil} + st := Status(C.notmuch_database_create(c_path, &self.db)) + if st != STATUS_SUCCESS { + return nil, st + } + return self, st +} + +/* Open an existing notmuch database located at 'path'. + * + * The database should have been created at some time in the past, + * (not necessarily by this process), by calling + * notmuch_database_create with 'path'. By default the database should be + * opened for reading only. In order to write to the database you need to + * pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode. + * + * An existing notmuch database can be identified by the presence of a + * directory named ".notmuch" below 'path'. + * + * The caller should call notmuch_database_destroy when finished with + * this database. + * + * In case of any failure, this function returns NULL, (after printing + * an error message on stderr). + */ +func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) { + + var c_path *C.char = C.CString(path) + defer C.free(unsafe.Pointer(c_path)) + + if c_path == nil { + return nil, STATUS_OUT_OF_MEMORY + } + + self := &Database{db:nil} + st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db)) + if st != STATUS_SUCCESS { + return nil, st + } + return self, st +} + +/* Close the given notmuch database, freeing all associated + * resources. See notmuch_database_open. */ +func (self *Database) Close() { + C.notmuch_database_destroy(self.db) +} + +/* Return the database path of the given database. + */ +func (self *Database) GetPath() string { + + /* The return value is a string owned by notmuch so should not be + * modified nor freed by the caller. */ + var p *C.char = C.notmuch_database_get_path(self.db) + if p != nil { + s := C.GoString(p) + return s + } + return "" +} + +/* Return the database format version of the given database. */ +func (self *Database) GetVersion() uint { + return uint(C.notmuch_database_get_version(self.db)) +} + +/* Does this database need to be upgraded before writing to it? + * + * If this function returns TRUE then no functions that modify the + * database (notmuch_database_add_message, notmuch_message_add_tag, + * notmuch_directory_set_mtime, etc.) will work unless the function + * notmuch_database_upgrade is called successfully first. */ +func (self *Database) NeedsUpgrade() bool { + do_upgrade := C.notmuch_database_needs_upgrade(self.db) + if do_upgrade == 0 { + return false + } + return true +} + +// TODO: notmuch_database_upgrade + + +/* Retrieve a directory object from the database for 'path'. + * + * Here, 'path' should be a path relative to the path of 'database' + * (see notmuch_database_get_path), or else should be an absolute path + * with initial components that match the path of 'database'. + * + * Can return NULL if a Xapian exception occurs. + */ +func (self *Database) GetDirectory(path string) *Directory { + var c_path *C.char = C.CString(path) + defer C.free(unsafe.Pointer(c_path)) + + if c_path == nil { + return nil + } + + c_dir := C.notmuch_database_get_directory(self.db, c_path) + if c_dir == nil { + return nil + } + return &Directory{dir:c_dir} +} + +/* Add a new message to the given notmuch database. + * + * Here,'filename' should be a path relative to the path of + * 'database' (see notmuch_database_get_path), or else should be an + * absolute filename with initial components that match the path of + * 'database'. + * + * The file should be a single mail message (not a multi-message mbox) + * that is expected to remain at its current location, (since the + * notmuch database will reference the filename, and will not copy the + * entire contents of the file. + * + * If 'message' is not NULL, then, on successful return '*message' + * will be initialized to a message object that can be used for things + * such as adding tags to the just-added message. The user should call + * notmuch_message_destroy when done with the message. On any failure + * '*message' will be set to NULL. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully added to database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, + * message not added. + * + * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message + * ID as another message already in the database. The new + * filename was successfully added to the message in the database + * (if not already present). + * + * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the + * file, (such as permission denied, or file not found, + * etc.). Nothing added to the database. + * + * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look + * like an email message. Nothing added to the database. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so no message can be added. + */ +func +(self *Database) AddMessage(fname string) (*Message, Status) { + var c_fname *C.char = C.CString(fname) + defer C.free(unsafe.Pointer(c_fname)) + + if c_fname == nil { + return nil, STATUS_OUT_OF_MEMORY + } + + var c_msg *C.notmuch_message_t = new(C.notmuch_message_t) + st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg)) + + return &Message{message:c_msg}, st +} + +/* Remove a message from the given notmuch database. + * + * Note that only this particular filename association is removed from + * the database. If the same message (as determined by the message ID) + * is still available via other filenames, then the message will + * persist in the database for those filenames. When the last filename + * is removed for a particular message, the database content for that + * message will be entirely removed. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: The last filename was removed and the + * message was removed from the database. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred, + * message not removed. + * + * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but + * the message persists in the database with at least one other + * filename. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so no message can be removed. + */ +func (self *Database) RemoveMessage(fname string) Status { + + var c_fname *C.char = C.CString(fname) + defer C.free(unsafe.Pointer(c_fname)) + + if c_fname == nil { + return STATUS_OUT_OF_MEMORY + } + + st := C.notmuch_database_remove_message(self.db, c_fname) + return Status(st) +} + +/* Find a message with the given message_id. + * + * If the database contains a message with the given message_id, then + * a new notmuch_message_t object is returned. The caller should call + * notmuch_message_destroy when done with the message. + * + * This function returns NULL in the following situations: + * + * * No message is found with the given message_id + * * An out-of-memory situation occurs + * * A Xapian exception occurs + */ +func (self *Database) FindMessage(message_id string) (*Message, Status) { + + var c_msg_id *C.char = C.CString(message_id) + defer C.free(unsafe.Pointer(c_msg_id)) + + if c_msg_id == nil { + return nil, STATUS_OUT_OF_MEMORY + } + + msg := &Message{message:nil} + st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message)) + if st != STATUS_SUCCESS { + return nil, st + } + return msg, st +} + +/* Return a list of all tags found in the database. + * + * This function creates a list of all tags found in the database. The + * resulting list contains all tags from all messages found in the database. + * + * On error this function returns NULL. + */ +func (self *Database) GetAllTags() *Tags { + tags := C.notmuch_database_get_all_tags(self.db) + if tags == nil { + return nil + } + return &Tags{tags:tags} +} + +/* Create a new query for 'database'. + * + * Here, 'database' should be an open database, (see + * notmuch_database_open and notmuch_database_create). + * + * For the query string, we'll document the syntax here more + * completely in the future, but it's likely to be a specialized + * version of the general Xapian query syntax: + * + * http://xapian.org/docs/queryparser.html + * + * As a special case, passing either a length-zero string, (that is ""), + * or a string consisting of a single asterisk (that is "*"), will + * result in a query that returns all messages in the database. + * + * See notmuch_query_set_sort for controlling the order of results. + * See notmuch_query_search_messages and notmuch_query_search_threads + * to actually execute the query. + * + * User should call notmuch_query_destroy when finished with this + * query. + * + * Will return NULL if insufficient memory is available. + */ +func (self *Database) CreateQuery(query string) *Query { + + var c_query *C.char = C.CString(query) + defer C.free(unsafe.Pointer(c_query)) + + if c_query == nil { + return nil + } + + q := C.notmuch_query_create(self.db, c_query) + if q == nil { + return nil + } + return &Query{query:q} +} + +/* Sort values for notmuch_query_set_sort */ +type Sort C.notmuch_sort_t +const ( + SORT_OLDEST_FIRST Sort = 0 + SORT_NEWEST_FIRST + SORT_MESSAGE_ID + SORT_UNSORTED +) + +/* Return the query_string of this query. See notmuch_query_create. */ +func (self *Query) String() string { + // FIXME: do we own 'q' or not ? + q := C.notmuch_query_get_query_string(self.query) + //defer C.free(unsafe.Pointer(q)) + + if q != nil { + s := C.GoString(q) + return s + } + + return "" +} + +/* Specify the sorting desired for this query. */ +func (self *Query) SetSort(sort Sort) { + C.notmuch_query_set_sort(self.query, C.notmuch_sort_t(sort)) +} + +/* Return the sort specified for this query. See notmuch_query_set_sort. */ +func (self *Query) GetSort() Sort { + return Sort(C.notmuch_query_get_sort(self.query)) +} + +/* Execute a query for threads, returning a notmuch_threads_t object + * which can be used to iterate over the results. The returned threads + * object is owned by the query and as such, will only be valid until + * notmuch_query_destroy. + * + * Typical usage might be: + * + * notmuch_query_t *query; + * notmuch_threads_t *threads; + * notmuch_thread_t *thread; + * + * query = notmuch_query_create (database, query_string); + * + * for (threads = notmuch_query_search_threads (query); + * notmuch_threads_valid (threads); + * notmuch_threads_move_to_next (threads)) + * { + * thread = notmuch_threads_get (threads); + * .... + * notmuch_thread_destroy (thread); + * } + * + * notmuch_query_destroy (query); + * + * Note: If you are finished with a thread before its containing + * query, you can call notmuch_thread_destroy to clean up some memory + * sooner (as in the above example). Otherwise, if your thread objects + * are long-lived, then you don't need to call notmuch_thread_destroy + * and all the memory will still be reclaimed when the query is + * destroyed. + * + * Note that there's no explicit destructor needed for the + * notmuch_threads_t object. (For consistency, we do provide a + * notmuch_threads_destroy function, but there's no good reason + * to call it if the query is about to be destroyed). + * + * If a Xapian exception occurs this function will return NULL. + */ +func (self *Query) SearchThreads() *Threads { + threads := C.notmuch_query_search_threads(self.query) + if threads == nil { + return nil + } + return &Threads{threads:threads} +} + +/* Execute a query for messages, returning a notmuch_messages_t object + * which can be used to iterate over the results. The returned + * messages object is owned by the query and as such, will only be + * valid until notmuch_query_destroy. + * + * Typical usage might be: + * + * notmuch_query_t *query; + * notmuch_messages_t *messages; + * notmuch_message_t *message; + * + * query = notmuch_query_create (database, query_string); + * + * for (messages = notmuch_query_search_messages (query); + * notmuch_messages_valid (messages); + * notmuch_messages_move_to_next (messages)) + * { + * message = notmuch_messages_get (messages); + * .... + * notmuch_message_destroy (message); + * } + * + * notmuch_query_destroy (query); + * + * Note: If you are finished with a message before its containing + * query, you can call notmuch_message_destroy to clean up some memory + * sooner (as in the above example). Otherwise, if your message + * objects are long-lived, then you don't need to call + * notmuch_message_destroy and all the memory will still be reclaimed + * when the query is destroyed. + * + * Note that there's no explicit destructor needed for the + * notmuch_messages_t object. (For consistency, we do provide a + * notmuch_messages_destroy function, but there's no good + * reason to call it if the query is about to be destroyed). + * + * If a Xapian exception occurs this function will return NULL. + */ +func (self *Query) SearchMessages() *Messages { + msgs := C.notmuch_query_search_messages(self.query) + if msgs == nil { + return nil + } + return &Messages{messages:msgs} +} + +/* Destroy a notmuch_query_t along with any associated resources. + * + * This will in turn destroy any notmuch_threads_t and + * notmuch_messages_t objects generated by this query, (and in + * turn any notmuch_thread_t and notmuch_message_t objects generated + * from those results, etc.), if such objects haven't already been + * destroyed. + */ +func (self *Query) Destroy() { + if self.query != nil { + C.notmuch_query_destroy(self.query) + } +} + +/* Return an estimate of the number of messages matching a search + * + * This function performs a search and returns Xapian's best + * guess as to number of matching messages. + * + * If a Xapian exception occurs, this function may return 0 (after + * printing a message). + */ +func (self *Query) CountMessages() uint { + return uint(C.notmuch_query_count_messages(self.query)) +} + +// TODO: wrap threads and thread + +/* Is the given 'threads' iterator pointing at a valid thread. + * + * When this function returns TRUE, notmuch_threads_get will return a + * valid object. Whereas when this function returns FALSE, + * notmuch_threads_get will return NULL. + * + * See the documentation of notmuch_query_search_threads for example + * code showing how to iterate over a notmuch_threads_t object. + */ +func (self *Threads) Valid() bool { + if self.threads == nil { + return false + } + valid := C.notmuch_threads_valid(self.threads) + if valid == 0 { + return false + } + return true +} + +/* Destroy a notmuch_threads_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_threads_t object will be reclaimed when the + * containg query object is destroyed. + */ +func (self *Threads) Destroy() { + if self.threads != nil { + C.notmuch_threads_destroy(self.threads) + } +} + +/* Is the given 'messages' iterator pointing at a valid message. + * + * When this function returns TRUE, notmuch_messages_get will return a + * valid object. Whereas when this function returns FALSE, + * notmuch_messages_get will return NULL. + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + */ +func (self *Messages) Valid() bool { + if self.messages == nil { + return false + } + valid := C.notmuch_messages_valid(self.messages) + if valid == 0 { + return false + } + return true +} + +/* Get the current message from 'messages' as a notmuch_message_t. + * + * Note: The returned message belongs to 'messages' and has a lifetime + * identical to it (and the query to which it belongs). + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + * + * If an out-of-memory situation occurs, this function will return + * NULL. + */ +func (self *Messages) Get() *Message { + if self.messages == nil { + return nil + } + msg := C.notmuch_messages_get(self.messages) + if msg == nil { + return nil + } + return &Message{message:msg} +} + +/* Move the 'messages' iterator to the next message. + * + * If 'messages' is already pointing at the last message then the + * iterator will be moved to a point just beyond that last message, + * (where notmuch_messages_valid will return FALSE and + * notmuch_messages_get will return NULL). + * + * See the documentation of notmuch_query_search_messages for example + * code showing how to iterate over a notmuch_messages_t object. + */ +func (self *Messages) MoveToNext() { + if self.messages == nil { + return + } + C.notmuch_messages_move_to_next(self.messages) +} + +/* Destroy a notmuch_messages_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_messages_t object will be reclaimed when the containing + * query object is destroyed. + */ +func (self *Messages) Destroy() { + if self.messages != nil { + C.notmuch_messages_destroy(self.messages) + } +} + +/* Return a list of tags from all messages. + * + * The resulting list is guaranteed not to contain duplicated tags. + * + * WARNING: You can no longer iterate over messages after calling this + * function, because the iterator will point at the end of the list. + * We do not have a function to reset the iterator yet and the only + * way how you can iterate over the list again is to recreate the + * message list. + * + * The function returns NULL on error. + */ +func (self *Messages) CollectTags() *Tags { + if self.messages == nil { + return nil + } + tags := C.notmuch_messages_collect_tags(self.messages) + if tags == nil { + return nil + } + return &Tags{tags:tags} +} + +/* Get the message ID of 'message'. + * + * The returned string belongs to 'message' and as such, should not be + * modified by the caller and will only be valid for as long as the + * message is valid, (which is until the query from which it derived + * is destroyed). + * + * This function will not return NULL since Notmuch ensures that every + * message has a unique message ID, (Notmuch will generate an ID for a + * message if the original file does not contain one). + */ +func (self *Message) GetMessageId() string { + + if self.message == nil { + return "" + } + id := C.notmuch_message_get_message_id(self.message) + // we dont own id + // defer C.free(unsafe.Pointer(id)) + if id == nil { + return "" + } + return C.GoString(id) +} + +/* Get the thread ID of 'message'. + * + * The returned string belongs to 'message' and as such, should not be + * modified by the caller and will only be valid for as long as the + * message is valid, (for example, until the user calls + * notmuch_message_destroy on 'message' or until a query from which it + * derived is destroyed). + * + * This function will not return NULL since Notmuch ensures that every + * message belongs to a single thread. + */ +func (self *Message) GetThreadId() string { + + if self.message == nil { + return "" + } + id := C.notmuch_message_get_thread_id(self.message) + // we dont own id + // defer C.free(unsafe.Pointer(id)) + + if id == nil { + return "" + } + + return C.GoString(id) +} + +/* Get a notmuch_messages_t iterator for all of the replies to + * 'message'. + * + * Note: This call only makes sense if 'message' was ultimately + * obtained from a notmuch_thread_t object, (such as by coming + * directly from the result of calling notmuch_thread_get_ + * toplevel_messages or by any number of subsequent + * calls to notmuch_message_get_replies). + * + * If 'message' was obtained through some non-thread means, (such as + * by a call to notmuch_query_search_messages), then this function + * will return NULL. + * + * If there are no replies to 'message', this function will return + * NULL. (Note that notmuch_messages_valid will accept that NULL + * value as legitimate, and simply return FALSE for it.) + */ +func (self *Message) GetReplies() *Messages { + if self.message == nil { + return nil + } + msgs := C.notmuch_message_get_replies(self.message) + if msgs == nil { + return nil + } + return &Messages{messages:msgs} +} + +/* Get a filename for the email corresponding to 'message'. + * + * The returned filename is an absolute filename, (the initial + * component will match notmuch_database_get_path() ). + * + * The returned string belongs to the message so should not be + * modified or freed by the caller (nor should it be referenced after + * the message is destroyed). + * + * Note: If this message corresponds to multiple files in the mail + * store, (that is, multiple files contain identical message IDs), + * this function will arbitrarily return a single one of those + * filenames. + */ +func (self *Message) GetFileName() string { + if self.message == nil { + return "" + } + fname := C.notmuch_message_get_filename(self.message) + // we dont own fname + // defer C.free(unsafe.Pointer(fname)) + + if fname == nil { + return "" + } + + return C.GoString(fname) +} + +type Flag C.notmuch_message_flag_t +const ( + MESSAGE_FLAG_MATCH Flag = 0 +) + +/* Get a value of a flag for the email corresponding to 'message'. */ +func (self *Message) GetFlag(flag Flag) bool { + if self.message == nil { + return false + } + v := C.notmuch_message_get_flag(self.message, C.notmuch_message_flag_t(flag)) + if v == 0 { + return false + } + return true +} + +/* Set a value of a flag for the email corresponding to 'message'. */ +func (self *Message) SetFlag(flag Flag, value bool) { + if self.message == nil { + return + } + var v C.notmuch_bool_t = 0 + if value { + v = 1 + } + C.notmuch_message_set_flag(self.message, C.notmuch_message_flag_t(flag), v) +} + +// TODO: wrap notmuch_message_get_date + +/* Get the value of the specified header from 'message'. + * + * The value will be read from the actual message file, not from the + * notmuch database. The header name is case insensitive. + * + * The returned string belongs to the message so should not be + * modified or freed by the caller (nor should it be referenced after + * the message is destroyed). + * + * Returns an empty string ("") if the message does not contain a + * header line matching 'header'. Returns NULL if any error occurs. + */ +func (self *Message) GetHeader(header string) string { + if self.message == nil { + return "" + } + + var c_header *C.char = C.CString(header) + defer C.free(unsafe.Pointer(c_header)) + + /* we dont own value */ + value := C.notmuch_message_get_header(self.message, c_header) + if value == nil { + return "" + } + + return C.GoString(value) +} + +/* Get the tags for 'message', returning a notmuch_tags_t object which + * can be used to iterate over all tags. + * + * The tags object is owned by the message and as such, will only be + * valid for as long as the message is valid, (which is until the + * query from which it derived is destroyed). + * + * Typical usage might be: + * + * notmuch_message_t *message; + * notmuch_tags_t *tags; + * const char *tag; + * + * message = notmuch_database_find_message (database, message_id); + * + * for (tags = notmuch_message_get_tags (message); + * notmuch_tags_valid (tags); + * notmuch_result_move_to_next (tags)) + * { + * tag = notmuch_tags_get (tags); + * .... + * } + * + * notmuch_message_destroy (message); + * + * Note that there's no explicit destructor needed for the + * notmuch_tags_t object. (For consistency, we do provide a + * notmuch_tags_destroy function, but there's no good reason to call + * it if the message is about to be destroyed). + */ +func (self *Message) GetTags() *Tags { + if self.message == nil { + return nil + } + tags := C.notmuch_message_get_tags(self.message) + if tags == nil { + return nil + } + return &Tags{tags:tags} +} + +/* The longest possible tag value. */ +const TAG_MAX = 200 + +/* Add a tag to the given message. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message + * + * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL + * + * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long + * (exceeds NOTMUCH_TAG_MAX) + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +func (self *Message) AddTag(tag string) Status { + if self.message == nil { + return STATUS_NULL_POINTER + } + c_tag := C.CString(tag) + defer C.free(unsafe.Pointer(c_tag)) + + return Status(C.notmuch_message_add_tag(self.message, c_tag)) +} + +/* Remove a tag from the given message. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message + * + * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL + * + * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long + * (exceeds NOTMUCH_TAG_MAX) + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +func (self *Message) RemoveTag(tag string) Status { + if self.message == nil { + return STATUS_NULL_POINTER + } + c_tag := C.CString(tag) + defer C.free(unsafe.Pointer(c_tag)) + + return Status(C.notmuch_message_remove_tag(self.message, c_tag)) +} + +/* Remove all tags from the given message. + * + * See notmuch_message_freeze for an example showing how to safely + * replace tag values. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +func (self *Message) RemoveAllTags() Status { + if self.message == nil { + return STATUS_NULL_POINTER + } + return Status(C.notmuch_message_remove_all_tags(self.message)) +} + +/* Freeze the current state of 'message' within the database. + * + * This means that changes to the message state, (via + * notmuch_message_add_tag, notmuch_message_remove_tag, and + * notmuch_message_remove_all_tags), will not be committed to the + * database until the message is thawed with notmuch_message_thaw. + * + * Multiple calls to freeze/thaw are valid and these calls will + * "stack". That is there must be as many calls to thaw as to freeze + * before a message is actually thawed. + * + * The ability to do freeze/thaw allows for safe transactions to + * change tag values. For example, explicitly setting a message to + * have a given set of tags might look like this: + * + * notmuch_message_freeze (message); + * + * notmuch_message_remove_all_tags (message); + * + * for (i = 0; i < NUM_TAGS; i++) + * notmuch_message_add_tag (message, tags[i]); + * + * notmuch_message_thaw (message); + * + * With freeze/thaw used like this, the message in the database is + * guaranteed to have either the full set of original tag values, or + * the full set of new tag values, but nothing in between. + * + * Imagine the example above without freeze/thaw and the operation + * somehow getting interrupted. This could result in the message being + * left with no tags if the interruption happened after + * notmuch_message_remove_all_tags but before notmuch_message_add_tag. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully frozen. + * + * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only + * mode so message cannot be modified. + */ +func (self *Message) Freeze() Status { + if self.message == nil { + return STATUS_NULL_POINTER + } + return Status(C.notmuch_message_freeze(self.message)) +} + +/* Thaw the current 'message', synchronizing any changes that may have + * occurred while 'message' was frozen into the notmuch database. + * + * See notmuch_message_freeze for an example of how to use this + * function to safely provide tag changes. + * + * Multiple calls to freeze/thaw are valid and these calls with + * "stack". That is there must be as many calls to thaw as to freeze + * before a message is actually thawed. + * + * Return value: + * + * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least + * its frozen count has successfully been reduced by 1). + * + * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw + * an unfrozen message. That is, there have been an unbalanced + * number of calls to notmuch_message_freeze and + * notmuch_message_thaw. + */ +func (self *Message) Thaw() Status { + if self.message == nil { + return STATUS_NULL_POINTER + } + + return Status(C.notmuch_message_thaw(self.message)) +} + +/* Destroy a notmuch_message_t object. + * + * It can be useful to call this function in the case of a single + * query object with many messages in the result, (such as iterating + * over the entire database). Otherwise, it's fine to never call this + * function and there will still be no memory leaks. (The memory from + * the messages get reclaimed when the containing query is destroyed.) + */ +func (self *Message) Destroy() { + if self.message == nil { + return + } + C.notmuch_message_destroy(self.message) +} + +/* Is the given 'tags' iterator pointing at a valid tag. + * + * When this function returns TRUE, notmuch_tags_get will return a + * valid string. Whereas when this function returns FALSE, + * notmuch_tags_get will return NULL. + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +func (self *Tags) Valid() bool { + if self.tags == nil { + return false + } + v := C.notmuch_tags_valid(self.tags) + if v == 0 { + return false + } + return true +} + +/* Get the current tag from 'tags' as a string. + * + * Note: The returned string belongs to 'tags' and has a lifetime + * identical to it (and the query to which it ultimately belongs). + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +func (self *Tags) Get() string { + if self.tags == nil { + return "" + } + s := C.notmuch_tags_get(self.tags) + // we dont own 's' + + return C.GoString(s) +} +func (self *Tags) String() string { + return self.Get() +} + +/* Move the 'tags' iterator to the next tag. + * + * If 'tags' is already pointing at the last tag then the iterator + * will be moved to a point just beyond that last tag, (where + * notmuch_tags_valid will return FALSE and notmuch_tags_get will + * return NULL). + * + * See the documentation of notmuch_message_get_tags for example code + * showing how to iterate over a notmuch_tags_t object. + */ +func (self *Tags) MoveToNext() { + if self.tags == nil { + return + } + C.notmuch_tags_move_to_next(self.tags) +} + +/* Destroy a notmuch_tags_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_tags_t object will be reclaimed when the containing + * message or query objects are destroyed. + */ +func (self *Tags) Destroy() { + if self.tags == nil { + return + } + C.notmuch_tags_destroy(self.tags) +} + +// TODO: wrap notmuch_directory_ + +/* Destroy a notmuch_directory_t object. */ +func (self *Directory) Destroy() { + if self.dir == nil { + return + } + C.notmuch_directory_destroy(self.dir) +} + +// TODO: wrap notmuch_filenames_ + +/* Destroy a notmuch_filenames_t object. + * + * It's not strictly necessary to call this function. All memory from + * the notmuch_filenames_t object will be reclaimed when the + * containing directory object is destroyed. + * + * It is acceptable to pass NULL for 'filenames', in which case this + * function will do nothing. + */ +func (self *Filenames) Destroy() { + if self.fnames == nil { + return + } + C.notmuch_filenames_destroy(self.fnames) +} +/* EOF */ -- cgit v1.2.3 From 3760a79b3fd551c389f1216af321d1ab45d0642f Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 13:15:17 +0200 Subject: go: set LDFLAGS to -lnotmuch in the packages source file Set the LDFLAGS to -lnotmuch so the resulting go package will be linked with libnotmuch. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/src/notmuch/notmuch.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bindings') diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go index 8faf3bb..86e577c 100644 --- a/bindings/go/src/notmuch/notmuch.go +++ b/bindings/go/src/notmuch/notmuch.go @@ -3,6 +3,8 @@ package notmuch /* +#cgo LDFLAGS: -lnotmuch + #include #include #include -- cgit v1.2.3 From 9bf6eec1a51c49f025454fdfc709b4d29142f84c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 13:15:18 +0200 Subject: go: update the addrlookup utility to go 1 Use the new built in error type that replaces os.Error, adapt the code to the fact that strings.Split has just two arguments now. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/src/notmuch-addrlookup/addrlookup.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bindings') diff --git a/bindings/go/src/notmuch-addrlookup/addrlookup.go b/bindings/go/src/notmuch-addrlookup/addrlookup.go index 03699fb..d172666 100644 --- a/bindings/go/src/notmuch-addrlookup/addrlookup.go +++ b/bindings/go/src/notmuch-addrlookup/addrlookup.go @@ -86,7 +86,7 @@ func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr // "\\b\\w+([-+.]\\w+)*\\@\\w+[-\\.\\w]*\\.([-\\.\\w]+)*\\w\\b)>?)" pattern = `.*` + strings.ToLower(name) + `.*` var re *regexp.Regexp = nil - var err os.Error = nil + var err error = nil if re,err = regexp.Compile(pattern); err != nil { log.Printf("error: %v\n", err) return &freqs @@ -103,7 +103,7 @@ func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr for _,header := range headers { froms := strings.ToLower(msg.GetHeader(header)) //println(" froms: ["+froms+"]") - for _,from := range strings.Split(froms, ",", -1) { + for _,from := range strings.Split(froms, ",") { from = strings.Trim(from, " ") match := re.FindString(from) //println(" -> match: ["+match+"]") @@ -179,7 +179,7 @@ type address_matcher struct { func new_address_matcher() *address_matcher { var cfg *config.Config - var err os.Error + var err error // honor NOTMUCH_CONFIG home := os.Getenv("NOTMUCH_CONFIG") -- cgit v1.2.3 From 3113731713ac49142c86c934906d0f5a1e6f3eb8 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 13:15:19 +0200 Subject: go: update the build system The new "go" utility does not require any Makefiles to compile go packages and programs. Remove the old Makefiles and replace the top level Makefile with one defining some convenience targets for compiling the notmuch bindings and the notmuch-addrlookup utility. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/Makefile | 70 +++++++++++++++++++++++++++-------------------- bindings/go/cmds/Makefile | 11 -------- bindings/go/pkg/Makefile | 17 ------------ 3 files changed, 40 insertions(+), 58 deletions(-) delete mode 100644 bindings/go/cmds/Makefile delete mode 100644 bindings/go/pkg/Makefile (limited to 'bindings') diff --git a/bindings/go/Makefile b/bindings/go/Makefile index aba2d59..c38f234 100644 --- a/bindings/go/Makefile +++ b/bindings/go/Makefile @@ -1,30 +1,40 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ${GOROOT}/src/Make.inc - -all: install - -DIRS=\ - pkg\ - cmds\ - - -clean.dirs: $(addsuffix .clean, $(DIRS)) -install.dirs: $(addsuffix .install, $(DIRS)) -nuke.dirs: $(addsuffix .nuke, $(DIRS)) -test.dirs: $(addsuffix .test, $(TEST)) -bench.dirs: $(addsuffix .bench, $(BENCH)) - -%.clean: - +cd $* && $(QUOTED_GOBIN)/gomake clean - -%.install: - +cd $* && $(QUOTED_GOBIN)/gomake install - -clean: clean.dirs - -install: install.dirs - -#-include ${GOROOT}/src/Make.deps +# Makefile for the go bindings of notmuch + +export GOPATH ?= $(shell pwd) +export CGO_CFLAGS ?= -I../../../../lib +export CGO_LDFLAGS ?= -L../../../../lib + +GO ?= go +GOFMT ?= gofmt + +all: notmuch notmuch-addrlookup + +.PHONY: notmuch +notmuch: + $(GO) install notmuch + +.PHONY: goconfig +goconfig: + if [ ! -d src/github.com/kless/goconfig/config ]; then \ + $(GO) get github.com/kless/goconfig/config; \ + fi + +.PHONY: notmuch-addrlookup +notmuch-addrlookup: notmuch goconfig + $(GO) install notmuch-addrlookup + +.PHONY: format +format: + $(GOFMT) -w=true $(GOFMT_OPTS) src/notmuch + $(GOFMT) -w=true $(GOFMT_OPTS) src/notmuch-addrlookup + +.PHONY: check-format +check-format: + $(GOFMT) -d=true $(GOFMT_OPTS) src/notmuch + $(GOFMT) -d=true $(GOFMT_OPTS) src/notmuch-addrlookup + +.PHONY: clean +clean: + $(GO) clean notmuch + $(GO) clean notmuch-addrlookup + rm -rf pkg bin diff --git a/bindings/go/cmds/Makefile b/bindings/go/cmds/Makefile deleted file mode 100644 index afbc6d2..0000000 --- a/bindings/go/cmds/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ${GOROOT}/src/Make.inc - -TARG=notmuch-addrlookup -GOFILES=\ - notmuch-addrlookup.go - -include ${GOROOT}/src/Make.cmd diff --git a/bindings/go/pkg/Makefile b/bindings/go/pkg/Makefile deleted file mode 100644 index de89dbc..0000000 --- a/bindings/go/pkg/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include $(GOROOT)/src/Make.inc - -TARG=notmuch -CGOFILES=notmuch.go -CGO_LDFLAGS=-lnotmuch - -CLEANFILES+=notmuch_test - -include $(GOROOT)/src/Make.pkg - -%: install %.go - $(GC) $*.go - $(LD) -o $@ $*.$O -- cgit v1.2.3 From 1952889353becc7b3bd254ea2695eca04bb9491f Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 9 May 2012 13:15:20 +0200 Subject: go: format the souce code using gofmt Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/go/src/notmuch-addrlookup/addrlookup.go | 80 ++++++++++----------- bindings/go/src/notmuch/notmuch.go | 89 ++++++++++++------------ 2 files changed, 86 insertions(+), 83 deletions(-) (limited to 'bindings') diff --git a/bindings/go/src/notmuch-addrlookup/addrlookup.go b/bindings/go/src/notmuch-addrlookup/addrlookup.go index d172666..59283f8 100644 --- a/bindings/go/src/notmuch-addrlookup/addrlookup.go +++ b/bindings/go/src/notmuch-addrlookup/addrlookup.go @@ -22,18 +22,18 @@ type frequencies map[string]uint /* Used to sort the email addresses from most to least used */ func sort_by_freq(m1, m2 *mail_addr_freq) int { - if (m1.count[0] == m2.count[0] && + if m1.count[0] == m2.count[0] && m1.count[1] == m2.count[1] && - m1.count[2] == m2.count[2]) { + m1.count[2] == m2.count[2] { return 0 } - if (m1.count[0] > m2.count[0] || + if m1.count[0] > m2.count[0] || m1.count[0] == m2.count[0] && - m1.count[1] > m2.count[1] || + m1.count[1] > m2.count[1] || m1.count[0] == m2.count[0] && - m1.count[1] == m2.count[1] && - m1.count[2] > m2.count[2]) { + m1.count[1] == m2.count[1] && + m1.count[2] > m2.count[2] { return -1 } @@ -46,17 +46,17 @@ func (self *maddresses) Len() int { return len(*self) } -func (self *maddresses) Less(i,j int) bool { +func (self *maddresses) Less(i, j int) bool { m1 := (*self)[i] m2 := (*self)[j] - v := sort_by_freq(m1, m2) - if v<=0 { + v := sort_by_freq(m1, m2) + if v <= 0 { return true } return false } -func (self *maddresses) Swap(i,j int) { +func (self *maddresses) Swap(i, j int) { (*self)[i], (*self)[j] = (*self)[j], (*self)[i] } @@ -66,7 +66,7 @@ func frequent_fullname(freqs frequencies) string { fullname := "" freqs_sz := len(freqs) - for mail,freq := range freqs { + for mail, freq := range freqs { if (freq > maxfreq && mail != "") || freqs_sz == 1 { // only use the entry if it has a real name // or if this is the only entry @@ -87,32 +87,32 @@ func addresses_by_frequency(msgs *notmuch.Messages, name string, pass uint, addr pattern = `.*` + strings.ToLower(name) + `.*` var re *regexp.Regexp = nil var err error = nil - if re,err = regexp.Compile(pattern); err != nil { + if re, err = regexp.Compile(pattern); err != nil { log.Printf("error: %v\n", err) return &freqs } - + headers := []string{"from"} if pass == 1 { headers = append(headers, "to", "cc", "bcc") } - for ;msgs.Valid();msgs.MoveToNext() { + for ; msgs.Valid(); msgs.MoveToNext() { msg := msgs.Get() //println("==> msg [", msg.GetMessageId(), "]") - for _,header := range headers { + for _, header := range headers { froms := strings.ToLower(msg.GetHeader(header)) //println(" froms: ["+froms+"]") - for _,from := range strings.Split(froms, ",") { + for _, from := range strings.Split(froms, ",") { from = strings.Trim(from, " ") match := re.FindString(from) //println(" -> match: ["+match+"]") - occ,ok := freqs[match] + occ, ok := freqs[match] if !ok { freqs[match] = 0 occ = 0 } - freqs[match] = occ+1 + freqs[match] = occ + 1 } } } @@ -125,7 +125,7 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string { addr_to_realname := make(map[string]*frequencies) var pass uint = 0 // 0-based - for _,query := range queries { + for _, query := range queries { if query == nil { //println("**warning: idx [",idx,"] contains a nil query") continue @@ -133,9 +133,9 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string { msgs := query.SearchMessages() ht := addresses_by_frequency(msgs, name, pass, &addr_to_realname) for addr, count := range *ht { - freq,ok := addr_freq[addr] + freq, ok := addr_freq[addr] if !ok { - freq = &mail_addr_freq{addr:addr, count:[3]uint{0,0,0}} + freq = &mail_addr_freq{addr: addr, count: [3]uint{0, 0, 0}} } freq.count[pass] = count addr_freq[addr] = freq @@ -154,8 +154,8 @@ func search_address_passes(queries [3]*notmuch.Query, name string) []string { } sort.Sort(&addrs) - for _,addr := range addrs { - freqs,ok := addr_to_realname[addr.addr] + for _, addr := range addrs { + freqs, ok := addr_to_realname[addr.addr] if ok { val = append(val, frequent_fullname(*freqs)) } else { @@ -187,31 +187,31 @@ func new_address_matcher() *address_matcher { home = os.Getenv("HOME") } - if cfg,err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil { - log.Fatalf("error loading config file:",err) + if cfg, err = config.ReadDefault(path.Join(home, ".notmuch-config")); err != nil { + log.Fatalf("error loading config file:", err) } - db_path,_ := cfg.String("database", "path") - primary_email,_ := cfg.String("user", "primary_email") - addrbook_tag,err := cfg.String("user", "addrbook_tag") + db_path, _ := cfg.String("database", "path") + primary_email, _ := cfg.String("user", "primary_email") + addrbook_tag, err := cfg.String("user", "addrbook_tag") if err != nil { addrbook_tag = "addressbook" } - self := &address_matcher{db:nil, - user_db_path:db_path, - user_primary_email:primary_email, - user_addrbook_tag:addrbook_tag} + self := &address_matcher{db: nil, + user_db_path: db_path, + user_primary_email: primary_email, + user_addrbook_tag: addrbook_tag} return self } func (self *address_matcher) run(name string) { queries := [3]*notmuch.Query{} - + // open the database if db, status := notmuch.OpenDatabase(self.user_db_path, notmuch.DATABASE_MODE_READ_ONLY); status == notmuch.STATUS_SUCCESS { - self.db = db + self.db = db } else { log.Fatalf("Failed to open the database: %v\n", status) } @@ -226,7 +226,7 @@ func (self *address_matcher) run(name string) { // pass 2: look at all to: addresses sent from our primary mail query = "" if name != "" { - query = "to:"+name+"*" + query = "to:" + name + "*" } if self.user_primary_email != "" { query = query + " from:" + self.user_primary_email @@ -234,17 +234,17 @@ func (self *address_matcher) run(name string) { queries[1] = self.db.CreateQuery(query) // if that leads only to a few hits, we check every from too - if queries[0].CountMessages() + queries[1].CountMessages() < 10 { + if queries[0].CountMessages()+queries[1].CountMessages() < 10 { query = "" if name != "" { - query = "from:"+name+"*" + query = "from:" + name + "*" } queries[2] = self.db.CreateQuery(query) } - + // actually retrieve and sort addresses results := search_address_passes(queries, name) - for _,v := range results { + for _, v := range results { if v != "" && v != "\n" { fmt.Println(v) } @@ -260,4 +260,4 @@ func main() { name = os.Args[1] } app.run(name) -} \ No newline at end of file +} diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go index 86e577c..12de4c8 100644 --- a/bindings/go/src/notmuch/notmuch.go +++ b/bindings/go/src/notmuch/notmuch.go @@ -15,25 +15,26 @@ import "unsafe" // Status codes used for the return values of most functions type Status C.notmuch_status_t + const ( STATUS_SUCCESS Status = iota STATUS_OUT_OF_MEMORY - STATUS_READ_ONLY_DATABASE - STATUS_XAPIAN_EXCEPTION - STATUS_FILE_ERROR - STATUS_FILE_NOT_EMAIL - STATUS_DUPLICATE_MESSAGE_ID - STATUS_NULL_POINTER - STATUS_TAG_TOO_LONG - STATUS_UNBALANCED_FREEZE_THAW - STATUS_UNBALANCED_ATOMIC - - STATUS_LAST_STATUS + STATUS_READ_ONLY_DATABASE + STATUS_XAPIAN_EXCEPTION + STATUS_FILE_ERROR + STATUS_FILE_NOT_EMAIL + STATUS_DUPLICATE_MESSAGE_ID + STATUS_NULL_POINTER + STATUS_TAG_TOO_LONG + STATUS_UNBALANCED_FREEZE_THAW + STATUS_UNBALANCED_ATOMIC + + STATUS_LAST_STATUS ) func (self Status) String() string { var p *C.char - + // p is read-only p = C.notmuch_status_to_string(C.notmuch_status_t(self)) if p != nil { @@ -83,9 +84,10 @@ type Filenames struct { } type DatabaseMode C.notmuch_database_mode_t + const ( - DATABASE_MODE_READ_ONLY DatabaseMode = 0 - DATABASE_MODE_READ_WRITE + DATABASE_MODE_READ_ONLY DatabaseMode = 0 + DATABASE_MODE_READ_WRITE ) // Create a new, empty notmuch database located at 'path' @@ -98,7 +100,7 @@ func NewDatabase(path string) (*Database, Status) { return nil, STATUS_OUT_OF_MEMORY } - self := &Database{db:nil} + self := &Database{db: nil} st := Status(C.notmuch_database_create(c_path, &self.db)) if st != STATUS_SUCCESS { return nil, st @@ -132,7 +134,7 @@ func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) { return nil, STATUS_OUT_OF_MEMORY } - self := &Database{db:nil} + self := &Database{db: nil} st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db)) if st != STATUS_SUCCESS { return nil, st @@ -149,9 +151,9 @@ func (self *Database) Close() { /* Return the database path of the given database. */ func (self *Database) GetPath() string { - - /* The return value is a string owned by notmuch so should not be - * modified nor freed by the caller. */ + + /* The return value is a string owned by notmuch so should not be + * modified nor freed by the caller. */ var p *C.char = C.notmuch_database_get_path(self.db) if p != nil { s := C.GoString(p) @@ -181,7 +183,6 @@ func (self *Database) NeedsUpgrade() bool { // TODO: notmuch_database_upgrade - /* Retrieve a directory object from the database for 'path'. * * Here, 'path' should be a path relative to the path of 'database' @@ -202,7 +203,7 @@ func (self *Database) GetDirectory(path string) *Directory { if c_dir == nil { return nil } - return &Directory{dir:c_dir} + return &Directory{dir: c_dir} } /* Add a new message to the given notmuch database. @@ -245,8 +246,7 @@ func (self *Database) GetDirectory(path string) *Directory { * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only * mode so no message can be added. */ -func -(self *Database) AddMessage(fname string) (*Message, Status) { +func (self *Database) AddMessage(fname string) (*Message, Status) { var c_fname *C.char = C.CString(fname) defer C.free(unsafe.Pointer(c_fname)) @@ -257,7 +257,7 @@ func var c_msg *C.notmuch_message_t = new(C.notmuch_message_t) st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg)) - return &Message{message:c_msg}, st + return &Message{message: c_msg}, st } /* Remove a message from the given notmuch database. @@ -285,7 +285,7 @@ func * mode so no message can be removed. */ func (self *Database) RemoveMessage(fname string) Status { - + var c_fname *C.char = C.CString(fname) defer C.free(unsafe.Pointer(c_fname)) @@ -310,7 +310,7 @@ func (self *Database) RemoveMessage(fname string) Status { * * A Xapian exception occurs */ func (self *Database) FindMessage(message_id string) (*Message, Status) { - + var c_msg_id *C.char = C.CString(message_id) defer C.free(unsafe.Pointer(c_msg_id)) @@ -318,7 +318,7 @@ func (self *Database) FindMessage(message_id string) (*Message, Status) { return nil, STATUS_OUT_OF_MEMORY } - msg := &Message{message:nil} + msg := &Message{message: nil} st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message)) if st != STATUS_SUCCESS { return nil, st @@ -338,7 +338,7 @@ func (self *Database) GetAllTags() *Tags { if tags == nil { return nil } - return &Tags{tags:tags} + return &Tags{tags: tags} } /* Create a new query for 'database'. @@ -366,7 +366,7 @@ func (self *Database) GetAllTags() *Tags { * Will return NULL if insufficient memory is available. */ func (self *Database) CreateQuery(query string) *Query { - + var c_query *C.char = C.CString(query) defer C.free(unsafe.Pointer(c_query)) @@ -378,11 +378,12 @@ func (self *Database) CreateQuery(query string) *Query { if q == nil { return nil } - return &Query{query:q} + return &Query{query: q} } /* Sort values for notmuch_query_set_sort */ type Sort C.notmuch_sort_t + const ( SORT_OLDEST_FIRST Sort = 0 SORT_NEWEST_FIRST @@ -395,7 +396,7 @@ func (self *Query) String() string { // FIXME: do we own 'q' or not ? q := C.notmuch_query_get_query_string(self.query) //defer C.free(unsafe.Pointer(q)) - + if q != nil { s := C.GoString(q) return s @@ -457,7 +458,7 @@ func (self *Query) SearchThreads() *Threads { if threads == nil { return nil } - return &Threads{threads:threads} + return &Threads{threads: threads} } /* Execute a query for messages, returning a notmuch_messages_t object @@ -503,7 +504,7 @@ func (self *Query) SearchMessages() *Messages { if msgs == nil { return nil } - return &Messages{messages:msgs} + return &Messages{messages: msgs} } /* Destroy a notmuch_query_t along with any associated resources. @@ -605,7 +606,7 @@ func (self *Messages) Get() *Message { if msg == nil { return nil } - return &Message{message:msg} + return &Message{message: msg} } /* Move the 'messages' iterator to the next message. @@ -657,7 +658,7 @@ func (self *Messages) CollectTags() *Tags { if tags == nil { return nil } - return &Tags{tags:tags} + return &Tags{tags: tags} } /* Get the message ID of 'message'. @@ -697,14 +698,14 @@ func (self *Message) GetMessageId() string { * message belongs to a single thread. */ func (self *Message) GetThreadId() string { - + if self.message == nil { return "" } id := C.notmuch_message_get_thread_id(self.message) // we dont own id // defer C.free(unsafe.Pointer(id)) - + if id == nil { return "" } @@ -737,7 +738,7 @@ func (self *Message) GetReplies() *Messages { if msgs == nil { return nil } - return &Messages{messages:msgs} + return &Messages{messages: msgs} } /* Get a filename for the email corresponding to 'message'. @@ -761,7 +762,7 @@ func (self *Message) GetFileName() string { fname := C.notmuch_message_get_filename(self.message) // we dont own fname // defer C.free(unsafe.Pointer(fname)) - + if fname == nil { return "" } @@ -770,6 +771,7 @@ func (self *Message) GetFileName() string { } type Flag C.notmuch_message_flag_t + const ( MESSAGE_FLAG_MATCH Flag = 0 ) @@ -816,16 +818,16 @@ func (self *Message) GetHeader(header string) string { if self.message == nil { return "" } - + var c_header *C.char = C.CString(header) defer C.free(unsafe.Pointer(c_header)) - + /* we dont own value */ value := C.notmuch_message_get_header(self.message, c_header) if value == nil { return "" } - + return C.GoString(value) } @@ -867,7 +869,7 @@ func (self *Message) GetTags() *Tags { if tags == nil { return nil } - return &Tags{tags:tags} + return &Tags{tags: tags} } /* The longest possible tag value. */ @@ -1124,4 +1126,5 @@ func (self *Filenames) Destroy() { } C.notmuch_filenames_destroy(self.fnames) } + /* EOF */ -- cgit v1.2.3 From cdaf253c9995fe00b096052ab85f0b8d5c010e7c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 13 May 2012 19:36:10 -0400 Subject: go: Update for changes to notmuch_database_get_directory --- bindings/go/src/notmuch/notmuch.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'bindings') diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go index 12de4c8..00bd53a 100644 --- a/bindings/go/src/notmuch/notmuch.go +++ b/bindings/go/src/notmuch/notmuch.go @@ -191,19 +191,20 @@ func (self *Database) NeedsUpgrade() bool { * * Can return NULL if a Xapian exception occurs. */ -func (self *Database) GetDirectory(path string) *Directory { +func (self *Database) GetDirectory(path string) (*Directory, Status) { var c_path *C.char = C.CString(path) defer C.free(unsafe.Pointer(c_path)) if c_path == nil { - return nil + return nil, STATUS_OUT_OF_MEMORY } - c_dir := C.notmuch_database_get_directory(self.db, c_path) - if c_dir == nil { - return nil + var c_dir *C.notmuch_directory_t + st := Status(C.notmuch_database_get_directory(self.db, c_path, &c_dir)) + if st != STATUS_SUCCESS || c_dir == nil { + return nil, st } - return &Directory{dir: c_dir} + return &Directory{dir: c_dir}, st } /* Add a new message to the given notmuch database. -- cgit v1.2.3 From ed4f73a080b08c304bd4603d8b6313c45e7c40d3 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 13 May 2012 19:36:11 -0400 Subject: python: Update for changes to notmuch_database_get_directory notmuch_database_get_directory now returns NOTMUCH_STATUS_READ_ONLY_DATABASE on its own (rather than crashing) so the workaround in Database.get_directory is no longer necessary. --- bindings/python/notmuch/database.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 1b1ddc3..797554d 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -73,8 +73,8 @@ class Database(object): """notmuch_database_get_directory""" _get_directory = nmlib.notmuch_database_get_directory - _get_directory.argtypes = [NotmuchDatabaseP, c_char_p] - _get_directory.restype = NotmuchDirectoryP + _get_directory.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchDirectoryP)] + _get_directory.restype = c_uint """notmuch_database_get_path""" _get_path = nmlib.notmuch_database_get_path @@ -359,13 +359,6 @@ class Database(object): """ self._assert_db_is_initialized() - # work around libnotmuch calling exit(3), see - # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de - # TODO: remove once this issue is resolved - if self.mode != Database.MODE.READ_WRITE: - raise ReadOnlyDatabaseError('The database has to be opened in ' - 'read-write mode for get_directory') - # sanity checking if path is valid, and make path absolute if path and path[0] == os.sep: # we got an absolute path @@ -378,7 +371,13 @@ class Database(object): #we got a relative path, make it absolute abs_dirpath = os.path.abspath(os.path.join(self.get_path(), path)) - dir_p = Database._get_directory(self._db, _str(path)) + dir_p = NotmuchDirectoryP() + status = Database._get_directory(self._db, _str(path), byref(dir_p)) + + if status != STATUS.SUCCESS: + raise NotmuchError(status) + if not dir_p: + return None # return the Directory, init it with the absolute path return Directory(abs_dirpath, dir_p, self) -- cgit v1.2.3 From bc4000a95289da7f4928ea448382c69781f2653c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 13 May 2012 19:36:12 -0400 Subject: ruby: Update for changes to notmuch_database_get_directory --- bindings/ruby/database.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index 409d54f..e84f726 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -252,6 +252,7 @@ VALUE notmuch_rb_database_get_directory (VALUE self, VALUE pathv) { const char *path; + notmuch_status_t ret; notmuch_directory_t *dir; notmuch_database_t *db; @@ -260,11 +261,11 @@ notmuch_rb_database_get_directory (VALUE self, VALUE pathv) SafeStringValue (pathv); path = RSTRING_PTR (pathv); - dir = notmuch_database_get_directory (db, path); - if (!dir) - rb_raise (notmuch_rb_eXapianError, "Xapian exception"); - - return Data_Wrap_Struct (notmuch_rb_cDirectory, NULL, NULL, dir); + ret = notmuch_database_get_directory (db, path, &dir); + notmuch_rb_status_raise (ret); + if (dir) + return Data_Wrap_Struct (notmuch_rb_cDirectory, NULL, NULL, dir); + return Qnil; } /* -- cgit v1.2.3 From 3fb08bc1259f9a9d80617542da64443e7e63a6c4 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Tue, 15 May 2012 18:18:45 -0300 Subject: version: bump to 0.13 --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index 25010f5..5945a50 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.13~rc1' +__VERSION__ = '0.13' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index 5c3b391..8cc9773 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-CONFIG 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index 0c87541..1eb70d1 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-COUNT 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index 50ec335..b03f804 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-DUMP 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index b05d278..37af146 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-NEW 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 1f86b09..593df3b 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-REPLY 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index f393c04..ec16868 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-RESTORE 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 4b02f4e..608178c 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-SEARCH 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index 14a2a5c..a7f0792 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-SHOW 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 55f79f8..346b188 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-TAG 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index f7ee528..465e324 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH 1 2012-05-15 "Notmuch 0.13" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index aa0839a..d9a86c7 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-HOOKS 5 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index 6af7a60..cbbafc1 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-05-08 "Notmuch 0.13~rc1" +.TH NOTMUCH-SEARCH-TERMS 7 2012-05-15 "Notmuch 0.13" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index 80fa719..f304084 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.13~rc1 +0.13 -- cgit v1.2.3 From eab15cc707ee0b3f2347caf63e9265435b62ca1e Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 16 May 2012 16:45:56 +0200 Subject: python: remove notmuch.py Removes notmuch.py. If someone wants to step up and work on this it can always be restored using the version control system. notmuch.py was meant to be a python implementation of the notmuch utility. It was never finished and hasn't been updated to changes in the API and bindings and its features and interface haven't been kept in sync with the notmuch utility. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch.py | 651 --------------------------------------------- 1 file changed, 651 deletions(-) delete mode 100755 bindings/python/notmuch.py (limited to 'bindings') diff --git a/bindings/python/notmuch.py b/bindings/python/notmuch.py deleted file mode 100755 index 3ff53ec..0000000 --- a/bindings/python/notmuch.py +++ /dev/null @@ -1,651 +0,0 @@ -#!/usr/bin/env python -"""This is a notmuch implementation in python. -It's goal is to allow running the test suite on the cnotmuch python bindings. - -This "binary" honors the NOTMUCH_CONFIG environmen variable for reading a user's -notmuch configuration (e.g. the database path). - - (c) 2010 by Sebastian Spaeth - Jesse Rosenthal - This code is licensed under the GNU GPL v3+. -""" -import sys -import os - -import re -import stat -import email - -from notmuch import Database, Query, NotmuchError, STATUS -try: - # python3.x - from configparser import SafeConfigParser -except ImportError: - # python2.x - from ConfigParser import SafeConfigParser -from cStringIO import StringIO - -PREFIX = re.compile('(\w+):(.*$)') - -HELPTEXT = """The notmuch mail system. -Usage: notmuch [args...] - -Where and [args...] are as follows: - setup Interactively setup notmuch for first use. - new [--verbose] - Find and import new messages to the notmuch database. - search [options...] [...] - Search for messages matching the given search terms. - show [...] - Show all messages matching the search terms. - count [...] - Count messages matching the search terms. - reply [options...] [...] - Construct a reply template for a set of messages. - tag +|- [...] [--] [...] - Add/remove tags for all messages matching the search terms. - dump [] - Create a plain-text dump of the tags for each message. - restore - Restore the tags from the given dump file (see 'dump'). - search-tags [ [...] ] - List all tags found in the database or matching messages. - help [] - This message, or more detailed help for the named command. - -Use "notmuch help " for more details on each command. -And "notmuch help search-terms" for the common search-terms syntax. -""" - -USAGE = """Notmuch is configured and appears to have a database. Excellent! - -At this point you can start exploring the functionality of notmuch by -using commands such as: - notmuch search tag:inbox - notmuch search to:"%(fullname)s" - notmuch search from:"%(mailaddress)s" - notmuch search subject:"my favorite things" - -See "notmuch help search" for more details. - -You can also use "notmuch show" with any of the thread IDs resulting -from a search. Finally, you may want to explore using a more sophisticated -interface to notmuch such as the emacs interface implemented in notmuch.el -or any other interface described at http://notmuchmail.org - -And don't forget to run "notmuch new" whenever new mail arrives. - -Have fun, and may your inbox never have much mail. -""" - -#------------------------------------------------------------------------- -def quote_query_line(argv): - # mangle arguments wrapping terms with spaces in quotes - for (num, item) in enumerate(argv): - if item.find(' ') >= 0: - # if we use prefix:termWithSpaces, put quotes around term - match = PREFIX.match(item) - if match: - argv[num] = '%s:"%s"' %(match.group(1), match.group(2)) - else: - argv[num] = '"%s"' % item - return ' '.join(argv) - -#------------------------------------------------------------------------- - - -class Notmuch(object): - - def __init__(self, configpath="~/.notmuch-config)"): - self._config = None - self._configpath = os.getenv('NOTMUCH_CONFIG', - os.path.expanduser(configpath)) - - def cmd_usage(self): - """Print the usage text and exits""" - data={} - names = self.get_user_email_addresses() - data['fullname'] = names[0] if names[0] else 'My Name' - data['mailaddress'] = names[1] if names[1] else 'My@email.address' - print USAGE % data - - def cmd_new(self): - """Run 'notmuch new'""" - #get the database directory - db = Database(mode=Database.MODE.READ_WRITE) - path = db.get_path() - print self._add_new_files_recursively(path, db) - - def cmd_help(self, subcmd=None): - """Print help text for 'notmuch help'""" - if len(subcmd) > 1: - print "Help for specific commands not implemented" - return - print HELPTEXT - - def _get_user_notmuch_config(self): - """Returns the ConfigParser of the user's notmuch-config""" - # return the cached config parser if we read it already - if self._config: - return self._config - - config = SafeConfigParser() - config.read(self._configpath) - self._config = config - return config - - def _add_new_files_recursively(self, path, db): - """:returns: (added, moved, removed)""" - print "Enter add new files with path %s" % path - - try: - #get the Directory() object for this path - db_dir = db.get_directory(path) - added = moved = removed = 0 - except NotmuchError: - # Occurs if we have wrong absolute paths in the db, for example - return (0,0,0) - - - # for folder in subdirs: - - # TODO, retrieve dir mtime here and store it later - # as long as Filenames() does not allow multiple iteration, we need to - # use this kludgy way to get a sorted list of filenames - # db_files is a list of subdirectories and filenames in this folder - db_files = set() - db_folders = set() - for subdir in db_dir.get_child_directories(): - db_folders.add(subdir) -# file is a keyword (remove this ;)) - for mail in db_dir.get_child_files(): - db_files.add(mail) - - fs_files = set(os.listdir(db_dir.path)) - - # list of files (and folders) on the fs, but not the db - for fs_file in ((fs_files - db_files) - db_folders): - absfile = os.path.normpath(os.path.join(db_dir.path, fs_file)) - statinfo = os.stat(absfile) - - if stat.S_ISDIR(statinfo.st_mode): - # This is a directory - if fs_file in ['.notmuch','tmp','.']: - continue - print "%s %s" % (fs_file, db_folders) - print "Directory not in db yet. Descending into %s" % absfile - new = self._add_new_files_recursively(absfile, db) - added += new[0] - moved += new[1] - removed += new[2] - - elif stat.S_ISLNK(statinfo.st_mode): - print ("%s is a symbolic link (%d). FIXME!!!" % - (absfile, statinfo.st_mode)) - exit(1) - - else: - # This is a regular file, not in the db yet. Add it. - print "This file needs to be added %s" % (absfile) - (msg, status) = db.add_message(absfile) - # We increases 'added', even on dupe messages. If it is a moved - # message, we will deduct it later and increase 'moved' instead - added += 1 - - if status == STATUS.DUPLICATE_MESSAGE_ID: - print "Added msg was in the db" - else: - print "New message." - - # Finally a list of files (not folders) in the database, - # but not the filesystem - for db_file in (db_files - fs_files): - absfile = os.path.normpath(os.path.join(db_dir.path, db_file)) - - # remove a mail message from the db - print ("%s is not on the fs anymore. Delete" % absfile) - status = db.remove_message(absfile) - - if status == STATUS.SUCCESS: - # we just deleted the last reference, so this was a remove - removed += 1 - sys.stderr.write("SUCCESS %d %s %s.\n" % - (status, STATUS.status2str(status), absfile)) - elif status == STATUS.DUPLICATE_MESSAGE_ID: - # The filename exists already somewhere else, so this is a move - moved += 1 - added -= 1 - sys.stderr.write("DUPE %d %s %s.\n" % - (status, STATUS.status2str(status), absfile)) - else: - # This should not occur - sys.stderr.write("This should not occur %d %s %s.\n" % - (status, STATUS.status2str(status), absfile)) - - # list of folders in the filesystem. Just descend into dirs - for fs_file in fs_files: - absfile = os.path.normpath(os.path.join(db_dir.path, fs_file)) - if os.path.isdir(absfile): - # This is a directory. Remove it from the db_folder list. - # All remaining db_folders at the end will be not present - # on the file system. - db_folders.remove(fs_file) - if fs_file in ['.notmuch','tmp','.']: - continue - new = self._add_new_files_recursively(absfile, db) - added += new[0] - moved += new[0] - removed += new[0] - - # we are not interested in anything but directories here - #TODO: All remaining elements of db_folders are not in the filesystem - #delete those - - return added, moved, removed - #Read the mtime of a directory from the filesystem - # - #* Call :meth:`Database.add_message` for all mail files in - # the directory - - #* Call notmuch_directory_set_mtime with the mtime read from the - # filesystem. Then, when wanting to check for updates to the - # directory in the future, the client can call :meth:`get_mtime` - # and know that it only needs to add files if the mtime of the - # directory and files are newer than the stored timestamp. - - def get_user_email_addresses(self): - """ Reads a user's notmuch config and returns his email addresses as - list (name, primary_address, other_address1,...)""" - - #read the config file - config = self._get_user_notmuch_config() - - conf = {'name': '', 'primary_email': ''} - for entry in conf: - if config.has_option('user', entry): - conf[entry] = config.get('user', entry) - - if config.has_option('user','other_email'): - other = config.get('user','other_email') - other = [mail.strip() for mail in other.split(';') if mail] - else: - other = [] - # for being compatible. It would be nicer to return a dict. - return conf.keys() + other - - def quote_msg_body(self, oldbody ,date, from_address): - """Transform a mail body into a quoted text, - starting with On foo, bar wrote: - - :param body: a str with a mail body - :returns: The new payload of the email.message() - """ - - # we get handed a string, wrap it in a file-like object - oldbody = StringIO(oldbody) - newbody = StringIO() - - newbody.write("On %s, %s wrote:\n" % (date, from_address)) - - for line in oldbody: - newbody.write("> " + line) - - return newbody.getvalue() - - def format_reply(self, msgs): - """Gets handed Messages() and displays the reply to them - - This is pretty ugly and hacky. It tries to mimic the "real" - notmuch output as much as it can to pass the test suite. It - could deserve a healthy bit of love. It is also buggy because - it returns after the first message it has handled.""" - - for msg in msgs: - f = open(msg.get_filename(), "r") - reply = email.message_from_file(f) - - # handle the easy non-multipart case: - if not reply.is_multipart(): - reply.set_payload(self.quote_msg_body(reply.get_payload(), - reply['date'], reply['from'])) - else: - # handle the tricky multipart case - deleted = "" - """A string describing which nontext attachements - that have been deleted""" - delpayloads = [] - """A list of payload indices to be deleted""" - payloads = reply.get_payload() - - for (num, part) in enumerate(payloads): - mime_main = part.get_content_maintype() - if mime_main not in ['multipart', 'message', 'text']: - deleted += "Non-text part: %s\n" % (part.get_content_type()) - payloads[num].set_payload("Non-text part: %s" % - (part.get_content_type())) - payloads[num].set_type('text/plain') - delpayloads.append(num) - elif mime_main == 'text': - payloads[num].set_payload(self.quote_msg_body( - payloads[num].get_payload(), - reply['date'], reply['from'])) - else: - # TODO handle deeply nested multipart messages - sys.stderr.write ("FIXME: Ignoring multipart part. Handle me\n") - # Delete those payloads that we don't need anymore - for item in reversed(sorted(delpayloads)): - del payloads[item] - - # Back to single- and multipart handling - my_addresses = self.get_user_email_addresses() - used_address = None - # filter our email addresses from all to: cc: and bcc: fields - # if we find one of "my" addresses being used, - # it is stored in used_address - for header in ['To', 'CC', 'Bcc']: - if not header in reply: - #only handle fields that exist - continue - addresses = email.utils.getaddresses(reply.get_all(header, [])) - purged_addr = [] - for (name, mail) in addresses: - if mail in my_addresses[1:]: - used_address = email.utils.formataddr( - (my_addresses[0], mail)) - else: - purged_addr.append(email.utils.formataddr((name, mail))) - - if purged_addr: - reply.replace_header(header, ", ".join(purged_addr)) - else: - # we deleted all addresses, delete the header - del reply[header] - - # Use our primary email address to the From - # (save original from line, we still need it) - new_to = reply['From'] - if used_address: - reply['From'] = used_address - else: - email.utils.formataddr((my_addresses[0], my_addresses[1])) - - reply['Subject'] = 'Re: ' + reply['Subject'] - - # Calculate our new To: field - # add all remaining original 'To' addresses - if 'To' in reply: - new_to += ", " + reply['To'] - reply.add_header('To', new_to) - - # Add our primary email address to the BCC - new_bcc = my_addresses[1] - if 'Bcc' in reply: - new_bcc += ', ' + reply['Bcc'] - reply['Bcc'] = new_bcc - - # Set replies 'In-Reply-To' header to original's Message-ID - if 'Message-ID' in reply: - reply['In-Reply-To'] = reply['Message-ID'] - - #Add original's Message-ID to replies 'References' header. - if 'References' in reply: - reply['References'] = ' '.join([reply['References'], reply['Message-ID']]) - else: - reply['References'] = reply['Message-ID'] - - # Delete the original Message-ID. - del(reply['Message-ID']) - - # filter all existing headers but a few and delete them from 'reply' - delheaders = filter(lambda x: x not in ['From', 'To', 'Subject', 'CC', - 'Bcc', 'In-Reply-To', - 'References', 'Content-Type'], - reply.keys()) - map(reply.__delitem__, delheaders) - - # TODO: OUCH, we return after the first msg we have handled rather than - # handle all of them - # return resulting message without Unixfrom - return reply.as_string(False) - - -def main(): - # Handle command line options - #------------------------------------ - # No option given, print USAGE and exit - if len(sys.argv) == 1: - Notmuch().cmd_usage() - #------------------------------------ - elif sys.argv[1] == 'setup': - """Interactively setup notmuch for first use.""" - exit("Not implemented.") - #------------------------------------- - elif sys.argv[1] == 'new': - """Check for new and removed messages.""" - Notmuch().cmd_new() - #------------------------------------- - elif sys.argv[1] == 'help': - """Print the help text""" - Notmuch().cmd_help(sys.argv[1:]) - #------------------------------------- - elif sys.argv[1] == 'part': - part() - #------------------------------------- - elif sys.argv[1] == 'search': - search() - #------------------------------------- - elif sys.argv[1] == 'show': - show() - #------------------------------------- - elif sys.argv[1] == 'reply': - db = Database() - if len(sys.argv) == 2: - # no search term. abort - exit("Error: notmuch reply requires at least one search term.") - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[2:]) - msgs = Query(db, querystr).search_messages() - print Notmuch().format_reply(msgs) - #------------------------------------- - elif sys.argv[1] == 'count': - if len(sys.argv) == 2: - # no further search term, count all - querystr = '' - else: - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[2:]) - print Database().create_query(querystr).count_messages() - #------------------------------------- - elif sys.argv[1] == 'tag': - # build lists of tags to be added and removed - add = [] - remove = [] - while not sys.argv[2] == '--' and \ - (sys.argv[2].startswith('+') or sys.argv[2].startswith('-')): - if sys.argv[2].startswith('+'): - # append to add list without initial + - add.append(sys.argv.pop(2)[1:]) - else: - # append to remove list without initial - - remove.append(sys.argv.pop(2)[1:]) - # skip eventual '--' - if sys.argv[2] == '--': sys.argv.pop(2) - # the rest is search terms - querystr = quote_query_line(sys.argv[2:]) - db = Database(mode=Database.MODE.READ_WRITE) - msgs = Query(db, querystr).search_messages() - for msg in msgs: - # actually add and remove all tags - map(msg.add_tag, add) - map(msg.remove_tag, remove) - #------------------------------------- - elif sys.argv[1] == 'search-tags': - if len(sys.argv) == 2: - # no further search term - print "\n".join(Database().get_all_tags()) - else: - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[2:]) - db = Database() - msgs = Query(db, querystr).search_messages() - print "\n".join([t for t in msgs.collect_tags()]) - #------------------------------------- - elif sys.argv[1] == 'dump': - if len(sys.argv) == 2: - f = sys.stdout - else: - f = open(sys.argv[2], "w") - db = Database() - query = Query(db, '') - query.set_sort(Query.SORT.MESSAGE_ID) - msgs = query.search_messages() - for msg in msgs: - f.write("%s (%s)\n" % (msg.get_message_id(), msg.get_tags())) - #------------------------------------- - elif sys.argv[1] == 'restore': - if len(sys.argv) == 2: - print("No filename given. Reading dump from stdin.") - f = sys.stdin - else: - f = open(sys.argv[2], "r") - - # split the msg id and the tags - MSGID_TAGS = re.compile("(\S+)\s\((.*)\)$") - db = Database(mode=Database.MODE.READ_WRITE) - - #read each line of the dump file - for line in f: - msgs = MSGID_TAGS.match(line) - if not msgs: - sys.stderr.write("Warning: Ignoring invalid input line: %s" % - line) - continue - # split line in components and fetch message - msg_id = msgs.group(1) - new_tags = set(msgs.group(2).split()) - msg = db.find_message(msg_id) - - if msg == None: - sys.stderr.write( - "Warning: Cannot apply tags to missing message: %s\n" % msg_id) - continue - - # do nothing if the old set of tags is the same as the new one - old_tags = set(msg.get_tags()) - if old_tags == new_tags: continue - - # set the new tags - msg.freeze() - # only remove tags if the new ones are not a superset anyway - if not (new_tags > old_tags): msg.remove_all_tags() - for tag in new_tags: msg.add_tag(tag) - msg.thaw() - #------------------------------------- - else: - # unknown command - exit("Error: Unknown command '%s' (see \"notmuch help\")" % sys.argv[1]) - -def part(): - db = Database() - query_string = '' - part_num = 0 - first_search_term = 0 - for (num, arg) in enumerate(sys.argv[1:]): - if arg.startswith('--part='): - part_num_str = arg.split("=")[1] - try: - part_num = int(part_num_str) - except ValueError: - # just emulating behavior - exit(1) - elif not arg.startswith('--'): - # save the position of the first sys.argv - # that is a search term - first_search_term = num + 1 - if first_search_term: - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[first_search_term:]) - qry = Query(db,querystr) - msgs = [msg for msg in qry.search_messages()] - - if not msgs: - sys.exit(1) - elif len(msgs) > 1: - raise Exception("search term did not match precisely one message") - else: - msg = msgs[0] - print msg.get_part(part_num) - -def search(): - db = Database() - query_string = '' - sort_order = "newest-first" - first_search_term = 0 - for (num, arg) in enumerate(sys.argv[1:]): - if arg.startswith('--sort='): - sort_order=arg.split("=")[1] - if not sort_order in ("oldest-first", "newest-first"): - raise Exception("unknown sort order") - elif not arg.startswith('--'): - # save the position of the first sys.argv that is a search term - first_search_term = num + 1 - - if first_search_term: - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[first_search_term:]) - - qry = Query(db, querystr) - if sort_order == "oldest-first": - qry.set_sort(Query.SORT.OLDEST_FIRST) - else: - qry.set_sort(Query.SORT.NEWEST_FIRST) - threads = qry.search_threads() - - for thread in threads: - print thread - -def show(): - entire_thread = False - db = Database() - out_format = "text" - querystr = '' - first_search_term = None - - # ugly homegrown option parsing - # TODO: use OptionParser - for (num, arg) in enumerate(sys.argv[1:]): - if arg == '--entire-thread': - entire_thread = True - elif arg.startswith("--format="): - out_format = arg.split("=")[1] - if out_format == 'json': - # for compatibility use --entire-thread for json - entire_thread = True - if not out_format in ("json", "text"): - raise Exception("unknown format") - elif not arg.startswith('--'): - # save the position of the first sys.argv that is a search term - first_search_term = num + 1 - - if first_search_term: - # mangle arguments wrapping terms with spaces in quotes - querystr = quote_query_line(sys.argv[first_search_term:]) - - threads = Query(db, querystr).search_threads() - first_toplevel = True - if out_format == "json": - sys.stdout.write("[") - for thread in threads: - msgs = thread.get_toplevel_messages() - if not first_toplevel: - if out_format == "json": - sys.stdout.write(", ") - first_toplevel = False - msgs.print_messages(out_format, 0, entire_thread) - - if out_format == "json": - sys.stdout.write("]") - sys.stdout.write("\n") - -if __name__ == '__main__': - main() -- cgit v1.2.3 From cd8fe010135c5f3fd5ad3b97a28c786d928c068a Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 16 May 2012 16:20:42 +0200 Subject: python: remove functions that have been marked as deprecated in 0.13 Removes Message.format_message_{internal,as_json,as_text}. This code adds functionality at the python level that is unlikely to be useful for anyone. Furthermore the python bindings strive to be a thin wrapper around libnotmuch. The code has been marked as deprecated in 0.13 and is now removed. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/message.py | 129 ------------------------------------- 1 file changed, 129 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 0e65694..0cac09c 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -610,135 +610,6 @@ class Message(Python3StringMixIn): out_part = parts[(num - 1)] return out_part.get_payload(decode=True) - def format_message_internal(self): - """Create an internal representation of the message parts, - which can easily be output to json, text, or another output - format. The argument match tells whether this matched a - query. - - .. deprecated:: 0.13 - This code adds functionality at the python - level that is unlikely to be useful for - anyone. Furthermore the python bindings strive - to be a thin wrapper around libnotmuch, so - this code will be removed in notmuch 0.14. - """ - output = {} - output["id"] = self.get_message_id() - output["match"] = self.is_match() - output["filename"] = self.get_filename() - output["tags"] = list(self.get_tags()) - - headers = {} - for h in ["Subject", "From", "To", "Cc", "Bcc", "Date"]: - headers[h] = self.get_header(h) - output["headers"] = headers - - body = [] - parts = self.get_message_parts() - for i in xrange(len(parts)): - msg = parts[i] - part_dict = {} - part_dict["id"] = i + 1 - # We'll be using this is a lot, so let's just get it once. - cont_type = msg.get_content_type() - part_dict["content-type"] = cont_type - # NOTE: - # Now we emulate the current behaviour, where it ignores - # the html if there's a text representation. - # - # This is being worked on, but it will be easier to fix - # here in the future than to end up with another - # incompatible solution. - disposition = msg["Content-Disposition"] - if disposition and disposition.lower().startswith("attachment"): - part_dict["filename"] = msg.get_filename() - else: - if cont_type.lower() == "text/plain": - part_dict["content"] = msg.get_payload() - elif (cont_type.lower() == "text/html" and - i == 0): - part_dict["content"] = msg.get_payload() - body.append(part_dict) - - output["body"] = body - - return output - - def format_message_as_json(self, indent=0): - """Outputs the message as json. This is essentially the same - as python's dict format, but we run it through, just so we - don't have to worry about the details. - - .. deprecated:: 0.13 - This code adds functionality at the python - level that is unlikely to be useful for - anyone. Furthermore the python bindings strive - to be a thin wrapper around libnotmuch, so - this code will be removed in notmuch 0.14. - """ - return json.dumps(self.format_message_internal()) - - def format_message_as_text(self, indent=0): - """Outputs it in the old-fashioned notmuch text form. Will be - easy to change to a new format when the format changes. - - .. deprecated:: 0.13 - This code adds functionality at the python - level that is unlikely to be useful for - anyone. Furthermore the python bindings strive - to be a thin wrapper around libnotmuch, so - this code will be removed in notmuch 0.14. - """ - - - format = self.format_message_internal() - output = "\fmessage{ id:%s depth:%d match:%d filename:%s" \ - % (format['id'], indent, format['match'], format['filename']) - output += "\n\fheader{" - - #Todo: this date is supposed to be prettified, as in the index. - output += "\n%s (%s) (" % (format["headers"]["From"], - format["headers"]["Date"]) - output += ", ".join(format["tags"]) - output += ")" - - output += "\nSubject: %s" % format["headers"]["Subject"] - output += "\nFrom: %s" % format["headers"]["From"] - output += "\nTo: %s" % format["headers"]["To"] - if format["headers"]["Cc"]: - output += "\nCc: %s" % format["headers"]["Cc"] - if format["headers"]["Bcc"]: - output += "\nBcc: %s" % format["headers"]["Bcc"] - output += "\nDate: %s" % format["headers"]["Date"] - output += "\n\fheader}" - - output += "\n\fbody{" - - parts = format["body"] - parts.sort(key=lambda x: x['id']) - for p in parts: - if not "filename" in p: - output += "\n\fpart{ " - output += "ID: %d, Content-type: %s\n" % (p["id"], - p["content-type"]) - if "content" in p: - output += "\n%s\n" % p["content"] - else: - output += "Non-text part: %s\n" % p["content-type"] - output += "\n\fpart}" - else: - output += "\n\fattachment{ " - output += "ID: %d, Content-type:%s\n" % (p["id"], - p["content-type"]) - output += "Attachment: %s\n" % p["filename"] - output += "\n\fattachment}\n" - - output += "\n\fbody}\n" - output += "\n\fmessage}" - - return output - def __hash__(self): """Implement hash(), so we can use Message() sets""" file = self.get_filename() -- cgit v1.2.3 From b9d1045474584c7bb2c294be19c7401f78a37f62 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 16 May 2012 16:57:45 +0200 Subject: python: remove format_message_as_{json,text} from the sphinx docs Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/message.rst | 4 ---- 1 file changed, 4 deletions(-) (limited to 'bindings') diff --git a/bindings/python/docs/source/message.rst b/bindings/python/docs/source/message.rst index 2ae280e..1a6cc3d 100644 --- a/bindings/python/docs/source/message.rst +++ b/bindings/python/docs/source/message.rst @@ -47,8 +47,4 @@ .. automethod:: thaw - .. automethod:: format_message_as_json - - .. automethod:: format_message_as_text - .. automethod:: __str__ -- cgit v1.2.3 From 5bc5471c54f30642f866d4537f7a1a6b35222dc5 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 16:55:29 +0200 Subject: python: remove unused import of the json module Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/message.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index 0cac09c..bdbe501 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -41,10 +41,6 @@ from .tag import Tags from .filenames import Filenames import email -try: - import simplejson as json -except ImportError: - import json class Message(Python3StringMixIn): -- cgit v1.2.3 From 05c3e83bd272635ecc5e86d767250de1eb680a09 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 16:58:53 +0200 Subject: python: use relative imports Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 6 +++--- bindings/python/notmuch/directory.py | 2 +- bindings/python/notmuch/filenames.py | 2 +- bindings/python/notmuch/query.py | 2 +- bindings/python/notmuch/tag.py | 2 +- bindings/python/notmuch/thread.py | 4 ++-- bindings/python/notmuch/threads.py | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 797554d..fb4c929 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -20,7 +20,7 @@ Copyright 2010 Sebastian Spaeth import os import codecs from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER -from notmuch.globals import ( +from .globals import ( nmlib, Enum, _str, @@ -37,8 +37,8 @@ from .errors import ( NotInitializedError, ReadOnlyDatabaseError, ) -from notmuch.message import Message -from notmuch.tag import Tags +from .message import Message +from .tag import Tags from .query import Query from .directory import Directory diff --git a/bindings/python/notmuch/directory.py b/bindings/python/notmuch/directory.py index ae115f8..3b0a525 100644 --- a/bindings/python/notmuch/directory.py +++ b/bindings/python/notmuch/directory.py @@ -18,7 +18,7 @@ Copyright 2010 Sebastian Spaeth """ from ctypes import c_uint, c_long -from notmuch.globals import ( +from .globals import ( nmlib, NotmuchDirectoryP, NotmuchFilenamesP diff --git a/bindings/python/notmuch/filenames.py b/bindings/python/notmuch/filenames.py index a0b2956..229f414 100644 --- a/bindings/python/notmuch/filenames.py +++ b/bindings/python/notmuch/filenames.py @@ -17,7 +17,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p -from notmuch.globals import ( +from .globals import ( nmlib, NotmuchMessageP, NotmuchFilenamesP, diff --git a/bindings/python/notmuch/query.py b/bindings/python/notmuch/query.py index 756e63b..4abba5b 100644 --- a/bindings/python/notmuch/query.py +++ b/bindings/python/notmuch/query.py @@ -18,7 +18,7 @@ Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p, c_uint -from notmuch.globals import ( +from .globals import ( nmlib, Enum, _str, diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py index 363c348..1d52345 100644 --- a/bindings/python/notmuch/tag.py +++ b/bindings/python/notmuch/tag.py @@ -17,7 +17,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p -from notmuch.globals import ( +from .globals import ( nmlib, Python3StringMixIn, NotmuchTagsP, diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 2f60d49..789f9a0 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -18,7 +18,7 @@ Copyright 2010 Sebastian Spaeth """ from ctypes import c_char_p, c_long, c_int -from notmuch.globals import ( +from .globals import ( nmlib, NotmuchThreadP, NotmuchMessagesP, @@ -29,7 +29,7 @@ from .errors import ( NotInitializedError, ) from .messages import Messages -from notmuch.tag import Tags +from .tag import Tags from datetime import date class Thread(object): diff --git a/bindings/python/notmuch/threads.py b/bindings/python/notmuch/threads.py index d2e0a91..f8ca34a 100644 --- a/bindings/python/notmuch/threads.py +++ b/bindings/python/notmuch/threads.py @@ -17,7 +17,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth """ -from notmuch.globals import ( +from .globals import ( nmlib, Python3StringMixIn, NotmuchThreadP, -- cgit v1.2.3 From 8dc8495010057202b725ac029831c03f4e3ab6bd Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 17:15:24 +0200 Subject: python: Fix the remaining broken NULL pointer tests Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 2 +- bindings/python/notmuch/message.py | 4 ++-- bindings/python/notmuch/messages.py | 2 +- bindings/python/notmuch/thread.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index fb4c929..8f1b37f 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -558,7 +558,7 @@ class Database(object): """ self._assert_db_is_initialized() tags_p = Database._get_all_tags(self._db) - if tags_p == None: + if not tags_p: raise NullPointerError() return Tags(tags_p, self) diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index bdbe501..d7f029f 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -229,7 +229,7 @@ class Message(Python3StringMixIn): #Returns NULL if any error occurs. header = Message._get_header(self._msg, _str(header)) - if header == None: + if not header: raise NullPointerError() return header.decode('UTF-8', 'ignore') @@ -300,7 +300,7 @@ class Message(Python3StringMixIn): raise NotInitializedError() tags_p = Message._get_tags(self._msg) - if tags_p == None: + if not tags_p: raise NullPointerError() return Tags(tags_p, self) diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index 59ef40a..aee4a77 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -142,7 +142,7 @@ class Messages(object): #reset _msgs as we iterated over it and can do so only once self._msgs = None - if tags_p == None: + if not tags_p: raise NullPointerError() return Tags(tags_p, self) diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py index 789f9a0..009cb2b 100644 --- a/bindings/python/notmuch/thread.py +++ b/bindings/python/notmuch/thread.py @@ -238,7 +238,7 @@ class Thread(object): raise NotInitializedError() tags_p = Thread._get_tags(self._thread) - if tags_p == None: + if not tags_p: raise NullPointerError() return Tags(tags_p, self) -- cgit v1.2.3 From 643719dfce3bc1c9fa3a0d861076069d08d7bbbc Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 17:47:49 +0200 Subject: python: remove the "notmuch binary" section from the docs Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/docs/source/index.rst | 1 - bindings/python/docs/source/notmuch.rst | 68 --------------------------------- 2 files changed, 69 deletions(-) delete mode 100644 bindings/python/docs/source/notmuch.rst (limited to 'bindings') diff --git a/bindings/python/docs/source/index.rst b/bindings/python/docs/source/index.rst index 9ad5fa9..1cece5f 100644 --- a/bindings/python/docs/source/index.rst +++ b/bindings/python/docs/source/index.rst @@ -28,7 +28,6 @@ functionality, returning :class:`Threads`, :class:`Messages` and threads thread filesystem - notmuch Indices and tables ================== diff --git a/bindings/python/docs/source/notmuch.rst b/bindings/python/docs/source/notmuch.rst deleted file mode 100644 index bf68f33..0000000 --- a/bindings/python/docs/source/notmuch.rst +++ /dev/null @@ -1,68 +0,0 @@ -The notmuch 'binary' -==================== - -The cnotmuch module provides *notmuch*, a python reimplementation of the standard notmuch binary for two purposes: first, to allow running the standard notmuch testsuite over the cnotmuch bindings (for correctness and performance testing) and second, to give some examples as to how to use cnotmuch. 'Notmuch' provides a command line interface to your mail database. - -A standard install via `easy_install cnotmuch` will not install the notmuch binary, however it is available in the `cnotmuch source code repository `_. - - -It is invoked with the following pattern: `notmuch [args...]`. - -Where and [args...] are as follows: - - **setup** Interactively setup notmuch for first use. - This has not yet been implemented, and will probably not be - implemented unless someone puts in the effort. - - **new** [--verbose] - Find and import new messages to the notmuch database. - - This has not been implemented yet. We cheat by calling - the regular "notmuch" binary (which must be in your path - somewhere). - - **search** [options...] [...] Search for messages matching the given search terms. - - This has been implemented but for the `--format` and - `--sort` options. - - **show** [...] - Show all messages matching the search terms. - - This has been partially implemented, we show a stub for each - found message, but do not output the full message body yet. - - **count** [...] - Count messages matching the search terms. - - This has been fully implemented. - - **reply** [options...] [...] - Construct a reply template for a set of messages. - - This has not been implemented yet. - - **tag** +|- [...] [--] [...] - Add/remove tags for all messages matching the search terms. - - This has been fully implemented. - - **dump** [] - Create a plain-text dump of the tags for each message. - - This has been fully implemented. - **restore** - Restore the tags from the given dump file (see 'dump'). - - This has been fully implemented. - - **search-tags** [ [...] ] - List all tags found in the database or matching messages. - - This has been fully implemented. - - **help** [] - This message, or more detailed help for the named command. - - The 'help' page has been implemented, help for single - commands are missing though. Patches are welcome. -- cgit v1.2.3 From 8e3faa7f18d9ca87a77834d76f4b8db95669252b Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 18:13:55 +0200 Subject: python: add a file abstracting away differences between python 2 and 3 Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/compat.py | 67 +++++++++++++++++++++++++++++++++++++ bindings/python/notmuch/database.py | 8 +---- bindings/python/notmuch/globals.py | 35 ++----------------- 3 files changed, 70 insertions(+), 40 deletions(-) create mode 100644 bindings/python/notmuch/compat.py (limited to 'bindings') diff --git a/bindings/python/notmuch/compat.py b/bindings/python/notmuch/compat.py new file mode 100644 index 0000000..adc8d24 --- /dev/null +++ b/bindings/python/notmuch/compat.py @@ -0,0 +1,67 @@ +''' +This file is part of notmuch. + +This module handles differences between python2.x and python3.x and +allows the notmuch bindings to support both version families with one +source tree. + +Notmuch is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +Notmuch is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with notmuch. If not, see . + +Copyright 2010 Sebastian Spaeth +Copyright 2012 Justus Winter <4winter@informatik.uni-hamburg.de> +''' + +import sys + +if sys.version_info[0] == 2: + from ConfigParser import SafeConfigParser + + class Python3StringMixIn(object): + def __str__(self): + return unicode(self).encode('utf-8') + + def encode_utf8(value): + ''' + Ensure a nicely utf-8 encoded string to pass to wrapped + libnotmuch functions. + + C++ code expects strings to be well formatted and unicode + strings to have no null bytes. + ''' + if not isinstance(value, basestring): + raise TypeError('Expected str or unicode, got %s' % type(value)) + + if isinstance(value, unicode): + return value.encode('utf-8', 'replace') + + return value +else: + from configparser import SafeConfigParser + + class Python3StringMixIn(object): + def __str__(self): + return self.__unicode__() + + def encode_utf8(value): + ''' + Ensure a nicely utf-8 encoded string to pass to wrapped + libnotmuch functions. + + C++ code expects strings to be well formatted and unicode + strings to have no null bytes. + ''' + if not isinstance(value, str): + raise TypeError('Expected str, got %s' % type(value)) + + return value.encode('utf-8', 'replace') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 8f1b37f..6dab932 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -20,6 +20,7 @@ Copyright 2010 Sebastian Spaeth import os import codecs from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER +from .compat import SafeConfigParser from .globals import ( nmlib, Enum, @@ -589,13 +590,6 @@ class Database(object): """ Reads a user's notmuch config and returns his db location Throws a NotmuchError if it cannot find it""" - try: - # python3.x - from configparser import SafeConfigParser - except ImportError: - # python2.x - from ConfigParser import SafeConfigParser - config = SafeConfigParser() conf_f = os.getenv('NOTMUCH_CONFIG', os.path.expanduser('~/.notmuch-config')) diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index f5fad72..c7632c3 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -16,7 +16,7 @@ along with notmuch. If not, see . Copyright 2010 Sebastian Spaeth """ -import sys + from ctypes import CDLL, Structure, POINTER #----------------------------------------------------------------------------- @@ -26,38 +26,7 @@ try: except: raise ImportError("Could not find shared 'notmuch' library.") - -if sys.version_info[0] == 2: - class Python3StringMixIn(object): - def __str__(self): - return unicode(self).encode('utf-8') - - - def _str(value): - """Ensure a nicely utf-8 encoded string to pass to libnotmuch - - C++ code expects strings to be well formatted and - unicode strings to have no null bytes.""" - if not isinstance(value, basestring): - raise TypeError("Expected str or unicode, got %s" % type(value)) - if isinstance(value, unicode): - return value.encode('UTF-8') - return value -else: - class Python3StringMixIn(object): - def __str__(self): - return self.__unicode__() - - - def _str(value): - """Ensure a nicely utf-8 encoded string to pass to libnotmuch - - C++ code expects strings to be well formatted and - unicode strings to have no null bytes.""" - if not isinstance(value, str): - raise TypeError("Expected str, got %s" % type(value)) - return value.encode('UTF-8') - +from .compat import Python3StringMixIn, encode_utf8 as _str class Enum(object): """Provides ENUMS as "code=Enum(['a','b','c'])" where code.a=0 etc...""" -- cgit v1.2.3 From 8f667be2aca7d903a82344490045dff4110f68d7 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 18:14:58 +0200 Subject: python: fix Message.get_header 8dc8495010057202b725ac029831c03f4e3ab6bd introduced a bug, if the requested header is not set the underlying notmuch function returns an empty string that also made the expression true resulting in an exception being raised. Partly revert the commit to fix this issue. Testing for equality with None is correct in this case since the restype of the function Message._get_header is c_char_p so NULL pointers are in fact converted to None in this case. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index d7f029f..d1c1b58 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -229,7 +229,7 @@ class Message(Python3StringMixIn): #Returns NULL if any error occurs. header = Message._get_header(self._msg, _str(header)) - if not header: + if header == None: raise NullPointerError() return header.decode('UTF-8', 'ignore') -- cgit v1.2.3 From 892bb1ee6d52556eaf88cc35b61048a4de862352 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 19:05:53 +0200 Subject: python: deprecate Database.db_p Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/database.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 6dab932..ee0366c 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -603,7 +603,9 @@ class Database(object): def db_p(self): """Property returning a pointer to `notmuch_database_t` or `None` - This should normally not be needed by a user (and is not yet - guaranteed to remain stable in future versions). + .. deprecated:: 0.14 + If you really need a pointer to the notmuch + database object use the `_pointer` field. This + alias will be removed in notmuch 0.15. """ return self._db -- cgit v1.2.3 From 8c123d0da61244b90e2b45bf6334e611ddd9a5d3 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 17 May 2012 19:06:57 +0200 Subject: python: deprecate Messages.{format,print}_messages This code adds functionality at the python level that is unlikely to be useful for anyone. Furthermore the python bindings strive to be a thin wrapper around libnotmuch, so this code will be removed in notmuch 0.15. Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de> --- bindings/python/notmuch/messages.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'bindings') diff --git a/bindings/python/notmuch/messages.py b/bindings/python/notmuch/messages.py index aee4a77..e83455b 100644 --- a/bindings/python/notmuch/messages.py +++ b/bindings/python/notmuch/messages.py @@ -199,6 +199,13 @@ class Messages(object): :param entire_thread: A bool, indicating whether we want to output whole threads or only the matching messages. :return: a list of lines + + .. deprecated:: 0.14 + This code adds functionality at the python + level that is unlikely to be useful for + anyone. Furthermore the python bindings strive + to be a thin wrapper around libnotmuch, so + this code will be removed in notmuch 0.15. """ result = list() @@ -255,6 +262,13 @@ class Messages(object): :param indent: A number indicating the reply depth of these messages. :param entire_thread: A bool, indicating whether we want to output whole threads or only the matching messages. + + .. deprecated:: 0.14 + This code adds functionality at the python + level that is unlikely to be useful for + anyone. Furthermore the python bindings strive + to be a thin wrapper around libnotmuch, so + this code will be removed in notmuch 0.15. """ handle.write(''.join(self.format_messages(format, indent, entire_thread))) -- cgit v1.2.3 From f1f1e3963910a845e2bc0ebe6b9b5c852b4564eb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:39 -0400 Subject: python: Update Database.get_directory documentation notmuch_database_get_directory no longer returns an error for read-only databases, so remove ReadOnlyDatabaseError from the list of get_directory exceptions. --- bindings/python/notmuch/database.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 797554d..ff89818 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -346,7 +346,6 @@ class Database(object): def get_directory(self, path): """Returns a :class:`Directory` of path, - (creating it if it does not exist(?)) :param path: An unicode string containing the path relative to the path of database (see :meth:`get_path`), or else should be an absolute @@ -354,8 +353,6 @@ class Database(object): :returns: :class:`Directory` or raises an exception. :raises: :exc:`FileError` if path is not relative database or absolute with initial components same as database. - :raises: :exc:`ReadOnlyDatabaseError` if the database has not been - opened in read-write mode """ self._assert_db_is_initialized() -- cgit v1.2.3 From 54508eb78d1c5c1c67c8b220cf2bd826af1203a9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:41 -0400 Subject: python: Remove find_message_by_filename workaround Now that notmuch_database_find_message_by_filename works on read-only databases, remove the workaround that disabled it on read-write databases. This also adds a regression test for find_message_by_filename. --- bindings/python/notmuch/database.py | 9 --------- test/python | 8 ++++++++ 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index ff89818..e5c74cf 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -526,19 +526,10 @@ class Database(object): retry. :raises: :exc:`NotInitializedError` if the database was not intitialized. - :raises: :exc:`ReadOnlyDatabaseError` if the database has not been - opened in read-write mode *Added in notmuch 0.9*""" self._assert_db_is_initialized() - # work around libnotmuch calling exit(3), see - # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de - # TODO: remove once this issue is resolved - if self.mode != Database.MODE.READ_WRITE: - raise ReadOnlyDatabaseError('The database has to be opened in ' - 'read-write mode for get_directory') - msg_p = NotmuchMessageP() status = Database._find_message_by_filename(self._db, _str(filename), byref(msg_p)) diff --git a/test/python b/test/python index 6018c2d..3f03a2e 100755 --- a/test/python +++ b/test/python @@ -28,4 +28,12 @@ EOF notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "get non-existent file" +test_python < Date: Fri, 25 May 2012 15:08:17 +0200 Subject: Revert "ruby: Add workarounds to use in-tree build not the installed one" This reverts commit 82b73ffd7380b85d259eeb91100dd6ac2d14223a. Only leave the copyright changes. Signed-off-by: Felipe Contreras --- bindings/ruby/defs.h | 2 +- bindings/ruby/extconf.rb | 24 +++--------------------- 2 files changed, 4 insertions(+), 22 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 85d8205..3f9512b 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -21,8 +21,8 @@ #ifndef DEFS_H #define DEFS_H +#include #include -#include "notmuch.h" VALUE notmuch_rb_cDatabase; VALUE notmuch_rb_cDirectory; diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb index 933f34a..7b9750f 100644 --- a/bindings/ruby/extconf.rb +++ b/bindings/ruby/extconf.rb @@ -5,27 +5,9 @@ require 'mkmf' -NOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib')) -NOTHDR = File.join(NOTDIR, 'notmuch.h') -NOTLIB = File.join(NOTDIR, 'libnotmuch.a') - -unless File.exists? NOTHDR - $stderr.puts "notmuch.h is missing under #{NOTDIR}" - exit 1 -end - -unless File.exists? NOTLIB - $stderr.puts "libnotmuch.a is missing under #{NOTDIR}" - exit 1 -end - -# Small hack to build with in-tree version not the installed one. -# find_header() and friends use standard include/library paths first. -$stderr.puts "Added -I#{NOTDIR} to $INCFLAGS" -$INCFLAGS = "-I#{NOTDIR}".quote + " " + $INCFLAGS -find_header('notmuch.h', NOTDIR) - -$LOCAL_LIBS += NOTLIB +# Notmuch Library +find_header('notmuch.h', '../../lib') +find_library('notmuch', 'notmuch_database_create', '../../lib') # Create Makefile dir_config('notmuch') -- cgit v1.2.3 From df96c93239b6e92e19f22f7759e7d1595c3fdcdd Mon Sep 17 00:00:00 2001 From: David Bremner Date: Fri, 25 May 2012 21:17:54 -0300 Subject: version: bump to 0.13.1 --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index 5945a50..cb1d625 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.13' +__VERSION__ = '0.13.1' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index 8cc9773..8192b9d 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-CONFIG 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index 1eb70d1..dd906f3 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-COUNT 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index b03f804..0a72f98 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-DUMP 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 37af146..4127632 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-NEW 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 593df3b..895f389 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-REPLY 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index ec16868..86e23fd 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-RESTORE 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 608178c..25e6a86 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-SEARCH 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index a7f0792..928e03c 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-SHOW 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 346b188..17e0310 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-TAG 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 465e324..7465fbd 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH 1 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index d9a86c7..e6ea3b2 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-HOOKS 5 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index cbbafc1..eae7c75 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-05-15 "Notmuch 0.13" +.TH NOTMUCH-SEARCH-TERMS 7 2012-05-25 "Notmuch 0.13.1" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index f304084..c317a91 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.13 +0.13.1 -- cgit v1.2.3 From 5946aba519ab99207ebf5d2863c60edd6a35bf9e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 25 May 2012 15:08:17 +0200 Subject: Revert "ruby: Add workarounds to use in-tree build not the installed one" This reverts commit 82b73ffd7380b85d259eeb91100dd6ac2d14223a. Only leave the copyright changes. Signed-off-by: Felipe Contreras (cherry picked from commit 35cb1c95cc8afa964900d29c813349ad8e24e7a8) --- bindings/ruby/defs.h | 2 +- bindings/ruby/extconf.rb | 24 +++--------------------- 2 files changed, 4 insertions(+), 22 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 85d8205..3f9512b 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -21,8 +21,8 @@ #ifndef DEFS_H #define DEFS_H +#include #include -#include "notmuch.h" VALUE notmuch_rb_cDatabase; VALUE notmuch_rb_cDirectory; diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb index 933f34a..7b9750f 100644 --- a/bindings/ruby/extconf.rb +++ b/bindings/ruby/extconf.rb @@ -5,27 +5,9 @@ require 'mkmf' -NOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib')) -NOTHDR = File.join(NOTDIR, 'notmuch.h') -NOTLIB = File.join(NOTDIR, 'libnotmuch.a') - -unless File.exists? NOTHDR - $stderr.puts "notmuch.h is missing under #{NOTDIR}" - exit 1 -end - -unless File.exists? NOTLIB - $stderr.puts "libnotmuch.a is missing under #{NOTDIR}" - exit 1 -end - -# Small hack to build with in-tree version not the installed one. -# find_header() and friends use standard include/library paths first. -$stderr.puts "Added -I#{NOTDIR} to $INCFLAGS" -$INCFLAGS = "-I#{NOTDIR}".quote + " " + $INCFLAGS -find_header('notmuch.h', NOTDIR) - -$LOCAL_LIBS += NOTLIB +# Notmuch Library +find_header('notmuch.h', '../../lib') +find_library('notmuch', 'notmuch_database_create', '../../lib') # Create Makefile dir_config('notmuch') -- cgit v1.2.3 From 9d5f73db7a948ddbed710309e7dc2f7d65d0f7d4 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Sat, 2 Jun 2012 18:10:55 -0300 Subject: version: update to 0.13.2 --- bindings/python/notmuch/version.py | 2 +- man/man1/notmuch-config.1 | 2 +- man/man1/notmuch-count.1 | 2 +- man/man1/notmuch-dump.1 | 2 +- man/man1/notmuch-new.1 | 2 +- man/man1/notmuch-reply.1 | 2 +- man/man1/notmuch-restore.1 | 2 +- man/man1/notmuch-search.1 | 2 +- man/man1/notmuch-show.1 | 2 +- man/man1/notmuch-tag.1 | 2 +- man/man1/notmuch.1 | 2 +- man/man5/notmuch-hooks.5 | 2 +- man/man7/notmuch-search-terms.7 | 2 +- version | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'bindings') diff --git a/bindings/python/notmuch/version.py b/bindings/python/notmuch/version.py index cb1d625..90bcadb 100644 --- a/bindings/python/notmuch/version.py +++ b/bindings/python/notmuch/version.py @@ -1,2 +1,2 @@ # this file should be kept in sync with ../../../version -__VERSION__ = '0.13.1' +__VERSION__ = '0.13.2' diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1 index 8192b9d..4f7985c 100644 --- a/man/man1/notmuch-config.1 +++ b/man/man1/notmuch-config.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-CONFIG 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-CONFIG 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-config \- Access notmuch configuration file. .SH SYNOPSIS diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1 index dd906f3..8029174 100644 --- a/man/man1/notmuch-count.1 +++ b/man/man1/notmuch-count.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-COUNT 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-COUNT 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-count \- Count messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1 index 0a72f98..9c7dd84 100644 --- a/man/man1/notmuch-dump.1 +++ b/man/man1/notmuch-dump.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-DUMP 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-DUMP 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-dump \- Creates a plain-text dump of the tags of each message. diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1 index 4127632..cd83a88 100644 --- a/man/man1/notmuch-new.1 +++ b/man/man1/notmuch-new.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-NEW 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-NEW 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-new \- Incorporate new mail into the notmuch database. .SH SYNOPSIS diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1 index 895f389..fb5114c 100644 --- a/man/man1/notmuch-reply.1 +++ b/man/man1/notmuch-reply.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-REPLY 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-REPLY 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-reply \- Constructs a reply template for a set of messages. diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1 index 86e23fd..3156af7 100644 --- a/man/man1/notmuch-restore.1 +++ b/man/man1/notmuch-restore.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-RESTORE 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-RESTORE 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-restore \- Restores the tags from the given file (see notmuch dump). diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 25e6a86..5c72c4b 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-SEARCH 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-search \- Search for messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index 928e03c..efd30a0 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SHOW 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-SHOW 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-show \- Show messages matching the given search terms. .SH SYNOPSIS diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 17e0310..27e682e 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -1,4 +1,4 @@ -.TH NOTMUCH-TAG 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-TAG 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-tag \- Add/remove tags for all messages matching the search terms. diff --git a/man/man1/notmuch.1 b/man/man1/notmuch.1 index 7465fbd..ebea4aa 100644 --- a/man/man1/notmuch.1 +++ b/man/man1/notmuch.1 @@ -16,7 +16,7 @@ .\" along with this program. If not, see http://www.gnu.org/licenses/ . .\" .\" Author: Carl Worth -.TH NOTMUCH 1 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH 1 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch \- thread-based email index, search, and tagging .SH SYNOPSIS diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 index e6ea3b2..b914a29 100644 --- a/man/man5/notmuch-hooks.5 +++ b/man/man5/notmuch-hooks.5 @@ -1,4 +1,4 @@ -.TH NOTMUCH-HOOKS 5 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-HOOKS 5 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-hooks \- hooks for notmuch diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index eae7c75..c559ed6 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -1,4 +1,4 @@ -.TH NOTMUCH-SEARCH-TERMS 7 2012-05-25 "Notmuch 0.13.1" +.TH NOTMUCH-SEARCH-TERMS 7 2012-06-01 "Notmuch 0.13.2" .SH NAME notmuch-search-terms \- Syntax for notmuch queries diff --git a/version b/version index c317a91..9beb74d 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.13.1 +0.13.2 -- cgit v1.2.3 From d796dad4edce71c1cfb245ffd2c438f26c84f804 Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Sun, 24 Jun 2012 21:48:34 +0300 Subject: ruby: extern linkage portability improvement Some C compilers are stricter when it comes to (tentative) definition of a variable -- in those compilers introducing variable without 'extern' keyword always allocates new 'storage' to the variable and linking all these modules fails due to duplicate symbols. This is reimplementation of Charlie Allom's patch: id:"1336481467-66356-1-git-send-email-charlie@mediasp.com", written originally by Ali Polatel. This version has more accurate commit message. --- bindings/ruby/defs.h | 50 +++++++++++++++++++++++++------------------------- bindings/ruby/init.c | 26 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 25 deletions(-) (limited to 'bindings') diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 3f9512b..fe81b3f 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -24,31 +24,31 @@ #include #include -VALUE notmuch_rb_cDatabase; -VALUE notmuch_rb_cDirectory; -VALUE notmuch_rb_cFileNames; -VALUE notmuch_rb_cQuery; -VALUE notmuch_rb_cThreads; -VALUE notmuch_rb_cThread; -VALUE notmuch_rb_cMessages; -VALUE notmuch_rb_cMessage; -VALUE notmuch_rb_cTags; - -VALUE notmuch_rb_eBaseError; -VALUE notmuch_rb_eDatabaseError; -VALUE notmuch_rb_eMemoryError; -VALUE notmuch_rb_eReadOnlyError; -VALUE notmuch_rb_eXapianError; -VALUE notmuch_rb_eFileError; -VALUE notmuch_rb_eFileNotEmailError; -VALUE notmuch_rb_eNullPointerError; -VALUE notmuch_rb_eTagTooLongError; -VALUE notmuch_rb_eUnbalancedFreezeThawError; -VALUE notmuch_rb_eUnbalancedAtomicError; - -ID ID_call; -ID ID_db_create; -ID ID_db_mode; +extern VALUE notmuch_rb_cDatabase; +extern VALUE notmuch_rb_cDirectory; +extern VALUE notmuch_rb_cFileNames; +extern VALUE notmuch_rb_cQuery; +extern VALUE notmuch_rb_cThreads; +extern VALUE notmuch_rb_cThread; +extern VALUE notmuch_rb_cMessages; +extern VALUE notmuch_rb_cMessage; +extern VALUE notmuch_rb_cTags; + +extern VALUE notmuch_rb_eBaseError; +extern VALUE notmuch_rb_eDatabaseError; +extern VALUE notmuch_rb_eMemoryError; +extern VALUE notmuch_rb_eReadOnlyError; +extern VALUE notmuch_rb_eXapianError; +extern VALUE notmuch_rb_eFileError; +extern VALUE notmuch_rb_eFileNotEmailError; +extern VALUE notmuch_rb_eNullPointerError; +extern VALUE notmuch_rb_eTagTooLongError; +extern VALUE notmuch_rb_eUnbalancedFreezeThawError; +extern VALUE notmuch_rb_eUnbalancedAtomicError; + +extern ID ID_call; +extern ID ID_db_create; +extern ID ID_db_mode; /* RSTRING_PTR() is new in ruby-1.9 */ #if !defined(RSTRING_PTR) diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index 3fe60fb..f4931d3 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -20,6 +20,32 @@ #include "defs.h" +VALUE notmuch_rb_cDatabase; +VALUE notmuch_rb_cDirectory; +VALUE notmuch_rb_cFileNames; +VALUE notmuch_rb_cQuery; +VALUE notmuch_rb_cThreads; +VALUE notmuch_rb_cThread; +VALUE notmuch_rb_cMessages; +VALUE notmuch_rb_cMessage; +VALUE notmuch_rb_cTags; + +VALUE notmuch_rb_eBaseError; +VALUE notmuch_rb_eDatabaseError; +VALUE notmuch_rb_eMemoryError; +VALUE notmuch_rb_eReadOnlyError; +VALUE notmuch_rb_eXapianError; +VALUE notmuch_rb_eFileError; +VALUE notmuch_rb_eFileNotEmailError; +VALUE notmuch_rb_eNullPointerError; +VALUE notmuch_rb_eTagTooLongError; +VALUE notmuch_rb_eUnbalancedFreezeThawError; +VALUE notmuch_rb_eUnbalancedAtomicError; + +ID ID_call; +ID ID_db_create; +ID ID_db_mode; + /* * Document-module: Notmuch * -- cgit v1.2.3