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/messages.py | 262 ++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 bindings/python/notmuch/messages.py (limited to 'bindings/python/notmuch/messages.py') 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__ -- 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/python/notmuch/messages.py') 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 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/python/notmuch/messages.py') 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 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/python/notmuch/messages.py') 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/python/notmuch/messages.py') 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 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/python/notmuch/messages.py') 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 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/python/notmuch/messages.py') 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