From 105ae292b90c8658a831695ae41d20ea7602bf75 Mon Sep 17 00:00:00 2001 From: Olivier Mangin Date: Wed, 19 Jun 2013 16:35:41 +0200 Subject: [PATCH] Support for many references and refactor. - Moves shared command code to helpers module. - Implements reference(s) argument for commands: + a helper to add single or multi-reference argument to parser, + two functions to transform this argument into a list of citekeys. --- papers/commands/add_cmd.py | 23 +---------------- papers/commands/edit_cmd.py | 8 +++--- papers/commands/export_cmd.py | 10 ++++++-- papers/commands/helpers.py | 48 +++++++++++++++++++++++++++++++++++ papers/commands/import_cmd.py | 2 +- papers/commands/open_cmd.py | 11 ++++---- papers/commands/remove_cmd.py | 17 +++++++------ papers/repo.py | 20 +++++++-------- 8 files changed, 86 insertions(+), 53 deletions(-) create mode 100644 papers/commands/helpers.py diff --git a/papers/commands/add_cmd.py b/papers/commands/add_cmd.py index 4256121..41d4126 100644 --- a/papers/commands/add_cmd.py +++ b/papers/commands/add_cmd.py @@ -2,28 +2,7 @@ from .. import repo from .. import files from ..paper import Paper, NoDocumentFile, get_bibentry_from_string from .. import configs - - -def add_paper_with_docfile(repo, paper, docfile=None, copy=False): - repo.add_paper(paper) - if docfile is not None: - if copy: - repo.import_document(paper.citekey, docfile) - else: - paper.set_external_document(docfile) - repo.add_or_update(paper) - - -def extract_doc_path_from_bibdata(paper, ui): - try: - file_path = paper.get_document_file_from_bibdata(remove=True) - if files.check_file(file_path): - return file_path - else: - ui.warning("File does not exist for %s (%s)." - % (paper.citekey, file_path)) - except NoDocumentFile: - return None +from .helpers import add_paper_with_docfile, extract_doc_path_from_bibdata def parser(subparsers, config): diff --git a/papers/commands/edit_cmd.py b/papers/commands/edit_cmd.py index 7aec8d5..d055150 100644 --- a/papers/commands/edit_cmd.py +++ b/papers/commands/edit_cmd.py @@ -1,21 +1,21 @@ from ..files import editor_input from .. import repo from ..paper import get_bibentry_from_string, get_safe_metadata_from_content +from .helpers import add_references_argument, parse_reference def parser(subparsers, config): parser = subparsers.add_parser('edit', help='open the paper bibliographic file in an editor') - parser.add_argument('reference', - help='reference to the paper (citekey or number)') parser.add_argument('-m', '--meta', action='store_true', default=False, help='edit metadata') + add_references_argument(parser, single=True) return parser -def command(config, ui, reference, meta): +def command(config, ui, meta, reference): rp = repo.Repository.from_directory(config) - key = rp.citekey_from_ref(reference, fatal=True) + key = parse_reference(ui, rp, reference) paper = rp.paper_from_citekey(key) to_edit = 'bib' if meta: diff --git a/papers/commands/export_cmd.py b/papers/commands/export_cmd.py index edf4ee0..f995f49 100644 --- a/papers/commands/export_cmd.py +++ b/papers/commands/export_cmd.py @@ -4,6 +4,7 @@ from pybtex.database import BibliographyData from .. import repo from .. import files +from .helpers import parse_references, add_references_argument def parser(subparsers, config): @@ -11,16 +12,21 @@ def parser(subparsers, config): help='export bibliography') parser.add_argument('-f', '--bib-format', default='bibtex', help="export format") + add_references_argument(parser) return parser -def command(config, ui, bib_format): +def command(config, ui, bib_format, references): """ :param bib_format (in 'bibtex', 'yaml') """ rp = repo.Repository.from_directory(config) + papers = [rp.paper_from_citekey(c) + for c in parse_references(ui, rp, references)] + if len(papers) == 0: + papers = rp.all_papers() bib = BibliographyData() - for p in rp.all_papers(): + for p in papers: bib.add_entry(p.citekey, p.bibentry) try: files.write_bibdata(bib, sys.stdout, bib_format) diff --git a/papers/commands/helpers.py b/papers/commands/helpers.py new file mode 100644 index 0000000..586f64d --- /dev/null +++ b/papers/commands/helpers.py @@ -0,0 +1,48 @@ +from .. import files +from .. import color +from ..repo import InvalidReference + + +def add_references_argument(parser, single=False): + if single: + parser.add_argument('reference', + help='reference to the paper (citekey or number)') + else: + parser.add_argument('references', nargs='*', + help="one or several reference to export (citekeysor numbers)") + + +def add_paper_with_docfile(repo, paper, docfile=None, copy=False): + repo.add_paper(paper) + if docfile is not None: + if copy: + repo.import_document(paper.citekey, docfile) + else: + paper.set_external_document(docfile) + repo.add_or_update(paper) + + +def extract_doc_path_from_bibdata(paper, ui): + try: + file_path = paper.get_document_file_from_bibdata(remove=True) + if files.check_file(file_path): + return file_path + else: + ui.warning("File does not exist for %s (%s)." + % (paper.citekey, file_path)) + except NoDocumentFile: + return None + + +def parse_reference(ui, rp, ref): + try: + return rp.citekey_from_ref(ref) + except InvalidReference: + ui.error("no paper with reference: %s." + % color.dye(ref, color.citekey)) + ui.exit(-1) + + +def parse_references(ui, rp, refs): + citekeys = [parse_reference(ui, rp, ref) for ref in refs] + return citekeys diff --git a/papers/commands/import_cmd.py b/papers/commands/import_cmd.py index d6cf496..bb2a3cd 100644 --- a/papers/commands/import_cmd.py +++ b/papers/commands/import_cmd.py @@ -1,6 +1,6 @@ from .. import repo from ..paper import Paper -from add_cmd import add_paper_with_docfile, extract_doc_path_from_bibdata +from .helpers import add_paper_with_docfile, extract_doc_path_from_bibdata from .. import configs diff --git a/papers/commands/open_cmd.py b/papers/commands/open_cmd.py index 21cc92b..f4cd142 100644 --- a/papers/commands/open_cmd.py +++ b/papers/commands/open_cmd.py @@ -4,6 +4,7 @@ from .. import repo from ..paper import NoDocumentFile from .. import configs from .. import color +from .helpers import add_references_argument, parse_reference def parser(subparsers, config): @@ -11,14 +12,14 @@ def parser(subparsers, config): help='open the paper in a pdf viewer') parser.add_argument('-w', '--with', dest='with_command', default=None, help='command to use to open the document file') - parser.add_argument('citekey', - help='the paper associated citekey') + add_references_argument(parser, single=True) return parser -def command(config, ui, with_command, citekey): +def command(config, ui, with_command, reference): rp = repo.Repository.from_directory(config) - paper = rp.paper_from_ref(citekey, fatal=True) + key = parse_reference(ui, rp, reference) + paper = rp.paper_from_citekey(key) if with_command is None: with_command = config.get(configs.MAIN_SECTION, 'open-cmd') try: @@ -27,7 +28,7 @@ def command(config, ui, with_command, citekey): ui.print_('{} opened.'.format(color.dye(filepath, color.filepath))) except NoDocumentFile: ui.error('No document associated with the entry {}.'.format( - color.dye(citekey, color.citekey))) + color.dye(key, color.citekey))) ui.exit() except OSError: ui.error("Command does not exist: %s." % with_command) diff --git a/papers/commands/remove_cmd.py b/papers/commands/remove_cmd.py index 31d6985..a40e40a 100644 --- a/papers/commands/remove_cmd.py +++ b/papers/commands/remove_cmd.py @@ -1,20 +1,21 @@ from .. import repo from .. import color +from .helpers import add_references_argument, parse_references + def parser(subparsers, config): parser = subparsers.add_parser('remove', help='removes a paper') - parser.add_argument('reference', - help='reference to the paper (citekey or number)') + add_references_argument(parser) return parser -def command(config, ui, reference): +def command(config, ui, references): rp = repo.Repository.from_directory(config) - key = rp.citekey_from_ref(reference, fatal=True) - paper = rp.paper_from_citekey(key) - are_you_sure = ("Are you sure you want to delete paper [%s]" + citekeys = parse_references(ui, rp, references) + are_you_sure = ("Are you sure you want to delete paper(s) [%s]" " (this will also delete associated documents)?" - % color.dye(paper.citekey, color.citekey)) + % ', '.join([color.dye(c, color.citekey) for c in citekeys])) sure = ui.input_yn(question=are_you_sure, default='n') if sure: - rp.remove(paper.citekey) + for c in citekeys: + rp.remove(c) diff --git a/papers/repo.py b/papers/repo.py index d9335bd..db4b1a5 100644 --- a/papers/repo.py +++ b/papers/repo.py @@ -4,7 +4,6 @@ import glob from . import files from .paper import PaperInRepo, NoDocumentFile -from . import color from . import configs @@ -19,6 +18,10 @@ class CiteKeyAlreadyExists(Exception): pass +class InvalidReference(Exception): + pass + + class Repository(object): def __init__(self, config=None): @@ -37,7 +40,7 @@ class Repository(object): self, self.path_to_paper_file(citekey, 'bib'), metapath=self.path_to_paper_file(citekey, 'meta')) - def citekey_from_ref(self, ref, fatal=True): + def citekey_from_ref(self, ref): """Tries to get citekey from given ref. Ref can be a citekey or a number. """ @@ -47,15 +50,10 @@ class Repository(object): try: return self.citekeys[int(ref)] except (IndexError, ValueError): - if fatal: - print('{}: no paper with reference {}'.format( - color.dye('error', color.error), - color.dye(ref, color.citekey))) - exit(-1) - raise(IOError('file not found')) - - def paper_from_ref(self, ref, fatal=True): - key = self.citekey_from_ref(ref, fatal=fatal) + raise(InvalidReference) + + def paper_from_ref(self, ref): + key = self.citekey_from_ref(ref) return self.paper_from_citekey(key) # creating new papers