Source code for inspirehep.modules.orcid.builder

# -*- coding: utf-8 -*-
#
# This file is part of INSPIRE.
# Copyright (C) 2014-2017 CERN.
#
# INSPIRE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# INSPIRE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with INSPIRE. If not, see <http://www.gnu.org/licenses/>.
#
# In applying this license, CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.

"""Builds an ORCID work record."""

from __future__ import absolute_import, division, print_function

from six import text_type

from lxml import etree
from lxml.builder import ElementMaker

_NAMESPACES = {
    'work': 'http://www.orcid.org/ns/work',
    'common': 'http://www.orcid.org/ns/common'
}

_WORK = ElementMaker(namespace=_NAMESPACES['work'], nsmap=_NAMESPACES)
_COMMON = ElementMaker(namespace=_NAMESPACES['common'], nsmap=_NAMESPACES)

_ELEMENT_MAKERS = {
    'work': _WORK,
    'common': _COMMON
}


[docs]class OrcidBuilder(object): """Class used to build ORCID-compatible work records in JSON.""" def __init__(self): self.record = _WORK.work()
[docs] def get_xml(self): """Get an XML record. Returns: lxml.etree._Element: ORCID work record compatible with API v2.0 """ return self.record
def __str__(self): """Get a string-serialized XML respresentation of a record. Returns: string: ORCID work record as an XML string """ return etree.tostring(self.get_xml())
[docs] def add_title(self, title, subtitle=None, translated_title=None): """Set a title of the work, and optionaly a subtitle. Args: title (string): title of the work subtitle (string): subtitle of the work translated_title (Tuple[string, string]): tuple consiting of the translated title and its language code """ title_field = _WORK.title(_COMMON.title(title)) if subtitle: title_field.append(_COMMON.subtitle(subtitle)) if translated_title: attributes = {'language-code': translated_title[1]} title_field.append(_COMMON('translated-title', translated_title[0], **attributes)) self.record.append(title_field)
[docs] def add_type(self, work_type): """Add a work type. Args: work_type (string): type of work, see: https://git.io/vdKXv#L118-L155 """ self.record.append(_WORK.type(work_type))
[docs] def add_url(self, url): """Add a url. Args: url (string): alternative url of the record """ self.record.append(_WORK.url(url))
[docs] def add_publication_date(self, partial_date): """Set publication date field. Args: partial_date (inspire_utils.date.PartialDate): publication date """ publication_date = _COMMON('publication-date') publication_date.append(_COMMON.year('{:04d}'.format(partial_date.year))) if partial_date.month: publication_date.append(_COMMON.month('{:02d}'.format(partial_date.month))) if partial_date.day: publication_date.append(_COMMON.day('{:02d}'.format(partial_date.day))) self.record.append(publication_date)
[docs] def add_country(self, country_code): """Set country if the ORCID record. Args: country_code (string): ISO ALPHA-2 country code """ self.record.append(_COMMON.country(country_code.upper()))
[docs] def add_contributor(self, credit_name, role='author', orcid=None, email=None): """Adds a contributor entry to the record. Args: credit_name (string): contributor's name orcid (string): ORCID identifier string role (string): role, see `OrcidBuilder._make_contributor_field` email (string): contributor's email address """ contributors = self._get_or_make_field(self.record, 'work:contributors') contributor = self._make_contributor_field(credit_name, role, orcid, email, not len(contributors)) contributors.append(contributor)
[docs] def add_external_id(self, type, value, url=None, relationship=None): """Add external identifier to the record. Args: type (string): type of external ID (doi, etc.) value (string): the identifier itself url (string): URL for the resource relationship (string): either "part-of" or "self", optional, see `OrcidBuilder._make_external_id_field` """ external_ids_field = self._get_or_make_field(self.record, 'common:external-ids') external_ids_field.append(self._make_external_id_field(type, value, url, relationship))
[docs] def add_recid(self, value, url, relationship=None): """Add Inspire recid to the record. Args: value (string): the recid. url (string): url to the Inspire record. relationship (string): either "part-of" or "self", optional, see `OrcidBuilder._make_external_id_field` """ self.add_external_id('other-id', str(value), url, relationship)
[docs] def add_doi(self, value, relationship=None): """Add DOI to the record. Args: value (string): the identifier itself relationship (string): either "part-of" or "self", optional, see `OrcidBuilder._make_external_id_field` """ self.add_external_id('doi', value, 'http://dx.doi.org/{}'.format(value), relationship)
[docs] def add_arxiv(self, value, relationship=None): """Add arXiv identifier to the record. Args: value (string): the identifier itself relationship (string): either "part-of" or "self", optional, see `OrcidBuilder._make_external_id_field` """ self.add_external_id('arxiv', value, 'http://arxiv.org/abs/{}'.format(value), relationship)
[docs] def add_citation(self, _type, value): """Add a citation string. Args: _type (string): citation type, one of: https://git.io/vdKXv#L313-L321 value (string): citation string for the provided citation type """ self.record.append( _WORK.citation( _WORK('citation-type', _type), _WORK('citation-value', value) ) )
[docs] def add_journal_title(self, journal_title): """Set title of the publication containing the record. Args: journal_title (string): Title of publication containing the record. After ORCID v2.0 schema (https://git.io/vdKXv#L268-L280): "The title of the publication or group under which the work was published. - If a journal, include the journal title of the work. - If a book chapter, use the book title. - If a translation or a manual, use the series title. - If a dictionary entry, use the dictionary title. - If a conference poster, abstract or paper, use the conference name." """ self.record.append(_WORK('journal-title', journal_title))
[docs] def set_visibility(self, visibility): """Set visibility setting on ORCID. Can only be set during record creation. Args: visibility (string): one of (private, limited, registered-only, public), see https://git.io/vdKXt#L904-L937 """ self.record.attrib['visibility'] = visibility
[docs] def set_put_code(self, put_code): """Set the put-code of an ORCID record, to update existing one. Args: put_code (string | integer): a number, being a put code """ self.record.attrib['put-code'] = text_type(put_code)
def _make_contributor_field(self, credit_name, role, orcid, email, first): """ Args: credit_name (string): contributor's name orcid (string): ORCID identifier string role (string): role, see https://git.io/vdKXv#L235-L245 email (string): contributor's email address first (bool): is mentioned first on the list of authors Returns: lxml.etree._Element: contributor field """ contributor_attributes = _WORK( 'contributor-attributes', _WORK('contributor-sequence', 'first' if first else 'additional') ) if role: contributor_attributes.append(_WORK('contributor-role', role)) contributor = _WORK('contributor') if orcid: contributor.append(self._make_contributor_orcid_field(orcid)) contributor.append(_WORK('credit-name', credit_name)) if email: contributor.append(_WORK('contributor-email', email)) contributor.append(contributor_attributes) return contributor def _make_external_id_field(self, type, value, url, relationship): """ Args: type (string): type of external ID (doi, issn, etc.) value (string): the identifier itself url (string): URL for the resource relationship (string): either "part-of" or "self", optional, see https://git.io/vdKXt#L1603-L1604 Returns: lxml.etree._Element: ORCID-compatible external ID field """ external_id_field = _COMMON( 'external-id', _COMMON('external-id-type', type), _COMMON('external-id-value', value) ) if url: external_id_field.append(_COMMON('external-id-url', url)) if relationship: external_id_field.append(_COMMON('external-id-relationship', relationship)) return external_id_field def _make_contributor_orcid_field(self, reference): """Generate a contributor-orcid field. Args: reference (string): ORCID identifier Returns: lxml.etree._Element: contributor-orcid field """ return _COMMON( 'contributor-orcid', _COMMON.uri('http://orcid.org/{}'.format(reference)), _COMMON.path(reference), _COMMON.host('orcid.org') ) def _get_or_make_field(self, root, field_tag): """Return existing ``field_tag`` element in ``root`` or add and return a new one. Args: root (lxml.etree._Element): root element to search the tag in field_tag (string): XML tag, including the namespace Returns: lxml.etree._Element: new or existing ``field_tag`` element """ namespace, relative_tag = tuple(field_tag.split(':')) element_maker = _ELEMENT_MAKERS[namespace] try: field = root.xpath('/*/{}'.format(field_tag), namespaces=_NAMESPACES)[0] except IndexError: field = element_maker(relative_tag) root.append(field) return field