Skip to content

Commit

Permalink
Merge branch 'release/0.1.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
mfcovington committed Dec 24, 2015
2 parents a08b5ae + 988382d commit 219f439
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.1.3
current_version = 0.1.4
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-dev(?P<dev>\d+))?
serialize =
{major}.{minor}.{patch}-dev{dev}
Expand Down
1 change: 1 addition & 0 deletions .landscape.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test-warnings: yes
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Revision History
================

0.1.4 2015-12-24

- Resolve PEP8 errors
- Refactor code to be cleaner
- Configure Landscape and add code health badge
- Convert Github installation instructions to install from develop branch


0.1.3 2015-07-29

- Add tests for Publication and PubMedLookup
Expand Down
14 changes: 10 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ pubmed-lookup

.. image:: https://badge.fury.io/py/pubmed-lookup.svg
:target: http://badge.fury.io/py/pubmed-lookup
:alt: PyPI Version

.. image:: https://travis-ci.org/mfcovington/pubmed-lookup.svg?branch=master
:target: https://travis-ci.org/mfcovington/pubmed-lookup
:alt: Build Status

.. image:: https://coveralls.io/repos/mfcovington/pubmed-lookup/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/mfcovington/pubmed-lookup?branch=master
:alt: Test Coverage

.. image:: https://landscape.io/github/mfcovington/pubmed-lookup/master/landscape.svg?style=flat
:target: https://landscape.io/github/mfcovington/pubmed-lookup/master
:alt: Code Health

``pubmed-lookup`` is package to lookup PubMed records and make Publication objects with info about a scientific publication.
``pubmed-lookup`` is a Python package to lookup PubMed records and make Publication objects with info about a scientific publication.

Source code is available on GitHub at `mfcovington/pubmed-lookup <https://github.com/mfcovington/pubmed-lookup>`_.

Expand All @@ -29,11 +35,11 @@ Installation
pip install pubmed-lookup
**GitHub**
**GitHub (development branch)**

.. code-block:: sh
pip install https://github.com/mfcovington/pubmed-lookup/releases/download/0.1.3/pubmed-lookup-0.1.3.tar.gz
pip install git+http://github.com/mfcovington/pubmed-lookup.git@develop
Usage
Expand Down Expand Up @@ -128,4 +134,4 @@ Usage
ABSTRACT:
Diverse life forms have evolved internal clocks enabling them to monitor time and thereby anticipate the daily environmental changes caused by Earth's rotation. The plant circadian clock regulates expression of about one-third of the Arabidopsis genome, yet the physiological relevance of this regulation is not fully understood. Here we show that the circadian clock, acting with hormone signals, provides selective advantage to plants through anticipation of and enhanced defense against herbivory. We found that cabbage loopers (Trichoplusia ni) display rhythmic feeding behavior that is sustained under constant conditions, and plants entrained in light/dark cycles coincident with the entrainment of the T. ni suffer only moderate tissue loss due to herbivory. In contrast, plants entrained out-of-phase relative to the insects are significantly more susceptible to attack. The in-phase entrainment advantage is lost in plants with arrhythmic clocks or deficient in jasmonate hormone; thus, both the circadian clock and jasmonates are required. Circadian jasmonate accumulation occurs in a phase pattern consistent with preparation for the onset of peak circadian insect feeding behavior, providing evidence for the underlying mechanism of clock-enhanced herbivory resistance. Furthermore, we find that salicylate, a hormone involved in biotrophic defense that often acts antagonistically to jasmonates, accumulates in opposite phase to jasmonates. Our results demonstrate that the plant circadian clock provides a strong physiological advantage by performing a critical role in Arabidopsis defense."

*Version 0.1.3*
*Version 0.1.4*
102 changes: 51 additions & 51 deletions pubmed_lookup/pubmed_lookup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import re
import sys
from functools import reduce
from urllib.error import URLError
from urllib.parse import urlparse
from urllib.request import urlopen

Expand All @@ -13,24 +14,26 @@ class Publication(object):
Use a PubMedLookup record to make a Publication object with info about
a scientific publication.
"""

def __init__(self, pubmed_record):
"""
Upon init: set Publication attributes (record, pmid, pubmed_url,
title, authors, first_author, last_author, journal, volume, issue,
pages, url, abstract, year, month, and day)
"""
self.record = pubmed_record.record
self.pmid = self.record['Id']
self.pmid = self.record.get('Id')
self.pubmed_url = 'http://www.ncbi.nlm.nih.gov/pubmed/{}' \
.format(self.pmid)
self.title = self.record['Title']
self.authors = ", ".join(self.record['AuthorList'])
self.first_author = self.record['AuthorList'][0]
self.last_author = self.record['AuthorList'][-1]
self.journal = self.record['Source']
self.volume = self.record['Volume']
self.issue = self.record['Issue']
self.pages = self.record['Pages']
self.title = self.record.get('Title')
self._author_list = self.record.get('AuthorList')
self.authors = ", ".join(self._author_list)
self.first_author = self._author_list[0]
self.last_author = self._author_list[-1]
self.journal = self.record.get('Source')
self.volume = self.record.get('Volume')
self.issue = self.record.get('Issue')
self.pages = self.record.get('Pages')
self.set_article_url()

xml_dict = self.get_pubmed_xml()
Expand All @@ -41,12 +44,12 @@ def authors_et_al(self, max_authors=5):
"""
Return string with a truncated author list followed by 'et al.'
"""
author_list = self.record['AuthorList']
author_list = self._author_list
if len(author_list) <= max_authors:
authors_et_al = self.authors
else:
authors_et_al = ", ".join(
self.record['AuthorList'][:max_authors]) + ", et al."
self._author_list[:max_authors]) + ", et al."
return authors_et_al

def cite(self, max_authors=5):
Expand All @@ -63,7 +66,9 @@ def cite(self, max_authors=5):
'issue': self.issue,
'pages': self.pages,
}
citation = "{authors} ({year}). {title} {journal}".format(**citation_data)
citation = "{authors} ({year}). {title} {journal}".format(
**citation_data)

if self.volume and self.issue and self.pages:
citation += " {volume}({issue}): {pages}.".format(**citation_data)
elif self.volume and self.issue:
Expand All @@ -86,7 +91,7 @@ def cite_mini(self):
"""
citation_data = [self.first_author]

if len(self.record['AuthorList']) > 1:
if len(self._author_list) > 1:
citation_data.append(self.last_author)

citation_data.extend([self.year, self.journal])
Expand All @@ -98,37 +103,39 @@ def parse_abstract(xml_dict):
"""
Parse PubMed XML dictionary to retrieve abstract.
"""
key_path = ['PubmedArticleSet', 'PubmedArticle', 'MedlineCitation',
'Article', 'Abstract', 'AbstractText']
abstract_xml = reduce(dict.get, key_path, xml_dict)

abstract_paragraphs = []
abstract_xml = xml_dict['PubmedArticleSet']['PubmedArticle'] \
['MedlineCitation']['Article']['Abstract']['AbstractText']

if isinstance(abstract_xml, str):
abstract_paragraphs.append(abstract_xml)

elif isinstance(abstract_xml, dict):
abstract_text = abstract_xml['#text']
abstract_text = abstract_xml.get('#text')
try:
abstract_label = abstract_xml['@Label']
except:
except KeyError:
abstract_paragraphs.append(abstract_text)
else:
abstract_paragraphs.append("{}: {}"
.format(abstract_label, abstract_text))
abstract_paragraphs.append(
"{}: {}".format(abstract_label, abstract_text))

elif isinstance(abstract_xml, list):
for abstract_section in abstract_xml:
try:
abstract_text = abstract_section['#text']
except:
except KeyError:
abstract_text = abstract_section

try:
abstract_label = abstract_section['@Label']
except:
except KeyError:
abstract_paragraphs.append(abstract_text)
else:
abstract_paragraphs.append("{}: {}"
.format(abstract_label, abstract_text))
abstract_paragraphs.append(
"{}: {}".format(abstract_label, abstract_text))

else:
raise RuntimeError("Error parsing abstract.")
Expand All @@ -145,7 +152,7 @@ def get_pubmed_xml(self):

try:
response = urlopen(url)
except:
except URLError:
xml_dict = ''
else:
xml = response.read().decode()
Expand All @@ -157,8 +164,8 @@ def set_abstract(self, xml_dict):
"""
If record has an abstract, get it extract it from PubMed's XML data
"""
if self.record['HasAbstract'] == 1 and xml_dict:
self.abstract = self.parse_abstract(xml_dict)
if self.record.get('HasAbstract') == 1 and xml_dict:
self.abstract = self.parse_abstract(xml_dict)
else:
self.abstract = ''

Expand All @@ -171,7 +178,7 @@ def set_article_url(self):

try:
response = urlopen(doi_url)
except:
except URLError:
self.url = ''
else:
self.url = response.geturl()
Expand All @@ -182,32 +189,25 @@ def set_pub_year_month_day(self, xml_dict):
"""
Set publication year, month, day from PubMed's XML data
"""
try:
pubdate_xml = xml_dict['PubmedArticleSet']['PubmedArticle'] \
['MedlineCitation']['Article']['Journal']['JournalIssue'] \
['PubDate']
except:
year = ''
month = ''
day = ''
else:
try:
year = pubdate_xml['Year']
except:
year = ''
key_path = ['PubmedArticleSet', 'PubmedArticle', 'MedlineCitation',
'Article', 'Journal', 'JournalIssue', 'PubDate']
pubdate_xml = reduce(dict.get, key_path, xml_dict)

try:
month_short = pubdate_xml['Month']
month = datetime.datetime.strptime(month_short, "%b").month
except:
month = ''
if isinstance(pubdate_xml, dict):
self.year = pubdate_xml.get('Year')
month_short = pubdate_xml.get('Month')
self.day = pubdate_xml.get('Day')

try:
day = pubdate_xml['Day']
except:
day = ''
self.month = datetime.datetime.strptime(
month_short, "%b").month
except ValueError:
self.month = ''

self.year, self.month, self.day = year, month, day
else:
self.year = ''
self.month = ''
self.day = ''


class PubMedLookup(object):
Expand Down Expand Up @@ -240,7 +240,7 @@ def __init__(self, query, user_email):
def parse_pubmed_url(pubmed_url):
"""Get PubMed ID (pmid) from PubMed URL."""
parse_result = urlparse(pubmed_url)
pattern = re.compile('^/pubmed/(\d+)$')
pattern = re.compile(r'^/pubmed/(\d+)$')
pmid = pattern.match(parse_result.path).group(1)
return pmid

Expand Down
33 changes: 19 additions & 14 deletions pubmed_lookup/test_pubmed_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def setUp(self):

def test_fields(self):
self.assertEqual(self.record.pmid, self.pmid)
self.assertEqual(self.record.pubmed_url,
self.assertEqual(
self.record.pubmed_url,
'http://www.ncbi.nlm.nih.gov/pubmed/22331878')
self.assertEqual(self.record.title, self.title)
self.assertEqual(self.record.authors, self.authors)
Expand All @@ -58,19 +59,21 @@ def test_fields(self):

def test_authors_et_al(self):
self.assertEqual(self.record.authors_et_al(), self.authors)
self.assertEqual(self.record.authors_et_al(max_authors=3),
self.assertEqual(
self.record.authors_et_al(max_authors=3),
'Goodspeed D, Chehab EW, Min-Venditti A, et al.')
self.assertEqual(self.record.authors_et_al(max_authors=10),
self.authors)
self.assertEqual(
self.record.authors_et_al(max_authors=10), self.authors)

def test_cite_mini(self):
self.assertEqual(self.record.cite_mini(),
self.assertEqual(
self.record.cite_mini(),
'Goodspeed D - Covington MF - 2012 - Proc Natl Acad Sci U S A')

def test_cite(self):
self.assertEqual(self.record.cite(),
'{} {volume}({issue}): {pages}.'.format(self.base_citation,
**self.citation_data))
self.assertEqual(
self.record.cite(), '{} {volume}({issue}): {pages}.'.format(
self.base_citation, **self.citation_data))

def test_cite_without_pages(self):
self.record.pages = ''
Expand Down Expand Up @@ -100,11 +103,12 @@ def test_cite_without_issue_pages_volume(self):
self.record.volume = ''
self.assertEqual(self.record.cite(), '{}.'.format(self.base_citation))

@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == 'true',
@unittest.skipIf(
"TRAVIS" in os.environ and os.environ["TRAVIS"] == 'true',
"Skipping this test on Travis CI.")
def test_doi(self):
self.assertEqual(self.record.url,
'http://www.pnas.org/content/109/12/4674')
self.assertEqual(
self.record.url, 'http://www.pnas.org/content/109/12/4674')

def test_missing_doi(self):
del self.record.record['DOI']
Expand All @@ -124,12 +128,13 @@ def setUp(self):
self.pmid = '22331878'

def test_pmid_and_url_return_same_record(self):
self.assertEqual(PubMedLookup(self.pmid, self.email).record,
self.assertEqual(
PubMedLookup(self.pmid, self.email).record,
PubMedLookup(self.pubmed_url, self.email).record)

def test_parse_pubmed_url(self):
self.assertEqual(PubMedLookup.parse_pubmed_url(self.pubmed_url),
self.pmid)
self.assertEqual(
PubMedLookup.parse_pubmed_url(self.pubmed_url), self.pmid)

def test_invalid_query(self):
with self.assertRaises(RuntimeError):
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def read(*paths):

setup(
name='pubmed-lookup',
version='0.1.3',
version='0.1.4',
packages=['pubmed_lookup'],
test_suite = 'pubmed_lookup.test_pubmed_lookup',
test_suite='pubmed_lookup.test_pubmed_lookup',
include_package_data=True,
license='BSD License',
keywords='citations lab literature pmid publications pubmed science',
Expand Down

0 comments on commit 219f439

Please sign in to comment.