diff --git a/changelog/13.feature.md b/changelog/13.feature.md new file mode 100644 index 0000000..4b27826 --- /dev/null +++ b/changelog/13.feature.md @@ -0,0 +1,2 @@ +Added the `--user-controlled-only` flag to `openscm-zenodo retrieve-metadata`. +This is the flag to use if you want to use the retrieved metadata as the starting point for the next version of a deposit. diff --git a/src/openscm_zenodo/cli/app.py b/src/openscm_zenodo/cli/app.py index 00872c4..ce0a776 100644 --- a/src/openscm_zenodo/cli/app.py +++ b/src/openscm_zenodo/cli/app.py @@ -150,6 +150,18 @@ def cli( def retrieve_metadata_command( deposition_id: DEPOSITION_ID_TYPE, token: TOKEN_TYPE = None, + user_controlled_only: Annotated[ + bool, + typer.Option( + help="""Only return metadata keys that the user can control. + +If this is `True`, the metadata keys controlled by Zenodo (e.g. the DOI) +are removed from the returned metadata. +This flag is important to use +if you want to use the retrieved metadata +as the starting point for the next version of a deposit.""" + ), + ] = False, zenodo_domain: ZENODO_DOMAIN_TYPE = ZenodoDomain.production, ) -> None: """ @@ -160,7 +172,9 @@ def retrieve_metadata_command( zenodo_domain=zenodo_domain, ) - metadata = zenoodo_interactor.get_metadata(deposition_id) + metadata = zenoodo_interactor.get_metadata( + deposition_id, user_controlled_only=user_controlled_only + ) print(json.dumps(metadata, indent=2, sort_keys=True)) diff --git a/src/openscm_zenodo/zenodo.py b/src/openscm_zenodo/zenodo.py index 35c5b27..20deb2c 100644 --- a/src/openscm_zenodo/zenodo.py +++ b/src/openscm_zenodo/zenodo.py @@ -218,6 +218,7 @@ def get_deposition( def get_metadata( self, deposition_id: str, + user_controlled_only: bool = False, ) -> MetadataType: """ Get the metadata for a given deposition ID @@ -227,6 +228,16 @@ def get_metadata( deposition_id The ID of the deposition + user_controlled_only + Only return metadata keys that the user can control. + + If this is `True`, the metadata keys controlled by Zenodo + (e.g. the DOI) + are removed from the returned metadata. + This flag is important to use + if you want to use the retrieved metadata + as the starting point for the next version of a deposit. + Returns ------- : @@ -244,6 +255,17 @@ def get_metadata( metadata = {"metadata": deposition.json()["metadata"]} + if user_controlled_only: + for k in [ + "doi", + "imprint_publisher", + "prereserve_doi", + "publication_date", + "relations", + ]: + if k in metadata["metadata"]: + metadata["metadata"].pop(k) + return metadata def get_bibtex_entry( diff --git a/tests/integration/test_cli.py b/tests/integration/test_cli.py index 0b777e4..96f9fee 100644 --- a/tests/integration/test_cli.py +++ b/tests/integration/test_cli.py @@ -123,6 +123,36 @@ def test_retrieve_metadata(test_data_dir): assert res.stdout == f"{json.dumps(exp, indent=2, sort_keys=True)}\n" +@pytest.mark.zenodo_token +def test_retrieve_metadata_user_controlled_only(test_data_dir): + """ + Test we can retrieve only user-controlled metadata from Zenodo + """ + deposition_id = "101709" + + res = runner.invoke( + app, + [ + "retrieve-metadata", + deposition_id, + "--zenodo-domain", + "https://sandbox.zenodo.org", + "--user-controlled-only", + ], + ) + assert res.exit_code == 0, res.stderr + exp = { + "metadata": { + "access_right": "open", + "creators": [{"affiliation": None, "name": "Nicholls, Zebedee"}], + "license": "cc-by-4.0", + "title": "OpenSCM-Zenodo testing 0", + "upload_type": "dataset", + } + } + assert res.stdout == f"{json.dumps(exp, indent=2, sort_keys=True)}\n" + + def test_retrieve_bibtex(test_data_dir): """ Test we can retrieve a bibtex entry from Zenodo diff --git a/tests/integration/test_flow.py b/tests/integration/test_flow.py index 3ddd94f..1a74755 100644 --- a/tests/integration/test_flow.py +++ b/tests/integration/test_flow.py @@ -4,8 +4,11 @@ from __future__ import annotations +import copy +import datetime as dt import json import os +from pathlib import Path import pytest import requests @@ -14,14 +17,14 @@ @pytest.mark.zenodo_token -def test_default_end_to_end_flow(test_data_dir): +def test_default_end_to_end_flow(test_data_dir, tmpdir): """ Test we can start with an ID and end up publishing a new version """ + tmpdir = Path(tmpdir) + any_deposition_id = "101709" - metadata_file = test_data_dir / "test-deposit-metadata.json" sub_dir_file = test_data_dir / "sub-dir" / "file-in-sub-dir.txt" - files_to_upload = [metadata_file, sub_dir_file] zenoodo_interactor = ZenodoInteractor( token=os.environ["ZENODO_TOKEN"], @@ -48,12 +51,26 @@ def test_default_end_to_end_flow(test_data_dir): for response in remove_all_files_responses ) - with open(metadata_file) as fh: - metadata = json.load(fh) + # Retrieve metadata from existing version + metadata_current = zenoodo_interactor.get_metadata( + latest_deposition_id, user_controlled_only=True + ) + + # Update this metadata for this version + timestamp = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + metadata_updated = copy.deepcopy(metadata_current) + metadata_updated["metadata"][ + "title" + ] = f"OpenSCM-Zenodo testing test run {timestamp}" + + # Save the metadata to a file + metadata_file = tmpdir / "test-deposit-metadata.json" + with open(metadata_file, "w") as fh: + json.dump(metadata_current, fh) update_metadata_response = zenoodo_interactor.update_metadata( deposition_id=new_deposition_id, - metadata=metadata, + metadata=metadata_updated, ) assert isinstance(update_metadata_response, requests.models.Response) @@ -61,8 +78,10 @@ def test_default_end_to_end_flow(test_data_dir): reserved_doi = get_reserved_doi(update_metadata_response) assert "10.5281/zenodo" in reserved_doi + # Upload files bucket_url = zenoodo_interactor.get_bucket_url(deposition_id=new_deposition_id) + files_to_upload = [metadata_file, sub_dir_file] for file in files_to_upload: resp = zenoodo_interactor.upload_file_to_bucket_url( file, @@ -79,12 +98,14 @@ def test_default_end_to_end_flow(test_data_dir): zenodo_altered_keys = ["prereserve_doi"] comparable_metadata_from_user = { - k: v for k, v in metadata["metadata"].items() if k not in zenodo_altered_keys + k: v + for k, v in metadata_updated["metadata"].items() + if k not in zenodo_altered_keys } comparable_metadata_from_publish_response = { k: v for k, v in publish_response_json["metadata"].items() - if k in metadata["metadata"] and k not in zenodo_altered_keys + if k in metadata_updated["metadata"] and k not in zenodo_altered_keys } assert comparable_metadata_from_user == comparable_metadata_from_publish_response