From 0d53619e1f9c6f4fe654c8ccd2119e753e3c2612 Mon Sep 17 00:00:00 2001 From: Olivier Mangin Date: Tue, 18 Dec 2012 16:48:40 +0100 Subject: [PATCH] Updates commands. Many bug fix. --- papers/commands/add_cmd.py | 2 +- papers/commands/add_library_cmd.py | 2 +- papers/commands/init_cmd.py | 7 +-- papers/commands/list_cmd.py | 9 ++-- papers/commands/open_cmd.py | 10 ++-- papers/commands/websearch_cmd.py | 4 +- papers/paper.py | 82 ++++++++++++++---------------- papers/pretty.py | 13 +++-- papers/repo.py | 27 +++++----- tests/test_paper.py | 2 +- 10 files changed, 76 insertions(+), 82 deletions(-) diff --git a/papers/commands/add_cmd.py b/papers/commands/add_cmd.py index 83ee256..750e600 100644 --- a/papers/commands/add_cmd.py +++ b/papers/commands/add_cmd.py @@ -12,5 +12,5 @@ def command(config, pdffile, bibfile): :param pdffilepath path (no url yet) to a pdf or ps file :param bibtex bibtex file (in .bib, .bibml or .yaml format. """ - rp = repo.Repository() + rp = repo.Repository.from_directory() rp.add_paper_from_paths(pdffile, bibfile) diff --git a/papers/commands/add_library_cmd.py b/papers/commands/add_library_cmd.py index ca744b7..883c720 100644 --- a/papers/commands/add_library_cmd.py +++ b/papers/commands/add_library_cmd.py @@ -11,5 +11,5 @@ def command(config, bibfile): """ :param bibtex bibtex file (in .bib, .bibml or .yaml format. """ - rp = repo.Repository() + rp = repo.Repository.from_directory() rp.add_papers(bibfile) diff --git a/papers/commands/init_cmd.py b/papers/commands/init_cmd.py index 3023d19..b85a448 100644 --- a/papers/commands/init_cmd.py +++ b/papers/commands/init_cmd.py @@ -1,17 +1,14 @@ # init command import os -try: - import ConfigParser as configparser -except ImportError: - import configparser from ..repo import Repository from .. import color def parser(subparsers, config): - parser = subparsers.add_parser('init', help="initialize the .papers directory") + parser = subparsers.add_parser('init', + help="initialize the .papers directory") return parser diff --git a/papers/commands/list_cmd.py b/papers/commands/list_cmd.py index 364099f..768a060 100644 --- a/papers/commands/list_cmd.py +++ b/papers/commands/list_cmd.py @@ -5,18 +5,19 @@ from .. import pretty from .. import color from .. import repo + def parser(subparsers, config): parser = subparsers.add_parser('list', help="list all papers") return parser + def command(config): - rp = repo.Repository() - + rp = repo.Repository.from_directory() articles = [] for n in range(rp.size()): paper = rp.paper_from_number(n, fatal=True) - bibdesc = pretty.bib_oneliner(paper.bib_data) - articles.append((u'{:3d} {}{}{}{} {}'.format(int(paper.number), color.purple, paper.citekey, color.end, (10 - len(paper.citekey))*' ', bibdesc)).encode('utf-8')) + bibdesc = pretty.bib_oneliner(paper.bibentry) + articles.append((u'{:3d} {}{}{}{} {}'.format(int(n), color.purple, rp.citekeys[n], color.end, (10 - len(paper.citekey))*' ', bibdesc)).encode('utf-8')) with tempfile.NamedTemporaryFile(suffix=".tmp", delete=True) as tmpf: tmpf.write('\n'.join(articles)) diff --git a/papers/commands/open_cmd.py b/papers/commands/open_cmd.py index b1dd0bf..6e7f31b 100644 --- a/papers/commands/open_cmd.py +++ b/papers/commands/open_cmd.py @@ -10,17 +10,17 @@ def parser(subparsers, config): return parser def command(config, citekey): - rp = repo.Repository() - paper = rp.paper_from_any(citekey, fatal = True) + rp = repo.Repository.from_directory() + paper = rp.paper_from_any(citekey, fatal=True) try: if paper.check_file(): filepath = paper.get_file_path() - - p = subprocess.Popen(['open', filepath]) + subprocess.Popen(['open', filepath]) print('{}{}{} opened.{}'.format( color.filepath, filepath, color.normal, color.end)) + else: + raise NoDocumentFile except NoDocumentFile: print('{}error{}: No document associated to this entry {}{}{}'.format( color.error, color.normal, color.citekey, citekey, color.end)) exit(-1) - diff --git a/papers/commands/websearch_cmd.py b/papers/commands/websearch_cmd.py index ba02037..c49f4af 100644 --- a/papers/commands/websearch_cmd.py +++ b/papers/commands/websearch_cmd.py @@ -1,11 +1,13 @@ import webbrowser import urllib + def parser(subparsers, config): parser = subparsers.add_parser('websearch', help="launch a search on Google Scholar") parser.add_argument("search_string", help="the search query (anything googly is possible)") return parser + def command(config, search_string): url = 'https://scholar.google.fr/scholar?q={}&lr='.format(urllib.quote_plus(search_string)) - webbrowser.open(url) \ No newline at end of file + webbrowser.open(url) diff --git a/papers/paper.py b/papers/paper.py index 9652fc9..38a42c1 100644 --- a/papers/paper.py +++ b/papers/paper.py @@ -5,8 +5,6 @@ import re from pybtex.database import Entry, BibliographyData import files -import color -import pretty DEFAULT_TYPE = 'article' @@ -17,6 +15,13 @@ CITEKEY_FORBIDDEN_CHARS = '@\'\\,#}{~%/' # '/' is OK for bibtex but forbidden CITEKEY_EXCLUDE_RE = re.compile('[%s]' % re.escape(CONTROL_CHARS + CITEKEY_FORBIDDEN_CHARS)) +BASE_META = { + 'filename': None, + 'extension': None, + 'path': None, + 'notes': [] + } + def str2citekey(s): key = unicodedata.normalize('NFKD', unicode(s)).encode('ascii', 'ignore') @@ -37,14 +42,6 @@ class Paper(object): biblography data and an additional dictionary to store meta data. """ -# @classmethod -# def from_bibpdffiles(cls, pdfpath, bibpath): -# bib_data = cls.import_bibdata(bibpath) -# name, meta = cls.create_meta(bib_data, pdfpath=pdfpath) -# p = Paper(name, bib_data = bib_data, metadata = meta) -# -# return p - def __init__(self, bibentry=None, metadata=None, citekey=None): if not bibentry: bibentry = Entry(DEFAULT_TYPE) @@ -54,7 +51,7 @@ class Paper(object): self.metadata = metadata # TODO This is not the right way to test that (17/12/2012) if unicode(citekey) != str2citekey(citekey): - raise(ValueError, "Wrong citekey: %s" % citekey) + raise(ValueError("Invalid citekey: %s" % citekey)) self.citekey = citekey def __eq__(self, other): @@ -84,7 +81,8 @@ class Paper(object): raise NoDocumentFile def check_file(self): - return files.check_file(self.get_file_path()) + path = self.get_file_path() + return os.path.exists(path) and os.path.isfile(path) def generate_citekey(self): """Generate a citekey from bib_data. @@ -98,8 +96,8 @@ class Paper(object): try: first_author = self.bibentry.persons[author_key][0] except KeyError: - raise(ValueError, - 'No author or editor defined: cannot generate a citekey.') + raise(ValueError( + 'No author or editor defined: cannot generate a citekey.')) try: year = self.bibentry.fields['year'] except KeyError: @@ -107,48 +105,44 @@ 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) + files.check_file(fullpdfpath) + name, ext = files.name_from_path(pdfpath) + 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. """ if self.citekey is None: - raise(ValueError, - 'No valid citekey initialized. Cannot save paper') + raise(ValueError( + 'No valid citekey initialized. Cannot save paper')) bibdata = BibliographyData(entries={self.citekey: self.bibentry}) files.save_bibdata(bibdata, bib_filepath) files.save_meta(self.metadata, meta_filepath) @classmethod - def load(cls, bibpath, metapath): - bib_data = files.load_externalbibfile(bibpath) - metadata = files.read_yamlfile(metapath) - # Extract first entry (supposed to be the only one) - first_key = bib_data.entries.keys()[0] - first_entry = bib_data.entries[first_key] - p = Paper(bibentry=first_entry, metadata=metadata, citekey=first_key) + def load(cls, bibpath, metapath=None): + key, entry = cls.get_bibentry(bibpath) + if metapath is None: + metadata = None + else: + metadata = files.read_yamlfile(metapath) + p = Paper(bibentry=entry, metadata=metadata, citekey=key) return p @classmethod - def import_bibdata(cls, bibfile): - """Import bibligraphic data from a .bibyaml, .bib or .bibtex file""" - fullbibpath = os.path.abspath(bibfile) - bib_data = files.load_externalbibfile(fullbibpath) - print('{}bibliographic data present in {}{}{}'.format( - color.grey, color.cyan, bibfile, color.end)) - print(pretty.bib_desc(bib_data)) - return bib_data + 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, pdfpath=None): - if pdfpath is None: - name, fullpdfpath, ext = None, None, None - else: - fullpdfpath = os.path.abspath(pdfpath) - files.check_file(fullpdfpath) - name, ext = files.name_from_path(pdfpath) - meta = {} - meta['filename'] = name # TODO remove ? - meta['extension'] = ext - meta['path'] = fullpdfpath - meta['notes'] = [] - return meta + def create_meta(cls): + return BASE_META.copy() diff --git a/papers/pretty.py b/papers/pretty.py index 5d6a637..fd1885a 100644 --- a/papers/pretty.py +++ b/papers/pretty.py @@ -9,16 +9,15 @@ def person_repr(p): ' '.join(p.last(abbr = False)), ' '.join(p.lineage(abbr = True))] if s) -def bib_oneliner(bib_data): - article = bib_data.entries[list(bib_data.entries.keys())[0]] - authors = ', '.join(person_repr(p) for p in article.persons['author']) - title = article.fields['title'] - year = article.fields.get('year', '') +def bib_oneliner(bibentry): + authors = ', '.join(person_repr(p) for p in bibentry.persons['author']) + title = bibentry.fields['title'] + year = bibentry.fields.get('year', '') journal = '' field = 'journal' - if article.type == 'inproceedings': + if bibentry.type == 'inproceedings': field = 'booktitle' - journal = article.fields.get(field, '') + journal = bibentry.fields.get(field, '') return u'{}{}{} \"{}{}{}\" {}{}{} {}({}{}{}){}'.format( color.green, authors, color.grey, color.bcyan, title, color.grey, color.yellow, journal, color.end, color.grey, color.end, year, diff --git a/papers/repo.py b/papers/repo.py index a315527..55a35ca 100644 --- a/papers/repo.py +++ b/papers/repo.py @@ -33,20 +33,20 @@ class Repository(object): color.error, color.normal, color.citekey, citekey, color.end)) exit(-1) - raise(IOError, 'file not found') + raise(IOError('file not found')) def paper_from_citekey(self, citekey, fatal=True): """Load a paper by its citekey from disk, if necessary.""" if citekey in self.citekeys: return Paper.load(self.path_to_paper_file(citekey, 'bib'), - self.path_to_paper_file(citekey, 'meta')) + metapath=self.path_to_paper_file(citekey, 'meta')) else: if fatal: print('{}error{}: no paper with citekey {}{}{}'.format( color.error, color.normal, color.citekey, citekey, color.end)) exit(-1) - raise(IOError, 'file not found') + raise(IOError('file not found')) def paper_from_any(self, key, fatal=True): try: @@ -59,20 +59,21 @@ class Repository(object): print('{}error{}: paper with citekey or number {}{}{} not found{}'.format( color.error, color.normal, color.citekey, key, color.normal, color.end)) exit(-1) - raise(IOError, 'file not found') + raise(IOError('file not found')) # creating new papers def add_paper_from_paths(self, pdfpath, bibpath): - p = Paper.from_bibpdffiles(pdfpath, bibpath) + p = Paper.load(bibpath) + p.set_pdf(pdfpath) self.add_paper(p) def add_paper(self, p): if p.citekey is None: # TODO also test if citekey is valid - raise(ValueError, "Invalid citekey: %s." % p.citekey) + raise(ValueError("Invalid citekey: %s." % p.citekey)) elif p.citekey in self.citekeys: - raise(ValueError, "Citekey already exists in repository: %s" - % p.citekey) + raise(ValueError("Citekey already exists in repository: %s" + % p.citekey)) self.citekeys.append(p.citekey) # write paper files self.save_paper(p) @@ -89,14 +90,14 @@ class Repository(object): def save_paper(self, paper): if not paper.citekey in self.citekeys: - raise(ValueError, 'Paper not in repository, first add it.') + raise(ValueError('Paper not in repository, first add it.')) paper.save_to_disc(self.path_to_paper_file(paper.citekey, 'bib'), self.path_to_paper_file(paper.citekey, 'meta')) def add_papers(self, bibpath): - bib_data = Paper.import_bibdata(bibpath) + bib_data = files.load_externalbibfile(bibpath) for k in bib_data.entries: - sub_bib = type(bib_data)(preamble=bib_data._preamble) + sub_bib = bib_data.entries[k] p = Paper(bibentry=sub_bib, citekey=k) self.add_paper(p) @@ -135,11 +136,11 @@ class Repository(object): elif file_ == 'meta': return os.path.join(self.papersdir, META_DIR, citekey + '.meta') else: - raise(ValueError, "%s is not a valid paper file." % file_) + raise(ValueError("%s is not a valid paper file." % file_)) @classmethod def from_directory(cls, papersdir=None): - repo = cls.__init__(papersdir=papersdir) + repo = cls(papersdir=papersdir) repo.load() return repo diff --git a/tests/test_paper.py b/tests/test_paper.py index 49e619e..c04c7c8 100644 --- a/tests/test_paper.py +++ b/tests/test_paper.py @@ -68,7 +68,7 @@ class TestSaveLoad(unittest.TestCase): self.dest_metafile = os.path.join(self.tmpdir, 'written_meta.yaml') def test_load_valid(self): - p = Paper.load(self.bibfile, self.metafile) + p = Paper.load(self.bibfile, metapath=self.metafile) self.assertEqual(fixtures.turing1950, p) def test_save_fails_with_no_citekey(self):