You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
5.6 KiB

"""
This module can't depend on configs.
If you feel the need to import configs, you are not in the right place.
"""
from __future__ import print_function
import os
import subprocess
import tempfile
from .p3 import io
from io import StringIO
import yaml
from . import ui
from . import color
try:
import pybtex
import pybtex.database
import pybtex.database.input
import pybtex.database.input.bibtex
import pybtex.database.input.bibtexml
import pybtex.database.input.bibyaml
import pybtex.database.output
import pybtex.database.output.bibtex
import pybtex.database.output.bibtexml
import pybtex.database.output.bibyaml
except ImportError:
print(color.dye('error', color.error) +
": you need to install Pybtex; try running 'pip install "
"pybtex' or 'easy_install pybtex'")
exit(-1)
_papersdir = None
BIB_EXTENSIONS = ['.bib', '.bibyaml', '.bibml', '.yaml']
FORMATS_INPUT = {'bib' : pybtex.database.input.bibtex,
'xml' : pybtex.database.input.bibtexml,
'yml' : pybtex.database.input.bibyaml,
'yaml' : pybtex.database.input.bibyaml,
'bibyaml': pybtex.database.input.bibyaml}
FORMATS_OUTPUT = {'bib' : pybtex.database.output.bibtex,
'bibtex' : pybtex.database.output.bibtex,
'xml' : pybtex.database.output.bibtexml,
'yml' : pybtex.database.output.bibyaml,
'yaml' : pybtex.database.output.bibyaml,
'bibyaml': pybtex.database.output.bibyaml}
def clean_path(*args):
return os.path.abspath(os.path.expanduser(os.path.join(*args)))
def name_from_path(fullpdfpath, verbose=False):
name, ext = os.path.splitext(os.path.split(fullpdfpath)[1])
if verbose:
if ext != '.pdf' and ext != '.ps':
print('{}: extension {} not recognized'.format(
color.dye('warning', color.warning),
color.dye(ext, color.cyan)))
return name, ext
def check_file(path, fail=False):
if fail:
if not os.path.exists(path):
raise IOError("File does not exist: {}.".format(path))
if not os.path.isfile(path):
raise IOError("{} is not a file.".format(path))
return True
else:
return os.path.exists(path) and os.path.isfile(path)
# yaml I/O
def write_yamlfile(filepath, datamap):
try:
with open(filepath, 'w') as f:
yaml.dump(datamap, f)
except IOError:
print('{}: impossible to read or write on file {}'.format(
color.dye('error', color.error),
color.dye(filepath, color.filepath)))
exit(-1)
def read_yamlfile(filepath):
check_file(filepath, fail=True)
try:
with open(filepath, 'r') as f:
return yaml.load(f)
except IOError:
print('{}: impossible to read file {}'.format(
color.dye('error', color.error),
color.dye(filepath, color.filepath)))
exit(-1)
def load_bibdata(filename, filepath):
return load_externalbibfile(filepath)
def write_bibdata(bib_data, file_, format_):
writer = FORMATS_OUTPUT[format_].Writer()
writer.write_stream(bib_data, file_)
def save_bibdata(bib_data, filepath):
with open(filepath, 'w') as f:
write_bibdata(bib_data, f, 'yaml')
def save_meta(meta_data, filepath):
new_meta = meta_data.copy()
# Cannot store sets in yaml
new_meta['tags'] = list(new_meta['tags'])
write_yamlfile(filepath, new_meta)
# is this function ever used? 08/06/2013
def load_meta(filepath):
return read_yamlfile(filepath)
# specific to bibliography data
def load_externalbibfile(fullbibpath):
check_file(fullbibpath, fail=True)
filename, ext = os.path.splitext(os.path.split(fullbibpath)[1])
if ext[1:] in list(FORMATS_INPUT.keys()):
with open(fullbibpath) as f:
return _parse_bibdata_formated_stream(f, ext[1:])
else:
print('{}: {} not recognized format for bibliography'.format(
color.dye('error', color.error),
color.dye(ext, color.cyan)))
exit(-1)
def _parse_bibdata_formated_stream(stream, fmt):
"""Parse a stream for bibdata, using the supplied format."""
try:
parser = FORMATS_INPUT[fmt].Parser()
data = parser.parse_stream(stream)
if len(list(data.entries.keys())) > 0:
return data
except Exception:
pass
raise ValueError('content format is not recognized.')
def parse_bibdata(content, format_ = None):
"""Parse bib data from string or stream.
Raise ValueError if no bibdata is present.
:content: stream
:param format_: (bib|xml|yml) if format is None, tries to recognize the
format automatically.
"""
fmts = [format_]
if format_ is None:
fmts = FORMATS_INPUT.keys()
# we need to reuse the content
content = content if type(content) == str else str(content.read())
for fmt in fmts:
try:
return _parse_bibdata_formated_stream(StringIO(content), fmt)
except Exception:
pass
raise ValueError('content format is not recognized.')
def editor_input(editor, initial="", suffix=None):
"""Use an editor to get input"""
if suffix is None:
suffix = '.tmp'
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as temp_file:
tfile_name = temp_file.name
temp_file.write(initial)
temp_file.flush()
subprocess.call([editor, tfile_name])
with open(tfile_name) as temp_file:
content = temp_file.read()
os.remove(tfile_name)
return content