Since release 0.32, libnotmuch provides searching for database and
configuration paths. This commit changes the python module notmuch2 to
use those facilities.
This fixes the bug reported in [1], along with a couple of the
deprecation warnings in the python bindings.
Database.default_path is deprecated, since it no longer faithfully
reflects what libnotmuch is doing, and it is also no longer used in
the bindings themselves.
This commit choose the default of config=CONFIG.EMPTY (equivalent to
passing "" to notmuch_database_open_with_config). This makes the
change upward compatible API-wise (at least as far as the test suite
verifies), but changing the default to CONFIG.SEARCH would probably be
more convenient for bindings users.
[1]: id:87h7d4wp6b.fsf@tethera.net
notmuch_status_to_string (notmuch_status_t status);
notmuch_status_t
notmuch_status_to_string (notmuch_status_t status);
notmuch_status_t
- notmuch_database_create_verbose (const char *path,
- notmuch_database_t **database,
- char **error_message);
- notmuch_status_t
- notmuch_database_create (const char *path, notmuch_database_t **database);
- notmuch_status_t
- notmuch_database_open_verbose (const char *path,
- notmuch_database_mode_t mode,
- notmuch_database_t **database,
- char **error_message);
- notmuch_status_t
- notmuch_database_open (const char *path,
- notmuch_database_mode_t mode,
- notmuch_database_t **database);
+ notmuch_database_create_with_config (const char *database_path,
+ const char *config_path,
+ const char *profile,
+ notmuch_database_t **database,
+ char **error_message);
+ notmuch_status_t
+ notmuch_database_open_with_config (const char *database_path,
+ notmuch_database_mode_t mode,
+ const char *config_path,
+ const char *profile,
+ notmuch_database_t **database,
+ char **error_message);
notmuch_status_t
notmuch_database_close (notmuch_database_t *database);
notmuch_status_t
notmuch_status_t
notmuch_database_close (notmuch_database_t *database);
notmuch_status_t
READ_ONLY = capi.lib.NOTMUCH_DATABASE_MODE_READ_ONLY
READ_WRITE = capi.lib.NOTMUCH_DATABASE_MODE_READ_WRITE
READ_ONLY = capi.lib.NOTMUCH_DATABASE_MODE_READ_ONLY
READ_WRITE = capi.lib.NOTMUCH_DATABASE_MODE_READ_WRITE
+class ConfigFile(enum.Enum):
+ EMPTY = b''
+ SEARCH = capi.ffi.NULL
class QuerySortOrder(enum.Enum):
OLDEST_FIRST = capi.lib.NOTMUCH_SORT_OLDEST_FIRST
class QuerySortOrder(enum.Enum):
OLDEST_FIRST = capi.lib.NOTMUCH_SORT_OLDEST_FIRST
:cvar EXCLUDE: Which messages to exclude from queries, ``TRUE``,
``FLAG``, ``FALSE`` or ``ALL``. See the query documentation
for details.
:cvar EXCLUDE: Which messages to exclude from queries, ``TRUE``,
``FLAG``, ``FALSE`` or ``ALL``. See the query documentation
for details.
+ :cvar CONFIG: Control loading of config file. Enumeration of
+ ``EMPTY`` (don't load a config file), and ``SEARCH`` (search as
+ in :ref:`config_search`)
:cvar AddedMessage: A namedtuple ``(msg, dup)`` used by
:meth:`add` as return value.
:cvar STR_MODE_MAP: A map mapping strings to :attr:`MODE` items.
:cvar AddedMessage: A namedtuple ``(msg, dup)`` used by
:meth:`add` as return value.
:cvar STR_MODE_MAP: A map mapping strings to :attr:`MODE` items.
still open.
:param path: The directory of where the database is stored. If
still open.
:param path: The directory of where the database is stored. If
- ``None`` the location will be read from the user's
- configuration file, respecting the ``NOTMUCH_CONFIG``
- environment variable if set.
+ ``None`` the location will be searched according to
+ :ref:`database`
:type path: str, bytes, os.PathLike or pathlib.Path
:param mode: The mode to open the database in. One of
:attr:`MODE.READ_ONLY` OR :attr:`MODE.READ_WRITE`. For
:type path: str, bytes, os.PathLike or pathlib.Path
:param mode: The mode to open the database in. One of
:attr:`MODE.READ_ONLY` OR :attr:`MODE.READ_WRITE`. For
:attr:`MODE.READ_ONLY` and ``rw`` for :attr:`MODE.READ_WRITE`.
:type mode: :attr:`MODE` or str.
:attr:`MODE.READ_ONLY` and ``rw`` for :attr:`MODE.READ_WRITE`.
:type mode: :attr:`MODE` or str.
+ :param config: Where to load the configuration from, if any.
+ :type config: :attr:`CONFIG.EMPTY`, :attr:`CONFIG.SEARCH`, str, bytes, os.PathLike, pathlib.Path
:raises KeyError: if an unknown mode string is used.
:raises OSError: or subclasses if the configuration file can not
be opened.
:raises KeyError: if an unknown mode string is used.
:raises OSError: or subclasses if the configuration file can not
be opened.
MODE = Mode
SORT = QuerySortOrder
EXCLUDE = QueryExclude
MODE = Mode
SORT = QuerySortOrder
EXCLUDE = QueryExclude
AddedMessage = collections.namedtuple('AddedMessage', ['msg', 'dup'])
_db_p = base.MemoryPointer()
STR_MODE_MAP = {
AddedMessage = collections.namedtuple('AddedMessage', ['msg', 'dup'])
_db_p = base.MemoryPointer()
STR_MODE_MAP = {
- def __init__(self, path=None, mode=MODE.READ_ONLY):
+ @staticmethod
+ def _cfg_path_encode(path):
+ if isinstance(path,ConfigFile):
+ path = path.value
+ elif path is None:
+ path = capi.ffi.NULL
+ elif not hasattr(os, 'PathLike') and isinstance(path, pathlib.Path):
+ path = bytes(path)
+ else:
+ path = os.fsencode(path)
+ return path
+
+ @staticmethod
+ def _db_path_encode(path):
+ if path is None:
+ path = capi.ffi.NULL
+ elif not hasattr(os, 'PathLike') and isinstance(path, pathlib.Path):
+ path = bytes(path)
+ else:
+ path = os.fsencode(path)
+ return path
+
+ def __init__(self, path=None, mode=MODE.READ_ONLY, config=CONFIG.EMPTY):
if isinstance(mode, str):
mode = self.STR_MODE_MAP[mode]
self.mode = mode
if isinstance(mode, str):
mode = self.STR_MODE_MAP[mode]
self.mode = mode
- if path is None:
- path = self.default_path()
- if not hasattr(os, 'PathLike') and isinstance(path, pathlib.Path):
- path = bytes(path)
db_pp = capi.ffi.new('notmuch_database_t **')
cmsg = capi.ffi.new('char**')
db_pp = capi.ffi.new('notmuch_database_t **')
cmsg = capi.ffi.new('char**')
- ret = capi.lib.notmuch_database_open_verbose(os.fsencode(path),
- mode.value, db_pp, cmsg)
+ ret = capi.lib.notmuch_database_open_with_config(self._db_path_encode(path),
+ mode.value,
+ self._cfg_path_encode(config),
+ capi.ffi.NULL,
+ db_pp, cmsg)
if cmsg[0]:
msg = capi.ffi.string(cmsg[0]).decode(errors='replace')
capi.lib.free(cmsg[0])
if cmsg[0]:
msg = capi.ffi.string(cmsg[0]).decode(errors='replace')
capi.lib.free(cmsg[0])
self.closed = False
@classmethod
self.closed = False
@classmethod
- def create(cls, path=None):
+ def create(cls, path=None, config=ConfigFile.EMPTY):
"""Create and open database in READ_WRITE mode.
This is creates a new notmuch database and returns an opened
instance in :attr:`MODE.READ_WRITE` mode.
"""Create and open database in READ_WRITE mode.
This is creates a new notmuch database and returns an opened
instance in :attr:`MODE.READ_WRITE` mode.
- :param path: The directory of where the database is stored. If
- ``None`` the location will be read from the user's
- configuration file, respecting the ``NOTMUCH_CONFIG``
- environment variable if set.
+ :param path: The directory of where the database is stored.
+ If ``None`` the location will be read searched by the
+ notmuch library (see notmuch(3)::notmuch_open_with_config).
:type path: str, bytes or os.PathLike
:type path: str, bytes or os.PathLike
+ :param config: The pathname of the notmuch configuration file.
+ :type config: :attr:`CONFIG.EMPTY`, :attr:`CONFIG.SEARCH`, str, bytes, os.PathLike, pathlib.Path
+
:raises OSError: or subclasses if the configuration file can not
be opened.
:raises configparser.Error: or subclasses if the configuration
:raises OSError: or subclasses if the configuration file can not
be opened.
:raises configparser.Error: or subclasses if the configuration
:returns: The newly created instance.
"""
:returns: The newly created instance.
"""
- if path is None:
- path = cls.default_path()
- if not hasattr(os, 'PathLike') and isinstance(path, pathlib.Path):
- path = bytes(path)
db_pp = capi.ffi.new('notmuch_database_t **')
cmsg = capi.ffi.new('char**')
db_pp = capi.ffi.new('notmuch_database_t **')
cmsg = capi.ffi.new('char**')
- ret = capi.lib.notmuch_database_create_verbose(os.fsencode(path),
- db_pp, cmsg)
+ ret = capi.lib.notmuch_database_create_with_config(cls._db_path_encode(path),
+ cls._cfg_path_encode(config),
+ capi.ffi.NULL,
+ db_pp, cmsg)
if cmsg[0]:
msg = capi.ffi.string(cmsg[0]).decode(errors='replace')
capi.lib.free(cmsg[0])
if cmsg[0]:
msg = capi.ffi.string(cmsg[0]).decode(errors='replace')
capi.lib.free(cmsg[0])
ret = capi.lib.notmuch_database_destroy(db_pp[0])
if ret != capi.lib.NOTMUCH_STATUS_SUCCESS:
raise errors.NotmuchError(ret)
ret = capi.lib.notmuch_database_destroy(db_pp[0])
if ret != capi.lib.NOTMUCH_STATUS_SUCCESS:
raise errors.NotmuchError(ret)
- return cls(path, cls.MODE.READ_WRITE)
+ return cls(path, cls.MODE.READ_WRITE, config=config)
@staticmethod
def default_path(cfg_path=None):
@staticmethod
def default_path(cfg_path=None):
file can not be parsed.
:raises NotmuchError: if the config file does not have the
database.path setting.
file can not be parsed.
:raises NotmuchError: if the config file does not have the
database.path setting.
+
+ .. deprecated:: 0.35
+ Use the ``config`` parameter to :meth:`__init__` or :meth:`__create__` instead.
"""
if not cfg_path:
cfg_path = _config_pathname()
"""
if not cfg_path:
cfg_path = _config_pathname()
CONFIGURATION
-------------
CONFIGURATION
-------------
;&
split)
test_begin_subtest "'to' header does not crash (python-cffi) ($config)"
;&
split)
test_begin_subtest "'to' header does not crash (python-cffi) ($config)"
- test_subtest_known_broken
echo 'notmuch@notmuchmail.org' > EXPECTED
test_python <<EOF
echo 'notmuch@notmuchmail.org' > EXPECTED
test_python <<EOF
-import notmuch2
-db=notmuch2.Database()
+from notmuch2 import Database
+db=Database(config=Database.CONFIG.SEARCH)
m=db.find('20091117232137.GA7669@griffis1.net')
to=m.header('To')
print(to)
m=db.find('20091117232137.GA7669@griffis1.net')
to=m.header('To')
print(to)
-test_begin_subtest "python cffi tests"
+test_begin_subtest "python cffi tests (NOTMUCH_CONFIG set)"
pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
printf "[pytest]\nminversion = 3.0\naddopts = -ra\n" > $pytest_dir/pytest.ini
test_expect_success "(cd $pytest_dir && ${NOTMUCH_PYTHON} -m pytest --verbose --log-file=$TMP_DIRECTORY/test.output)"
pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
printf "[pytest]\nminversion = 3.0\naddopts = -ra\n" > $pytest_dir/pytest.ini
test_expect_success "(cd $pytest_dir && ${NOTMUCH_PYTHON} -m pytest --verbose --log-file=$TMP_DIRECTORY/test.output)"
+
+test_begin_subtest "python cffi tests (NOTMUCH_CONFIG unset)"
+pytest_dir=$NOTMUCH_BUILDDIR/bindings/python-cffi/build/stage
+printf "[pytest]\nminversion = 3.0\naddopts = -ra\n" > $pytest_dir/pytest.ini
+unset NOTMUCH_CONFIG
+test_expect_success "(cd $pytest_dir && ${NOTMUCH_PYTHON} -m pytest --verbose --log-file=$TMP_DIRECTORY/test.output)"