From a6fcb5af624ed667d7c2b3a6ede3ad41ae0f067b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 19:05:59 +0000 Subject: [PATCH] Pin the Database context manager contract with Database(...) closes the connection on exit without committing, so uncommitted changes are rolled back. This was the existing behavior but was undocumented and untested - it is now stated in the docs and pinned by a test. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01UnLnhsH25Nnv7LHhekUfPd --- docs/python-api.rst | 2 ++ tests/test_constructor.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/docs/python-api.rst b/docs/python-api.rst index f03f963..d575ba6 100644 --- a/docs/python-api.rst +++ b/docs/python-api.rst @@ -144,6 +144,8 @@ The ``Database`` object also works as a context manager, which will automaticall db["my_table"].insert({"name": "Example"}) # Connection is automatically closed here +Exiting the block closes the connection without committing, so any changes that are still inside an open transaction at that point - for example writes made with raw ``db.execute()`` calls - will be rolled back. Commit explicitly, or use methods such as ``.insert()`` and the ``db.atomic()`` context manager which commit their own transactions. + .. _python_api_attach: Attaching additional databases diff --git a/tests/test_constructor.py b/tests/test_constructor.py index 8743911..0798996 100644 --- a/tests/test_constructor.py +++ b/tests/test_constructor.py @@ -29,6 +29,21 @@ def test_sqlite_version(): assert actual == as_string +def test_database_context_manager(tmpdir): + path = str(tmpdir / "test.db") + with Database(path) as db: + db["t"].insert({"id": 1}) + # A raw write left uncommitted on purpose: + db.execute("insert into t (id) values (2)") + # The connection is closed... + with pytest.raises(sqlite3.ProgrammingError): + db.execute("select 1") + # ... and the uncommitted change was rolled back, not committed + db2 = Database(path) + assert [r["id"] for r in db2["t"].rows] == [1] + db2.close() + + @pytest.mark.parametrize("memory", [True, False]) def test_database_close(tmpdir, memory): if memory: