Skip to content

Commit

Permalink
Merge pull request #65 from dvklopfenstein/dev
Browse files Browse the repository at this point in the history
updates
  • Loading branch information
dvklopfenstein authored Jan 21, 2024
2 parents f5d9288 + d76c2d1 commit 6376737
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 195 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# PubMed ID (PMID) Cite

[![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Python%20library%20to%20download%20pubmed%20citation%20counts%20and%20data,%20given%20a%20PMID&url=https://github.com/dvklopfenstein/pmidcite&via=dvklopfenstein&hashtags=pubmed,pmid,citations,pubmed2cite,writingtips,scientificwriting)
[![build](https://github.com/dvklopfenstein/pmidcite/actions/workflows/build.yml/badge.svg)](https://github.com/dvklopfenstein/pmidcite/actions/workflows/build.yml)
[![CodeQL](https://github.com/dvklopfenstein/pmidcite/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/dvklopfenstein/pmidcite/actions/workflows/codeql-analysis.yml)
[![Latest PyPI version](https://img.shields.io/pypi/v/pmidcite.svg)](https://pypi.org/project/pmidcite/)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5172712.svg)](https://doi.org/10.5281/zenodo.5172712)
Expand Down
7 changes: 1 addition & 6 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ p:
d:
find src -regextype posix-extended -regex "[a-z./]*" -type d

g:
git status -uno
git remote -v
git branch

cli:
find src/pmidcite/cli -name \*.py

Expand Down Expand Up @@ -129,4 +124,4 @@ clobber_tmp:
rm -rf ./src/tests/icite

clobber:
make -f makefile clobber_tmp clean_build
make -f makefile clobber_tmp clean_build pyc
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def get_long_description():
with open(join(dir_cur, 'README.md'), 'rb') as ifstrm:
return ifstrm.read().decode("UTF-8")

CONSOLE_SCRIPTS = [
'icite=pmidcite.scripts.icite:main',
'sumpaps=pmidcite.scripts.summarize_papers:main',
]

setup(
name=NAME,
Expand All @@ -49,10 +53,7 @@ def get_long_description():
package_dir=PACKAGE_DIRS,
scripts=glob('src/bin/*.py'),
entry_points={
'console_scripts':[
'icite=pmidcite.scripts.icite:main',
'sumpaps=pmidcite.scripts.summarize_papers:main',
],
'console_scripts': CONSOLE_SCRIPTS,
},
# https://pypi.org/classifiers/
classifiers=[
Expand Down
9 changes: 5 additions & 4 deletions src/pmidcite/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,14 @@ def _chk_apikey(self, loaded):
"""Check to see that user has added a NCBI API key"""
try:
int(loaded['apikey'], 16)
except ValueError:
msg = ('SET API KEY IN {CFG}\n'
except ValueError as exc:
msg = (f'SET API KEY IN {self.cfgfile}\n'
'Get an NCBI API key to run the E-utilities:\n'
'https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/'
'new-api-keys-for-the-e-utilities\n'
'To ensure your API key is not made public, add {CFG} to the .gitignore')
raise RuntimeError(msg.format(CFG=self.cfgfile))
'To ensure your API key is not made public, '
f'add {self.cfgfile} to the .gitignore')
raise RuntimeError(msg) from exc

def _err_notfound(self):
"""Report the config file was not found"""
Expand Down
56 changes: 13 additions & 43 deletions src/pmidcite/eutils/cmds/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,48 +211,25 @@ def epost(self, database, ids, num_ids_p_epost=10):
ret['querykey'] = rsp['querykey']
return ret

@staticmethod
def _return_einforesult(record):
"""Return EInfo result"""
einforesult = record['einforesult']
cmdtype = record['header']['type']
if 'dblist' in einforesult:
return einforesult['dblist']
if cmdtype == 'einfo' and 'dbinfo' in einforesult:
assert len(record['einforesult']['dbinfo']) == 1
## print('RRRRRRRRRRRRRRR', record.keys())
## print('RRRRRRRRRRRRRRR', len(record['einforesult']['dbinfo']))
## print('RRRRRRRRRRRRRRR', record)
return record['einforesult']['dbinfo'][0]
raise RuntimeError('IMPLEMENT _return_einforesult')

@staticmethod
def _return_linksets(record):
"""Return ELink result"""
links_all = []
for dct0 in record['linksets']:
## print('DCT', dct0)
if 'linksetdbs' in dct0:
for dct1 in dct0['linksetdbs']:
links_all.extend(dct1['links'])
print('{N} LINKED ITEMS'.format(N=len(links_all)))
return links_all

# ------------------------------------------------------------------------------------
def run_eutilscmd(self, cmd, **params): # params=None, post=None, ecitmatch=False):
"""Run NCBI E-Utilities command"""
# params example: db retstart retmax rettype retmode webenv query_key
# print('RUN NCBI EUTILS CMD', cmd)
rsp_dct = self.run_req(cmd, **params) # post=None, ecitmatch=False):
## print('RRRRRRRRRRRRRRRRRRRRRRR', rsp_dct)
# print('RRRRRRRRRRRRRRRRRRRRRRR', rsp_dct.keys())
# dict_keys(['code', 'msg', 'url', 'headers', 'data'])
# print('RRRRRRRRRRRRRRRRRRRRRRR', rsp_dct['data'])
# print('RRRRRRRRRRRRRRRRRRRRRRR', rsp_dct)
if rsp_dct is not None:
return self._extract_rsp(rsp_dct['data'], params.get('retmode'))
return None

def _mk_cgi(self, cmd, **params):
"""Get Fast Common Gateway Interface (fcgi) string, given E-utils command/parameters"""
cgi = self.cgifmt.format(ECMD=cmd)
##print('PARAMS', params)
params = self._construct_params(params)
## print('PARAMS', params)
options = self._encode_options(params)
cgi += '?' + options
return cgi
Expand Down Expand Up @@ -333,29 +310,19 @@ def _extract_rsp(self, record, retmode):
"""Extract the data from a response from running a Entrez Utilities command"""
if retmode == 'json':
try:
dct = json.loads(record)
if 'esearchresult' in dct:
return dct['esearchresult']
if 'einforesult' in dct:
return self._return_einforesult(dct)
if 'linksets' in dct:
return self._return_linksets(dct)
print('KEYS:', dct.keys())
print('DCT:', dct)
raise RuntimeError('UNKNOWN RESULT in _run_req')
return json.loads(record)
except json.decoder.JSONDecodeError as errobj:
print('JSONDecodeError = {ERR}'.format(ERR=str(errobj)))
traceback.print_exc()
print('\n**FATAL JSONDecodeError:\n{RECORD}'.format(RECORD=record.decode('utf-8')))

if retmode == 'text':
if retmode in {'text', 'asn.1'}:
## print('RECORD:', str(record))
return record.decode('utf-8')

## print('RETMODE', retmode)
## print('RECORD', record)

## print(record)
# <?xml version="1.0" encoding="ISO-8859-1"?>
# <!DOCTYPE ePostResult
# SYSTEM "https://eutils.ncbi.nlm.nih.gov/eutils/dtd/20090526/epost.dtd"
Expand All @@ -366,8 +333,11 @@ def _extract_rsp(self, record, retmode):
# </ePostResult>
# Parse XML
root = ElementTree.fromstring(record)
## print('root.tag', root.tag)
assert root.tag in 'ePostResult', root.tag
#print(f'ElementTree.fromstring(record).root:\n{root}')
return root
# TODO
#print('root.tag', root.tag)
assert root.tag in 'ePostResult', f'ElementTree.fromstring(record).tag: {root.tag}'
dct = {r.tag.lower():r.text for r in root}
if 'querykey' in dct:
dct['querykey'] = int(dct['querykey'])
Expand Down
26 changes: 0 additions & 26 deletions src/pmidcite/eutils/cmds/cmdbase.py

This file was deleted.

76 changes: 0 additions & 76 deletions src/pmidcite/eutils/cmds/efetch.py

This file was deleted.

34 changes: 16 additions & 18 deletions src/pmidcite/eutils/cmds/elink.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
"""Fetch items and write"""
"""ELink"""

__author__ = 'DV Klopfenstein, PhD'
__copyright__ = "Copyright (C) 2016-present DV Klopfenstein, PhD. All rights reserved."
__license__ = "GPL"

import sys
import re
from pmidcite.eutils.cmds.cmdbase import CommandBase
from pmidcite.eutils.cmds.base import EntrezUtilities


# TBD:
class ELink(CommandBase):
"""Fetch and write text"""
class ELink(EntrezUtilities):
"""ELink"""

# pylint: disable=too-many-arguments
def __init__(self, retmax=10000, rettype='medline', retmode='text', batch_size=100, **kws):
kws_base = {k:v for k, v in kws.items() if k in CommandBase.exp_kws}
super(ELink, self).__init__(**kws_base)
def __init__(self, email, apikey, tool, batch_size=100):
super().__init__(email, apikey, tool)
self.batch_size = batch_size

def elink(self, database_from, linkname, webenv, querykey, num_fetches):
"""EFetch records found for PMIDs, page by page"""
Expand All @@ -29,7 +28,6 @@ def elink(self, database_from, linkname, webenv, querykey, num_fetches):
## sys.stdout.write(msg)
record = None
try:
# pylint: disable=bad-whitespace
record = self.run_eutilscmd(
'elink',
db = database_from,
Expand All @@ -41,15 +39,15 @@ def elink(self, database_from, linkname, webenv, querykey, num_fetches):
query_key = querykey)
print('ELINK:', linkname, record)
except IOError as err:
msg = "\n*FATAL: EFetching FAILED: {}".format(err)
msg = f"\n*FATAL: EFetching FAILED: {err}"
sys.stdout.write(msg)
sys.stdout.write(" database: {}\n".format(database_from))
sys.stdout.write(" retstart: {}\n".format(start))
# sys.stdout.write(" retmax: {}\n".format(retmax))
sys.stdout.write(" batch_size: {}\n".format(self.batch_size))
sys.stdout.write(" linkname: {}\n".format(linkname))
sys.stdout.write(" webenv: {}\n".format(webenv))
sys.stdout.write(" querykey: {}\n".format(querykey))
sys.stdout.write(f" database: {database_from}\n")
sys.stdout.write(f" retstart: {start}\n")
# sys.stdout.write(f" retmax: {retmax}\n")
sys.stdout.write(f" batch_size: {self.batch_size}\n")
sys.stdout.write(f" linkname: {linkname}\n")
sys.stdout.write(f" webenv: {webenv}\n")
sys.stdout.write(f" querykey: {querykey}\n")

if record is not None:
try:
Expand All @@ -61,7 +59,7 @@ def elink(self, database_from, linkname, webenv, querykey, num_fetches):
# ostrm.flush()
# pylint: disable=broad-except
except Exception as err:
sys.stdout.write("*FATAL: BAD READ SOCKET HANDLE: {}\n".format(str(err)))
sys.stdout.write(f"*FATAL: BAD READ SOCKET HANDLE: {str(err)}\n")
else:
sys.stdout.write("*FATAL: NO SOCKET HANDLE TO READ FROM\n")

Expand Down
Loading

0 comments on commit 6376737

Please sign in to comment.