Added in-memory database support to storage and switched tests to use it.
CI / Formatting (push) Failing after 32s
CI / Linting (push) Successful in 34s
CI / Tests (Python 3.12) (push) Successful in 39s
CI / Tests (Python 3.13) (push) Successful in 26s
CI / Tests (Python 3.14) (push) Successful in 16s
CI / Type Checking (push) Successful in 21s
CI / Spelling (push) Successful in 18s

This commit is contained in:
2026-04-04 18:48:27 -04:00
parent 15e9cd6131
commit 7957ceabfa
3 changed files with 20 additions and 18 deletions
+14 -5
View File
@@ -21,13 +21,13 @@ import contextlib
import contextvars
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from typing import TYPE_CHECKING, Any
import aiosqlite
if TYPE_CHECKING:
from collections.abc import AsyncIterator
from pathlib import Path
class StorageError(Exception):
@@ -41,6 +41,9 @@ class ModuleStorage:
created lazily on the first storage operation and reused for all
subsequent calls. WAL mode is enabled for crash resilience.
Pass ``None`` as ``storage_dir`` to use an in-memory database
instead of a file, which is useful for testing.
Each storage operation (execute, fetch_one, etc.) auto-commits on
success and rolls back on failure. No transaction state is held
between calls.
@@ -50,13 +53,18 @@ class ModuleStorage:
unit.
"""
def __init__(self, storage_dir: Path, module_name: str):
def __init__(self, storage_dir: Path | None, module_name: str):
"""Initialize the storage API.
:param storage_dir: Directory where module databases are stored.
Pass ``None`` to use an in-memory database (useful for tests).
:param module_name: Name of the module this storage belongs to.
"""
self._db_path = storage_dir / f"{module_name}.db"
self._db_path: Path | str = (
storage_dir / f"{module_name}.db"
if storage_dir is not None
else ":memory:"
)
self._module_name = module_name
self._conn: aiosqlite.Connection | None = None
self._closed = False
@@ -242,7 +250,8 @@ class ModuleStorage:
raise StorageError("Storage is closed")
if self._conn is not None:
return self._conn
self._db_path.parent.mkdir(parents=True, exist_ok=True)
if isinstance(self._db_path, Path):
self._db_path.parent.mkdir(parents=True, exist_ok=True)
conn = await aiosqlite.connect(self._db_path)
try:
conn.row_factory = aiosqlite.Row
@@ -257,7 +266,7 @@ class ModuleStorage:
await asyncio.shield(conn.close())
raise
self._conn = conn
self._logger.info(f"Database opened at: {self._db_path.absolute()}")
self._logger.info(f"Database opened at: {self._db_path}")
return conn
@asynccontextmanager
+3 -4
View File
@@ -25,7 +25,6 @@ from owlbot.api.storage import ModuleStorage
if TYPE_CHECKING:
from collections.abc import AsyncIterator
from pathlib import Path
def make_module_context(
@@ -47,7 +46,7 @@ def make_module_context(
@pytest.fixture
async def storage(tmp_path: Path) -> AsyncIterator[ModuleStorage]:
"""Yield an open ModuleStorage backed by a temporary directory."""
async with ModuleStorage(tmp_path, "test_module") as s:
async def storage() -> AsyncIterator[ModuleStorage]:
"""Yield an open in-memory ModuleStorage."""
async with ModuleStorage(None, "test_module") as s:
yield s
+3 -9
View File
@@ -24,7 +24,6 @@ import pytest
if TYPE_CHECKING:
from collections.abc import Callable
from pathlib import Path
from owlbot.api.storage import ModuleStorage, StorageError
@@ -54,12 +53,7 @@ class TestLazyConnections:
class TestPragmas:
"""WAL mode and foreign keys are enabled on new connections."""
async def test_wal_mode(self, storage: ModuleStorage) -> None:
"""journal_mode is set to WAL."""
value = await storage.fetch_value("PRAGMA journal_mode")
assert value == "wal"
"""Foreign keys are enabled on new connections."""
async def test_foreign_keys_enabled(self, storage: ModuleStorage) -> None:
"""foreign_keys pragma is enabled."""
@@ -369,9 +363,9 @@ class TestClose:
await storage._close()
await storage._close()
async def test_context_manager_closes_on_exit(self, tmp_path: Path) -> None:
async def test_context_manager_closes_on_exit(self) -> None:
"""Exiting the async with block closes the connection."""
async with ModuleStorage(tmp_path, "ctx_test") as s:
async with ModuleStorage(None, "ctx_test") as s:
await s.execute("SELECT 1")
assert s._conn is not None
assert s._closed