Source code for metapub.cite

__doc__ = "Common functions for the formatting of academic reference citations."

article_cit_fmt = '{author}. {title}. {journal}. {year}; {volume}:{pages}.{doi}'
book_cit_fmt = '{author}. {book.title}. {cdate} (Update {mdate}). In: {editors}, editors. {book.journal} (Internet). {book.book_publisher}'
bibtex_fmt = '@{entrytype}{{{citeID},\n{author}{doi}{title}{abstract}{journal}{year}{volume}{pages}{url}}}'

# HTML format strings for citation_html functionality
article_cit_fmt_html = '{author}. {title}. <i>{journal}</i>. {year}; <b>{volume}</b>:{pages}.{doi}'
book_cit_fmt_html = '{author}. <i>{book.title}</i>. {cdate} (Update {mdate}). In: {editors}, editors. <i>{book.journal}</i> (Internet). {book.book_publisher}'


[docs] def author_str(author_list_or_string, as_html=False): """ Helper function for constructing article citations. :param author_list_or_string: :return: author(s) str suitable for printed citation """ if type(author_list_or_string) == list: authors = author_list_or_string else: authors = author_list_or_string.split(';') if len(authors) > 2: auth = authors[0].strip() if as_html: auth += ', <i>et al</i>' else: auth += ', et al' elif len(authors) == 2: auth = ' and '.join([aut.strip() for aut in authors]) else: auth = authors[0] return auth
[docs] def citation(**kwargs): """ Returns a formatted citation string built from this article's author(s), title, journal, year, volume, pages, and doi. see cite.article and cite.book for more specific use cases. Note that "authors" (as list) will be used preferentially over "author" (as str). Keywords: as_html: (bool) returns citation with light HTML formatting. author: (str) -- prints author as-is without modification authors: (list) -- prints as author1 (first in list) as "Lastname_FirstInitials, et al" title: (str) journal: (str) year: (str or int) volume: (str or int) pages: (str) should be formatted "nn-mm", e.g. "55-58" doi: (str) Returns: citation (str) """ #Author(s) if kwargs.get('authors', None): author = author_str(kwargs['authors'], as_html=kwargs.get('as_html', False)) else: author = kwargs.get('author', '(None)') #DOI doi_str = '' if not kwargs.get('doi', None) else ' doi: %s' % kwargs['doi'] #Title title = '(None)' if not kwargs.get('title', None) else kwargs['title'].strip('.') #Journal journal = '(None)' if not kwargs.get('journal', None) else kwargs['journal'].strip('.') # Year year = '(unknown year)' if not kwargs.get('year', None) else kwargs['year'] # Volume volume = '(unknown volume)' if not kwargs.get('volume', None) else str(kwargs['volume']) # Pages pages = '(unknown pages)' if not kwargs.get('pages', None) else kwargs['pages'] #TODO: how many articles DON'T have a volume, or are missing pages? (not that important for now.) # Choose format string based on HTML preference fmt = article_cit_fmt_html if kwargs.get('as_html', False) else article_cit_fmt return fmt.format(author=author, volume=volume, pages=pages, year=year, title=title, journal=journal, doi=doi_str)
[docs] def article(**kwargs): """ Returns a formatted citation string built from this article's author(s), title, journal, year, volume, pages, and doi. This function uses the Article format citation template. For example: McNally EM, et al. Genetic mutations and mechanisms in dilated cardiomyopathy. Journal of Clinical Investigation. 2013; 123:19-26. doi: 10.1172/JCI62862. Keywords: journal title doi authors (str or list) -- if str, prints authors without modification. Return: citation (str) """ return citation(**kwargs)
[docs] def book(book, **kwargs): """ Takes a PubMedArticle "book" and formats a citation string. This is a special type of citation built mostly for NCBI GeneReviews and not currently generalizable to other academic books (yet). Returns a formatted citation string for a book. A "book" needs to contain the following attributes: author title book_date_revised book_contribution_date editors journal book_publisher (may be a URL) This function uses the Book format citation template: book_cit_fmt = '{author}. {title}. {cdate} (Update {mdate}). In: {editors}, editors. {journal} (Internet). {book_publisher}' For example: Tranebjarg L, et al. Jervell and Lange-Nielsen syndrome. 2002 Jul 29 (Updated 2014 Nov 20). In: Pagon RA, et al., editors. GeneReviews (Internet). Seattle (WA): University of Washington, Seattle; 1993-2015. Available from: https://www.ncbi.nlm.nih.gov/books/NBK1405/. :param book: PubMedArticle of type "book" :param use_html: (bool) whether to return with light HTML formatting :return: formatted citation string :rtype: str """ author = author_str(book.authors_str, as_html=kwargs.get('as_html', False)) # Special handling for GeneReviews and other books: if book.book_accession_id: mdate = book.book_date_revised.strftime('%Y %b %d') cdate = book.book_contribution_date.strftime('%Y %b %d') editors = author_str(book.book_editors, as_html=kwargs.get('as_html', False)) if editors.endswith(', et al'): editors += '.' # Choose format string based on HTML preference fmt = book_cit_fmt_html if kwargs.get('as_html', False) else book_cit_fmt return fmt.format(editors=editors, author=author, book=book, mdate=mdate, cdate=cdate)
[docs] def bibtex(**kwargs): """ Returns a BibTeX formatted citation string built from the book or article author(s), title, journal, year, volume, pages, and doi if the fields exist see cite.article and cite.book for more specific use cases. see https://ctan.org/tex-archive/biblio/bibtex/contrib/doc/ for more on the BibTeX format Note that "authors" (as list) will be used preferentially over "author" (as str). Keywords: isbook: (bool) returns citation with standard entry type as 'book' author: (str) -- prints author as-is without modification authors: (list) -- prints as author1 (first in list) as "Lastname_FirstInitials, et al" title: (str) journal: (str) year: (str or int) volume: (str or int) pages: (str) should be formatted "nn-mm", e.g. "55-58" doi: (str) Returns: bibtex citation (str) """ entrytype = 'article' if not kwargs.get('isbook', False) else 'book' # Citation ID - create from first author last name and year year_str = str(kwargs.get('year', '')) if kwargs.get('authors', None) and len(kwargs['authors']) > 0 and year_str: # Extract last name from first author first_author = kwargs['authors'][0] # Handle formats like "Smith J" or "Smith, John" if ',' in first_author: last_name = first_author.split(',')[0].strip() else: # Handle "LastName Initial" or "Multi Word LastName Initial" formats parts = first_author.strip().split(' ') if len(parts) >= 2: # Take all but the last part (which should be initials) last_name = ''.join(parts[:-1]) # Join without spaces for citation ID else: last_name = parts[0].strip() citeID = last_name + year_str else: # Fallback to PMID if available citeID = kwargs.get('pmid', 'UnknownCitation') # Author(s) if kwargs.get('authors', None): # Convert author list to BibTeX format: "Last, First and Last, First" authorlist = [] for a in kwargs['authors']: if ',' in a: # Already in "Last, First" format authorlist.append(a.strip()) else: # Convert "LastName Initial" to "LastName, Initial" parts = a.strip().split(' ') if len(parts) >= 2: # For PubMed format "Smith J" -> "Smith, J" last_name = ' '.join(parts[:-1]) initials = parts[-1] authorlist.append(f"{last_name}, {initials}") else: authorlist.append(a.strip()) author = 'author = {%s},\n' % ' and '.join(authorlist) else: author = '' if not kwargs.get('author', None) else 'author = {%s},\n' % kwargs['author'] # DOI doi_str = '' if not kwargs.get('doi', None) else 'doi = {%s},\n' % kwargs['doi'] # Title title = '' if not kwargs.get('title', None) else 'title = {%s},\n' % kwargs['title'].strip('.') # Abstract (optional for BibTeX, often excluded for brevity) if kwargs.get('abstract', None): abs_text = kwargs['abstract'].strip('.') if len(abs_text) > 500: abs_text = abs_text[:500] + '...' abstract = 'abstract = {%s},\n' % abs_text else: abstract = '' # Journal journal = '' if not kwargs.get('journal', None) else 'journal = {%s},\n' % kwargs['journal'].strip('.') # Year year = '' if not kwargs.get('year', None) else 'year = {%s},\n' % kwargs['year'] # Volume volume = '' if not kwargs.get('volume', None) else 'volume = {%s},\n' % str(kwargs['volume']) # Pages pages = '' if not kwargs.get('pages', None) else 'pages = {%s},\n' % kwargs['pages'] # URL url = '' if not kwargs.get('url', None) else 'url = {%s},\n' % kwargs['url'].strip('.') # bibtex_fmt = '@{entrytype}{{{citeID},\n{author}{doi_str}{title}{abstract}{journal}{year}{volume}{pages}{url}}}' return bibtex_fmt.format(author=author, volume=volume, pages=pages, year=year, abstract=abstract, citeID=citeID, entrytype=entrytype, title=title, journal=journal, doi=doi_str, url=url)