From 3af75908273e066f4493bbcc0925527139f169a0 Mon Sep 17 00:00:00 2001 From: Olivier Mangin Date: Thu, 20 Dec 2012 17:56:34 +0100 Subject: [PATCH] Adds basic import command with document file copy. Still lot to be improve on ui and features. --- papers/commands/__init__.py | 1 + papers/commands/import_cmd.py | 55 +++++++++++++++++++++++++++++++++++ papers/commands/open_cmd.py | 1 - papers/configs.py | 32 ++++++++++++++++++++ papers/files.py | 7 ++++- papers/paper.py | 46 ++++++++++++++++++++++++----- papers/papers | 9 ++---- papers/repo.py | 13 +++++++-- 8 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 papers/commands/import_cmd.py create mode 100644 papers/configs.py diff --git a/papers/commands/__init__.py b/papers/commands/__init__.py index 5b9cdd1..af89798 100644 --- a/papers/commands/__init__.py +++ b/papers/commands/__init__.py @@ -1,5 +1,6 @@ import add_cmd import add_library_cmd +import import_cmd import init_cmd import list_cmd import open_cmd diff --git a/papers/commands/import_cmd.py b/papers/commands/import_cmd.py new file mode 100644 index 0000000..0844c43 --- /dev/null +++ b/papers/commands/import_cmd.py @@ -0,0 +1,55 @@ +import os +import sys +import shutil + +from .. import repo +from ..paper import Paper, NoDocumentFile + + +def parser(subparsers, config): + parser = subparsers.add_parser('import', + help='import paper(s) to the repository') + parser.add_argument('bibpath', + help='path to bibtex, bibtexml or bibyaml file (or directory)') + parser.add_argument('-c', '--copy', action='store_true', default=None, + help="copy document files into library directory (default)") + parser.add_argument('-C', '--nocopy', action='store_false', dest='copy', + help="don't copy document files (opposite of -c)") + return parser + + +def command(config, bibpath, copy): + """ + :param pdffilepath path (no url yet) to a pdf or ps file + :param bibtex bibtex file (in .bib, .bibml or .yaml format. + """ + if copy is None: + copy = config.get('papers', 'import-copy') + rp = repo.Repository.from_directory() + # Get directory for document + doc_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) + for p in papers: + doc_file = None + try: + file_path = p.get_document_file_from_bibdata(remove=True) + if os.path.exists(file_path): + doc_file = file_path + else: + print "File does not exist for %s." % p.citekey + 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) + else: + new_doc_file = doc_file + p.set_document(new_doc_file) + rp.add_or_update(p) diff --git a/papers/commands/open_cmd.py b/papers/commands/open_cmd.py index 299c965..a820ce4 100644 --- a/papers/commands/open_cmd.py +++ b/papers/commands/open_cmd.py @@ -12,7 +12,6 @@ def parser(subparsers, config): def command(config, citekey): - print config.get('papers', 'open-cmd') rp = repo.Repository.from_directory() paper = rp.paper_from_any(citekey, fatal=True) try: diff --git a/papers/configs.py b/papers/configs.py new file mode 100644 index 0000000..39c22ea --- /dev/null +++ b/papers/configs.py @@ -0,0 +1,32 @@ +import os +import ConfigParser + + +DEFAULT_OPEN_CMD = 'open' +DEFAULT_EDIT_CMD = 'vim' + +DEFAULT_IMPORT_COPY = 'yes' +DEFAULT_IMPORT_MOVE = 'no' + +CONFIG = ConfigParser.SafeConfigParser({ + 'open-cmd': DEFAULT_OPEN_CMD, + 'edit-cmd': DEFAULT_EDIT_CMD, + 'import-copy': DEFAULT_IMPORT_COPY, + 'import-move': DEFAULT_IMPORT_MOVE, + }) +CONFIG.add_section('papers') + + +def read_config(): + CONFIG.read(os.path.expanduser('~/.papersrc')) + return CONFIG + + +def get_boolean(value, default): + value = str(value).lower() + if value in ('yes', 'true', 't', 'y', '1'): + return True + elif value in ('no', 'false', 'f', 'n', '0'): + return False + else: + return 0 diff --git a/papers/files.py b/papers/files.py index 9b5d529..8f74fdc 100644 --- a/papers/files.py +++ b/papers/files.py @@ -29,13 +29,18 @@ try: EDITOR = os.environ['EDITOR'] except KeyError: EDITOR = 'nano' +BIB_EXTENSIONS = ['.bib', '.bibyaml', '.bibml', '.yaml'] + + +def clean_path(path): + return os.path.abspath(os.path.expanduser(path)) def find_papersdir(): """Find .papers directory in this directory and the parent directories""" global _papersdir if _papersdir is None: - curdir = os.path.abspath(os.getcwd()) + curdir = os.path.abspath('') while curdir != '': if (os.path.exists(curdir + '/.papers') and os.path.isdir(curdir + '/.papers')): diff --git a/papers/paper.py b/papers/paper.py index ab27a47..f7353fa 100644 --- a/papers/paper.py +++ b/papers/paper.py @@ -105,10 +105,10 @@ class Paper(object): citekey = u'{}{}'.format(u''.join(first_author.last()), year) return str2citekey(citekey) - def set_pdf(self, pdfpath): - fullpdfpath = os.path.abspath(pdfpath) + def set_document(self, docpath): + fullpdfpath = os.path.abspath(docpath) files.check_file(fullpdfpath) - name, ext = files.name_from_path(pdfpath) + name, ext = files.name_from_path(docpath) self.metadata['filename'] = name self.metadata['extension'] = ext self.metadata['path'] = fullpdfpath @@ -124,6 +124,30 @@ class Paper(object): files.save_bibdata(bibdata, bib_filepath) files.save_meta(self.metadata, meta_filepath) + def get_document_file_from_bibdata(self, remove=False): + """Try extracting document file from bib data. + Raises NoDocumentFile if not found. + + Parameters: + ----------- + remove: default: False + remove field after extracting information + """ + try: + field = self.bibentry.fields['file'] + # Check if this is mendeley specific + for f in field.split(':'): + if len(f) > 0: + break + if remove: + self.bibentry.fields.pop('file') + # This is a hck for Mendeley. Make clean + if f[0] != '/': + f = '/' + f + return f + except (KeyError, IndexError): + raise(NoDocumentFile('No file found in bib data.')) + @classmethod def load(cls, bibpath, metapath=None): key, entry = cls.get_bibentry(bibpath) @@ -148,7 +172,15 @@ class Paper(object): return BASE_META.copy() @classmethod - def many_from_bib(cls, bibpath): - bib_data = files.load_externalbibfile(bibpath) - return [Paper(bibentry=bib_data.entries[k], citekey=k) - for k in bib_data.entries] + def many_from_path(cls, bibpath): + """Extract list of papers found in bibliographic files in path. + """ + bibpath = files.clean_path(bibpath) + if os.path.isdir(bibpath): + all_files = [os.path.join(bibpath, f) for f in os.listdir(bibpath) + if os.path.splitext(f)[-1] in files.BIB_EXTENSIONS] + else: + all_files = [bibpath] + bib_data = [files.load_externalbibfile(f) for f in all_files] + return [Paper(bibentry=b.entries[k], citekey=k) + for b in bib_data for k in b.entries] diff --git a/papers/papers b/papers/papers index f91673b..01ef4a8 100755 --- a/papers/papers +++ b/papers/papers @@ -6,24 +6,21 @@ import os import argparse import collections -import ConfigParser +from papers import configs from papers import commands cmds = collections.OrderedDict([ ('init', commands.init_cmd), ('add', commands.add_cmd), ('add_library', commands.add_library_cmd), + ('import', commands.import_cmd), ('list', commands.list_cmd), ('open', commands.open_cmd), ('websearch', commands.websearch_cmd) ]) -config = ConfigParser.SafeConfigParser() -config.add_section('papers') -config.set('papers', 'open-cmd', 'open') -config.set('papers', 'edit-cmd', 'vim') -config.read(os.path.expanduser('~/.papersrc')) +config = configs.read_config() parser = argparse.ArgumentParser(description="research papers repository") subparsers = parser.add_subparsers(title="valid commands", dest="command") diff --git a/papers/repo.py b/papers/repo.py index 0eb0003..810a444 100644 --- a/papers/repo.py +++ b/papers/repo.py @@ -9,6 +9,7 @@ ALPHABET = 'abcdefghijklmopqrstuvwxyz' BASE_FILE = 'papers.yaml' BIB_DIR = 'bibdata' META_DIR = 'meta' +DOC_DIR = 'doc' class Repository(object): @@ -60,9 +61,9 @@ class Repository(object): # creating new papers - def add_paper_from_paths(self, pdfpath, bibpath): + def add_paper_from_paths(self, docpath, bibpath): p = Paper.load(bibpath) - p.set_pdf(pdfpath) + p.set_document(docpath) self.add_paper(p) def add_paper(self, p): @@ -83,7 +84,7 @@ class Repository(object): if not paper.citekey in self.citekeys: self.add_paper(paper) else: - paper.save_paper(paper) + self.save_paper(paper) def save_paper(self, paper): if not paper.citekey in self.citekeys: @@ -129,6 +130,12 @@ 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') + else: + return os.path.join(self.papersdir, DOC_DIR) + @classmethod def from_directory(cls, papersdir=None): repo = cls()