libbmc/libbmc/bibtex.py

200 lines
5.9 KiB
Python

"""
This file contains functions to deal with Bibtex files and edit them.
"""
import bibtexparser
import re
from codecs import open
from libbmc import tools
default_papers_filename_mask = "{first}_{last}-{journal}-{year}{arxiv_version}"
default_books_filename_mask = "{authors} - {title}"
def dict2BibTeX(data):
"""
Convert a single BibTeX entry dict to a BibTeX string.
:param data: A dict representing BibTeX entry, as the ones from \
``bibtexparser`` output.
:return: A formatted BibTeX string.
"""
"""Convert a single bibtex entry dict to bibtex string"""
bibtex = '@' + data['ENTRYTYPE'] + '{' + data['ID'] + ",\n"
for field in [i for i in sorted(data) if i not in ['ENTRYTYPE', 'ID']]:
bibtex += "\t" + field + "={" + data[field] + "},\n"
bibtex += "}\n"
return bibtex
def write(filename, data):
"""
Create a new BibTeX file.
:param filename: The name of the BibTeX file to write.
:param data: A list of dict representing BibTeX entries, as the ones from \
``bibtexparser`` output.
"""
bibtex = "\n".join([dict2BibTeX(i) for i in data])
with open(filename, 'w', encoding='utf-8') as fh:
fh.write(bibtex)
def append(filename, data):
"""
Append some entries to a bibtex file.
:param filename: The name of the BibTeX file to edit.
:param data: A list of dict representing BibTeX entries, as the ones from \
``bibtexparser`` output.
"""
with open(filename, 'a', encoding="utf-8") as fh:
fh.write("\n".join([dict2BibTeX(i) for i in data]))
def edit(filename, identifier, data):
"""
Update an entry in a BibTeX file.
:param filename: The name of the BibTeX file to edit.
:param identifier: The id of the entry to update, in the BibTeX file.
:param data: A dict associating fields and updated values. Fields present \
in the BibTeX file but not in this dict will be kept as is.
"""
# Get current bibtex
with open(filename, 'r', encoding="utf-8") as fh:
bibtex = bibtexparser.load(fh)
bibtex = bibtex.entries_dict
# Update it
for k in data:
bibtex[identifier][k] = data[k]
# Write the resulting BibTeX
write(filename, bibtex)
def replace(filename, identifier, data):
"""
Replace an entry in a BibTeX file.
:param filename: The name of the BibTeX file to edit.
:param identifier: The id of the entry to replace, in the BibTeX file.
:param data: A dict representing a BibTeX entry, as the one from \
``bibtexparser`` output.
"""
# Get current bibtex
with open(filename, 'r', encoding="utf-8") as fh:
bibtex = bibtexparser.load(fh)
bibtex = bibtex.entries_dict
# Update the bibtex
bibtex[identifier] = data
# Write the resulting BibTeX
write(filename, bibtex)
def delete(filename, identifier):
"""
Delete an entry in a BibTeX file.
:param filename: The name of the BibTeX file to edit.
:param identifier: The id of the entry to delete, in the BibTeX file.
"""
# Get current bibtex
with open(filename, 'r', encoding="utf-8") as fh:
bibtex = bibtexparser.load(fh)
bibtex = bibtex.entries_dict
# Delete the bibtex entry
del(bibtex[identifier])
# Write the resulting BibTeX
write(filename, bibtex)
def get(filename, ignore_fields=[]):
"""
Get all entries from a BibTeX file.
:param filename: The name of the BibTeX file.
:param ignore_fields: An optional list of fields to strip from the BibTeX \
file.
:returns: A list of ``bibtexparser`` dicts representing the fetched \
entries.
"""
# Open bibtex file
with open(filename, 'r', encoding="utf-8") as fh:
bibtex = bibtexparser.load(fh)
bibtex = bibtex.entries_dict
# Clean the entry dict if necessary
bibtex = [{k: entry[k] for k in entry if k not in ignore_fields}
for entry in bibtex]
return bibtex
def get_entry(filename, identifier, ignore_fields=[]):
"""
Get an entry from a BibTeX file.
:param filename: The name of the BibTeX file.
:param identifier: An id of the entry to fetch, in the BibTeX file.
:param ignore_fields: An optional list of fields to strip from the BibTeX \
file.
:returns: A ``bibtexparser`` dict representing the fetched entry. \
``None`` if entry was not found.
"""
# Open bibtex file
with open(filename, 'r', encoding="utf-8") as fh:
bibtex = bibtexparser.load(fh)
bibtex = bibtex.entries_dict
try:
# Try to fetch the matching entry dict
entry = bibtex[identifier]
except KeyError:
# If none found, return None
return None
# Clean the entry dict if necessary
entry = {k: entry[k] for k in entry if k not in ignore_fields}
return entry
def to_filename(bibtex, mask=default_papers_filename_mask):
"""
Convert a bibtex entry to a formatted filename according to a given mask.
:param bibtex: A dict representing a BibTeX entry, as the one from \
``bibtexparser`` output.
:param mask: A Python format string.
:returns: A formatted filename.
"""
authors = re.split(' and ', bibtex['author'])
filename = mask
filename = filename.format(journal=bibtex.get("journal", default=""))
filename = filename.format(title=bibtex.get("title", default=""))
filename = filename.format(year=bibtex.get("year", default=""))
filename = filename.format(first=authors[0].split(',')[0].strip())
filename = filename.format(last=authors[-1].split(',')[0].strip())
filename = filename.format(authors=", ".join(
[i.split(',')[0].strip() for i in authors]))
arxiv_version = ""
if "eprint" in bibtex:
arxiv_version = '-' + bibtex['eprint'][bibtex['eprint'].rfind('v'):]
filename = filename.format(arxiv_version=arxiv_version)
return tools.slugify(filename)