|
| 1 | +"""Custom VCR.py persister that stores all cassettes in a single SQLite database file. |
| 2 | +
|
| 3 | +Instead of creating one YAML file per test cassette (which can produce 1000+ files), |
| 4 | +this persister stores all cassettes as rows in a single SQLite database. |
| 5 | +""" |
| 6 | + |
| 7 | +import sqlite3 |
| 8 | +from pathlib import Path |
| 9 | + |
| 10 | +from vcr.cassette import CassetteNotFoundError |
| 11 | +from vcr.serialize import deserialize, serialize |
| 12 | + |
| 13 | + |
| 14 | +class SQLitePersister: |
| 15 | + """Stores VCR cassettes in a single SQLite database file.""" |
| 16 | + |
| 17 | + db_path: str = "tests/cassettes.db" |
| 18 | + |
| 19 | + @classmethod |
| 20 | + def _get_connection(cls) -> sqlite3.Connection: |
| 21 | + conn = sqlite3.connect(cls.db_path) |
| 22 | + conn.execute( |
| 23 | + """ |
| 24 | + CREATE TABLE IF NOT EXISTS cassettes ( |
| 25 | + cassette_path TEXT PRIMARY KEY, |
| 26 | + data TEXT NOT NULL |
| 27 | + ) |
| 28 | + """ |
| 29 | + ) |
| 30 | + return conn |
| 31 | + |
| 32 | + @classmethod |
| 33 | + def load_cassette(cls, cassette_path: str, serializer: str) -> tuple[list, list]: |
| 34 | + # Normalize the path to use as a key |
| 35 | + key = str(Path(cassette_path)) |
| 36 | + conn = cls._get_connection() |
| 37 | + try: |
| 38 | + row = conn.execute( |
| 39 | + "SELECT data FROM cassettes WHERE cassette_path = ?", (key,) |
| 40 | + ).fetchone() |
| 41 | + if row is None: |
| 42 | + raise CassetteNotFoundError(f"Cassette not found: {key}") |
| 43 | + cassette_content = row[0] |
| 44 | + return deserialize(cassette_content, serializer) |
| 45 | + finally: |
| 46 | + conn.close() |
| 47 | + |
| 48 | + @classmethod |
| 49 | + def save_cassette( |
| 50 | + cls, cassette_path: str, cassette_dict: dict, serializer: str |
| 51 | + ) -> None: |
| 52 | + key = str(Path(cassette_path)) |
| 53 | + data = serialize(cassette_dict, serializer) |
| 54 | + conn = cls._get_connection() |
| 55 | + try: |
| 56 | + conn.execute( |
| 57 | + "INSERT OR REPLACE INTO cassettes (cassette_path, data) VALUES (?, ?)", |
| 58 | + (key, data), |
| 59 | + ) |
| 60 | + conn.commit() |
| 61 | + finally: |
| 62 | + conn.close() |
0 commit comments