Module Contents



A Requests session.



Settings required to deposit into Invenio(RDM).


Base class that implements the generic deposition workflow.



class hermes.commands.deposit.invenio.InvenioClient(config, auth_token=None, platform_name=None)

Bases: requests.Session

A Requests session.

Provides cookie persistence, connection-pooling, and configuration.

Basic Usage:

>>> import requests
>>> s = requests.Session()
>>> s.get('')
<Response [200]>

Or as a context manager:

>>> with requests.Session() as s:
...     s.get('')
<Response [200]>
property api_paths
property licenses_api_path
property communities_api_path
property depositions_api_path
property records_api_path
DEFAULT_DEPOSITIONS_API_PATH = 'api/deposit/depositions'
platform_name = 'invenio'
request(method, url, headers=None, **kwargs) requests.Response

Overridden request method to automatically set Authorization header for all requests to the configured site.

See [requests documentation]( for details.

class hermes.commands.deposit.invenio.InvenioResolver(client=None)
resolve_latest_id(record_id=None, doi=None, codemeta_identifier=None) Tuple[str | None, dict]

Using the given metadata parameters, figure out the latest record id.

If record_id is given, it will be used to identify the latest version of the record. Otherwise, if there is a DOI present (either as doi parameter or as codemeta_identifier), the DOI will be used to resolve the base record id.

Either way the record id will be used to resolve the latest version.

If any of the resolution steps fail or produce an unexpected result, a ValueError will be raised.

resolve_doi(doi) str

Resolve a DOI to an Invenio URL and extract the record id.


doi – The DOI to be resolved (only the identifier without the prefix).


The record ID on the respective instance.

resolve_record_id(record_id: str) Tuple[str, dict]

Find the latest version of a given record.


record_id – The record that sould be resolved.


The record id of the latest version for the requested record.

resolve_license_id(license_url: str | None) str | None

Get Invenio license representation from CodeMeta.

The license to use is extracted from the license field in the CodeMetaContext and converted into an appropiate license identifier to be passed to an Invenio instance.

A license according to CodeMeta may be a URL (text) or a CreativeWork. This function only handles URLs. If a license field is present in the CodeMeta and it is not of type str, a RuntimeError is raised.

Invenio instances take a license string which refers to a license identifier. Typically, Invenio instances offer licenses from and However, it is possible to mint PIDs for custom licenses.

An API endpoint (usually /api/licenses) can be used to check whether a given license is supported by the Invenio instance. This function tries to retrieve the license by the identifier at the end of the license URL path. If this identifier does not exist on the Invenio instance, a RuntimeError is raised. If no license is given in the CodeMeta, None is returned.

class hermes.commands.deposit.invenio.InvenioDepositSettings(/, **data: Any)

Bases: pydantic.BaseModel

Settings required to deposit into Invenio(RDM).

site_url: str = ''
communities: list[str]
access_right: str
embargo_date: str
access_conditions: str
api_paths: Dict
auth_token: str = ''
files: list[pathlib.Path] = []
record_id: int
doi: str
class hermes.commands.deposit.invenio.InvenioDepositPlugin(command: hermes.commands.deposit.base.HermesDepositCommand, ctx: hermes.model.context.CodeMetaContext, client=None, resolver=None)

Bases: hermes.commands.deposit.base.BaseDepositPlugin

Base class that implements the generic deposition workflow.

TODO: describe workflow… needs refactoring to be less stateful!

platform_name = 'invenio'
prepare() None

Prepare the deposition on an Invenio-based platform.

In this function we do the following:

  • resolve the latest published version of this publication (if any)

  • check whether the current version (given in the CodeMeta) was already published

  • check whether we have a valid license identifier (if any)

  • check wether the communities are valid (if configured)

  • check access modalities (access right, access conditions, embargo data, existence of license)

  • check whether required configuration options are present

  • update self.ctx with metadata collected during the checks

map_metadata() None

Map the harvested metadata onto the Invenio schema.

is_initial_publication() bool

Decide whether to do an initial publication or publish a new version.

Returning True indicates that publication of an initial version will be executed, resulting in a call of create_initial_version(). False indicates a new version of an existing publication, leading to a call of create_new_version().

By default, this returns True.

create_initial_version() None

Create an initial version of a publication.

create_new_version() None

Create a new version of an existing publication.

update_metadata() None

Update the metadata of a draft.

delete_artifacts() None

Delete existing file artifacts.

This is done so that files which existed in an earlier publication but don’t exist any more, are removed. Otherwise they would cause an error because the didn’t change between versions.

upload_artifacts() None

Upload file artifacts to the deposit.

We’ll use the bucket API rather than the files API as it supports file sizes above 100MB.

publish() None

Publish the deposited record.

_codemeta_to_invenio_deposition() dict

The mapping logic.

Functionality similar to this exists in the convert_codemeta package which uses the crosswalk tables to do the mapping:

invenio_metadata = convert_codemeta.crosswalk(
    metadata, "codemeta", "Zenodo"

Unfortunately, this doesn’t work well with additional metadata in the same dict, so it is safer to provide our own implementation.

Currently, this function handles a lot of cases which we want to be able to configure. A simple mapping from one JSON path to another is not enough.

The metadata expected by Zenodo is described in the Zenodo Developers guide. Unfortunately, there doesn’t seem to be a schema one can download in order to validate these metadata. There might be differences between Invenio-based platforms.

_get_license_identifier() str | None

Get Invenio license identifier that matches the given license URL.

If no license is configured, None will be returned.


Get Invenio community identifiers from config.

This function gets the communities to be used for the deposition on an Invenio-based site from the config and checks their validity against the site’s API. If one of the identifiers can not be found on the site, a MisconfigurationError is raised.


Get access right, embargo date and access conditions based on configuration and given license.

This function implements the rules laid out in the Zenodo developer documentation:

  • access_right is a controlled vocabulary

  • embargoed access depositions need an embargo date

  • restricted access depositions need access conditions

  • open and embargoed access depositions need a license

  • closed access depositions have no further requirements

This function also makes sure that the given embargo date can be parsed as an ISO 8601 string representation and that the access rights are given as a string.