From 4bf8f6f3e9f7e9dafe5b6040c2b3b68b035c1429 Mon Sep 17 00:00:00 2001 From: Mohammed Taha Khan Date: Wed, 16 Sep 2026 14:45:37 +0200 Subject: [PATCH] fix(harvester): keep shared DOI on the latest version --- .../inspire_harvester/transform/splitter.py | 11 +++++++++ .../transform/transform_entry.py | 6 ++++- .../inspire_harvester/test_transformer.py | 24 ++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/site/cds_rdm/inspire_harvester/transform/splitter.py b/site/cds_rdm/inspire_harvester/transform/splitter.py index b1286b62..dc8641b8 100644 --- a/site/cds_rdm/inspire_harvester/transform/splitter.py +++ b/site/cds_rdm/inspire_harvester/transform/splitter.py @@ -15,6 +15,17 @@ def _is_arxiv(source: str) -> bool: return (source or "").lower() in _ARXIV_SOURCES +def keep_shared_doi_on_latest(latest_entry, versions): + """Leave a DOI used by extra versions on the latest version only.""" + latest_doi = (latest_entry.get("pids") or {}).get("doi", {}).get("identifier") + if not latest_doi: + return + for version in versions: + pids = version.get("pids") or {} + if pids.get("doi", {}).get("identifier") == latest_doi: + pids.pop("doi", None) + + class InspireVersionSplitter: """Split one INSPIRE record with multiple doc types into two source-filtered sub-records. diff --git a/site/cds_rdm/inspire_harvester/transform/transform_entry.py b/site/cds_rdm/inspire_harvester/transform/transform_entry.py index 4449a3c0..0f4c2c7b 100644 --- a/site/cds_rdm/inspire_harvester/transform/transform_entry.py +++ b/site/cds_rdm/inspire_harvester/transform/transform_entry.py @@ -14,7 +14,10 @@ from cds_rdm.inspire_harvester.transform.config import mapper_policy from cds_rdm.inspire_harvester.transform.context import MetadataSerializationContext from cds_rdm.inspire_harvester.transform.resource_types import ResourceTypeDetector -from cds_rdm.inspire_harvester.transform.splitter import InspireVersionSplitter +from cds_rdm.inspire_harvester.transform.splitter import ( + InspireVersionSplitter, + keep_shared_doi_on_latest, +) from cds_rdm.inspire_harvester.utils import assert_unique_ids, deep_merge_all @@ -106,6 +109,7 @@ def build(self): ) versions = self._versions() + keep_shared_doi_on_latest(rdm_record, versions) return rdm_record, versions, self.cds_id, self.errors diff --git a/site/tests/inspire_harvester/test_transformer.py b/site/tests/inspire_harvester/test_transformer.py index d7103a8a..6365d60e 100644 --- a/site/tests/inspire_harvester/test_transformer.py +++ b/site/tests/inspire_harvester/test_transformer.py @@ -37,7 +37,10 @@ RelatedIdentifiersMapper, ) from cds_rdm.inspire_harvester.transform.resource_types import ResourceType -from cds_rdm.inspire_harvester.transform.splitter import InspireVersionSplitter +from cds_rdm.inspire_harvester.transform.splitter import ( + InspireVersionSplitter, + keep_shared_doi_on_latest, +) from cds_rdm.inspire_harvester.transform.transform_entry import Inspire2RDM @@ -643,6 +646,25 @@ def test_splitter_creates_one_version_for_duplicate_resource_types(mock_logger): policy.build_for.assert_called_once_with(ResourceType.REPORT) +def test_keep_shared_doi_on_latest_drops_duplicate_from_extra_versions(): + """Latest version keeps a shared DOI; extra versions lose it.""" + journal_doi = { + "identifier": "10.1016/j.nima.2022.166874", + "provider": "external", + } + latest = {"pids": {"doi": journal_doi}} + note = {"pids": {"doi": dict(journal_doi)}} + report = { + "pids": {"doi": {"identifier": "10.17181/other", "provider": "datacite"}} + } + + keep_shared_doi_on_latest(latest, [note, report]) + + assert latest["pids"]["doi"]["identifier"] == journal_doi["identifier"] + assert "doi" not in note["pids"] + assert report["pids"]["doi"]["identifier"] == "10.17181/other" + + def test_transform_document_type_unmapped(running_app): """Test ResourceTypeDetector with unmapped type.""" from cds_rdm.inspire_harvester.transform.resource_types import ResourceTypeDetector