From 4f47d0c6d9d69479ef77b579003fbecbc53eaa94 Mon Sep 17 00:00:00 2001 From: Viktor Dmitriyev Date: Mon, 4 Mar 2024 13:42:53 +0100 Subject: [PATCH] EDIT: make examples consisten with the latest package update + improve code quality --- .gitignore | 1 + README.md | 2 +- docs/core.md | 9 + docs/examples.md | 9 +- docs/examples/extracting_bibtex.py | 47 +++--- docs/examples/orcid_bibtex_to_html.py | 44 +++-- docs/examples/search_authors.py | 7 + orcidpyclient/__init__.py | 4 +- orcidpyclient/constants.py | 7 +- orcidpyclient/exceptions.py | 1 + orcidpyclient/functions.py | 76 +++++++++ orcidpyclient/logger_config.py | 13 ++ orcidpyclient/rest.py | 227 +++++++++----------------- orcidpyclient/rest_helpers.py | 21 +++ orcidpyclient/utils.py | 19 ++- setup.py | 2 +- tests/test_basic.py | 64 +++++--- 17 files changed, 328 insertions(+), 225 deletions(-) create mode 100644 docs/examples/search_authors.py create mode 100644 orcidpyclient/functions.py create mode 100644 orcidpyclient/logger_config.py create mode 100644 orcidpyclient/rest_helpers.py diff --git a/.gitignore b/.gitignore index 423e64c..2ec1856 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ dist/* orcidpyclient.egg-info/* docs/_build/* +generated/* # extensions *.pyc diff --git a/README.md b/README.md index 00cdd53..9ad8079 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A simple wrapper around the orcid.org API. Ready to run examples can be found in Install latest relased version ``` -pip install -i https://test.pypi.org/simple/ orcidpyclient +pip install -i https://test.pypi.org/simple/ orcidpyclient --upgrade ``` Install latest version from source code diff --git a/docs/core.md b/docs/core.md index 134c6f4..34ce052 100644 --- a/docs/core.md +++ b/docs/core.md @@ -36,6 +36,15 @@ for key_word in orcid_res.keywords: print (key_word) ``` +#### Iterate over publications + +```python +import orcidpyclient +orcid_res = orcidpyclient.get('0000-0002-4510-0385') +for value in obj.publications: + print(value) +``` + #### Trying different author with a different ORCID ```python diff --git a/docs/examples.md b/docs/examples.md index 3b36afe..21aa853 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -12,10 +12,13 @@ * Additional information + iterates through the list or ID's, extracts ORCID, creates bat file to compile bibtex into HTMLs with help of JabRef - List should be in the python dict format, here is the example (I created file 'orcid-list.json') - ``` + ```json [ - { 'John Wilbanks' : '0000-0002-4510-0385'}, - ] + { + "name": "John Wilbanks", + "orcid": "0000-0002-4510-0385" + } + ] ``` + **NOTE**: To make in run on Mac OS, it's better if you will copy JabRef into the 'generated' folder directly diff --git a/docs/examples/extracting_bibtex.py b/docs/examples/extracting_bibtex.py index 21b39e3..dfb45a2 100644 --- a/docs/examples/extracting_bibtex.py +++ b/docs/examples/extracting_bibtex.py @@ -2,30 +2,28 @@ import logging import os -import orcidpyclient as orcid +try: + import orcidpyclient +except: -logging.getLogger(__name__).setLevel(logging.INFO) - -# retrieve a profile from his ORCID -me = orcid.get("0000-0001-5661-4587") - -TARGET_FODLER = "generated" + import os + import sys + from pathlib import Path + current_path = Path(os.path.abspath(os.path.dirname(__file__))) + _path_to_add = os.path.join(str(current_path.parent.parent)) + print(f"[i] Try following path to load package: {_path_to_add})") + sys.path.append(_path_to_add) -def print_keyword(obj): - """Printing author keywords""" + import orcidpyclient - print("[i] printing author keywords") - for key_word in obj.keywords: - print(key_word) + print(f"[i] Use dev version of package with version") -def print_publications(obj): - """Printing author publications""" +logging.getLogger(__name__).setLevel(logging.INFO) - print("[i] printing author publications") - for value in obj.publications: - print(value) +TARGET_FODLER = "generated" +ORCID_ID = "0000-0001-5661-4587" def save_bibtex(bibtex, file_name="orcid-bibtex-output.bib", encoding="utf-8"): @@ -88,19 +86,19 @@ def extract_bibtex(obj): bibtex = {} for value in obj.publications: - if value.citation_type == "BIBTEX": + if value.citation_type.lower() == "bibtex": if value.publicationyear not in bibtex: bibtex[value.publicationyear] = list() bibtex[value.publicationyear].append(value.citation_value) else: bibtex[value.publicationyear].append(value.citation_value) else: - print("[i] this publications is having no BIBTEX {0}".format(value)) + print("[i] this publications is having NO BibTeX {0}".format(value)) return bibtex -def orcid_bibtex(obj): +def extract_bibtex_orcid(orcid_profile): """ (Class) -> None @@ -111,7 +109,7 @@ def orcid_bibtex(obj): os.makedirs(TARGET_FODLER) # extracting bibtex - orcid_bibtex = extract_bibtex(me) + orcid_bibtex = extract_bibtex(orcid_profile) # saving bibtex to file save_bibtex(orcid_bibtex) @@ -120,6 +118,7 @@ def orcid_bibtex(obj): save_nocite(orcid_bibtex) -# print_keyword(me) -# print_publications(me) -orcid_bibtex(me) +if __name__ == "__main__": + # retrieve a profile from his ORCID + orcid_profile = orcidpyclient.get(ORCID_ID, debug=False) + extract_bibtex_orcid(orcid_profile) diff --git a/docs/examples/orcid_bibtex_to_html.py b/docs/examples/orcid_bibtex_to_html.py index 8a0e7e0..d6740c7 100644 --- a/docs/examples/orcid_bibtex_to_html.py +++ b/docs/examples/orcid_bibtex_to_html.py @@ -6,7 +6,23 @@ import traceback import uuid -import orcidpyclient as orcid +try: + import orcidpyclient +except: + + import os + import sys + from pathlib import Path + + current_path = Path(os.path.abspath(os.path.dirname(__file__))) + _path_to_add = os.path.join(str(current_path.parent.parent)) + + print(f"[i] Try following path to load package: {_path_to_add})") + sys.path.append(_path_to_add) + + import orcidpyclient + + print(f"[i] Use dev version of package with version") logging.getLogger(__name__).setLevel(logging.INFO) @@ -160,7 +176,7 @@ def extract_bitex(obj, author): for value in obj.publications: try: if hasattr(value, "citation_type"): - if value.citation_type == "BIBTEX": + if value.citation_type.lower() == "bibtex": if value.publicationyear not in bibtex: bibtex[value.publicationyear] = list() bibtex[value.publicationyear].append(value.citation_value) @@ -184,7 +200,8 @@ def extract_bitex(obj, author): return bibtex -def load_list(fname: str = "orcid-list.json"): +def load_list(fname: str): + if not os.path.exists(fname): raise Exception("JSON file was not found: {fname}") @@ -200,12 +217,15 @@ def main(): Extrating bibtex from ORCID, saving it to the file """ - + orcid_file_name_ = "orcid-list.json" separate_by_year = False try: - orcid_list = load_list() - except: - print("No py file with ORCIDS to work with was found") + orcid_list = load_list(fname=orcid_file_name_) + print(orcid_list) + except Exception as ex: + print(f"[e] JSON file with ORCIDs was NOT found: {orcid_file_name_}") + _, _, ex_traceback = sys.exc_info() + log_traceback(ex, ex_traceback) exit(0) orcid_extracted = list() @@ -215,13 +235,12 @@ def main(): years = {} # extracting bibtex - for key in orcid_list: + for item in orcid_list: - name = key + name, orcidid = item["name"], item["orcid"] years[name] = list() - orcidid = orcid_list[key] print("[i] extracting bibtex for {0}".format(name)) - orcid_obj = orcid.get(orcidid) + orcid_obj = orcidpyclient.get(orcidid) # extracting bibtex try: @@ -230,7 +249,8 @@ def main(): # years tmp_list = list() for key in orcid_bibtex: - tmp_list.append(key) + tmp_list.append(int(key)) + years[name] = sorted(tmp_list, reverse=True) # saving bibtex into separated files diff --git a/docs/examples/search_authors.py b/docs/examples/search_authors.py new file mode 100644 index 0000000..b1caa9b --- /dev/null +++ b/docs/examples/search_authors.py @@ -0,0 +1,7 @@ +# importing module located in parent folder +import sys + +sys.path.insert(0, "../") + +import sys +import pyorcid diff --git a/orcidpyclient/__init__.py b/orcidpyclient/__init__.py index dfa02c1..b7e2e61 100644 --- a/orcidpyclient/__init__.py +++ b/orcidpyclient/__init__.py @@ -1,3 +1,3 @@ -__all__ = ('get', 'search', 'orcid_api_version') +__all__ = ("get", "search", "orcid_api_version") -from .rest import get, search, orcid_api_version +from .functions import get, orcid_api_version, search diff --git a/orcidpyclient/constants.py b/orcidpyclient/constants.py index be55dff..bda0aa3 100644 --- a/orcidpyclient/constants.py +++ b/orcidpyclient/constants.py @@ -1,4 +1,5 @@ -ORCID_API_VERSION = '3.0' -ORCID_PUBLIC_BASE_URL = f'https://pub.orcid.org/v{ORCID_API_VERSION}/' -ORCID_SANDBOX_BASE_URL = 'https://pub.orcid.org/' +ORCID_API_VERSION = "3.0" +ORCID_PUBLIC_BASE_URL = f"https://pub.orcid.org/v{ORCID_API_VERSION}/" +ORCID_SANDBOX_BASE_URL = "https://pub.orcid.org/" +BASE_HEADERS = {"Accept": "application/orcid+json", "Content-Type": "application/json;charset=UTF-8"} diff --git a/orcidpyclient/exceptions.py b/orcidpyclient/exceptions.py index 284b2ea..b7bf996 100644 --- a/orcidpyclient/exceptions.py +++ b/orcidpyclient/exceptions.py @@ -1,5 +1,6 @@ class ORCIDException(Exception): pass + class NotFoundException(ORCIDException): pass diff --git a/orcidpyclient/functions.py b/orcidpyclient/functions.py new file mode 100644 index 0000000..633e788 --- /dev/null +++ b/orcidpyclient/functions.py @@ -0,0 +1,76 @@ +import json +import logging +import sys + +import requests + +from .constants import BASE_HEADERS, ORCID_API_VERSION, ORCID_PUBLIC_BASE_URL +from .logger_config import logger, stdout_sh +from .rest import Author + + +def _set_logger_debug(debug: bool = False): + """_summary_ + + Args: + debug (bool, optional): _description_. Defaults to False. + """ + + if debug: + logger.setLevel(logging.DEBUG) + stdout_sh.setLevel(logging.DEBUG) + + +def get(orcid_id: str, debug: bool = False): + """Get an author based on an ORCID identifier.""" + + _set_logger_debug(debug) + + if sys.version_info[0] < 3: + raise Exception("Python 2 is not supported") + + _url = f"{ORCID_PUBLIC_BASE_URL}{orcid_id}" + _res = requests.get(_url, headers=BASE_HEADERS) + + json_body = _res.json() + + logger.debug("RESPONSE (BASE): {0}".format(json.dumps(json_body, sort_keys=True, indent=4, separators=(",", ": ")))) + + return Author(json_body) + + +def search(query, debug: bool = False): + """Search the ORCID by sending a query to API + + API documentation: + https://info.orcid.org/documentation/api-tutorials/api-tutorial-searching-the-orcid-registry/ + + api_example_query = {'q':'family-name:Malavolti+AND+given-names:Marco'} + + Args: + query (_type_): query string + debug (bool, optional): option for the logging. Defaults to False. + + Returns: + _type_: iterator of the results + """ + + _set_logger_debug(debug) + + if sys.version_info[0] < 3: + raise Exception("Python 2 is not supported") + + _url = f"{ORCID_PUBLIC_BASE_URL}search?q={query}" + resp = requests.get(_url, headers=BASE_HEADERS) + logger.debug(resp.url) + json_body = resp.json() + logger.debug(json_body) + if json_body.get("result") is not None: + return (get(res.get("orcid-identifier", {}).get("path")) for res in json_body.get("result", {})) + else: + return iter(list()) + + +def orcid_api_version(): + """Provides version of ORCID API that is used""" + return ORCID_API_VERSION diff --git a/orcidpyclient/logger_config.py b/orcidpyclient/logger_config.py new file mode 100644 index 0000000..defc033 --- /dev/null +++ b/orcidpyclient/logger_config.py @@ -0,0 +1,13 @@ +import logging +import sys + +_logger_depth = "INFO" + +logger = logging.getLogger("#orcid#") +logger.setLevel(getattr(logging, _logger_depth)) + +stdout_sh = logging.StreamHandler(sys.stdout) +stdout_sh.setLevel(getattr(logging, _logger_depth)) +stdout_sh.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")) + +logger.addHandler(stdout_sh) diff --git a/orcidpyclient/rest.py b/orcidpyclient/rest.py index 2f1ca5a..06358cd 100644 --- a/orcidpyclient/rest.py +++ b/orcidpyclient/rest.py @@ -1,126 +1,95 @@ -# coding: utf-8 - -import sys import json -import requests -import logging - -from .constants import ORCID_PUBLIC_BASE_URL, ORCID_SANDBOX_BASE_URL, ORCID_API_VERSION -from .utils import dictmapper, u, MappingRule as to - -from .exceptions import NotFoundException - -# -# configure logger -# - -_logger_depth = 'INFO' - -logger = logging.getLogger("#orcid#") -logger.setLevel(getattr(logging, _logger_depth)) -stdout_sh = logging.StreamHandler(sys.stdout) -stdout_sh.setLevel(getattr(logging, _logger_depth)) -custom_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') -stdout_sh.setFormatter(custom_formatter) -logger.addHandler(stdout_sh) +import unicodedata -BASE_HEADERS = {'Accept':'application/orcid+json', - 'Content-Type': 'application/json;charset=UTF-8'} +import requests -# -# HELPERS -# +from .constants import BASE_HEADERS, ORCID_PUBLIC_BASE_URL +from .logger_config import logger +from .rest_helpers import _parse_affiliations, _parse_keywords +from .utils import MappingRule as to +from .utils import dictmapper, u -def _parse_keywords(d): - if d is not None: - return [val['content'] for val in d['keyword']] - return [] def _parse_researcher_urls(l): if l is not None: return [Website(d) for d in l] return [] + def _parse_publications(l): _publications = [] if l is not None: # logger.debug(json.dumps(l, sort_keys=True, indent=4, separators=(',', ': '))) # getting through all works - for d in l: - path = d['work-summary'][0]['path'] - _url = '{0}{1}'.format(ORCID_PUBLIC_BASE_URL, path[1:]) # remove first symbol '/' - _res = requests.get(_url, headers = BASE_HEADERS) + for _, d in enumerate(l): + path = d["work-summary"][0]["path"] + _url = "{0}{1}".format(ORCID_PUBLIC_BASE_URL, path[1:]) # remove first symbol '/' + _res = requests.get(_url, headers=BASE_HEADERS) _json_body = _res.json() - logger.debug('REQUEST (PUBLICATIONS): {0}'.format(json.dumps(_json_body, sort_keys=True, indent=4, separators=(',', ': ')))) + logger.debug( + "REQUEST (PUBLICATIONS): {0}".format( + json.dumps(_json_body, sort_keys=True, indent=4, separators=(",", ": ")) + ) + ) _publications.append(Publication(_json_body)) return _publications -def _parse_affiliations(l): - ''' Parses given JSON to get an affiliation (could be education and employment)''' - _affiliations = [] - if l is not None: - for d in l: - name = d['organization']['name'] - _affiliations.append(name) - return _affiliations - - -# -# MAPPERS -# - -AuthorBase = dictmapper('AuthorBase', { - #'orcid' :['orcid-profile','orcid-identifier','path'], - 'orcid' :['orcid-identifier', 'path'], - 'family_name' :['person', 'name', 'family-name', 'value'], - 'given_name' :['person', 'name', 'given-names', 'value'], - 'biography' :['person', 'biography', 'content'], - 'keywords' :to(['person', 'keywords'], _parse_keywords), - 'researcher_urls' :to(['person', 'researcher-urls','researcher-url'], _parse_researcher_urls), - 'educations' :to(['activities-summary', 'educations', 'education-summary'], _parse_affiliations), - 'employments' :to(['activities-summary', 'employments', 'employment-summary'], _parse_affiliations) -}) - - -Works = dictmapper('Works', { - 'publications': to(['group'], _parse_publications), -}) - -PublicationBase = dictmapper('PublicationBase',{ - 'title' : ['title','title', 'value'], - 'url' : ['external-ids','external-id', 'external-id-url'], - #'citation' : to(['citation'], lambda l: map(CitationBase, l) if l is not None else None), - 'citation_value': ['citation', 'citation-value'], - 'citation_type' : ['citation', 'citation-type'], - 'publicationyear': [u'publication-date', u'year', u'value'] -}) - -ExternalIDBase = dictmapper('ExternalIDBase', { - 'id' : ['work-external-identifier-id','value'], - 'type' : ['work-external-identifier-type'] -}) - -CitationBase = dictmapper('CitationBase', { - 'type' : ['citation-type'], - 'value' : ['citation-value'] -}) - -WebsiteBase = dictmapper('WebsiteBase', { - 'name' : ['url-name'], - 'url' : ['url', 'value'] -}) +AuthorBase = dictmapper( + "AuthorBase", + { + #'orcid' :['orcid-profile','orcid-identifier','path'], + "orcid": ["orcid-identifier", "path"], + "family_name": ["person", "name", "family-name", "value"], + "given_name": ["person", "name", "given-names", "value"], + "biography": ["person", "biography", "content"], + "keywords": to(["person", "keywords"], _parse_keywords), + "researcher_urls": to(["person", "researcher-urls", "researcher-url"], _parse_researcher_urls), + "educations": to(["activities-summary", "educations", "education-summary"], _parse_affiliations), + "employments": to(["activities-summary", "employments", "employment-summary"], _parse_affiliations), + }, +) + +Works = dictmapper( + "Works", + { + "publications": to(["group"], _parse_publications), + }, +) + +PublicationBase = dictmapper( + "PublicationBase", + { + "title": ["title", "title", "value"], + "url": ["external-ids", "external-id", "external-id-url"], + #'citation' : to(['citation'], lambda l: map(CitationBase, l) if l is not None else None), + "citation_value": ["citation", "citation-value"], + "citation_type": ["citation", "citation-type"], + "publicationyear": ["publication-date", "year", "value"], + }, +) + +ExternalIDBase = dictmapper( + "ExternalIDBase", {"id": ["work-external-identifier-id", "value"], "type": ["work-external-identifier-type"]} +) + +CitationBase = dictmapper("CitationBase", {"type": ["citation-type"], "value": ["citation-value"]}) + +WebsiteBase = dictmapper("WebsiteBase", {"name": ["url-name"], "url": ["url", "value"]}) + class Author(AuthorBase): _loaded_works = None def _load_works(self): - _url = '{0}{1}/{2}'.format(ORCID_PUBLIC_BASE_URL, self.orcid, 'works') - _res = requests.get(_url, headers = BASE_HEADERS) + _url = "{0}{1}/{2}".format(ORCID_PUBLIC_BASE_URL, self.orcid, "works") + _res = requests.get(_url, headers=BASE_HEADERS) _json_body = _res.json() - logger.debug('RESPONSE (WORKS): {0}'.format(json.dumps(_json_body, sort_keys=True, indent=4, separators=(',', ': ')))) + logger.debug( + "RESPONSE (WORKS): {0}".format(json.dumps(_json_body, sort_keys=True, indent=4, separators=(",", ": "))) + ) self._loaded_works = Works(_json_body) @property @@ -134,11 +103,13 @@ def affiliations(self): return self.educations + self.employments def __repr__(self): - obj_repr = "<{} {} {}, ORCID {}>" - return obj_repr.format(type(self).__name__, - self.given_name.encode('utf-8') if self.given_name else 'None', - self.family_name.encode('utf-8') if self.family_name else 'None', - self.orcid) + obj_repr = "<{} {} {}, ORCID {}>" + return obj_repr.format( + type(self).__name__, + self.given_name.encode("utf-8") if self.given_name else "None", + self.family_name.encode("utf-8") if self.family_name else "None", + self.orcid, + ) def __str__(self): return self.__repr__() @@ -157,67 +128,17 @@ def __unicode__(self): return self.text def __repr__(self): - return '<%s [type: %s]>' % (type(self).__name__, self.type) + return "<%s [type: %s]>" % (type(self).__name__, self.type) class ExternalID(ExternalIDBase): def __unicode__(self): - return unicode(self.id) + return unicodedata(self.id) def __repr__(self): - return '<%s %s:%s>' % (type(self).__name__, self.type, str(self.id)) + return "<%s %s:%s>" % (type(self).__name__, self.type, str(self.id)) class Publication(PublicationBase): def __repr__(self): return '<%s "%s">' % (type(self).__name__, self.title) - -# -# MAIN FUNCTIONS -# - -def get(orcid_id): - """ Get an author based on an ORCID identifier. """ - - if sys.version_info[0] >= 3: - unicode = str - - _url = '{0}{1}'.format(ORCID_PUBLIC_BASE_URL, unicode(orcid_id)) - _res = requests.get(_url, headers=BASE_HEADERS) - - json_body = _res.json() - - logger.debug('RESPONSE (BASE): {0}'.format(json.dumps(json_body, sort_keys=True, indent=4, separators=(',', ': ')))) - - return Author(json_body) - -def search(query, verbose = False): - """ - - API documentation: - - https://info.orcid.org/documentation/api-tutorials/api-tutorial-searching-the-orcid-registry/ - - api_example_query = {'q':'family-name:Malavolti+AND+given-names:Marco'} - """ - - if verbose: - logger.setLevel(logging.DEBUG) - stdout_sh.setLevel(logging.DEBUG) - - _url = '{0}{1}?q={2}'.format(ORCID_PUBLIC_BASE_URL, - 'search', - query) - resp = requests.get(_url, headers=BASE_HEADERS) - logger.debug(resp.url) - json_body = resp.json() - logger.debug(json_body) - if json_body.get('result') is not None: - return (get(res.get('orcid-identifier', {}).get('path')) for res in json_body.get('result', {})) - else: - return iter(list()) - -def orcid_api_version(): - """ - """ - return ORCID_API_VERSION \ No newline at end of file diff --git a/orcidpyclient/rest_helpers.py b/orcidpyclient/rest_helpers.py new file mode 100644 index 0000000..c00de33 --- /dev/null +++ b/orcidpyclient/rest_helpers.py @@ -0,0 +1,21 @@ +import requests + +from .constants import BASE_HEADERS, ORCID_PUBLIC_BASE_URL +from .logger_config import logger + + +def _parse_keywords(d): + if d is not None: + return [val["content"] for val in d["keyword"]] + return [] + + +def _parse_affiliations(l): + """Parses given JSON to get an affiliation (could be education and employment)""" + + _affiliations = [] + if l is not None: + for d in l: + name = d["organization"]["name"] + _affiliations.append(name) + return _affiliations diff --git a/orcidpyclient/utils.py b/orcidpyclient/utils.py index 47285af..7d3d385 100644 --- a/orcidpyclient/utils.py +++ b/orcidpyclient/utils.py @@ -1,11 +1,13 @@ import sys + def dict_value_from_path(d, path): cur_dict = d for key in path[:-1]: cur_dict = cur_dict.get(key, {}) return cur_dict.get(path[-1], None) if cur_dict is not None else None + def dictmapper(typename, mapping): """ A factory to create `namedtuple`-like classes from a field-to-dict-path @@ -19,6 +21,7 @@ def dictmapper(typename, mapping): If a function is specified as a mapping value instead of a dict "path", it will be run with the backing dict as its first argument. """ + def init(self, d, *args, **kwargs): """ Initialize `dictmapper` classes with a dict to back getters. @@ -27,28 +30,32 @@ def init(self, d, *args, **kwargs): def getter_from_dict_path(path): if not callable(path) and len(path) < 1: - raise ValueError('Dict paths should be iterables with at least one' - ' key or callable objects that take one argument.') + raise ValueError( + "Dict paths should be iterables with at least one" " key or callable objects that take one argument." + ) + def getter(self): cur_dict = self._original_dict if callable(path): return path(cur_dict) return dict_value_from_path(cur_dict, path) + return getter - prop_mapping = dict((k, property(getter_from_dict_path(v))) - for k, v in mapping.items()) - prop_mapping['__init__'] = init + prop_mapping = dict((k, property(getter_from_dict_path(v))) for k, v in mapping.items()) + prop_mapping["__init__"] = init return type(typename, tuple(), prop_mapping) + class MappingRule(object): - def __init__(self, path, further_func = lambda x : x): + def __init__(self, path, further_func=lambda x: x): self.path = path self.further_func = further_func def __call__(self, d): return self.further_func(dict_value_from_path(d, self.path)) + def u(s): if sys.version_info < (3,): return unicode(s) diff --git a/setup.py b/setup.py index e90aa96..c0b6bfe 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ def get_long_description() -> str: setup( name="orcidpyclient", - version="1.3", + version="1.5", description="A simple wrapper around the ORCID.org API", long_description=get_long_description(), long_description_content_type="text/markdown", diff --git a/tests/test_basic.py b/tests/test_basic.py index fd03a07..41d7a4c 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1,46 +1,70 @@ import sys try: - import pyorcid + import orcidpyclient except: - sys.path.append('../') - import pyorcid + + import os + import sys + from pathlib import Path + + current_path = Path(os.path.abspath(os.path.dirname(__file__))) + _path_to_add = os.path.join(str(current_path.parent.parent)) + + print(f"[i] Try following path to load package: {_path_to_add})") + sys.path.append(_path_to_add) + + import orcidpyclient + + print(f"[i] Use dev version of package with version") + def test_orcid_api_version(): - assert pyorcid.orcid_api_version() == '3.0' + assert orcidpyclient.orcid_api_version() == "3.0" + def test_existing_name(): - expected = 'wilbanks' - authors = pyorcid.search('family-name:wilbanks+AND+given-names:john') - + expected = "wilbanks" + authors = orcidpyclient.search("family-name:wilbanks+AND+given-names:john") + assert (next(authors).family_name) == expected + def test_existing_name_object(): - expected = '' - orcid_res = pyorcid.get('0000-0002-4510-0385') + expected = "" + orcid_res = orcidpyclient.get("0000-0002-4510-0385") assert str(orcid_res) == expected + def test_non_existing_name(): - authors = pyorcid.search('family-name:wilbanksTestName+AND+given-names:john', verbose=True) - expected = 'No authors found' + authors = orcidpyclient.search("family-name:wilbanksTestName+AND+given-names:john", debug=True) + expected = "No authors found" found = None - + try: first = next(authors) except StopIteration as ex: - found = expected - assert expected == found + found = expected + assert expected == found + def test_keywords(): - - keywords_expected = ['big data', 'machine learning', 'data mining', 'databases', 'data analysis', 'user-defined functions'] - orcid_res = pyorcid.get('0000-0001-5661-4587') - keywords_orcid = orcid_res.keywords - + keywords_expected = [ + "big data", + "machine learning", + "data mining", + "databases", + "data analysis", + "user-defined functions", + ] + + orcid_res = orcidpyclient.get("0000-0001-5661-4587") + keywords_orcid = orcid_res.keywords + keywords_expected.sort() keywords_orcid.sort() - + assert keywords_expected == keywords_orcid