X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=bindings%2Fpython%2Fnotmuch%2Fdatabase.py;h=88ca836e2d1aa4c78471ede28f7541fac630aafa;hp=342d665a224761a2557ea00233f7d99c7dbae321;hb=HEAD;hpb=9e158fb6942cd74a9babc43e3c8e7bfc9125212a diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py deleted file mode 100644 index 342d665a..00000000 --- a/bindings/python/notmuch/database.py +++ /dev/null @@ -1,786 +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 -""" - -import os -import codecs -import warnings -from ctypes import c_char_p, c_void_p, c_uint, byref, POINTER -from .compat import SafeConfigParser -from .globals import ( - nmlib, - Enum, - _str, - NotmuchConfigListP, - NotmuchDatabaseP, - NotmuchDirectoryP, - NotmuchIndexoptsP, - NotmuchMessageP, - NotmuchTagsP, -) -from .errors import ( - STATUS, - FileError, - NotmuchError, - NullPointerError, - NotInitializedError, -) -from .message import Message -from .tag import Tags -from .query import Query -from .directory import Directory - -class Database(object): - """The :class:`Database` is the highest-level object that notmuch - provides. It references a notmuch database, and can be opened in - read-only or read-write mode. A :class:`Query` can be derived from - or be applied to a specific database to find messages. Also adding - and removing messages to the database happens via this - object. Modifications to the database are not atmic by default (see - :meth:`begin_atomic`) and once a database has been modified, all - other database objects pointing to the same data-base will throw an - :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. See :meth:`close` for more - information. - - .. note:: - - Any function in this class can and will throw an - :exc:`NotInitializedError` if the database was not intitialized - properly. - """ - _std_db_path = None - """Class attribute to cache user's default database""" - - MODE = Enum(['READ_ONLY', 'READ_WRITE']) - """Constants: Mode in which to open the database""" - - DECRYPTION_POLICY = Enum(['FALSE', 'TRUE', 'AUTO', 'NOSTASH']) - """Constants: policies for decrypting messages during indexing""" - - """notmuch_database_get_directory""" - _get_directory = nmlib.notmuch_database_get_directory - _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 - _get_path.argtypes = [NotmuchDatabaseP] - _get_path.restype = c_char_p - - """notmuch_database_get_version""" - _get_version = nmlib.notmuch_database_get_version - _get_version.argtypes = [NotmuchDatabaseP] - _get_version.restype = c_uint - - """notmuch_database_get_revision""" - _get_revision = nmlib.notmuch_database_get_revision - _get_revision.argtypes = [NotmuchDatabaseP, POINTER(c_char_p)] - _get_revision.restype = c_uint - - """notmuch_database_open""" - _open = nmlib.notmuch_database_open - _open.argtypes = [c_char_p, c_uint, POINTER(NotmuchDatabaseP)] - _open.restype = c_uint - - """notmuch_database_upgrade""" - _upgrade = nmlib.notmuch_database_upgrade - _upgrade.argtypes = [NotmuchDatabaseP, c_void_p, c_void_p] - _upgrade.restype = c_uint - - """ notmuch_database_find_message""" - _find_message = nmlib.notmuch_database_find_message - _find_message.argtypes = [NotmuchDatabaseP, c_char_p, - POINTER(NotmuchMessageP)] - _find_message.restype = c_uint - - """notmuch_database_find_message_by_filename""" - _find_message_by_filename = nmlib.notmuch_database_find_message_by_filename - _find_message_by_filename.argtypes = [NotmuchDatabaseP, c_char_p, - POINTER(NotmuchMessageP)] - _find_message_by_filename.restype = c_uint - - """notmuch_database_get_all_tags""" - _get_all_tags = nmlib.notmuch_database_get_all_tags - _get_all_tags.argtypes = [NotmuchDatabaseP] - _get_all_tags.restype = NotmuchTagsP - - """notmuch_database_create""" - _create = nmlib.notmuch_database_create - _create.argtypes = [c_char_p, POINTER(NotmuchDatabaseP)] - _create.restype = c_uint - - 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 - *NOTMUCH_CONFIG*, falling back to the default `~/.notmuch-config`. - - If *create* is `True`, the database will always be created in - :attr:`MODE`.READ_WRITE mode. Default mode for opening is READ_ONLY. - - :param path: Directory to open/create the database in (see - above for behavior if `None`) - :type path: `str` or `None` - :param create: Pass `False` to open an existing, `True` to create a new - database. - :type create: bool - :param mode: Mode to open a database in. Is always - :attr:`MODE`.READ_WRITE when creating a new one. - :type mode: :attr:`MODE` - :raises: :exc:`NotmuchError` or derived exception in case of - 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: - #the following line throws a NotmuchError if it fails - Database._std_db_path = self._get_user_default_db() - path = Database._std_db_path - - if create == False: - self.open(path, mode) - else: - self.create(path) - - _destroy = nmlib.notmuch_database_destroy - _destroy.argtypes = [NotmuchDatabaseP] - _destroy.restype = c_uint - - def __del__(self): - if self._db: - status = self._destroy(self._db) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - - def _assert_db_is_initialized(self): - """Raises :exc:`NotInitializedError` if self._db is `None`""" - if not self._db: - raise NotInitializedError() - - def create(self, path): - """Creates a new notmuch database - - This function is used by __init__() and usually does not need - to be called directly. It wraps the underlying - *notmuch_database_create* function and creates a new notmuch - database at *path*. It will always return a database in :attr:`MODE` - .READ_WRITE mode as creating an empty database for - reading only does not make a great deal of sense. - - :param path: A directory in which we should create the database. - :type path: str - :raises: :exc:`NotmuchError` in case of any failure - (possibly after printing an error message on stderr). - """ - if self._db: - raise NotmuchError(message="Cannot create db, this Database() " - "already has an open one.") - - db = NotmuchDatabaseP() - status = Database._create(_str(path), byref(db)) - - if status != STATUS.SUCCESS: - raise NotmuchError(status) - self._db = db - return status - - def open(self, path, mode=0): - """Opens an existing database - - This function is used by __init__() and usually does not need - to be called directly. It wraps the underlying - *notmuch_database_open* function. - - :param status: Open the database in read-only or read-write mode - :type status: :attr:`MODE` - :raises: Raises :exc:`NotmuchError` in case of any failure - (possibly after printing an error message on stderr). - """ - db = NotmuchDatabaseP() - status = Database._open(_str(path), mode, byref(db)) - - if status != STATUS.SUCCESS: - raise NotmuchError(status) - self._db = db - return status - - _close = nmlib.notmuch_database_close - _close.argtypes = [NotmuchDatabaseP] - _close.restype = c_uint - - 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: - status = self._close(self._db) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - - 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() - return Database._get_path(self._db).decode('utf-8') - - def get_version(self): - """Returns the database format version - - :returns: The database version as positive integer - """ - self._assert_db_is_initialized() - return Database._get_version(self._db) - - def get_revision (self): - """Returns the committed database revison and UUID - - :returns: (revison, uuid) The database revision as a positive integer - and the UUID of the database. - """ - self._assert_db_is_initialized() - uuid = c_char_p () - revision = Database._get_revision(self._db, byref (uuid)) - return (revision, uuid.value.decode ('utf-8')) - - _needs_upgrade = nmlib.notmuch_database_needs_upgrade - _needs_upgrade.argtypes = [NotmuchDatabaseP] - _needs_upgrade.restype = bool - - def needs_upgrade(self): - """Does this database need to be upgraded before writing to it? - - If this function returns `True` then no functions that modify the - database (:meth:`index_file`, - :meth:`Message.add_tag`, :meth:`Directory.set_mtime`, - etc.) will work unless :meth:`upgrade` is called successfully first. - - :returns: `True` or `False` - """ - self._assert_db_is_initialized() - return self._needs_upgrade(self._db) - - def upgrade(self): - """Upgrades the current database - - After opening a database in read-write mode, the client should - check if an upgrade is needed (notmuch_database_needs_upgrade) and - if so, upgrade with this function before making any modifications. - - NOT IMPLEMENTED: The optional progress_notify callback can be - used by the caller to provide progress indication to the - user. If non-NULL it will be called periodically with - 'progress' as a floating-point value in the range of [0.0..1.0] - indicating the progress made so far in the upgrade process. - - :TODO: catch exceptions, document return values and etc... - """ - self._assert_db_is_initialized() - status = Database._upgrade(self._db, None, None) - # TODO: catch exceptions, document return values and etc - return status - - _begin_atomic = nmlib.notmuch_database_begin_atomic - _begin_atomic.argtypes = [NotmuchDatabaseP] - _begin_atomic.restype = c_uint - - def begin_atomic(self): - """Begin an atomic database operation - - Any modifications performed between a successful - :meth:`begin_atomic` and a :meth:`end_atomic` will be applied to - the database atomically. Note that, unlike a typical database - transaction, this only ensures atomicity, not durability; - neither begin nor end necessarily flush modifications to disk. - - :returns: :attr:`STATUS`.SUCCESS or raises - :raises: :exc:`NotmuchError`: :attr:`STATUS`.XAPIAN_EXCEPTION - Xapian exception occurred; atomic section not entered. - - *Added in notmuch 0.9*""" - self._assert_db_is_initialized() - status = self._begin_atomic(self._db) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - return status - - _end_atomic = nmlib.notmuch_database_end_atomic - _end_atomic.argtypes = [NotmuchDatabaseP] - _end_atomic.restype = c_uint - - def end_atomic(self): - """Indicate the end of an atomic database operation - - See :meth:`begin_atomic` for details. - - :returns: :attr:`STATUS`.SUCCESS or raises - - :raises: - :exc:`NotmuchError`: - :attr:`STATUS`.XAPIAN_EXCEPTION - A Xapian exception occurred; atomic section not - ended. - :attr:`STATUS`.UNBALANCED_ATOMIC: - end_atomic has been called more times than begin_atomic. - - *Added in notmuch 0.9*""" - self._assert_db_is_initialized() - status = self._end_atomic(self._db) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - return status - - def get_directory(self, path): - """Returns a :class:`Directory` of path, - - :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. - """ - self._assert_db_is_initialized() - - # sanity checking if path is valid, and make path absolute - 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 - raise FileError('Database().get_directory() called ' - 'with a wrong absolute path') - abs_dirpath = path - else: - #we got a relative path, make it absolute - abs_dirpath = os.path.abspath(os.path.join(self.get_path(), 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) - - _get_default_indexopts = nmlib.notmuch_database_get_default_indexopts - _get_default_indexopts.argtypes = [NotmuchDatabaseP] - _get_default_indexopts.restype = NotmuchIndexoptsP - - _indexopts_set_decrypt_policy = nmlib.notmuch_indexopts_set_decrypt_policy - _indexopts_set_decrypt_policy.argtypes = [NotmuchIndexoptsP, c_uint] - _indexopts_set_decrypt_policy.restype = None - - _indexopts_destroy = nmlib.notmuch_indexopts_destroy - _indexopts_destroy.argtypes = [NotmuchIndexoptsP] - _indexopts_destroy.restype = None - - _index_file = nmlib.notmuch_database_index_file - _index_file.argtypes = [NotmuchDatabaseP, c_char_p, - c_void_p, - POINTER(NotmuchMessageP)] - _index_file.restype = c_uint - - def index_file(self, filename, sync_maildir_flags=False, decrypt_policy=None): - """Adds a new message to the database - - :param filename: should be a path relative to the path of the - open database (see :meth:`get_path`), or else should be an - absolute filename with initial components that match the - path of the 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. - - :param sync_maildir_flags: If the message contains Maildir - flags, we will -depending on the notmuch configuration- sync - those tags to initial notmuch tags, if set to `True`. It is - `False` by default to remain consistent with the libnotmuch - API. You might want to look into the underlying method - :meth:`Message.maildir_flags_to_tags`. - - :param decrypt_policy: If the message contains any encrypted - parts, and decrypt_policy is set to - :attr:`DECRYPTION_POLICY`.TRUE, notmuch will try to - decrypt the message and index the cleartext, stashing any - discovered session keys. If it is set to - :attr:`DECRYPTION_POLICY`.FALSE, it will never try to - decrypt during indexing. If it is set to - :attr:`DECRYPTION_POLICY`.AUTO, then it will try to use - any stashed session keys it knows about, but will not try - to access the user's secret keys. - :attr:`DECRYPTION_POLICY`.NOSTASH behaves the same as - :attr:`DECRYPTION_POLICY`.TRUE except that no session keys - are stashed in the database. If decrypt_policy is set to - None (the default), then the database itself will decide - whether to decrypt, based on the `index.decrypt` - configuration setting (see notmuch-config(1)). - - :returns: On success, we return - - 1) a :class:`Message` object that can be used for things - such as adding tags to the just-added message. - 2) one of the following :attr:`STATUS` values: - - :attr:`STATUS`.SUCCESS - Message successfully added to database. - :attr:`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 list of the filenames for the existing message. - - :rtype: 2-tuple(:class:`Message`, :attr:`STATUS`) - - :raises: Raises a :exc:`NotmuchError` with the following meaning. - If such an exception occurs, nothing was added to the database. - - :attr:`STATUS`.FILE_ERROR - An error occurred trying to open the file, (such as - permission denied, or file not found, etc.). - :attr:`STATUS`.FILE_NOT_EMAIL - The contents of filename don't look like an email - message. - :attr:`STATUS`.READ_ONLY_DATABASE - Database was opened in read-only mode so no message can - be added. - """ - self._assert_db_is_initialized() - msg_p = NotmuchMessageP() - indexopts = c_void_p(None) - if decrypt_policy is not None: - indexopts = self._get_default_indexopts(self._db) - self._indexopts_set_decrypt_policy(indexopts, decrypt_policy) - - status = self._index_file(self._db, _str(filename), indexopts, byref(msg_p)) - - if indexopts: - self._indexopts_destroy(indexopts) - - if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: - raise NotmuchError(status) - - #construct Message() and return - msg = Message(msg_p, self) - #automatic sync initial tags from Maildir flags - if sync_maildir_flags: - msg.maildir_flags_to_tags() - return (msg, status) - - def add_message(self, filename, sync_maildir_flags=False): - """Deprecated alias for :meth:`index_file` - """ - warnings.warn( - "This function is deprecated and will be removed in the future, use index_file.", DeprecationWarning) - - return self.index_file(filename, sync_maildir_flags=sync_maildir_flags) - - _remove_message = nmlib.notmuch_database_remove_message - _remove_message.argtypes = [NotmuchDatabaseP, c_char_p] - _remove_message.restype = c_uint - - def remove_message(self, filename): - """Removes a message (filename) from the given notmuch database - - 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. - - :returns: A :attr:`STATUS` value with the following meaning: - - :attr:`STATUS`.SUCCESS - The last filename was removed and the message was removed - from the database. - :attr:`STATUS`.DUPLICATE_MESSAGE_ID - This filename was removed but the message persists in the - database with at least one other filename. - - :raises: Raises a :exc:`NotmuchError` with the following meaning. - If such an exception occurs, nothing was removed from the - database. - - :attr:`STATUS`.READ_ONLY_DATABASE - Database was opened in read-only mode so no message can be - removed. - """ - self._assert_db_is_initialized() - status = self._remove_message(self._db, _str(filename)) - if status not in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: - raise NotmuchError(status) - return status - - def find_message(self, msgid): - """Returns a :class:`Message` as identified by its message ID - - Wraps the underlying *notmuch_database_find_message* function. - - :param msgid: The message ID - :type msgid: unicode or str - :returns: :class:`Message` or `None` if no message is found. - :raises: - :exc:`OutOfMemoryError` - If an Out-of-memory occurred 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. - """ - self._assert_db_is_initialized() - msg_p = NotmuchMessageP() - status = Database._find_message(self._db, _str(msgid), byref(msg_p)) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - return msg_p and Message(msg_p, self) or None - - def find_message_by_filename(self, filename): - """Find a message with the given filename - - :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 - filename. - - :raises: :exc:`OutOfMemoryError` if an Out-of-memory occurred 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() - - msg_p = NotmuchMessageP() - status = Database._find_message_by_filename(self._db, _str(filename), - byref(msg_p)) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - return msg_p and Message(msg_p, self) or None - - def get_all_tags(self): - """Returns :class:`Tags` with a list of all tags found in the database - - :returns: :class:`Tags` - :execption: :exc:`NotmuchError` with :attr:`STATUS`.NULL_POINTER - on error - """ - self._assert_db_is_initialized() - tags_p = Database._get_all_tags(self._db) - if not tags_p: - raise NullPointerError() - return Tags(tags_p, self) - - def create_query(self, querystring): - """Returns a :class:`Query` derived from this database - - This is a shorthand method for doing:: - - # short version - # Automatically frees the Database() when 'q' is deleted - - q = Database(dbpath).create_query('from:"Biene Maja"') - - # long version, which is functionally equivalent but will keep the - # Database in the 'db' variable around after we delete 'q': - - db = Database(dbpath) - q = Query(db,'from:"Biene Maja"') - - This function is a python extension and not in the underlying C API. - """ - return Query(self, querystring) - - """notmuch_database_status_string""" - _status_string = nmlib.notmuch_database_status_string - _status_string.argtypes = [NotmuchDatabaseP] - _status_string.restype = c_char_p - - def status_string(self): - """Returns the status string of the database - - This is sometimes used for additional error reporting - """ - self._assert_db_is_initialized() - s = Database._status_string(self._db) - if s: - return s.decode('utf-8', 'ignore') - return s - - def __repr__(self): - return "'Notmuch DB " + self.get_path() + "'" - - def _get_user_default_db(self): - """ Reads a user's notmuch config and returns his db location - - Throws a NotmuchError if it cannot find it""" - config = SafeConfigParser() - conf_f = os.getenv('NOTMUCH_CONFIG', - os.path.expanduser('~/.notmuch-config')) - 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') - - """notmuch_database_get_config""" - _get_config = nmlib.notmuch_database_get_config - _get_config.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(c_char_p)] - _get_config.restype = c_uint - - def get_config(self, key): - """Return the value of the given config key. - - Note that only config values that are stored in the database are - searched and returned. The config file is not read. - - :param key: the config key under which a value should be looked up, it - should probably be in the form "section.key" - :type key: str - :returns: the config value or the empty string if no value is present - for that key - :rtype: str - :raises: :exc:`NotmuchError` in case of failure. - - """ - self._assert_db_is_initialized() - return_string = c_char_p() - status = self._get_config(self._db, _str(key), byref(return_string)) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - return return_string.value.decode('utf-8') - - """notmuch_database_get_config_list""" - _get_config_list = nmlib.notmuch_database_get_config_list - _get_config_list.argtypes = [NotmuchDatabaseP, c_char_p, - POINTER(NotmuchConfigListP)] - _get_config_list.restype = c_uint - - _config_list_valid = nmlib.notmuch_config_list_valid - _config_list_valid.argtypes = [NotmuchConfigListP] - _config_list_valid.restype = bool - - _config_list_key = nmlib.notmuch_config_list_key - _config_list_key.argtypes = [NotmuchConfigListP] - _config_list_key.restype = c_char_p - - _config_list_value = nmlib.notmuch_config_list_value - _config_list_value.argtypes = [NotmuchConfigListP] - _config_list_value.restype = c_char_p - - _config_list_move_to_next = nmlib.notmuch_config_list_move_to_next - _config_list_move_to_next.argtypes = [NotmuchConfigListP] - _config_list_move_to_next.restype = None - - _config_list_destroy = nmlib.notmuch_config_list_destroy - _config_list_destroy.argtypes = [NotmuchConfigListP] - _config_list_destroy.restype = None - - def get_configs(self, prefix=''): - """Return a generator of key, value pairs where the start of key - matches the given prefix - - Note that only config values that are stored in the database are - searched and returned. The config file is not read. If no `prefix` is - given all config values are returned. - - This could be used to get all named queries into a dict for example:: - - queries = {k[6:]: v for k, v in db.get_configs('query.')} - - :param prefix: a string by which the keys should be selected - :type prefix: str - :yields: all key-value pairs where `prefix` matches the beginning - of the key - :ytype: pairs of str - :raises: :exc:`NotmuchError` in case of failure. - - """ - self._assert_db_is_initialized() - config_list_p = NotmuchConfigListP() - status = self._get_config_list(self._db, _str(prefix), - byref(config_list_p)) - if status != STATUS.SUCCESS: - raise NotmuchError(status) - while self._config_list_valid(config_list_p): - key = self._config_list_key(config_list_p).decode('utf-8') - value = self._config_list_value(config_list_p).decode('utf-8') - yield key, value - self._config_list_move_to_next(config_list_p) - - """notmuch_database_set_config""" - _set_config = nmlib.notmuch_database_set_config - _set_config.argtypes = [NotmuchDatabaseP, c_char_p, c_char_p] - _set_config.restype = c_uint - - def set_config(self, key, value): - """Set a config value in the notmuch database. - - If an empty string is provided as `value` the `key` is unset! - - :param key: the key to set - :type key: str - :param value: the value to store under `key` - :type value: str - :returns: None - :raises: :exc:`NotmuchError` in case of failure. - - """ - self._assert_db_is_initialized() - status = self._set_config(self._db, _str(key), _str(value)) - if status != STATUS.SUCCESS: - raise NotmuchError(status)