def test_do_not_add_bibtex_citation(self): converter = OrcidConverter( record=self.inspire_record, url_pattern='http://inspirehep.net/record/{recid}', ) xml_root = converter.get_xml() top_level_tags = [ etree.QName(node).localname for node in xml_root.getchildren() ] assert 'citation' not in top_level_tags
def calculate_hash_for_record(record): """Generate hash for an ORCID-serialised HEP record Args: record (dict): HEP record Returns: string: hash of the record """ orcid_rec = OrcidConverter(record, app.config['LEGACY_RECORD_URL_PATTERN']) return hash_xml_element(orcid_rec.get_xml())
def test_format_thesis(app, api_client): response = api_client.get('/literature/1395663') assert response.status_code == 200 phdthesis = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>MAGIC $\\gamma$-ray observations of distant AGN and a study of source variability and the extragalactic background light using FERMI and air Cherenkov telescopes</common:title> </work:title> <work:type>dissertation</work:type> <work:url>http://inspirehep.net/record/1395663</work:url> <work:contributors> <work:contributor> <work:credit-name>Mankuzhiyil, Nijil</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( phdthesis['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert hash_xml_element(expected) == hash_xml_element(result)
def test_format_book(app, api_client): response = api_client.get('/literature/736770') assert response.status_code == 200 book = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>Differential geometry and Lie groups for physicists</common:title> </work:title> <work:type>book</work:type> <common:publication-date> <common:year>2011</common:year> <common:month>03</common:month> <common:day>03</common:day> </common:publication-date> <common:external-ids> <common:external-id> <common:external-id-type>isbn</common:external-id-type> <common:external-id-value>9780521187961</common:external-id-value> </common:external-id> <common:external-id> <common:external-id-type>isbn</common:external-id-type> <common:external-id-value>9780521845076</common:external-id-value> </common:external-id> <common:external-id> <common:external-id-type>isbn</common:external-id-type> <common:external-id-value>9780511242960</common:external-id-value> </common:external-id> </common:external-ids> <work:url>http://inspirehep.net/record/736770</work:url> <work:contributors> <work:contributor> <work:credit-name>Fecko, M.</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( book['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert _OrcidHasher( mock.Mock())._hash_xml_element(expected) == _OrcidHasher( mock.Mock())._hash_xml_element(result)
def test_format_proceedings(app, api_client): response = api_client.get('/literature/701585') assert response.status_code == 200 proceedings = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>HERA and the LHC: A Workshop on the implications of HERA for LHC physics: Proceedings Part A</common:title> </work:title> <work:type>edited-book</work:type> <common:publication-date> <common:year>2005</common:year> </common:publication-date> <common:external-ids> <common:external-id> <common:external-id-type>arxiv</common:external-id-type> <common:external-id-value>hep-ph/0601012</common:external-id-value> <common:external-id-url>http://arxiv.org/abs/hep-ph/0601012</common:external-id-url> <common:external-id-relationship>self</common:external-id-relationship> </common:external-id> </common:external-ids> <work:url>http://inspirehep.net/record/701585</work:url> <work:contributors> <work:contributor> <work:credit-name>De Roeck, A.</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>editor</work:contributor-role> </work:contributor-attributes> </work:contributor> <work:contributor> <work:credit-name>Jung, H.</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>additional</work:contributor-sequence> <work:contributor-role>editor</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( proceedings['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert _OrcidHasher( mock.Mock())._hash_xml_element(expected) == _OrcidHasher( mock.Mock())._hash_xml_element(result)
def test_format_thesis_with_author_orcid(app, api_client): response = api_client.get('/literature/1395663') assert response.status_code == 200 phdthesis = json.loads(response.data) phdthesis['metadata']['authors'][0]['ids'] = [{ 'schema': 'ORCID', 'value': '0000-0002-1825-0097', }] phdthesis['metadata']['authors'][0]['emails'] = ['*****@*****.**'] expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>MAGIC $\\gamma$-ray observations of distant AGN and a study of source variability and the extragalactic background light using FERMI and air Cherenkov telescopes</common:title> </work:title> <work:type>dissertation</work:type> <work:url>http://inspirehep.net/record/1395663</work:url> <work:contributors> <work:contributor> <common:contributor-orcid> <common:uri>http://orcid.org/0000-0002-1825-0097</common:uri> <common:path>0000-0002-1825-0097</common:path> <common:host>orcid.org</common:host> </common:contributor-orcid> <work:credit-name>Mankuzhiyil, Nijil</work:credit-name> <work:contributor-email>[email protected]</work:contributor-email> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( phdthesis['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert _OrcidHasher( mock.Mock())._hash_xml_element(expected) == _OrcidHasher( mock.Mock())._hash_xml_element(result)
def test_format_article(app, api_client): response = api_client.get('/literature/4328') assert response.status_code == 200 article = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>Partial Symmetries of Weak Interactions</common:title> </work:title> <work:journal-title>Nucl.Phys.</work:journal-title> <work:type>journal-article</work:type> <common:publication-date> <common:year>1961</common:year> </common:publication-date> <common:external-ids> <common:external-id> <common:external-id-type>doi</common:external-id-type> <common:external-id-value>10.1016/0029-5582(61)90469-2</common:external-id-value> <common:external-id-url>http://dx.doi.org/10.1016/0029-5582(61)90469-2</common:external-id-url> <common:external-id-relationship>self</common:external-id-relationship> </common:external-id> </common:external-ids> <work:url>http://inspirehep.net/record/4328</work:url> <work:contributors> <work:contributor> <work:credit-name>Glashow, S.L.</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( article['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert _OrcidHasher( mock.Mock())._hash_xml_element(expected) == _OrcidHasher( mock.Mock())._hash_xml_element(result)
def test_format_conference_paper(app, api_client): response = api_client.get('/literature/524480') assert response.status_code == 200 inproceedings = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>CMB anisotropies: A Decadal survey</common:title> </work:title> <work:journal-title>4th RESCEU International Symposium on Birth and Evolution of the Universe</work:journal-title> <work:type>conference-paper</work:type> <common:external-ids> <common:external-id> <common:external-id-type>arxiv</common:external-id-type> <common:external-id-value>astro-ph/0002520</common:external-id-value> <common:external-id-url>http://arxiv.org/abs/astro-ph/0002520</common:external-id-url> <common:external-id-relationship>self</common:external-id-relationship> </common:external-id> </common:external-ids> <work:url>http://inspirehep.net/record/524480</work:url> <work:contributors> <work:contributor> <work:credit-name>Hu, Wayne</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( inproceedings['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert _OrcidHasher( mock.Mock())._hash_xml_element(expected) == _OrcidHasher( mock.Mock())._hash_xml_element(result)
def test_format_book_chapter(app, api_client): response = api_client.get('/literature/1375491') assert response.status_code == 200 inbook = json.loads(response.data) expected = xml_parse(""" <work:work xmlns:common="http://www.orcid.org/ns/common" xmlns:work="http://www.orcid.org/ns/work"> <work:title> <common:title>Supersymmetry</common:title> </work:title> <work:type>book-chapter</work:type> <common:publication-date> <common:year>2015</common:year> </common:publication-date> <common:external-ids> <common:external-id> <common:external-id-type>doi</common:external-id-type> <common:external-id-value>10.1007/978-3-319-15001-7_10</common:external-id-value> <common:external-id-url>http://dx.doi.org/10.1007/978-3-319-15001-7_10</common:external-id-url> <common:external-id-relationship>self</common:external-id-relationship> </common:external-id> <common:external-id> <common:external-id-type>arxiv</common:external-id-type> <common:external-id-value>1506.03091</common:external-id-value> <common:external-id-url>http://arxiv.org/abs/1506.03091</common:external-id-url> <common:external-id-relationship>self</common:external-id-relationship> </common:external-id> </common:external-ids> <work:url>http://inspirehep.net/record/1375491</work:url> <work:contributors> <work:contributor> <work:credit-name>Bechtle, Philip</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>first</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> <work:contributor> <work:credit-name>Plehn, Tilman</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>additional</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> <work:contributor> <work:credit-name>Sander, Christian</work:credit-name> <work:contributor-attributes> <work:contributor-sequence>additional</work:contributor-sequence> <work:contributor-role>author</work:contributor-role> </work:contributor-attributes> </work:contributor> </work:contributors> </work:work> """) result = OrcidConverter( inbook['metadata'], url_pattern='http://inspirehep.net/record/{recid}', ).get_xml() assert valid_against_schema(result) assert xml_compare(expected, result) assert hash_xml_element(expected) == hash_xml_element(result)
def push_record_with_orcid(recid, orcid, oauth_token): """Push record to ORCID with a specific ORCID ID. Args: recid (string): HEP record to push orcid (string): ORCID identifier to push onto oauth_token (string): ORCID user OAUTH token Returns: Tuple[string, string]: a tuple with two elements: - the put-code of the inserted item, - and the new hash of the ORCID record """ inspire_record = get_db_record('lit', recid) orcid_cache = OrcidCache(orcid, recid) putcode = orcid_cache.read_work_putcode() if not orcid_cache.has_work_content_changed(inspire_record): LOGGER.info( 'Hash unchanged: not pushing #%s as not a meaningful update' ' for orcid:', recid, orcid) return putcode # TODO Move bibtex serialization into the the converter try: bibtex = bibtex_v1.serialize(recid, inspire_record) except Exception: bibtex = None LOGGER.error( 'Pushing record #%s without BibTex, as fetching it failed!', recid) # TODO Split orcid API client networking part from our business logic. # This TODO is also a requirement for proper app monitoring. orcid_api = _get_api() orcid_xml = OrcidConverter(inspire_record, app.config['LEGACY_RECORD_URL_PATTERN'], put_code=putcode, bibtex_citation=bibtex).get_xml() lock_name = 'orcid:{}'.format(orcid) # It's an update: PUT. if putcode: LOGGER.info( "Pushing record #%s with put-code %s onto %s.", recid, putcode, orcid, ) with log_time_context('Pushing updated record', LOGGER), \ distributed_lock(lock_name, blocking=True): orcid_api.update_record( orcid_id=orcid, token=oauth_token, request_type='work', data=orcid_xml, put_code=putcode, content_type='application/orcid+xml', ) # It's a new record: POST. else: LOGGER.info( "No put-code found, pushing new record #%s to ORCID %s.", recid, orcid, ) try: with log_time_context('Pushing new record', LOGGER), \ distributed_lock(lock_name, blocking=True): putcode = orcid_api.add_record( orcid_id=orcid, token=oauth_token, request_type='work', data=orcid_xml, content_type='application/orcid+xml', ) except Exception as exc: if DuplicatedExternalIdentifiersError.match(exc): recache_author_putcodes(orcid, oauth_token) putcode = orcid_cache.read_work_putcode() if not putcode: raise PutcodeNotFoundInCacheException( 'Putcode not found in cache for recid {} after having' ' recached all putcodes for the orcid {}'.format( recid, orcid)) return push_record_with_orcid(recid, orcid, oauth_token) else: raise if not putcode: raise ValueError('Empty putcode not allowed') LOGGER.info("Push of %s onto %s completed with put-code %s.", recid, orcid, putcode) orcid_cache.write_work_putcode(putcode, inspire_record) return putcode
def push_record_with_orcid(recid, orcid, oauth_token, put_code=None, old_hash=None): """Push record to ORCID with a specific ORCID ID. Args: recid (string): HEP record to push orcid (string): ORCID identifier to push onto oauth_token (string): ORCID user OAUTH token put_code (Union[string, NoneType]): put-code to push record onto, if None will push as a new record old_hash (Optional[string]): previous hash of the record Returns: Tuple[string, string]: a tuple with two elements: - the put-code of the inserted item, - and the new hash of the ORCID record """ record = get_db_record('lit', recid) new_hash = calculate_hash_for_record(record) if new_hash == old_hash: LOGGER.info( 'Hash unchanged: not pushing #%s as not a meaningful update', recid) return put_code, new_hash try: bibtex = bibtex_v1.serialize(recid, record) except Exception: bibtex = None LOGGER.error( 'Pushing record #%s without BibTex, as fetching it failed!', recid) orcid_api = _get_api() orcid_xml = OrcidConverter(record, app.config['LEGACY_RECORD_URL_PATTERN'], put_code=put_code, bibtex_citation=bibtex).get_xml() lock_name = 'orcid:{}'.format(orcid) if put_code: LOGGER.info( "Pushing record #%s with put-code %s onto %s.", recid, put_code, orcid, ) with log_time_context('Pushing updated record', LOGGER), \ distributed_lock(lock_name, blocking=True): orcid_api.update_record( orcid_id=orcid, token=oauth_token, request_type='work', data=orcid_xml, put_code=put_code, content_type='application/orcid+xml', ) else: LOGGER.info( "No put-code found, pushing new record #%s to ORCID %s.", recid, orcid, ) with log_time_context('Pushing new record', LOGGER), \ distributed_lock(lock_name, blocking=True): put_code = orcid_api.add_record( orcid_id=orcid, token=oauth_token, request_type='work', data=orcid_xml, content_type='application/orcid+xml', ) LOGGER.info("Push of %s onto %s completed with put-code %s.", recid, orcid, put_code) return put_code, new_hash