diff --git a/.pit/pit-956ed1a521100b3b b/.pit/pit-956ed1a521100b3b index b4faf58..4dac007 100644 --- a/.pit/pit-956ed1a521100b3b +++ b/.pit/pit-956ed1a521100b3b @@ -1,7 +1,7 @@ [header] title = citekey support id = 956ed1a521100b3b0bb0638f61b3b5a03204ffa6 -status = open +status = closed type = feature author = Fabien Benureau mail = fabien.benureau+git@gmail.com @@ -9,6 +9,7 @@ date = 2012-10-05 at 15:00 UCT [eventlog] opened[0] = opened the 2012-10-05 at 15:00 UCT by Fabien Benureau +closed[1] = closed the 2012-10-11 at 17:57(UCT) by Fabien Benureau [discussion] desc = # enter your description here diff --git a/.pit/pit-ac8c05c020d251c6 b/.pit/pit-ac8c05c020d251c6 new file mode 100644 index 0000000..e753aba --- /dev/null +++ b/.pit/pit-ac8c05c020d251c6 @@ -0,0 +1,16 @@ +[header] +title = remove configparser for internal mapping +id = ac8c05c020d251c6fa9ac5fc239038837b636b3b +status = closed +type = bug +author = Fabien Benureau +mail = fabien.benureau+git@gmail.com +date = 2012-10-11 at 07:25 UCT + +[eventlog] +opened[0] = opened the 2012-10-11 at 07:25 UCT by Fabien Benureau +closed[1] = closed the 2012-10-11 at 17:57(UCT) by Fabien Benureau + +[discussion] +desc = # enter your description here + diff --git a/papers/commands/add_cmd.py b/papers/commands/add_cmd.py index d870d3a..0a0e55c 100644 --- a/papers/commands/add_cmd.py +++ b/papers/commands/add_cmd.py @@ -7,6 +7,7 @@ except ImportError: from .. import color from .. import files from .. import pretty +from .. import repo def parser(subparsers, config): @@ -20,41 +21,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. """ - papersdir = files.find_papersdir() - - fullpdfpath = os.path.abspath(pdffile) - fullbibpath = os.path.abspath(bibfile) - files.check_file(fullpdfpath) - files.check_file(fullbibpath) - - filename, ext = os.path.splitext(os.path.split(fullpdfpath)[1]) - if ext != '.pdf' and ext != '.ps': - print('{}warning{}: extention {}{}{} not recognized{}'.format( - color.yellow, color.grey, color.cyan, ext, color.grey, color.end)) - - meta = configparser.ConfigParser() - meta.add_section('metadata') - - meta.set('metadata', 'filename', filename) - meta.set('metadata', 'extension', ext) - meta.set('metadata', 'path', os.path.normpath(fullpdfpath)) - - meta.add_section('notes') - - if bibfile is not None: - 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)) - files.write_bibdata(bib_data, filename) - - papers = files.load_papers() - count = papers.get('header', 'count') - papers.set('header', 'count', int(count) + 1) - - citekey = pretty.create_citekey(bib_data) - papers.set('papers', citekey, filename) - papers.set('citekeys', 'ck' + count, citekey) - - files.write_papers(papers) - files.write_meta(meta, filename) + rp = repo.Repository() + rp.add_paper(pdffile, bibfile) \ No newline at end of file diff --git a/papers/commands/init_cmd.py b/papers/commands/init_cmd.py index 136c7bb..66fd3f9 100644 --- a/papers/commands/init_cmd.py +++ b/papers/commands/init_cmd.py @@ -26,12 +26,11 @@ def command(config): os.makedirs(papersdir+os.sep+'bibdata') os.makedirs(papersdir+os.sep+'meta') - papers = configparser.ConfigParser() - papers.add_section('header') - papers.set('header', 'count', 0) - papers.add_section('papers') - papers.add_section('citekeys') - files.write_papers(papers) + papers = {} + papers['count'] = 0 + papers['citekeys'] = {} + papers['numbers'] = {} + files.save_papers(papers) else: print('{}error {} : papers already present in {}{}{}'.format( diff --git a/papers/commands/list_cmd.py b/papers/commands/list_cmd.py index f3e0dfe..9e49bd5 100644 --- a/papers/commands/list_cmd.py +++ b/papers/commands/list_cmd.py @@ -1,25 +1,22 @@ -from .. import files -from .. import pretty -from .. import color - import subprocess import tempfile +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): - papers = files.load_papers() - + rp = repo.Repository() + articles = [] - for p in papers.options('citekeys'): - number = p[2:] - citekey = papers.get('citekeys', p) - filename = papers.get('papers', citekey) - bibdata = files.load_bibdata(filename + '.bibyaml') - bibdesc = pretty.bib_oneliner(bibdata) - articles.append('{:3d} {}{}{}{} {}'.format(int(number), color.purple, citekey, color.end, (8-len(citekey))*' ', bibdesc)) + for n in sorted(rp.numbers.keys()): + paper = rp.paper_from_number(n, fatal = True) + bibdesc = pretty.bib_oneliner(paper.bib_data) + articles.append('{:3d} {}{}{}{} {}'.format(int(paper.number), color.purple, paper.citekey, color.end, (8-len(paper.citekey))*' ', bibdesc)) 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 983da8a..b1dd0bf 100644 --- a/papers/commands/open_cmd.py +++ b/papers/commands/open_cmd.py @@ -1,30 +1,26 @@ -try: - import ConfigParser as configparser -except ImportError: - import configparser import subprocess -from .. import files from .. import color +from .. import repo +from ..paper import NoDocumentFile def parser(subparsers, config): - parser = subparsers.add_parser('open', help="open the paper in a pdf viewer") - parser.add_argument("citekey", help="the paper associated citekey") + parser = subparsers.add_parser('open', help='{}open the paper in a pdf viewer{}'.format(color.normal, color.end)) + parser.add_argument('citekey', help='{}the paper associated citekey{}'.format(color.normal, color.end)) return parser def command(config, citekey): - papers = files.load_papers() + rp = repo.Repository() + paper = rp.paper_from_any(citekey, fatal = True) try: - filename = papers.get('papers', str(citekey)) - except configparser.NoOptionError: - try: - ck = papers.get('citekeys', 'ck'+str(citekey)) - filename = papers.get('papers', str(ck)) - except configparser.NoOptionError: - print('{}error{}: paper with citekey or number {}{}{} not found{}'.format( - color.red, color.grey, color.cyan, citekey, color.grey, color.end)) - exit(-1) - meta_data = files.load_meta(filename) - filepath = meta_data.get('metadata', 'path') - p = subprocess.Popen(['open', filepath]) - print('{}{}{} opened.{}'.format(color.cyan, filepath, color.grey, color.end)) \ No newline at end of file + if paper.check_file(): + filepath = paper.get_file_path() + + p = subprocess.Popen(['open', filepath]) + print('{}{}{} opened.{}'.format( + color.filepath, filepath, color.normal, color.end)) + 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/files.py b/papers/files.py index bbe2ef4..ee98ca7 100644 --- a/papers/files.py +++ b/papers/files.py @@ -8,6 +8,8 @@ try: except ImportError: import configparser +import yaml + import color try: @@ -49,6 +51,13 @@ def find_papersdir(): return _papersdir +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('{}warning{}: extension {}{}{} not recognized{}'.format( + color.yellow, color.grey, color.cyan, ext, color.grey, color.end)) + return name, ext def check_file(filepath): if not os.path.exists(filepath): @@ -59,29 +68,46 @@ def check_file(filepath): print '{}error{}: {}{}{} is not a file{}'.format( color.red, color.grey, color.cyan, filepath, color.grey, color.end) exit(-1) + +# yaml I/O -def write_configfile(config, filepath): +def write_yamlfile(filepath, datamap): try: with open(filepath, 'w') as f: - config.write(f) + yaml.dump(datamap, f) except IOError as e: - print '{}error{} : impossible to write on file {}{:s}{}'.format( + print '{}error{} : impossible to read file {}{:s}{}'.format( color.red, color.grey, color.cyan, filepath, color.end) - print 'Verify permissions' exit(-1) -def read_configfile(filepath): +def read_yamlfile(filepath): + check_file(filepath) try: with open(filepath, 'r') as f: - config = configparser.ConfigParser() - config.readfp(f) - return config + return yaml.load(f) except IOError as e: print '{}error{} : impossible to read file {}{:s}{}'.format( - color.red, color.grey, color.cyan, filepath, color.end) - print 'Verify permissions' + color.red, color.grey, color.cyan, paperdir, color.end) exit(-1) +def save_papers(datamap): + paperyaml = find_papersdir() + os.sep + 'papers.yaml' + write_yamlfile(paperyaml, datamap) + +def load_papers(): + paperyaml = find_papersdir() + os.sep + 'papers.yaml' + return read_yamlfile(paperyaml) + +def save_meta(meta_data, filename): + filepath = find_papersdir() + os.sep + 'meta' + os.sep + filename + '.meta' + write_yamlfile(filepath, meta_data) + +def load_meta(filename): + filepath = find_papersdir() + os.sep + 'meta' + os.sep + filename + '.meta' + return read_yamlfile(filepath) + +# specific to bibliography data + def load_externalbibfile(fullbibpath): check_file(fullbibpath) @@ -102,31 +128,17 @@ def load_externalbibfile(fullbibpath): return bib_data - -def write_papers(config): - write_configfile(config, find_papersdir() + os.sep + 'papers') - -def load_papers(): - return read_configfile(find_papersdir() + os.sep + 'papers') - def load_bibdata(filename): - fullbibpath = find_papersdir() + os.sep + 'bibdata' + os.sep + filename + fullbibpath = find_papersdir() + os.sep + 'bibdata' + os.sep + filename + '.bibyaml' return load_externalbibfile(fullbibpath) -def write_bibdata(bib_data, filename): +def save_bibdata(bib_data, filename): filepath = find_papersdir() + os.sep + 'bibdata' + os.sep + filename + '.bibyaml' with open(filepath, 'w') as f: parser = pybtex.database.output.bibyaml.Writer() parser.write_stream(bib_data, f) -def write_meta(meta_data, filename): - filepath = find_papersdir() + os.sep + 'meta' + os.sep + filename + '.meta' - write_configfile(meta_data, filepath) - -def load_meta(filename): - filepath = find_papersdir() + os.sep + 'meta' + os.sep + filename + '.meta' - return read_configfile(filepath) - +# vim input try: EDITOR = os.environ['EDITOR'] diff --git a/papers/paper.py b/papers/paper.py new file mode 100644 index 0000000..2ad9073 --- /dev/null +++ b/papers/paper.py @@ -0,0 +1,68 @@ +import os + +import files +import color +import pretty + +class Paper(object): + """Paper class. The object is responsible for the integrity of its own data, + and for loading and writing it to disc. + """ + + @classmethod + def from_disc(cls, name, citekey = None, number = None): + bib_data = files.load_bibdata(name) + metadata = files.load_meta(name) + p = Paper(name, bib_data = bib_data, metadata = metadata, + citekey = citekey, number = number) + return p + + @classmethod + def from_bibpdffiles(cls, pdfpath, bibpath): + bib_data = cls.import_bibdata(bibpath) + name, meta = cls.create_meta(pdfpath, bib_data) + p = Paper(name, bib_data = bib_data, metadata = meta) + + return p + + def __init__(self, name, bib_data = None, metadata = None, + citekey = None, number = None): + self.name = name + self.bib_data = bib_data + self.metadata = metadata + self.citekey = citekey + self.number = number + + def save_to_disc(self): + files.save_bibdata(self.bib_data, self.name) + files.save_meta(self.metadata, self.name) + + @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 + + @classmethod + def create_meta(cls, pdfpath, bib_data): + + fullpdfpath = os.path.abspath(pdfpath) + files.check_file(fullpdfpath) + + name, ext = files.name_from_path(pdfpath) + + meta = {} + + meta['name'] = name + meta['extension'] = ext + meta['path'] = fullpdfpath + + meta['notes'] = [] + + return name, meta diff --git a/papers/pretty.py b/papers/pretty.py index 9b48790..bbad9aa 100644 --- a/papers/pretty.py +++ b/papers/pretty.py @@ -26,33 +26,3 @@ def bib_desc(bib_data): s += '\n' s += '\n'.join('{}: {}'.format(k, v) for k, v in article.fields.items()) return s - -alphabet = 'abcdefghijklmopqrstuvwxyz' - -try: - import ConfigParser as configparser -except ImportError: - import configparser -import files - -def create_citekey(bib_data): - """Create a cite key unique to the paper""" - article = bib_data.entries[list(bib_data.entries.keys())[0]] - first_author = article.persons['author'][0] - year = article.fields['year'] - prefix = '{}{}'.format(first_author.last()[0][:6], year[2:]) - - papers = files.load_papers() - letter = 0, False - citekey = None - - citekey = prefix - while not letter[1]: - try: - papers.get('papers', citekey) - citekey = prefix + alphabet[letter[0]] - letter = letter[0]+1, False - except configparser.NoOptionError: - letter = letter[0], True - - return citekey diff --git a/papers/repo.py b/papers/repo.py new file mode 100644 index 0000000..99f85d3 --- /dev/null +++ b/papers/repo.py @@ -0,0 +1,100 @@ +import files +import color +from paper import Paper + +alphabet = 'abcdefghijklmopqrstuvwxyz' + + +class Repository(object): + + def __init__(self): + self.paperdir = files.find_papersdir() + self.papers_config = files.load_papers() + self.citekeys = self.papers_config['citekeys'] + self.numbers = self.papers_config['numbers'] + + # loading existing papers + + def paper_from_number(self, number, fatal = True): + try: + citekey = self.numbers[int(number)] + paper = self.paper_from_citekey(citekey) + paper.number = int(number) + return paper + except KeyError: + if fatal: + print('{}error{}: no paper with number {}{}{}'.format( + color.error, color.normal, color.citekey, citekey, color.end)) + exit(-1) + raise IOError, 'file not found' + + def paper_from_citekey(self, citekey, fatal = True): + """Load a paper by its citekey from disk, if necessary.""" + try: + name = self.citekeys[citekey] + paper = Paper.from_disc(name, citekey = citekey) + paper.citekey = citekey + return paper + except KeyError: + 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' + + def paper_from_any(self, key, fatal = True): + try: + return self.paper_from_citekey(key, fatal = False) + except IOError: + try: + return self.paper_from_number(key, fatal = False) + except IOError: + if fatal: + 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' + + # creating new papers + + def add_paper(self, pdfpath, bibpath): + + p = Paper.from_bibpdffiles(pdfpath, bibpath) + + # updating papersconfig + p.citekey = self.create_citekey(p.bib_data) + p.number = self.create_number() + + self.papers_config['citekeys'][p.citekey] = p.name + self.papers_config['numbers'][p.number] = p.citekey + + self.citekeys[p.citekey] = p.name + self.numbers[p.number] = p.citekey + + # writing all to disk + files.save_papers(self.papers_config) + p.save_to_disc() + + return p + + def create_citekey(self, bib_data, allowed = tuple()): + """Create a cite key unique to a given bib_data""" + article = bib_data.entries[list(bib_data.entries.keys())[0]] + first_author = article.persons['author'][0] + year = article.fields['year'] + prefix = '{}{}'.format(first_author.last()[0][:6], year[2:]) + + letter = 0 + citekey = None + + citekey = prefix + while citekey in self.citekeys and citekey not in allowed: + citekey = prefix + alphabet[letter] + letter += 1 + + return citekey + + def create_number(self): + count = int(self.papers_config['count']) + self.papers_config['count'] = count + 1 + return count