From 99024804727138d01530974bf680960986210768 Mon Sep 17 00:00:00 2001 From: Philipp Tempel Date: Tue, 17 Dec 2019 19:35:14 +0100 Subject: [PATCH 1/2] Rename file `config.json` to `elapsy.json` --- .gitignore | 4 +- CONFIG.md | 32 +-- exampleProg.py | 212 +++++++-------- test_elsapy.py | 700 ++++++++++++++++++++++++------------------------- 4 files changed, 474 insertions(+), 474 deletions(-) diff --git a/.gitignore b/.gitignore index 80d2f97..75de702 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .cache -config.json +elapsy.json niso_training_prog.py test_elsapy.py dump.json @@ -10,4 +10,4 @@ dump.json /logs /dist /build -/elsapy.egg-info \ No newline at end of file +/elsapy.egg-info diff --git a/CONFIG.md b/CONFIG.md index 34c0e17..eba7ab3 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,16 +1,16 @@ -# configuration -If you are using (or adapting) exampleProg.py, do this: -- In the folder in which exampleProg.py resides, create a file called 'config.json' -- Open 'config.json' in a file editor, and insert the following: - - ``` - { - "apikey": "ENTER_APIKEY_HERE", - "insttoken": "ENTER_INSTTOKEN_HERE_IF_YOU_HAVE_ONE_ELSE_DELETE" - } - ``` - -- Paste your APIkey (obtained from http://dev.elsevier.com) in the right place -- If you don't have a valid insttoken (which you would have received from Elsevier support staff), delete the placeholder text. If you enter a dummy value, your API requests will fail. - -The '.gitignore' file lists 'config.json' as a file to be ignored when committing elsapy to a GIT repository, which is to prevent your APIkey from being shared with the world. Make similar provisions when you change your configuration setup. +# configuration +If you are using (or adapting) exampleProg.py, do this: +- In the folder in which exampleProg.py resides, create a file called 'j' +- Open 'elapsy.json' in a file editor, and insert the following: + + ``` + { + "apikey": "ENTER_APIKEY_HERE", + "insttoken": "ENTER_INSTTOKEN_HERE_IF_YOU_HAVE_ONE_ELSE_DELETE" + } + ``` + +- Paste your APIkey (obtained from http://dev.elsevier.com) in the right place +- If you don't have a valid insttoken (which you would have received from Elsevier support staff), delete the placeholder text. If you enter a dummy value, your API requests will fail. + +The '.gitignore' file lists 'elapsy.json' as a file to be ignored when committing elsapy to a GIT repository, which is to prevent your APIkey from being shared with the world. Make similar provisions when you change your configuration setup. diff --git a/exampleProg.py b/exampleProg.py index 2bd56d3..01613ab 100644 --- a/exampleProg.py +++ b/exampleProg.py @@ -1,106 +1,106 @@ -"""An example program that uses the elsapy module""" - -from elsapy.elsclient import ElsClient -from elsapy.elsprofile import ElsAuthor, ElsAffil -from elsapy.elsdoc import FullDoc, AbsDoc -from elsapy.elssearch import ElsSearch -import json - -## Load configuration -con_file = open("config.json") -config = json.load(con_file) -con_file.close() - -## Initialize client -client = ElsClient(config['apikey']) -client.inst_token = config['insttoken'] - -## Author example -# Initialize author with uri -my_auth = ElsAuthor( - uri = 'https://api.elsevier.com/content/author/author_id/7004367821') -# Read author data, then write to disk -if my_auth.read(client): - print ("my_auth.full_name: ", my_auth.full_name) - my_auth.write() -else: - print ("Read author failed.") - -## Affiliation example -# Initialize affiliation with ID as string -my_aff = ElsAffil(affil_id = '60101411') -if my_aff.read(client): - print ("my_aff.name: ", my_aff.name) - my_aff.write() -else: - print ("Read affiliation failed.") - -## Scopus (Abtract) document example -# Initialize document with ID as integer -scp_doc = AbsDoc(scp_id = 84872135457) -if scp_doc.read(client): - print ("scp_doc.title: ", scp_doc.title) - scp_doc.write() -else: - print ("Read document failed.") - -## ScienceDirect (full-text) document example using PII -pii_doc = FullDoc(sd_pii = 'S1674927814000082') -if pii_doc.read(client): - print ("pii_doc.title: ", pii_doc.title) - pii_doc.write() -else: - print ("Read document failed.") - -## ScienceDirect (full-text) document example using DOI -doi_doc = FullDoc(doi = '10.1016/S1525-1578(10)60571-5') -if doi_doc.read(client): - print ("doi_doc.title: ", doi_doc.title) - doi_doc.write() -else: - print ("Read document failed.") - - -## Load list of documents from the API into affilation and author objects. -# Since a document list is retrieved for 25 entries at a time, this is -# a potentially lenghty operation - hence the prompt. -print ("Load documents (Y/N)?") -s = input('--> ') - -if (s == "y" or s == "Y"): - - ## Read all documents for example author, then write to disk - if my_auth.read_docs(client): - print ("my_auth.doc_list has " + str(len(my_auth.doc_list)) + " items.") - my_auth.write_docs() - else: - print ("Read docs for author failed.") - - ## Read all documents for example affiliation, then write to disk - if my_aff.read_docs(client): - print ("my_aff.doc_list has " + str(len(my_aff.doc_list)) + " items.") - my_aff.write_docs() - else: - print ("Read docs for affiliation failed.") - -## Initialize author search object and execute search -auth_srch = ElsSearch('authlast(keuskamp)','author') -auth_srch.execute(client) -print ("auth_srch has", len(auth_srch.results), "results.") - -## Initialize affiliation search object and execute search -aff_srch = ElsSearch('affil(amsterdam)','affiliation') -aff_srch.execute(client) -print ("aff_srch has", len(aff_srch.results), "results.") - -## Initialize doc search object using Scopus and execute search, retrieving -# all results -doc_srch = ElsSearch("AFFIL(dartmouth) AND AUTHOR-NAME(lewis) AND PUBYEAR > 2011",'scopus') -doc_srch.execute(client, get_all = True) -print ("doc_srch has", len(doc_srch.results), "results.") - -## Initialize doc search object using ScienceDirect and execute search, -# retrieving all results -doc_srch = ElsSearch("star trek vs star wars",'sciencedirect') -doc_srch.execute(client, get_all = False) -print ("doc_srch has", len(doc_srch.results), "results.") \ No newline at end of file +"""An example program that uses the elsapy module""" + +from elsapy.elsclient import ElsClient +from elsapy.elsprofile import ElsAuthor, ElsAffil +from elsapy.elsdoc import FullDoc, AbsDoc +from elsapy.elssearch import ElsSearch +import json + +## Load configuration +con_file = open("elapsy.json") +config = json.load(con_file) +con_file.close() + +## Initialize client +client = ElsClient(config['apikey']) +client.inst_token = config['insttoken'] + +## Author example +# Initialize author with uri +my_auth = ElsAuthor( + uri = 'https://api.elsevier.com/content/author/author_id/7004367821') +# Read author data, then write to disk +if my_auth.read(client): + print ("my_auth.full_name: ", my_auth.full_name) + my_auth.write() +else: + print ("Read author failed.") + +## Affiliation example +# Initialize affiliation with ID as string +my_aff = ElsAffil(affil_id = '60101411') +if my_aff.read(client): + print ("my_aff.name: ", my_aff.name) + my_aff.write() +else: + print ("Read affiliation failed.") + +## Scopus (Abtract) document example +# Initialize document with ID as integer +scp_doc = AbsDoc(scp_id = 84872135457) +if scp_doc.read(client): + print ("scp_doc.title: ", scp_doc.title) + scp_doc.write() +else: + print ("Read document failed.") + +## ScienceDirect (full-text) document example using PII +pii_doc = FullDoc(sd_pii = 'S1674927814000082') +if pii_doc.read(client): + print ("pii_doc.title: ", pii_doc.title) + pii_doc.write() +else: + print ("Read document failed.") + +## ScienceDirect (full-text) document example using DOI +doi_doc = FullDoc(doi = '10.1016/S1525-1578(10)60571-5') +if doi_doc.read(client): + print ("doi_doc.title: ", doi_doc.title) + doi_doc.write() +else: + print ("Read document failed.") + + +## Load list of documents from the API into affilation and author objects. +# Since a document list is retrieved for 25 entries at a time, this is +# a potentially lenghty operation - hence the prompt. +print ("Load documents (Y/N)?") +s = input('--> ') + +if (s == "y" or s == "Y"): + + ## Read all documents for example author, then write to disk + if my_auth.read_docs(client): + print ("my_auth.doc_list has " + str(len(my_auth.doc_list)) + " items.") + my_auth.write_docs() + else: + print ("Read docs for author failed.") + + ## Read all documents for example affiliation, then write to disk + if my_aff.read_docs(client): + print ("my_aff.doc_list has " + str(len(my_aff.doc_list)) + " items.") + my_aff.write_docs() + else: + print ("Read docs for affiliation failed.") + +## Initialize author search object and execute search +auth_srch = ElsSearch('authlast(keuskamp)','author') +auth_srch.execute(client) +print ("auth_srch has", len(auth_srch.results), "results.") + +## Initialize affiliation search object and execute search +aff_srch = ElsSearch('affil(amsterdam)','affiliation') +aff_srch.execute(client) +print ("aff_srch has", len(aff_srch.results), "results.") + +## Initialize doc search object using Scopus and execute search, retrieving +# all results +doc_srch = ElsSearch("AFFIL(dartmouth) AND AUTHOR-NAME(lewis) AND PUBYEAR > 2011",'scopus') +doc_srch.execute(client, get_all = True) +print ("doc_srch has", len(doc_srch.results), "results.") + +## Initialize doc search object using ScienceDirect and execute search, +# retrieving all results +doc_srch = ElsSearch("star trek vs star wars",'sciencedirect') +doc_srch.execute(client, get_all = False) +print ("doc_srch has", len(doc_srch.results), "results.") diff --git a/test_elsapy.py b/test_elsapy.py index 385facd..992a2ab 100644 --- a/test_elsapy.py +++ b/test_elsapy.py @@ -1,350 +1,350 @@ -"""Test cases for elsapy""" - -## TODO: -## - break down in modules (test suites) for each class to allow faster unit-testing -## - this will require a shared 'utility class' -## - add a module that integrates all - -from elsapy.elsclient import ElsClient -from elsapy.elsprofile import ElsAuthor, ElsAffil -from elsapy.elsdoc import FullDoc, AbsDoc -from elsapy.elssearch import ElsSearch -from urllib.parse import quote_plus as url_encode -import json, pathlib - -## Load good client configuration -conFile = open("config.json") -config = json.load(conFile) -conFile.close() - -## Set local path for test data and ensure it's clean -test_path = pathlib.Path.cwd() / 'test_data' -if not test_path.exists(): - test_path.mkdir() -else: - file_list = list(test_path.glob('*')) - ## TODO: write recursive function that also identifies and clears out child directories - for e in file_list: - if e.is_file(): - e.unlink() - -class util: - """Contains tests common to test cases from multiple classes""" - - def file_exist_with_id(id): - """Test case: exactly one local file exist with given ID in the filename""" - if len(list(test_path.glob('*' + id +'*'))) == 1: - return True - - -class TestElsClient: - """Test general client functionality""" - - def test_init_apikey_(self): - """Test case: APIkey and token are set correctly during initialization""" - my_client = ElsClient(config['apikey']) - assert my_client.api_key == config['apikey'] - assert my_client.inst_token == None - - def test_init_apikey_insttoken(self): - """Test case: APIkey and insttoken are set correctly during initialization""" - my_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - assert my_client.api_key == config['apikey'] - assert my_client.inst_token == config['insttoken'] - - def test_init_apikey_insttoken_path(self): - """Test case: APIkey, insttoken and local path are set correctly during initialization""" - loc_dir = '\\TEMP' - my_client = ElsClient(config['apikey'], inst_token = config['insttoken'], local_dir = loc_dir) - assert my_client.api_key == config['apikey'] - assert my_client.inst_token == config['insttoken'] - assert str(my_client.local_dir) == loc_dir - - def test_set_apikey_insttoken(self): - """Test case: APIkey and insttoken are set correctly using setters""" - my_client = ElsClient("dummy") - my_client.api_key = config['apikey'] - my_client.inst_token = config['insttoken'] - assert my_client.api_key == config['apikey'] - assert my_client.inst_token == config['insttoken'] - -class TestElsAuthor: - """Test author object functionality""" - - ## Test data - auth_uri = "https://api.elsevier.com/content/author/author_id/55070335500" - auth_id_int = 55070335500 - auth_id_str = "55070335500" - - ## Test initialization - def test_init_uri(self): - """ Test case: uri is set correctly during initialization with uri""" - myAuth = ElsAuthor(uri = self.auth_uri) - assert myAuth.uri == self.auth_uri - - def test_init_auth_id_int(self): - """ Test case: uri is set correctly during initialization with author id as integer""" - myAuth = ElsAuthor(author_id = self.auth_id_int) - assert myAuth.uri == self.auth_uri - - def test_init_auth_id_str(self): - """ Test case: uri is set correctly during initialization with author id as string""" - myAuth = ElsAuthor(author_id = self.auth_id_str) - assert myAuth.uri == self.auth_uri - - ## Test reading/writing author profile data - bad_client = ElsClient("dummy") - good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - good_client.local_dir = str(test_path) - - myAuth = ElsAuthor(uri = auth_uri) - - def test_read_good_bad_client(self): - """Test case: using a well-configured client leads to successful read - and using a badly-configured client does not.""" - assert self.myAuth.read(self.bad_client) == False - assert self.myAuth.read(self.good_client) == True - - def test_json_to_dict(self): - """Test case: the JSON read by the author object from the API is parsed - into a Python dictionary""" - assert type(self.myAuth.data) == dict - - def test_name_getter(self): - """Test case: the full name attribute is returned as a non-empty string""" - assert (type(self.myAuth.full_name) == str and self.myAuth.full_name != '') - - def test_write(self): - """Test case: the author object's data is written to a file with the author - ID in the filename""" - self.myAuth.write() - assert util.file_exist_with_id(self.myAuth.data['coredata']['dc:identifier'].split(':')[1]) - - def test_read_docs(self): - self.myAuth.read_docs() - assert len(self.myAuth.doc_list) > 0 - ## TODO: once author metrics inconsistency is resolved, change to: - # assert len(self.myAuth.doc_list) == int(self.myAuth.data['coredata']['document-count']) - - def test_read_metrics_new_author(self): - myAuth = ElsAuthor(uri = self.auth_uri) - myAuth.read_metrics(self.good_client) - assert ( - myAuth.data['coredata']['citation-count'] and - myAuth.data['coredata']['cited-by-count'] and - myAuth.data['coredata']['document-count'] and - myAuth.data['h-index']) - - def test_read_metrics_existing_author(self): - self.myAuth.read_metrics(self.good_client) - assert ( - self.myAuth.data['coredata']['citation-count'] and - self.myAuth.data['coredata']['cited-by-count'] and - self.myAuth.data['coredata']['document-count'] and - self.myAuth.data['h-index']) - - -class TestElsAffil: - """Test affiliation functionality""" - - ## Test data - aff_uri = "https://api.elsevier.com/content/affiliation/affiliation_id/60101411" - aff_id_int = 60101411 - aff_id_str = "60101411" - - ## Test initialization - def test_init_uri(self): - """ Test case: uri is set correctly during initialization with uri""" - myAff = ElsAffil(uri = self.aff_uri) - assert myAff.uri == self.aff_uri - - def test_init_aff_id_int(self): - """ Test case: uri is set correctly during initialization with affiliation id as integer""" - myAff = ElsAffil(affil_id = self.aff_id_int) - assert myAff.uri == self.aff_uri - - def test_init_aff_id_str(self): - """ Test case: uri is set correctly during initialization with affiliation id as string""" - myAff = ElsAffil(affil_id = self.aff_id_str) - assert myAff.uri == self.aff_uri - - ## Test reading/writing author profile data - bad_client = ElsClient("dummy") - good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - good_client.local_dir = str(test_path) - - myAff = ElsAffil(uri = aff_uri) - - def test_read_good_bad_client(self): - """Test case: using a well-configured client leads to successful read - and using a badly-configured client does not.""" - assert self.myAff.read(self.bad_client) == False - assert self.myAff.read(self.good_client) == True - - def test_json_to_dict(self): - """Test case: the JSON read by the author object from the API is parsed - into a Python dictionary""" - assert type(self.myAff.data) == dict - - def test_name_getter(self): - """Test case: the name attribute is returned as a non-empty string""" - assert (type(self.myAff.name) == str and self.myAff.name != '') - - def test_write(self): - """Test case: the author object's data is written to a file with the author - ID in the filename""" - self.myAff.write() - assert util.file_exist_with_id(self.myAff.data['coredata']['dc:identifier'].split(':')[1]) - - def test_read_docs(self): - self.myAff.read_docs() - assert len(self.myAff.doc_list) == int(self.myAff.data['coredata']['document-count']) - - -class TestAbsDoc: - """Test Scopus document functionality""" - - ## Test data - abs_uri = "https://api.elsevier.com/content/abstract/scopus_id/84872135457" - scp_id_int = 84872135457 - scp_id_str = "84872135457" - - ## Test initialization - def test_init_uri(self): - """ Test case: uri is set correctly during initialization with uri""" - myAbsDoc = AbsDoc(uri = self.abs_uri) - assert myAbsDoc.uri == self.abs_uri - - def test_init_scp_id_int(self): - """ Test case: uri is set correctly during initialization with Scopus id as integer""" - myAbsDoc = AbsDoc(scp_id = self.scp_id_int) - assert myAbsDoc.uri == self.abs_uri - - def test_init_scp_id_str(self): - """ Test case: uri is set correctly during initialization with Scopus id as string""" - myAbsDoc = AbsDoc(scp_id = self.scp_id_str) - assert myAbsDoc.uri == self.abs_uri - - ## Test reading/writing author profile data - bad_client = ElsClient("dummy") - good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - good_client.local_dir = str(test_path) - - myAbsDoc = AbsDoc(uri = abs_uri) - - def test_read_good_bad_client(self): - """Test case: using a well-configured client leads to successful read - and using a badly-configured client does not.""" - assert self.myAbsDoc.read(self.bad_client) == False - assert self.myAbsDoc.read(self.good_client) == True - - def test_json_to_dict(self): - """Test case: the JSON read by the abstract document object from the - API is parsed into a Python dictionary""" - assert type(self.myAbsDoc.data) == dict - - def test_title_getter(self): - """Test case: the title attribute is returned as a non-empty string""" - assert (type(self.myAbsDoc.title) == str and self.myAbsDoc.title != '') - - def test_write(self): - """Test case: the abstract document object's data is written to a file with the Scopus - ID in the filename""" - self.myAbsDoc.write() - assert util.file_exist_with_id(self.myAbsDoc.data['coredata']['dc:identifier'].split(':')[1]) - -class TestFullDoc: - """Test ScienceDirect article functionality""" - - ## Test data - full_pii_uri = "https://api.elsevier.com/content/article/pii/S1674927814000082" - sd_pii = 'S1674927814000082' - full_doi_uri = "https://api.elsevier.com/content/article/doi/10.1016/S1525-1578(10)60571-5" - doi = '10.1016/S1525-1578(10)60571-5' - - ## Test initialization - def test_init_uri(self): - """ Test case: uri is set correctly during initialization with uri""" - myFullDoc = FullDoc(uri = self.full_pii_uri) - assert myFullDoc.uri == self.full_pii_uri - - def test_init_sd_pii(self): - """ Test case: uri is set correctly during initialization with ScienceDirect PII""" - myFullDoc = FullDoc(sd_pii = self.sd_pii) - assert myFullDoc.uri == self.full_pii_uri - - def test_init_doi(self): - """ Test case: uri is set correctly during initialization with DOI""" - myFullDoc = FullDoc(doi = self.doi) - assert myFullDoc.uri == self.full_doi_uri - - ## Test reading/writing author profile data - bad_client = ElsClient("dummy") - good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - good_client.local_dir = str(test_path) - - myFullDoc = FullDoc(uri = full_pii_uri) - - def test_read_good_bad_client(self): - """Test case: using a well-configured client leads to successful read - and using a badly-configured client does not.""" - assert self.myFullDoc.read(self.bad_client) == False - assert self.myFullDoc.read(self.good_client) == True - - def test_json_to_dict(self): - """Test case: the JSON read by the full article object from the - API is parsed into a Python dictionary""" - assert type(self.myFullDoc.data) == dict - - def test_title_getter(self): - """Test case: the title attribute is returned as a non-empty string""" - assert (type(self.myFullDoc.title) == str and self.myFullDoc.title != '') - - def test_write(self): - """Test case: the full article object's data is written to a file with the ID in the filename""" - self.myFullDoc.write() - ## TODO: replace following (strung-together replace) with regex - assert util.file_exist_with_id( - self.myFullDoc.data['coredata']['pii'].replace('-','').replace('(','').replace(')','')) - - - -class TestSearch: - """Test search functionality""" - - ## Test data - base_url = u'https://api.elsevier.com/content/search/' - search_types = [ - {"query" : "authlast(keuskamp)", "index" : "author"}, - {"query" : "affil(amsterdam)", "index" : "affiliation"}, - {"query" : "AFFIL(dartmouth) AND AUTHOR-NAME(lewis) AND PUBYEAR > 2011", - "index" : "scopus"}, - {"query" : "star trek vs star wars", "index" : "sciencedirect"} - ] - - searches = [ ElsSearch(search_type["query"], search_type["index"]) - for search_type in search_types] - - good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) - - - ## Test initialization - def test_init_uri(self): - """Test case: query, index and uri are set correctly during - initialization""" - match_all = True - for i in range(len(self.search_types)): - if (self.searches[i].query != self.search_types[i]['query'] or - self.searches[i].index != self.search_types[i]['index'] or - self.searches[i].uri != (self.base_url + - self.search_types[i]['index'] + - '?query=' + - url_encode(self.search_types[i]['query']))): - match_all = False - assert match_all == True - - def test_execution(self): - '''Test case: all searches are executed without raising an exception.''' - for search in self.searches: - search.execute(self.good_client) - assert True +"""Test cases for elsapy""" + +## TODO: +## - break down in modules (test suites) for each class to allow faster unit-testing +## - this will require a shared 'utility class' +## - add a module that integrates all + +from elsapy.elsclient import ElsClient +from elsapy.elsprofile import ElsAuthor, ElsAffil +from elsapy.elsdoc import FullDoc, AbsDoc +from elsapy.elssearch import ElsSearch +from urllib.parse import quote_plus as url_encode +import json, pathlib + +## Load good client configuration +conFile = open("elapsy.json") +config = json.load(conFile) +conFile.close() + +## Set local path for test data and ensure it's clean +test_path = pathlib.Path.cwd() / 'test_data' +if not test_path.exists(): + test_path.mkdir() +else: + file_list = list(test_path.glob('*')) + ## TODO: write recursive function that also identifies and clears out child directories + for e in file_list: + if e.is_file(): + e.unlink() + +class util: + """Contains tests common to test cases from multiple classes""" + + def file_exist_with_id(id): + """Test case: exactly one local file exist with given ID in the filename""" + if len(list(test_path.glob('*' + id +'*'))) == 1: + return True + + +class TestElsClient: + """Test general client functionality""" + + def test_init_apikey_(self): + """Test case: APIkey and token are set correctly during initialization""" + my_client = ElsClient(config['apikey']) + assert my_client.api_key == config['apikey'] + assert my_client.inst_token == None + + def test_init_apikey_insttoken(self): + """Test case: APIkey and insttoken are set correctly during initialization""" + my_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + assert my_client.api_key == config['apikey'] + assert my_client.inst_token == config['insttoken'] + + def test_init_apikey_insttoken_path(self): + """Test case: APIkey, insttoken and local path are set correctly during initialization""" + loc_dir = '\\TEMP' + my_client = ElsClient(config['apikey'], inst_token = config['insttoken'], local_dir = loc_dir) + assert my_client.api_key == config['apikey'] + assert my_client.inst_token == config['insttoken'] + assert str(my_client.local_dir) == loc_dir + + def test_set_apikey_insttoken(self): + """Test case: APIkey and insttoken are set correctly using setters""" + my_client = ElsClient("dummy") + my_client.api_key = config['apikey'] + my_client.inst_token = config['insttoken'] + assert my_client.api_key == config['apikey'] + assert my_client.inst_token == config['insttoken'] + +class TestElsAuthor: + """Test author object functionality""" + + ## Test data + auth_uri = "https://api.elsevier.com/content/author/author_id/55070335500" + auth_id_int = 55070335500 + auth_id_str = "55070335500" + + ## Test initialization + def test_init_uri(self): + """ Test case: uri is set correctly during initialization with uri""" + myAuth = ElsAuthor(uri = self.auth_uri) + assert myAuth.uri == self.auth_uri + + def test_init_auth_id_int(self): + """ Test case: uri is set correctly during initialization with author id as integer""" + myAuth = ElsAuthor(author_id = self.auth_id_int) + assert myAuth.uri == self.auth_uri + + def test_init_auth_id_str(self): + """ Test case: uri is set correctly during initialization with author id as string""" + myAuth = ElsAuthor(author_id = self.auth_id_str) + assert myAuth.uri == self.auth_uri + + ## Test reading/writing author profile data + bad_client = ElsClient("dummy") + good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + good_client.local_dir = str(test_path) + + myAuth = ElsAuthor(uri = auth_uri) + + def test_read_good_bad_client(self): + """Test case: using a well-configured client leads to successful read + and using a badly-configured client does not.""" + assert self.myAuth.read(self.bad_client) == False + assert self.myAuth.read(self.good_client) == True + + def test_json_to_dict(self): + """Test case: the JSON read by the author object from the API is parsed + into a Python dictionary""" + assert type(self.myAuth.data) == dict + + def test_name_getter(self): + """Test case: the full name attribute is returned as a non-empty string""" + assert (type(self.myAuth.full_name) == str and self.myAuth.full_name != '') + + def test_write(self): + """Test case: the author object's data is written to a file with the author + ID in the filename""" + self.myAuth.write() + assert util.file_exist_with_id(self.myAuth.data['coredata']['dc:identifier'].split(':')[1]) + + def test_read_docs(self): + self.myAuth.read_docs() + assert len(self.myAuth.doc_list) > 0 + ## TODO: once author metrics inconsistency is resolved, change to: + # assert len(self.myAuth.doc_list) == int(self.myAuth.data['coredata']['document-count']) + + def test_read_metrics_new_author(self): + myAuth = ElsAuthor(uri = self.auth_uri) + myAuth.read_metrics(self.good_client) + assert ( + myAuth.data['coredata']['citation-count'] and + myAuth.data['coredata']['cited-by-count'] and + myAuth.data['coredata']['document-count'] and + myAuth.data['h-index']) + + def test_read_metrics_existing_author(self): + self.myAuth.read_metrics(self.good_client) + assert ( + self.myAuth.data['coredata']['citation-count'] and + self.myAuth.data['coredata']['cited-by-count'] and + self.myAuth.data['coredata']['document-count'] and + self.myAuth.data['h-index']) + + +class TestElsAffil: + """Test affiliation functionality""" + + ## Test data + aff_uri = "https://api.elsevier.com/content/affiliation/affiliation_id/60101411" + aff_id_int = 60101411 + aff_id_str = "60101411" + + ## Test initialization + def test_init_uri(self): + """ Test case: uri is set correctly during initialization with uri""" + myAff = ElsAffil(uri = self.aff_uri) + assert myAff.uri == self.aff_uri + + def test_init_aff_id_int(self): + """ Test case: uri is set correctly during initialization with affiliation id as integer""" + myAff = ElsAffil(affil_id = self.aff_id_int) + assert myAff.uri == self.aff_uri + + def test_init_aff_id_str(self): + """ Test case: uri is set correctly during initialization with affiliation id as string""" + myAff = ElsAffil(affil_id = self.aff_id_str) + assert myAff.uri == self.aff_uri + + ## Test reading/writing author profile data + bad_client = ElsClient("dummy") + good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + good_client.local_dir = str(test_path) + + myAff = ElsAffil(uri = aff_uri) + + def test_read_good_bad_client(self): + """Test case: using a well-configured client leads to successful read + and using a badly-configured client does not.""" + assert self.myAff.read(self.bad_client) == False + assert self.myAff.read(self.good_client) == True + + def test_json_to_dict(self): + """Test case: the JSON read by the author object from the API is parsed + into a Python dictionary""" + assert type(self.myAff.data) == dict + + def test_name_getter(self): + """Test case: the name attribute is returned as a non-empty string""" + assert (type(self.myAff.name) == str and self.myAff.name != '') + + def test_write(self): + """Test case: the author object's data is written to a file with the author + ID in the filename""" + self.myAff.write() + assert util.file_exist_with_id(self.myAff.data['coredata']['dc:identifier'].split(':')[1]) + + def test_read_docs(self): + self.myAff.read_docs() + assert len(self.myAff.doc_list) == int(self.myAff.data['coredata']['document-count']) + + +class TestAbsDoc: + """Test Scopus document functionality""" + + ## Test data + abs_uri = "https://api.elsevier.com/content/abstract/scopus_id/84872135457" + scp_id_int = 84872135457 + scp_id_str = "84872135457" + + ## Test initialization + def test_init_uri(self): + """ Test case: uri is set correctly during initialization with uri""" + myAbsDoc = AbsDoc(uri = self.abs_uri) + assert myAbsDoc.uri == self.abs_uri + + def test_init_scp_id_int(self): + """ Test case: uri is set correctly during initialization with Scopus id as integer""" + myAbsDoc = AbsDoc(scp_id = self.scp_id_int) + assert myAbsDoc.uri == self.abs_uri + + def test_init_scp_id_str(self): + """ Test case: uri is set correctly during initialization with Scopus id as string""" + myAbsDoc = AbsDoc(scp_id = self.scp_id_str) + assert myAbsDoc.uri == self.abs_uri + + ## Test reading/writing author profile data + bad_client = ElsClient("dummy") + good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + good_client.local_dir = str(test_path) + + myAbsDoc = AbsDoc(uri = abs_uri) + + def test_read_good_bad_client(self): + """Test case: using a well-configured client leads to successful read + and using a badly-configured client does not.""" + assert self.myAbsDoc.read(self.bad_client) == False + assert self.myAbsDoc.read(self.good_client) == True + + def test_json_to_dict(self): + """Test case: the JSON read by the abstract document object from the + API is parsed into a Python dictionary""" + assert type(self.myAbsDoc.data) == dict + + def test_title_getter(self): + """Test case: the title attribute is returned as a non-empty string""" + assert (type(self.myAbsDoc.title) == str and self.myAbsDoc.title != '') + + def test_write(self): + """Test case: the abstract document object's data is written to a file with the Scopus + ID in the filename""" + self.myAbsDoc.write() + assert util.file_exist_with_id(self.myAbsDoc.data['coredata']['dc:identifier'].split(':')[1]) + +class TestFullDoc: + """Test ScienceDirect article functionality""" + + ## Test data + full_pii_uri = "https://api.elsevier.com/content/article/pii/S1674927814000082" + sd_pii = 'S1674927814000082' + full_doi_uri = "https://api.elsevier.com/content/article/doi/10.1016/S1525-1578(10)60571-5" + doi = '10.1016/S1525-1578(10)60571-5' + + ## Test initialization + def test_init_uri(self): + """ Test case: uri is set correctly during initialization with uri""" + myFullDoc = FullDoc(uri = self.full_pii_uri) + assert myFullDoc.uri == self.full_pii_uri + + def test_init_sd_pii(self): + """ Test case: uri is set correctly during initialization with ScienceDirect PII""" + myFullDoc = FullDoc(sd_pii = self.sd_pii) + assert myFullDoc.uri == self.full_pii_uri + + def test_init_doi(self): + """ Test case: uri is set correctly during initialization with DOI""" + myFullDoc = FullDoc(doi = self.doi) + assert myFullDoc.uri == self.full_doi_uri + + ## Test reading/writing author profile data + bad_client = ElsClient("dummy") + good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + good_client.local_dir = str(test_path) + + myFullDoc = FullDoc(uri = full_pii_uri) + + def test_read_good_bad_client(self): + """Test case: using a well-configured client leads to successful read + and using a badly-configured client does not.""" + assert self.myFullDoc.read(self.bad_client) == False + assert self.myFullDoc.read(self.good_client) == True + + def test_json_to_dict(self): + """Test case: the JSON read by the full article object from the + API is parsed into a Python dictionary""" + assert type(self.myFullDoc.data) == dict + + def test_title_getter(self): + """Test case: the title attribute is returned as a non-empty string""" + assert (type(self.myFullDoc.title) == str and self.myFullDoc.title != '') + + def test_write(self): + """Test case: the full article object's data is written to a file with the ID in the filename""" + self.myFullDoc.write() + ## TODO: replace following (strung-together replace) with regex + assert util.file_exist_with_id( + self.myFullDoc.data['coredata']['pii'].replace('-','').replace('(','').replace(')','')) + + + +class TestSearch: + """Test search functionality""" + + ## Test data + base_url = u'https://api.elsevier.com/content/search/' + search_types = [ + {"query" : "authlast(keuskamp)", "index" : "author"}, + {"query" : "affil(amsterdam)", "index" : "affiliation"}, + {"query" : "AFFIL(dartmouth) AND AUTHOR-NAME(lewis) AND PUBYEAR > 2011", + "index" : "scopus"}, + {"query" : "star trek vs star wars", "index" : "sciencedirect"} + ] + + searches = [ ElsSearch(search_type["query"], search_type["index"]) + for search_type in search_types] + + good_client = ElsClient(config['apikey'], inst_token = config['insttoken']) + + + ## Test initialization + def test_init_uri(self): + """Test case: query, index and uri are set correctly during + initialization""" + match_all = True + for i in range(len(self.search_types)): + if (self.searches[i].query != self.search_types[i]['query'] or + self.searches[i].index != self.search_types[i]['index'] or + self.searches[i].uri != (self.base_url + + self.search_types[i]['index'] + + '?query=' + + url_encode(self.search_types[i]['query']))): + match_all = False + assert match_all == True + + def test_execution(self): + '''Test case: all searches are executed without raising an exception.''' + for search in self.searches: + search.execute(self.good_client) + assert True From 19e85c4b8e7416a04f23e757b97e47379510d3ee Mon Sep 17 00:00:00 2001 From: Philipp Tempel Date: Tue, 17 Dec 2019 19:42:54 +0100 Subject: [PATCH 2/2] Opsie, it's actually `elsapy` and not `elapsy` --- .gitignore | 2 +- CONFIG.md | 4 ++-- exampleProg.py | 2 +- test_elsapy.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 75de702..b23e056 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .cache -elapsy.json +elsapy.json niso_training_prog.py test_elsapy.py dump.json diff --git a/CONFIG.md b/CONFIG.md index eba7ab3..4136be0 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,7 +1,7 @@ # configuration If you are using (or adapting) exampleProg.py, do this: - In the folder in which exampleProg.py resides, create a file called 'j' -- Open 'elapsy.json' in a file editor, and insert the following: +- Open 'elsapy.json' in a file editor, and insert the following: ``` { @@ -13,4 +13,4 @@ If you are using (or adapting) exampleProg.py, do this: - Paste your APIkey (obtained from http://dev.elsevier.com) in the right place - If you don't have a valid insttoken (which you would have received from Elsevier support staff), delete the placeholder text. If you enter a dummy value, your API requests will fail. -The '.gitignore' file lists 'elapsy.json' as a file to be ignored when committing elsapy to a GIT repository, which is to prevent your APIkey from being shared with the world. Make similar provisions when you change your configuration setup. +The '.gitignore' file lists 'elsapy.json' as a file to be ignored when committing elsapy to a GIT repository, which is to prevent your APIkey from being shared with the world. Make similar provisions when you change your configuration setup. diff --git a/exampleProg.py b/exampleProg.py index 01613ab..d75db45 100644 --- a/exampleProg.py +++ b/exampleProg.py @@ -7,7 +7,7 @@ import json ## Load configuration -con_file = open("elapsy.json") +con_file = open("elsapy.json") config = json.load(con_file) con_file.close() diff --git a/test_elsapy.py b/test_elsapy.py index 992a2ab..f281964 100644 --- a/test_elsapy.py +++ b/test_elsapy.py @@ -13,7 +13,7 @@ import json, pathlib ## Load good client configuration -conFile = open("elapsy.json") +conFile = open("elsapy.json") config = json.load(conFile) conFile.close()