fix(openalex): canonicalize arXiv DOI to bare arXiv id (DQ-5 arXiv half)
OpenAlex returns arXiv works under the arXiv DOI (10.48550/arXiv.<id>); _normalize_doi (DQ-5) left it as 10.48550/arxiv.<id>, but the corpus keys arXiv papers on the BARE id (2305.10988 / math/0603097). So re-ingesting an arXiv paper by its bare id missed INSERT ... ON CONFLICT (id) and tripped papers_openalex_id_key — the arXiv half of DQ-5, explicitly deferred there and surfaced again driving the R-C .tex re-ingest. Add _canonical_id() (normalize DOI, then strip the 10.48550/arxiv. prefix) and use it in _map_paper. Regression tests (modern + legacy arXiv DOI, regular DOI unchanged, fetch_paper bare id). Confirmed live: re-ingesting 2305.10988 now UPDATEs in place. Full suite 370 passed; ruff + mypy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import pytest
|
||||
|
||||
from codex.models import Citation, Paper
|
||||
from codex.sources import openalex
|
||||
from codex.sources.openalex import _normalize_doi, _resolve_id
|
||||
from codex.sources.openalex import _canonical_id, _normalize_doi, _resolve_id
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
@@ -97,6 +97,42 @@ def test_normalize_doi_already_bare_is_idempotent() -> None:
|
||||
assert _normalize_doi("10.1007/s00454-019-00132-8") == "10.1007/s00454-019-00132-8"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _canonical_id — arXiv DOI → bare arXiv id (arXiv half of DQ-5)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_canonical_id_strips_arxiv_doi_modern() -> None:
|
||||
# arXiv works carry the arXiv DOI; the canonical id is the bare arXiv id.
|
||||
assert _canonical_id("https://doi.org/10.48550/arXiv.2305.10988") == "2305.10988"
|
||||
|
||||
|
||||
def test_canonical_id_strips_arxiv_doi_legacy() -> None:
|
||||
assert _canonical_id("https://doi.org/10.48550/arXiv.math/0603097") == "math/0603097"
|
||||
|
||||
|
||||
def test_canonical_id_leaves_regular_doi_bare() -> None:
|
||||
# A normal journal DOI is only normalized (bare + lower-case), not stripped.
|
||||
assert _canonical_id("https://doi.org/10.1007/S00454-019-00132-8") == (
|
||||
"10.1007/s00454-019-00132-8"
|
||||
)
|
||||
|
||||
|
||||
def test_fetch_paper_arxiv_doi_yields_bare_id(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""An arXiv work maps to the BARE arXiv id (not the arXiv DOI), so re-ingesting
|
||||
by arXiv id hits ON CONFLICT (id) instead of tripping papers_openalex_id_key."""
|
||||
work = {**_SAMPLE_WORK, "doi": "https://doi.org/10.48550/arXiv.2305.10988"}
|
||||
|
||||
def mock_get(url: str, params: dict[str, str] | None = None) -> httpx.Response:
|
||||
return httpx.Response(200, json=work)
|
||||
|
||||
monkeypatch.setattr(openalex, "_get", mock_get)
|
||||
paper = openalex.fetch_paper("2305.10988")
|
||||
|
||||
assert paper is not None
|
||||
assert paper.id == "2305.10988"
|
||||
|
||||
|
||||
def test_map_paper_falls_back_to_openalex_id_without_doi(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user