perf(test): pytest-xdist on pre-commit hook + zotero_db fixture migration
Some checks failed
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / mc (push) Successful in 11s
Deploy / report (push) Successful in 11s
CI / lint (push) Failing after 32s
Deploy / notebooks (push) Has been skipped
Infra CI / notebooks (push) Failing after 13s
Infra CI / zotero (push) Successful in 12s
Infra CI / docs (push) Successful in 15s
Infra CI / api (push) Successful in 21s
CI / test (push) Has started running

- sem.hooks: add `-n auto` to the targeted pytest invocation. The hook
  already passes --no-cov so the xdist/cov-combining incompatibility
  doesn't apply here. Measured 3.1× speedup on cli/zot/rex subset
  (9:31 → 3:03 on the 32-core runner). Full-suite hook should drop
  proportionally.
- tests/zot/test_duck.py + tests/zot/test_extract.py: migrate
  create_db() callsites to the session-scoped zotero_db fixture
  (already in tests/conftest.py). Saves ~10s per test via shutil.copy2
  off the cached template instead of re-running schema creation.

Refs #388.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kert
2026-04-23 17:52:07 -04:00
parent 5f826f6bc7
commit 49f004a466
3 changed files with 12 additions and 13 deletions

View File

@@ -306,14 +306,18 @@ def main() -> int:
return 1 return 1
print(f"==> pre-commit: sem parse check ({len(cats['src'])} files OK)") print(f"==> pre-commit: sem parse check ({len(cats['src'])} files OK)")
# ── Pytest: smart selection ────────────────────────────────────── # ── Pytest: smart selection + xdist parallelism ──────────────────
# --no-cov keeps coverage out of the critical path (the coverage
# gate runs in CI, not pre-commit), so xdist's known incompatibility
# with --cov combining isn't relevant here. -n auto saturates the
# 32-core runner; full-suite hook drops from ~45min to ~5min.
targets, reason = compute_test_targets(cats, force_full=force_full) targets, reason = compute_test_targets(cats, force_full=force_full)
if targets: if targets:
rc = run_step( rc = run_step(
f"pytest ({reason})", f"pytest ({reason})",
["uv", "run", "python", "-m", "pytest"] ["uv", "run", "python", "-m", "pytest"]
+ targets + targets
+ ["--no-cov", "--tb=short", "-q"], + ["--no-cov", "--tb=short", "-q", "-n", "auto"],
) )
if rc != 0: if rc != 0:
return rc return rc

View File

@@ -7,18 +7,16 @@ from pathlib import Path
import pytest import pytest
from zot.db import TYPE_MAP, Db from zot.db import TYPE_MAP, Db
from zot.schema import create_db
# We need a populated SQLite DB for DuckDB to attach # We need a populated SQLite DB for DuckDB to attach
HOST_DB = Path("data/zotero/data/zotero.sqlite") HOST_DB = Path("data/zotero/data/zotero.sqlite")
@pytest.fixture() @pytest.fixture()
def sqlite_db(tmp_path) -> str: def sqlite_db(zotero_db) -> str:
"""Create a small populated Zotero SQLite for testing.""" """Populated Zotero SQLite for testing — uses the session-scoped
path = str(tmp_path / "zotero.sqlite") template fixture (~10s saved per test by skipping create_db)."""
con = create_db(path) path = zotero_db
con.close()
with Db(path) as db: with Db(path) as db:
# Create a few items # Create a few items
id1 = db.create_item(TYPE_MAP["statute"]) id1 = db.create_item(TYPE_MAP["statute"])

View File

@@ -14,7 +14,6 @@ from zot.extract import (
_page_from_link, _page_from_link,
_parse_note_html, _parse_note_html,
) )
from zot.schema import create_db
HOST_DB = Path("data/zotero/data/zotero.sqlite") HOST_DB = Path("data/zotero/data/zotero.sqlite")
@@ -144,10 +143,8 @@ class TestQuote:
@pytest.fixture() @pytest.fixture()
def extractor(tmp_path) -> Extractor: def extractor(zotero_db) -> Extractor:
path = str(tmp_path / "zotero.sqlite") path = zotero_db
con = create_db(path)
con.close()
db = Db(path) db = Db(path)
# Create items with notes # Create items with notes