Improves document handling.
- configuration is now referenced in repo object, - introduces new class PaperInRepo, - simplifies storage of documents in metadata, - changes a few names.
This commit is contained in:
parent
49821eab51
commit
2d700073a8
@ -1,7 +1,3 @@
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
from .. import repo
|
||||
from ..paper import Paper, NoDocumentFile
|
||||
from .. import files
|
||||
@ -27,30 +23,23 @@ def command(config, ui, bibpath, copy):
|
||||
if copy is None:
|
||||
copy = config.get('papers', 'import-copy')
|
||||
rp = repo.Repository.from_directory()
|
||||
# Get directory for document
|
||||
doc_path = files.clean_path(rp.get_document_directory(config))
|
||||
if not (os.path.exists(doc_path) and os.path.isdir(doc_path)):
|
||||
print "Document directory %s, does not exist." % doc_path
|
||||
sys.exit(1)
|
||||
# Extract papers from bib
|
||||
papers = Paper.many_from_path(bibpath, fatal=False)
|
||||
for p in papers:
|
||||
doc_file = None
|
||||
try:
|
||||
file_path = p.get_document_file_from_bibdata(remove=True)
|
||||
if os.path.exists(file_path):
|
||||
if files.check_file(file_path):
|
||||
doc_file = file_path
|
||||
else:
|
||||
print "File does not exist for %s." % p.citekey
|
||||
print("File does not exist for %s (%s)."
|
||||
% (p.citekey, file_path))
|
||||
except NoDocumentFile:
|
||||
print "No file for %s." % p.citekey
|
||||
rp.add_paper(p)
|
||||
if doc_file:
|
||||
if copy:
|
||||
ext = os.path.splitext(doc_file)[1]
|
||||
new_doc_file = os.path.join(doc_path, p.citekey + ext)
|
||||
shutil.copy(doc_file, new_doc_file)
|
||||
rp.import_document(p.citekey, doc_file)
|
||||
else:
|
||||
new_doc_file = doc_file
|
||||
p.set_document(new_doc_file)
|
||||
rp.add_or_update(p)
|
||||
p.set_external_document(doc_file)
|
||||
rp.add_or_update(p)
|
||||
|
@ -17,14 +17,10 @@ def command(config, ui, citekey):
|
||||
rp = repo.Repository.from_directory()
|
||||
paper = rp.paper_from_ref(citekey, fatal=True)
|
||||
try:
|
||||
if paper.check_file():
|
||||
filepath = paper.get_file_path()
|
||||
subprocess.Popen([config.get('papers', 'open-cmd'),
|
||||
filepath])
|
||||
print('{} opened.'.format(colored(filepath, 'filepath')))
|
||||
else:
|
||||
raise NoDocumentFile
|
||||
filepath = paper.get_document_path()
|
||||
subprocess.Popen([config.get('papers', 'open-cmd'), filepath])
|
||||
print("%s opened." % colored(filepath, 'filepath'))
|
||||
except NoDocumentFile:
|
||||
print('{}: No document associated to this entry {}{}{}'.format(
|
||||
colored('error', 'error'), colored('citekey', 'citekey')))
|
||||
print("%s: No document associated to this entry %s."
|
||||
% (colored('error', 'error'), colored(citekey, 'citekey')))
|
||||
exit(-1)
|
||||
|
@ -72,17 +72,15 @@ def name_from_path(fullpdfpath, verbose=False):
|
||||
return name, ext
|
||||
|
||||
|
||||
def check_file(filepath):
|
||||
if not os.path.exists(filepath):
|
||||
print(colored('error', 'error') +
|
||||
': {} does not exists'.format(
|
||||
colored(filepath, 'filepath')))
|
||||
exit(-1)
|
||||
if not os.path.isfile(filepath):
|
||||
print(colored('error', 'error')
|
||||
+ ': {} is not a file'.format(
|
||||
colored(filepath, 'filepath')))
|
||||
exit(-1)
|
||||
def check_file(path, fail=False):
|
||||
if fail:
|
||||
if not os.path.exists(path):
|
||||
raise(IOError, "File does not exist: %s." % path)
|
||||
if not os.path.isfile(path):
|
||||
raise(IOError, "%s is not a file." % path)
|
||||
return True
|
||||
else:
|
||||
return os.path.exists(path) and os.path.isfile(path)
|
||||
|
||||
|
||||
# yaml I/O
|
||||
@ -99,7 +97,7 @@ def write_yamlfile(filepath, datamap):
|
||||
|
||||
|
||||
def read_yamlfile(filepath):
|
||||
check_file(filepath)
|
||||
check_file(filepath, fail=True)
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return yaml.load(f)
|
||||
@ -131,8 +129,7 @@ def load_meta(filepath):
|
||||
# specific to bibliography data
|
||||
|
||||
def load_externalbibfile(fullbibpath):
|
||||
check_file(fullbibpath)
|
||||
|
||||
check_file(fullbibpath, fail=True)
|
||||
filename, ext = os.path.splitext(os.path.split(fullbibpath)[1])
|
||||
if ext[1:] in FORMATS.keys():
|
||||
with open(fullbibpath) as f:
|
||||
|
109
papers/paper.py
109
papers/paper.py
@ -1,6 +1,9 @@
|
||||
import os
|
||||
|
||||
import unicodedata
|
||||
import re
|
||||
from cStringIO import StringIO
|
||||
import glob
|
||||
|
||||
from pybtex.database import Entry, BibliographyData
|
||||
|
||||
@ -16,9 +19,7 @@ CITEKEY_EXCLUDE_RE = re.compile('[%s]'
|
||||
% re.escape(CONTROL_CHARS + CITEKEY_FORBIDDEN_CHARS))
|
||||
|
||||
BASE_META = {
|
||||
'filename': None,
|
||||
'extension': None,
|
||||
'path': None,
|
||||
'external-document': None,
|
||||
'notes': []
|
||||
}
|
||||
|
||||
@ -30,6 +31,31 @@ def str2citekey(s):
|
||||
return key
|
||||
|
||||
|
||||
def get_bibentry_from_file(bibfile):
|
||||
"""Extract first entry (supposed to be the only one) from given file.
|
||||
"""
|
||||
bib_data = files.load_externalbibfile(bibfile)
|
||||
first_key = bib_data.entries.keys()[0]
|
||||
first_entry = bib_data.entries[first_key]
|
||||
return first_key, first_entry
|
||||
|
||||
|
||||
def get_bibentry_from_string(content):
|
||||
"""Extract first entry (supposed to be the only one) from given file.
|
||||
"""
|
||||
bib_data = files.parse_bibdata(StringIO(content))
|
||||
first_key = bib_data.entries.keys()[0]
|
||||
first_entry = bib_data.entries[first_key]
|
||||
return first_key, first_entry
|
||||
|
||||
|
||||
def get_safe_metadata(metapath):
|
||||
if metapath is None:
|
||||
return None
|
||||
else:
|
||||
return files.read_yamlfile(metapath)
|
||||
|
||||
|
||||
class NoDocumentFile(Exception):
|
||||
pass
|
||||
|
||||
@ -69,20 +95,22 @@ class Paper(object):
|
||||
|
||||
# TODO add mechanism to verify keys (15/12/2012)
|
||||
|
||||
def has_file(self):
|
||||
"""Whether there exist a document file for this entry.
|
||||
"""
|
||||
return self.metadata['path'] is not None
|
||||
|
||||
def get_file_path(self):
|
||||
if self.has_file():
|
||||
return self.metadata['path']
|
||||
def get_external_document_path(self):
|
||||
if self.metadata['external-document'] is not None:
|
||||
return self.metadata['external-document']
|
||||
else:
|
||||
raise NoDocumentFile
|
||||
|
||||
def check_file(self):
|
||||
path = self.get_file_path()
|
||||
return os.path.exists(path) and os.path.isfile(path)
|
||||
def get_document_path(self):
|
||||
return self.get_external_document_path()
|
||||
|
||||
def set_external_document(self, docpath):
|
||||
fullpdfpath = os.path.abspath(docpath)
|
||||
files.check_file(fullpdfpath, fail=True)
|
||||
self.metadata['external-document'] = fullpdfpath
|
||||
|
||||
def check_document_path(self):
|
||||
return files.check_file(self.get_external_document_path())
|
||||
|
||||
def generate_citekey(self):
|
||||
"""Generate a citekey from bib_data.
|
||||
@ -105,14 +133,6 @@ class Paper(object):
|
||||
citekey = u'{}{}'.format(u''.join(first_author.last()), year)
|
||||
return str2citekey(citekey)
|
||||
|
||||
def set_document(self, docpath):
|
||||
fullpdfpath = os.path.abspath(docpath)
|
||||
files.check_file(fullpdfpath)
|
||||
name, ext = files.name_from_path(docpath)
|
||||
self.metadata['filename'] = name
|
||||
self.metadata['extension'] = ext
|
||||
self.metadata['path'] = fullpdfpath
|
||||
|
||||
def save_to_disc(self, bib_filepath, meta_filepath):
|
||||
"""Creates a BibliographyData object containing a single entry and
|
||||
saves it to disc.
|
||||
@ -150,23 +170,11 @@ class Paper(object):
|
||||
|
||||
@classmethod
|
||||
def load(cls, bibpath, metapath=None):
|
||||
key, entry = cls.get_bibentry(bibpath)
|
||||
if metapath is None:
|
||||
metadata = None
|
||||
else:
|
||||
metadata = files.read_yamlfile(metapath)
|
||||
key, entry = get_bibentry_from_file(bibpath)
|
||||
metadata = get_safe_metadata(metapath)
|
||||
p = Paper(bibentry=entry, metadata=metadata, citekey=key)
|
||||
return p
|
||||
|
||||
@classmethod
|
||||
def get_bibentry(cls, bibfile):
|
||||
"""Extract first entry (supposed to be the only one) from given file.
|
||||
"""
|
||||
bib_data = files.load_externalbibfile(bibfile)
|
||||
first_key = bib_data.entries.keys()[0]
|
||||
first_entry = bib_data.entries[first_key]
|
||||
return first_key, first_entry
|
||||
|
||||
@classmethod
|
||||
def create_meta(cls):
|
||||
return BASE_META.copy()
|
||||
@ -194,3 +202,32 @@ class Paper(object):
|
||||
except ValueError, e:
|
||||
print "Warning, skipping paper (%s)." % e
|
||||
return papers
|
||||
|
||||
|
||||
class PaperInRepo(Paper):
|
||||
|
||||
def __init__(self, repo, *args, **kwargs):
|
||||
Paper.__init__(self, *args, **kwargs)
|
||||
self.repo = repo
|
||||
|
||||
def get_document_path_in_repo(self):
|
||||
doc_dir = files.clean_path(self.repo.get_document_directory())
|
||||
found = glob.glob(doc_dir + "/%s.*" % self.citekey)
|
||||
if found:
|
||||
return found[0]
|
||||
else:
|
||||
raise NoDocumentFile
|
||||
|
||||
def get_document_path(self):
|
||||
try:
|
||||
return self.get_document_path_in_repo()
|
||||
except NoDocumentFile:
|
||||
return self.get_external_document_path()
|
||||
|
||||
@classmethod
|
||||
def load(cls, repo, bibpath, metapath=None):
|
||||
key, entry = get_bibentry_from_file(bibpath)
|
||||
metadata = get_safe_metadata(metapath)
|
||||
p = PaperInRepo(repo, bibentry=entry, metadata=metadata,
|
||||
citekey=key)
|
||||
return p
|
||||
|
@ -14,12 +14,14 @@ def person_repr(p):
|
||||
|
||||
|
||||
def short_authors(bibentry):
|
||||
authors = [person_repr(p) for p in bibentry.persons['author']]
|
||||
if len(authors) < 3:
|
||||
return ', '.join(authors)
|
||||
else:
|
||||
return authors[0] + (' et al.' if len(authors) > 1 else '')
|
||||
|
||||
try:
|
||||
authors = [person_repr(p) for p in bibentry.persons['author']]
|
||||
if len(authors) < 3:
|
||||
return ', '.join(authors)
|
||||
else:
|
||||
return authors[0] + (' et al.' if len(authors) > 1 else '')
|
||||
except KeyError: # When no author is defined
|
||||
return ''
|
||||
|
||||
def bib_oneliner(bibentry):
|
||||
authors = short_authors(bibentry)
|
||||
|
@ -1,8 +1,10 @@
|
||||
from .color import colored
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import files
|
||||
from paper import Paper
|
||||
from paper import Paper, PaperInRepo
|
||||
from color import colored
|
||||
import configs
|
||||
|
||||
|
||||
ALPHABET = 'abcdefghijklmopqrstuvwxyz'
|
||||
@ -14,16 +16,20 @@ DOC_DIR = 'doc'
|
||||
|
||||
class Repository(object):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, config=None):
|
||||
self.papersdir = None
|
||||
self.citekeys = []
|
||||
if config is None:
|
||||
config = configs.CONFIG
|
||||
self.config = config
|
||||
|
||||
# loading existing papers
|
||||
|
||||
def paper_from_citekey(self, citekey):
|
||||
"""Load a paper by its citekey from disk, if necessary."""
|
||||
return Paper.load(self.path_to_paper_file(citekey, 'bib'),
|
||||
metapath=self.path_to_paper_file(citekey, 'meta'))
|
||||
return PaperInRepo.load(
|
||||
self, self.path_to_paper_file(citekey, 'bib'),
|
||||
metapath=self.path_to_paper_file(citekey, 'meta'))
|
||||
|
||||
def citekey_from_ref(self, ref, fatal=True):
|
||||
"""Tries to get citekey from given ref.
|
||||
@ -48,9 +54,11 @@ class Repository(object):
|
||||
|
||||
# creating new papers
|
||||
|
||||
# Deprecated
|
||||
# TODO merge
|
||||
def add_paper_from_paths(self, docpath, bibpath):
|
||||
p = Paper.load(bibpath)
|
||||
p.set_document(docpath)
|
||||
p.set_external_document(docpath)
|
||||
self.add_paper(p)
|
||||
|
||||
def add_paper(self, p):
|
||||
@ -73,6 +81,15 @@ class Repository(object):
|
||||
else:
|
||||
self.save_paper(paper)
|
||||
|
||||
def remove(self, citekey):
|
||||
self.citetekeys.remove(citekey)
|
||||
paper = self.paper_from_citekey(citekey)
|
||||
for f in ('bib', 'meta'):
|
||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
||||
# TODO change
|
||||
if paper.metadata['in-repo']:
|
||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
||||
|
||||
def save_paper(self, paper):
|
||||
if not paper.citekey in self.citekeys:
|
||||
raise(ValueError('Paper not in repository, first add it.'))
|
||||
@ -117,9 +134,9 @@ class Repository(object):
|
||||
else:
|
||||
raise(ValueError("%s is not a valid paper file." % file_))
|
||||
|
||||
def get_document_directory(self, config):
|
||||
if config.has_option('papers', 'document-directory'):
|
||||
return config.get('papers', 'document-directory')
|
||||
def get_document_directory(self):
|
||||
if self.config.has_option('papers', 'document-directory'):
|
||||
return self.config.get('papers', 'document-directory')
|
||||
else:
|
||||
return os.path.join(self.papersdir, DOC_DIR)
|
||||
|
||||
@ -127,6 +144,18 @@ class Repository(object):
|
||||
for key in self.citekeys:
|
||||
yield self.paper_from_citekey(key)
|
||||
|
||||
def import_document(self, citekey, doc_file):
|
||||
if citekey not in self.citekeys:
|
||||
raise(ValueError, "Unknown citekey: %s." % citekey)
|
||||
else:
|
||||
doc_path = self.get_document_directory()
|
||||
if not (os.path.exists(doc_path) and os.path.isdir(doc_path)):
|
||||
raise(ValueError,
|
||||
"Document directory %s, does not exist." % doc_path)
|
||||
ext = os.path.splitext(doc_file)[1]
|
||||
new_doc_file = os.path.join(doc_path, citekey + ext)
|
||||
shutil.copy(doc_file, new_doc_file)
|
||||
|
||||
@classmethod
|
||||
def from_directory(cls, papersdir=None):
|
||||
repo = cls()
|
||||
|
Loading…
x
Reference in New Issue
Block a user