major restructuring of code. many oliver remarks implemented. no new features.

divided code into multiple files
paperpile style argparse
setup.py with script option
main
Fabien Benureau 13 years ago
parent 60d17982e4
commit acab1b8044

2
.gitignore vendored

@ -0,0 +1,2 @@
build/
*.pyc

@ -0,0 +1,6 @@
A paper correspond to 3 files :
name.pdf a pdf or ps file, the paper itself, whose location is arbitrary
bibdata/name.bibyaml a bibyaml file with all bibliographic data.
meta/name.meta a metadata file for internal use, notes, citekeys, status, etc.

318
papers

@ -1,318 +0,0 @@
#!/usr/bin/env python
import sys, os
import datetime
import shutil
import tempfile
import textwrap
from subprocess import call
import webbrowser
import urllib
import ConfigParser
import yaml
import subprocess
try:
import pybtex
import pybtex.database
import pybtex.database.input
import pybtex.database.input.bibtex
import pybtex.database.input.bibtexml
import pybtex.database.input.bibyaml
import pybtex.database.output
import pybtex.database.output.bibtex
import pybtex.database.output.bibtexml
import pybtex.database.output.bibyaml
except ImportError:
print '{}error{}: you need to install Pybtex; try running \'pip install pybtex\'.'.format(red, end)
# display
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'
# 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'
# utility functions
currentdir = os.getcwd()
papersdir = None
try:
EDITOR = os.environ['EDITOR']
except KeyError:
EDITOR = 'nano'
def find_papersdir():
global papersdir
curdir = os.path.abspath(os.getcwd())
while curdir != '':
if os.path.exists(curdir + '/.papers') and os.path.isdir(curdir + '/.papers'):
papersdir = curdir + '/.papers'
curdir = ''
if 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(red, grey, end)
exit(0)
def write_configfile(config, filepath):
try:
with open(filepath, 'w') as f:
config.write(f)
except IOError as e:
print '{}error{} : impossible to write on file {}{:s}{}'.format(red, grey, cyan, filepath, end)
print 'Verify permissions'
exit(-1)
def write_papers(config):
write_configfile(config, papersdir + os.sep + 'papers')
def read_configfile(filepath):
try:
with open(filepath, 'r') as f:
config = ConfigParser.ConfigParser()
config.readfp(f)
return config
except IOError as e:
print '{}error{} : impossible to read file {}{:s}{}'.format(red, grey, cyan, filepath, end)
print 'Verify permissions'
exit(-1)
def read_papers():
return read_configfile(papersdir + os.sep + 'papers')
def vim_input(initial = ""):
"""Use an editor to get input"""
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=False) as temp_file:
tfile_name = temp_file.name
temp_file.write(initial)
temp_file.flush()
call([EDITOR, tfile_name])
with open(tfile_name) as temp_file:
content = temp_file.read()
os.remove(tfile_name)
return content
def load_externalbibfile(fullbibpath):
check_file(fullbibpath)
filename, ext = os.path.splitext(os.path.split(fullbibpath)[1])
if ext == '.bib':
parser = pybtex.database.input.bibtex.Parser()
bib_data = parser.parse_file(fullbibpath)
elif ext == '.xml' or ext == '.bibtexml':
parser = pybtex.database.input.bibtexml.Parser()
bib_data = parser.parse_file(fullbibpath)
elif ext == '.yaml' or ext == '.bibyaml':
parser = pybtex.database.input.bibyaml.Parser()
bib_data = parser.parse_file(fullbibpath)
else:
print '{}error{}: {}{}{} not recognized format for bibliography{}'.format(red, grey, cyan, ext, grey, end)
return bib_data
def load_bibfile(filename):
fullbibpath = papersdir + os.sep + 'bibdata' + os.sep + filename
return load_externalbibfile(fullbibpath)
def write_bibfile(bib_data, filename):
filepath = 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 = papersdir + os.sep + 'meta' + os.sep + filename + '.meta'
write_configfile(meta_data, filepath)
def load_meta(filename):
filepath = papersdir + os.sep + 'meta' + os.sep + filename + '.meta'
return read_configfile(filepath)
def check_file(filepath):
if not os.path.exists(filepath):
print '{}error{}: {}{}{} does not exists{}'.format(red, grey, cyan, filepath, grey, end)
exit(-1)
if not os.path.isfile(filepath):
print '{}error{}: {}{}{} is not a file{}'.format(red, grey, cyan, filepath, grey, end)
exit(-1)
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)
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['year']
journal = article.fields['journal']
return '{}{}{} \"{}{}{}\" {}{}{} {}({}{}{}){}'.format(green, authors, grey, bcyan, title, grey, yellow, journal, end, grey, end, year, grey, end)
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'
s += '\n'.join('{}: {}'.format(k, v) for k, v in article.fields.items())
return s
# commands
def init_cmd():
"""Create a .papers directory"""
global papersdir
# create dir
papersdir = os.getcwd() + '/.papers'
if not os.path.exists(papersdir):
print '{}initializing papers in {}{}{}'.format(grey, cyan, papersdir, end)
os.makedirs(papersdir)
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')
write_papers(papers)
else:
print '{}error{} : papers already present in {}{}{}'.format(red, grey, cyan, papersdir, end)
exit(-1)
def install_cmd():
"""Install command on the system"""
print '{}file to install : {}{}{}'.format(grey, cyan, __file__, end)
default = '/usr/local/bin'
print "{}folder to install the papers command [{}{:s}{}] : {}".format(grey, cyan, default, grey, end),
sys.stdout.flush()
path = raw_input()
if path == '':
path = default
if not os.path.exists(path):
print "{}error{}: {}{:s}{} does not exist - installation aborted".format(red, end, cyan, path, end)
else:
if os.path.exists(path+'/papers'):
if os.path.samefile(path+'/papers', __file__):
return
shutil.copy(__file__, path)
def websearch_cmd(search_string):
url = 'https://scholar.google.fr/scholar?hl=fr&q={}&lr='.format(urllib.quote_plus(search_string))
webbrowser.open(url)
def add_cmd(pdffilepath, bibtex = None):
"""
:param pdffilepath path (no url yet) to a pdf or ps file
:param bibtex bibtex file (in .bib, .bibml or .yaml format.
"""
fullpdfpath = os.path.abspath(pdffilepath)
fullbibpath = os.path.abspath(bibtex)
check_file(fullpdfpath)
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(yellow, grey, cyan, ext, grey, 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 bibtex is not None:
bib_data = load_externalbibfile(fullbibpath)
print '{}bibliographic data present in {}{}{}'.format(grey, cyan, bibtex, end)
print bib_desc(bib_data)
write_bibfile(bib_data, filename)
papers = read_papers()
count = papers.get('header', 'count')
papers.set('header', 'count', int(count) + 1)
papers.set('papers', 'p' + count, filename)
write_papers(papers)
write_meta(meta, filename)
def list_cmd():
papers = read_papers()
articles = []
for p in papers.options('papers'):
filename = papers.get('papers', p)
number = p[1:]
bibdata = load_bibfile(filename + '.bibyaml')
bibdesc = bib_oneliner(bibdata)
articles.append('{:3d} {}'.format(int(number), bibdesc))
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=True) as tmpf:
tmpf.write('\n'.join(articles))
tmpf.flush()
call(['less', '-XRF', tmpf.name])
def open_cmd(number):
papers = read_papers()
filename = papers.get('papers', 'p' + str(number))
meta_data = load_meta(filename)
filepath = meta_data.get('metadata', 'path')
p = subprocess.Popen(['open', filepath])
print '{}{}{} opened.{}'.format(cyan, filepath, grey, end)
# argument parsing (old school)
cmds = {'init': init_cmd,
'install': install_cmd,
'websearch': websearch_cmd,
'add': add_cmd,
'list': list_cmd,
'open': open_cmd,
}
error_msg = "{}banana {}banana {}banana{}".format(purple, yellow, cyan, end)
if len(sys.argv) == 1:
print error_msg
else:
cmd = sys.argv[1]
if cmd in cmds and cmd not in ['init', 'install', 'websearch']:
find_papersdir()
args = sys.argv[2:]
cmds[cmd](*args)
# try:
# args = sys.argv[2:]
# cmds[cmd](*args)
# except KeyError, TypeError:
# print error_msg
#

@ -0,0 +1,23 @@
# display
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'
# 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'

@ -0,0 +1,5 @@
import add_cmd
import init_cmd
import list_cmd
import open_cmd
import websearch_cmd

@ -0,0 +1,57 @@
from .. import color
from .. import files
try:
import ConfigParser as configparser
except ImportError:
import configparser
def parser(subparsers, config):
parser = subparsers.add_parser('add', help='add a paper to the repository')
parser.add_argument('pdffile', help='pdf or ps file')
parser.add_argument('bibfile', help='bibtex, bibtexml or bibyaml file')
return parser
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(bibtex)
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 bibtex is not None:
bib_data = files.load_externalbibfile(fullbibpath)
print('{}bibliographic data present in {}{}{}'.format(
color.grey, color.cyan, bibtex, color.end))
print(bib_desc(bib_data))
files.write_bibfile(bib_data, filename)
papers = files.read_papers()
count = papers.get('header', 'count')
papers.set('header', 'count', int(count) + 1)
papers.set('papers', 'p' + count, filename)
files.write_papers(papers)
files.write_meta(meta, filename)

@ -0,0 +1,37 @@
# init command
try:
import ConfigParser as configparser
except ImportError:
import configparser
from .. import color
from .. import files
def parser(subparsers, config):
parser = subparsers.add_parser('init', help="initialize the .papers directory")
return parser
def command(config):
"""Create a .papers directory"""
# create dir
papersdir = os.getcwd() + '/.papers'
if not os.path.exists(papersdir):
print('{}initializing papers in {}{}{}'.format(
color.grey, color.cyan, papersdir, color.end))
os.makedirs(papersdir)
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')
files.write_papers(papers)
else:
print('{}error {} : papers already present in {}{}{}'.format(
color.red, color.grey, color.cyan, papersdir, color.end))
exit(-1)

@ -0,0 +1,25 @@
# install command
# Probably useless if setup.py is provided
#import shutil
# def parser(subparsers, config):
# parser = subparsers.add_parser('install', help="install papers on the system")
# return parser
#
# def command():
# """Install command on the system"""
# print '{}file to install : {}{}{}'.format(grey, cyan, __file__, end)
# default = '/usr/local/bin'
# print "{}folder to install the papers command [{}{:s}{}] : {}".format(grey, cyan, default, grey, end),
# sys.stdout.flush()
# path = raw_input()
# if path == '':
# path = default
# if not os.path.exists(path):
# print "{}error{}: {}{:s}{} does not exist - installation aborted".format(red, end, cyan, path, end)
# else:
# if os.path.exists(path+'/papers'):
# if os.path.samefile(path+'/papers', __file__):
# return
# shutil.copy(__file__, path)

@ -0,0 +1,25 @@
from .. import files
from .. import pretty
import subprocess
import tempfile
def parser(subparsers, config):
parser = subparsers.add_parser('list', help="list all papers")
return parser
def command(config):
papers = files.read_papers()
articles = []
for p in papers.options('papers'):
filename = papers.get('papers', p)
number = p[1:]
bibdata = files.load_bibdata(filename + '.bibyaml')
bibdesc = pretty.bib_oneliner(bibdata)
articles.append('{:3d} {}'.format(int(number), bibdesc))
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=True) as tmpf:
tmpf.write('\n'.join(articles))
tmpf.flush()
subprocess.call(['less', '-XRF', tmpf.name])

@ -0,0 +1,17 @@
from .. import files
from .. import color
import subprocess
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")
return parser
def command(config, citekey):
papers = files.read_papers()
filename = papers.get('papers', 'p' + str(citekey))
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))

@ -0,0 +1,11 @@
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)

@ -0,0 +1,149 @@
import sys, os
import subprocess
import tempfile
try:
import ConfigParser as configparser
except ImportError:
import configparser
import color
try:
import pybtex
import pybtex.database
import pybtex.database.input
import pybtex.database.input.bibtex
import pybtex.database.input.bibtexml
import pybtex.database.input.bibyaml
import pybtex.database.output
import pybtex.database.output.bibtex
import pybtex.database.output.bibtexml
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)
_papersdir = None
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())
while curdir != '':
if os.path.exists(curdir + '/.papers') and os.path.isdir(curdir + '/.papers'):
_papersdir = curdir + '/.papers'
curdir = ''
if 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)
exit(-1)
return _papersdir
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)
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)
exit(-1)
def write_configfile(config, filepath):
try:
with open(filepath, 'w') as f:
config.write(f)
except IOError as e:
print '{}error{} : impossible to write on file {}{:s}{}'.format(
color.red, color.grey, color.cyan, filepath, color.end)
print 'Verify permissions'
exit(-1)
def read_configfile(filepath):
try:
with open(filepath, 'r') as f:
config = configparser.ConfigParser()
config.readfp(f)
return config
except IOError as e:
print '{}error{} : impossible to read file {}{:s}{}'.format(
color.red, color.grey, color.cyan, filepath, color.end)
print 'Verify permissions'
exit(-1)
def load_externalbibfile(fullbibpath):
check_file(fullbibpath)
filename, ext = os.path.splitext(os.path.split(fullbibpath)[1])
if ext == '.bib':
parser = pybtex.database.input.bibtex.Parser()
bib_data = parser.parse_file(fullbibpath)
elif ext == '.xml' or ext == '.bibtexml':
parser = pybtex.database.input.bibtexml.Parser()
bib_data = parser.parse_file(fullbibpath)
elif ext == '.yaml' or ext == '.bibyaml':
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)
exit(-1)
return bib_data
def write_papers(config):
write_configfile(config, find_papersdir() + os.sep + 'papers')
def read_papers():
return read_configfile(find_papersdir() + os.sep + 'papers')
def load_bibdata(filename):
fullbibpath = find_papersdir() + os.sep + 'bibdata' + os.sep + filename
return load_externalbibfile(fullbibpath)
def write_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)
try:
EDITOR = os.environ['EDITOR']
except KeyError:
EDITOR = 'nano'
def vim_input(initial = ""):
"""Use an editor to get input"""
with tempfile.NamedTemporaryFile(suffix=".tmp", delete=False) as temp_file:
tfile_name = temp_file.name
temp_file.write(initial)
temp_file.flush()
subprocess.call([EDITOR, tfile_name])
with open(tfile_name) as temp_file:
content = temp_file.read()
os.remove(tfile_name)
return content

@ -0,0 +1,30 @@
#!/usr/bin/env python2
import argparse
import collections
import papers
from papers import commands
cmds = collections.OrderedDict([
('init', commands.init_cmd),
('add' , commands.add_cmd),
('list', commands.list_cmd),
('open', commands.open_cmd),
('websearch', commands.websearch_cmd)
])
config = None
parser = argparse.ArgumentParser(description="research papers repository")
subparsers = parser.add_subparsers(title="valid commands", dest="command")
for cmd_mod in cmds.values():
subparser = cmd_mod.parser(subparsers, config)
args = parser.parse_args()
args.config = config
cmd = args.command
del args.command
cmds[cmd].command(**vars(args))

@ -0,0 +1,28 @@
# display formatting
import color
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)
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['year']
journal = article.fields['journal']
return '{}{}{} \"{}{}{}\" {}{}{} {}({}{}{}){}'.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)
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'
s += '\n'.join('{}: {}'.format(k, v) for k, v in article.fields.items())
return s

@ -0,0 +1,14 @@
#!/usr/bin/env python
from distutils.core import setup
setup(name='papers',
version='1',
author='Fabien Benureau, Olivier Mangin',
author_email='fabien.benureau+inria@gmail.com',
url='',
description='research papers manager',
requires=['pybtex'],
packages = ['papers', 'papers.commands'],
scripts=['papers/papers']
)
Loading…
Cancel
Save