X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=cnotmuch%2Fdatabase.py;h=92afa0a047d8f773ec76b1459723bc9f0cdbc1b1;hp=9c78b461310399e4531f3b8945b7d417ad7997de;hb=4ed01d055ac59b182535dfe44a33e52fc271279b;hpb=23b32a7dfdeec9acc2ad800e1d307b31cf82052d diff --git a/cnotmuch/database.py b/cnotmuch/database.py index 9c78b461..92afa0a0 100644 --- a/cnotmuch/database.py +++ b/cnotmuch/database.py @@ -1,5 +1,5 @@ import ctypes -from ctypes import c_int, c_char_p, c_void_p, c_uint64 +from ctypes import c_int, c_char_p, c_void_p, c_uint, c_uint64, c_bool from cnotmuch.globals import nmlib, STATUS, NotmuchError, Enum import logging from datetime import date @@ -23,6 +23,10 @@ class Database(object): _get_path = nmlib.notmuch_database_get_path _get_path.restype = c_char_p + """notmuch_database_get_version""" + _get_version = nmlib.notmuch_database_get_version + _get_version.restype = c_uint + """notmuch_database_open (const char *path, notmuch_database_mode_t mode)""" _open = nmlib.notmuch_database_open _open.restype = c_void_p @@ -124,6 +128,35 @@ class Database(object): Wraps notmuch_database_get_path""" return Database._get_path(self._db) + def get_version(self): + """Returns the database format version + + :returns: The database version as positive integer + :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if + the database was not intitialized. + """ + if self._db is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + + return Database._get_version (self._db) + + def needs_upgrade(self): + """Does this database need to be upgraded before writing to it? + + If this function returns True then no functions that modify the + database (:meth:`add_message`, :meth:`add_tag`, + :meth:`Directory.set_mtime`, etc.) will work unless :meth:`upgrade` + is called successfully first. + + :returns: `True` or `False` + :exception: :exc:`NotmuchError` with STATUS.NOT_INITIALIZED if + the database was not intitialized. + """ + if self._db is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + + return notmuch_database_needs_upgrade(self.db) + def find_message(self, msgid): """Returns a :class:`Message` as identified by its message ID @@ -688,15 +721,12 @@ class Message(object): 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. """ @@ -725,15 +755,14 @@ class Message(object): STATUS.NULL_POINTER The 'tag' argument is NULL - NOTMUCH_STATUS_TAG_TOO_LONG + STATUS.TAG_TOO_LONG The length of 'tag' is too long (exceeds NOTMUCH_TAG_MAX) - NOTMUCH_STATUS_READ_ONLY_DATABASE + 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. - """ if self._msg is None: raise NotmuchError(STATUS.NOT_INITIALIZED) @@ -746,6 +775,120 @@ class Message(object): raise NotmuchError(status) + def remove_all_tags(self): + """Removes all tags from the given message. + + See :meth:`freeze` for an example showing how to safely + replace tag values. + + :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. + """ + if self._msg is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + + status = nmlib.notmuch_message_remove_all_tags(self._msg) + + if STATUS.SUCCESS == status: + # return on success + return status + + raise NotmuchError(status) + + def freeze(self): + """Freezes the current state of 'message' within the database + + This means that changes to the message state, (via :meth:`add_tag`, + :meth:`remove_tag`, and :meth:`remove_all_tags`), will not be + committed to the database until the message is :meth:`thaw`ed. + + 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:: + + msg.freeze() + msg.remove_all_tags() + for tag in new_tags: + msg.add_tag(tag) + msg.thaw() + + 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 + :meth:`remove_all_tags` but before :meth:`add_tag`. + + :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. + """ + if self._msg is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + + status = nmlib.notmuch_message_freeze(self._msg) + + if STATUS.SUCCESS == status: + # return on success + return status + + raise NotmuchError(status) + + def thaw(self): + """Thaws the current 'message' + + Thaw the current 'message', synchronizing any changes that may have + occurred while 'message' was frozen into the notmuch database. + + See :meth:`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. + + :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. + """ + if self._msg is None: + raise NotmuchError(STATUS.NOT_INITIALIZED) + + status = nmlib.notmuch_message_thaw(self._msg) + + if STATUS.SUCCESS == status: + # return on success + return status + + raise NotmuchError(status) + + def __str__(self): """A message() is represented by a 1-line summary""" msg = {}