diff --git a/papers/color.py b/papers/color.py index a01d350..7a4a1c7 100644 --- a/papers/color.py +++ b/papers/color.py @@ -1,29 +1,55 @@ # display -bold = '\033[1m' -end = '\033[0m' +BOLD = '\033[1m' +END = '\033[0m' -black = '\033[0;30m' -red = '\033[0;31m' -green = '\033[0;32m' -yellow = '\033[0;33m' -blue = '\033[0;34m' -purple = '\033[0;35m' -cyan = '\033[0;36m' -grey = '\033[0;37m' +COLORS = { + 'black' : '\033[0;30m', + 'red' : '\033[0;31m', + 'green' : '\033[0;32m', + 'yellow': '\033[0;33m', + 'blue' : '\033[0;34m', + 'purple': '\033[0;35m', + 'cyan' : '\033[0;36m', + 'grey' : '\032[0;37m', + } # Bold -bblack = '\033[1;30m' -bred = '\033[1;31m' -bgreen = '\033[1;32m' -byellow = '\033[1;33m' -bblue = '\033[1;34m' -bpurple = '\033[1;35m' -bcyan = '\033[1;36m' -bgrey = '\033[1;37m' +BCOLORS = { + 'black' : '\033[1;30m', + 'red' : '\033[1;31m', + 'green' : '\033[1;32m', + 'yellow': '\033[1;33m', + 'blue' : '\033[1;34m', + 'purple': '\033[1;35m', + 'cyan' : '\033[1;36m', + 'grey' : '\033[1;37m', + } # application specific -error = red -normal = grey -citekey = purple -filepath = cyan +ALIASES = { + 'error' : 'red', + 'normal' : 'grey', + 'citekey' : 'purple', + 'filepath': 'cyan', + } + + +def colored(s, color=None, bold=False): + if color in ALIASES: + color = ALIASES[color] + try: + if bold: + color_code = BCOLORS[color] + else: + color_code = COLORS[color] + except KeyError: + if bold: + color_code = CODE + else: + color_code = '' + if color_code != '': + end_code = END + else: + end_code = '' + return color_code + s + end_code diff --git a/papers/commands/import_cmd.py b/papers/commands/import_cmd.py index 0844c43..3d9e029 100644 --- a/papers/commands/import_cmd.py +++ b/papers/commands/import_cmd.py @@ -4,6 +4,7 @@ import shutil from .. import repo from ..paper import Paper, NoDocumentFile +from .. import files def parser(subparsers, config): @@ -27,12 +28,12 @@ def command(config, bibpath, copy): copy = config.get('papers', 'import-copy') rp = repo.Repository.from_directory() # Get directory for document - doc_path = rp.get_document_directory(config) + 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) + papers = Paper.many_from_path(bibpath, fatal=False) for p in papers: doc_file = None try: diff --git a/papers/commands/init_cmd.py b/papers/commands/init_cmd.py index 070bc1b..03db14a 100644 --- a/papers/commands/init_cmd.py +++ b/papers/commands/init_cmd.py @@ -3,7 +3,7 @@ import os from ..repo import Repository -from .. import color +from ..color import colored def parser(subparsers, config): @@ -16,12 +16,13 @@ def command(config): """Create a .papers directory""" papersdir = os.getcwd() + '/.papers' if not os.path.exists(papersdir): - print('{}initializing papers in {}{}{}'.format( - color.grey, color.cyan, papersdir, color.end)) + print('Initializing papers in {}'.format( + colored(papersdir, 'filepath'))) repo = Repository() repo.init(papersdir) # Creates directories repo.save() # Saves empty repository description else: - print('{}error {} : papers already present in {}{}{}'.format( - color.red, color.grey, color.cyan, papersdir, color.end)) + print(colored('error', 'error') + + ' : papers already present in {}.'.format( + colored(papersdir, 'filepath'))) exit(-1) diff --git a/papers/commands/list_cmd.py b/papers/commands/list_cmd.py index 768a060..ea8c788 100644 --- a/papers/commands/list_cmd.py +++ b/papers/commands/list_cmd.py @@ -2,7 +2,7 @@ import subprocess import tempfile from .. import pretty -from .. import color +from ..color import colored from .. import repo @@ -17,7 +17,11 @@ def command(config): for n in range(rp.size()): paper = rp.paper_from_number(n, fatal=True) 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')) + articles.append((u'{num:d}: [{citekey}] {descr}'.format( + num=int(n), + citekey=colored(rp.citekeys[n], 'purple'), + descr=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 a820ce4..391bbe2 100644 --- a/papers/commands/open_cmd.py +++ b/papers/commands/open_cmd.py @@ -1,13 +1,15 @@ import subprocess -from .. import color +from ..color import colored from .. import repo from ..paper import NoDocumentFile def parser(subparsers, config): - 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)) + parser = subparsers.add_parser('open', + help=colored('open the paper in a pdf viewer', 'normal')) + parser.add_argument('citekey', + help=colored('the paper associated citekey', 'normal')) return parser @@ -19,11 +21,10 @@ def command(config, citekey): filepath = paper.get_file_path() subprocess.Popen([config.get('papers', 'open-cmd'), filepath]) - print('{}{}{} opened.{}'.format( - color.filepath, filepath, color.normal, color.end)) + print('{} opened.'.format(colored(filepath, 'filepath'))) else: raise NoDocumentFile except NoDocumentFile: - print('{}error{}: No document associated to this entry {}{}{}'.format( - color.error, color.normal, color.citekey, citekey, color.end)) + print('{}: No document associated to this entry {}{}{}'.format( + colored('error', 'error'), colored('citekey', 'citekey'))) exit(-1) diff --git a/papers/files.py b/papers/files.py index 8f74fdc..1508478 100644 --- a/papers/files.py +++ b/papers/files.py @@ -4,7 +4,7 @@ import tempfile import yaml -import color +from .color import colored try: import pybtex @@ -19,8 +19,9 @@ try: import pybtex.database.output.bibyaml except ImportError: - print '{}error{}: you need to install Pybtex; try running \'pip install' - 'pybtex\' or \'easy_install pybtex\''.format(color.red, color.end) + print(colored('error', 'error') + + ': you need to install Pybtex; try running \'pip install' + 'pybtex\' or \'easy_install pybtex\'') _papersdir = None @@ -42,17 +43,20 @@ def find_papersdir(): if _papersdir is None: curdir = os.path.abspath('') while curdir != '': - if (os.path.exists(curdir + '/.papers') - and os.path.isdir(curdir + '/.papers')): + curdir_path = os.path.join(clean_path(curdir), '.papers') + if (os.path.exists(curdir_path) and os.path.isdir(curdir_path)): _papersdir = curdir + '/.papers' curdir = '' if curdir == '/': + curdir = '~' + elif curdir == '~': curdir = '' else: curdir = os.path.split(curdir)[0] if _papersdir is None: - print '{}error{} : no papers repo found in this directory or in' - 'any parent directory.{}'.format(color.red, color.grey, color.end) + print (colored('error', 'error') + + ': no papers repo found in this directory or in ' + 'any parent directory.') exit(-1) return _papersdir @@ -61,22 +65,22 @@ 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)) + print(colored('warning', 'yellow') + + '{: extension {ext} not recognized'.format( + ext=colored(ext, 'cyan'))) return name, ext def check_file(filepath): if not os.path.exists(filepath): - print '{}error{}: {}{}{} does not exists{}'.format( - color.red, color.grey, color.cyan, filepath, color.grey, - color.end) + print(colored('error', 'error') + + ': {} does not exists'.format( + colored(filepath, 'filepath'))) exit(-1) if not os.path.isfile(filepath): - print '{}error{}: {}{}{} is not a file{}'.format( - color.red, color.grey, color.cyan, filepath, color.grey, - color.end) + print(colored('error', 'error') + + ': {} is not a file'.format( + colored(filepath, 'filepath'))) exit(-1) @@ -87,8 +91,9 @@ def write_yamlfile(filepath, datamap): with open(filepath, 'w') as f: yaml.dump(datamap, f) except IOError: - print '{}error{} : impossible to read file {}{:s}{}'.format( - color.red, color.grey, color.cyan, filepath, color.end) + print(colored('error', 'error') + + ': impossible to read file {}'.format( + colored(filepath, 'filepath'))) exit(-1) @@ -98,8 +103,9 @@ def read_yamlfile(filepath): with open(filepath, 'r') as f: return yaml.load(f) except IOError: - print '{}error{} : impossible to read file {}{:s}{}'.format( - color.red, color.grey, color.cyan, filepath, color.end) + print(colored('error', 'error') + + ': impossible to read file {}'.format( + colored(filepath, 'filepath'))) exit(-1) @@ -137,8 +143,9 @@ def load_externalbibfile(fullbibpath): parser = pybtex.database.input.bibyaml.Parser() bib_data = parser.parse_file(fullbibpath) else: - print '{}error{}: {}{}{} not recognized format for bibliography{}'.format( - color.red, color.grey, color.cyan, ext, color.grey, color.end) + print(colored('error', 'error') + + ': {} not recognized format for bibliography'.format( + colored(ext, 'cyan'))) exit(-1) return bib_data diff --git a/papers/paper.py b/papers/paper.py index f7353fa..c8a14aa 100644 --- a/papers/paper.py +++ b/papers/paper.py @@ -172,7 +172,7 @@ class Paper(object): return BASE_META.copy() @classmethod - def many_from_path(cls, bibpath): + def many_from_path(cls, bibpath, fatal=True): """Extract list of papers found in bibliographic files in path. """ bibpath = files.clean_path(bibpath) @@ -182,5 +182,15 @@ class Paper(object): 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] + if fatal: + return [Paper(bibentry=b.entries[k], citekey=k) + for b in bib_data for k in b.entries] + else: + papers = [] + for b in bib_data: + for k in b.entries: + try: + papers.append(Paper(bibentry=b.entries[k], citekey=k)) + except ValueError, e: + print "Warning, skipping paper (%s)." % e + return papers diff --git a/papers/pretty.py b/papers/pretty.py index fd1885a..1e2405b 100644 --- a/papers/pretty.py +++ b/papers/pretty.py @@ -1,16 +1,27 @@ # display formatting -import color +from color import colored + def person_repr(p): - return ' '.join(s for s in [' '.join(p.first(abbr = True)), - ' '.join(p.middle(abbr = True)), - ' '.join(p.prelast(abbr = False)), - ' '.join(p.last(abbr = False)), - ' '.join(p.lineage(abbr = True))] if s) + return ' '.join(s for s in [ + ' '.join(p.first(abbr=True)), + ' '.join(p.middle(abbr=True)), + ' '.join(p.prelast(abbr=False)), + ' '.join(p.last(abbr=False)), + ' '.join(p.lineage(abbr=True))] if s) + + +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 '') + def bib_oneliner(bibentry): - authors = ', '.join(person_repr(p) for p in bibentry.persons['author']) + authors = short_authors(bibentry) title = bibentry.fields['title'] year = bibentry.fields.get('year', '') journal = '' @@ -18,14 +29,18 @@ def bib_oneliner(bibentry): if bibentry.type == 'inproceedings': field = 'booktitle' 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, - color.grey, color.end) + return u'{authors} \"{title}\" {journal} ({year})'.format( + authors=colored(authors, 'green'), + title=title, + journal=colored(journal, 'yellow'), + year=year, + ) + def bib_desc(bib_data): article = bib_data.entries[list(bib_data.entries.keys())[0]] - s = '\n'.join('author: {}'.format(person_repr(p)) for p in article.persons['author']) + s = '\n'.join('author: {}'.format(person_repr(p)) + for p in article.persons['author']) s += '\n' s += '\n'.join('{}: {}'.format(k, v) for k, v in article.fields.items()) return s diff --git a/papers/repo.py b/papers/repo.py index 810a444..4f04fa8 100644 --- a/papers/repo.py +++ b/papers/repo.py @@ -1,4 +1,4 @@ -import color +from .color import colored import os import files @@ -25,11 +25,11 @@ class Repository(object): citekey = self.citekeys[int(number)] paper = self.paper_from_citekey(citekey) return paper - except KeyError: + except (IndexError, ValueError): if fatal: - print('{}error{}: no paper with number {}{}{}'.format( - color.error, color.normal, color.citekey, citekey, - color.end)) + print(colored('error', 'error') + + ': no paper with number {}'.format( + colored(number, 'citekey'))) exit(-1) raise(IOError('file not found')) @@ -40,9 +40,9 @@ class Repository(object): 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)) + print(colored('error', 'error') + + ': no paper with citekey {}'.format( + colored(citekey, 'citekey'))) exit(-1) raise(IOError('file not found')) @@ -54,8 +54,9 @@ class Repository(object): 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)) + print(colored('error', 'error') + + (': paper with citekey or number %s not found' + % colored(key, 'citekey'))) exit(-1) raise(IOError('file not found')) @@ -141,7 +142,7 @@ class Repository(object): repo = cls() if papersdir is None: papersdir = files.find_papersdir() - repo.papersdir = papersdir + repo.papersdir = files.clean_path(papersdir) repo.load() return repo