From abdff73a3333b295a599135ad2777e852189e188 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 14 Sep 2025 17:07:43 +0200 Subject: [PATCH] bindings/python-cffi: allow reopening a database This will be useful for handling NOTMUCH_STATUS_OPERATION_INVALIDATED errors that will be exposed through the bindings in a following commit. --- bindings/python-cffi/notmuch2/_build.py | 3 +++ bindings/python-cffi/notmuch2/_database.py | 24 +++++++++++++++++++ bindings/python-cffi/tests/test_database.py | 26 +++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/bindings/python-cffi/notmuch2/_build.py b/bindings/python-cffi/notmuch2/_build.py index 65d7dcb6..0429691a 100644 --- a/bindings/python-cffi/notmuch2/_build.py +++ b/bindings/python-cffi/notmuch2/_build.py @@ -118,6 +118,9 @@ ffibuilder.cdef( notmuch_database_t **database, char **error_message); notmuch_status_t + notmuch_database_reopen (notmuch_database_t *database, + notmuch_database_mode_t new_mode); + notmuch_status_t notmuch_database_close (notmuch_database_t *database); notmuch_status_t notmuch_database_destroy (notmuch_database_t *database); diff --git a/bindings/python-cffi/notmuch2/_database.py b/bindings/python-cffi/notmuch2/_database.py index c13d9fcf..a47049ba 100644 --- a/bindings/python-cffi/notmuch2/_database.py +++ b/bindings/python-cffi/notmuch2/_database.py @@ -285,6 +285,30 @@ class Database(base.NotmuchObject): raise errors.NotmuchError(ret) self.closed = True + def reopen(self, mode=None): + """Reopen an opened notmuch database. + + :param mode: Mode to reopen the database with. When None, the previously + active mode is preserved. + :type mode: :attr:`MODE`, str, or None. + + This is useful e.g. for: + - switching the mode between read-only and read-write + - recovering from OperationInvalidatedError + """ + if isinstance(mode, str): + try: + mode = self.STR_MODE_MAP[mode] + except KeyError: + raise ValueError('Invalid mode: %s' % mode) + else: + mode = mode or self.mode + self.mode = mode + + ret = capi.lib.notmuch_database_reopen(self._db_p, mode.value) + if ret != capi.lib.NOTMUCH_STATUS_SUCCESS: + raise errors.NotmuchError(ret) + def __enter__(self): return self diff --git a/bindings/python-cffi/tests/test_database.py b/bindings/python-cffi/tests/test_database.py index 1557235d..1143cf33 100644 --- a/bindings/python-cffi/tests/test_database.py +++ b/bindings/python-cffi/tests/test_database.py @@ -173,6 +173,32 @@ class TestRevision: # XXX add tests for revisions comparisons + +class TestMode: + + def test_readonly_raises(self, db, maildir): + with pytest.raises(errors.ReadOnlyDatabaseError): + with dbmod.Database(maildir.path, 'ro', + config=notmuch2.Database.CONFIG.EMPTY) as db_ro: + _, pathname = maildir.deliver() + db_ro.add(pathname) + + def test_reopen_ro(self, db, maildir): + db.reopen(mode = dbmod.Mode.READ_ONLY) + with pytest.raises(errors.ReadOnlyDatabaseError): + _, pathname = maildir.deliver() + db.add(pathname) + + def test_reopen_rw(self, db, maildir): + # release the write lock + db.close() + + with dbmod.Database(maildir.path, 'ro', + config=notmuch2.Database.CONFIG.EMPTY) as db: + _, pathname = maildir.deliver() + db.reopen(mode = dbmod.Mode.READ_WRITE) + db.add(pathname) + class TestMessages: def test_add_message(self, db, maildir): -- 2.45.2