Rewritten config module

It depends on configobj, is cleaner and simpler than the previous implementation.
It adds comments in the config file, and type verification.

Related: #18
main
Fabien Benureau 9 years ago
parent da4723d6db
commit 93c54939b3

@ -1,5 +1,4 @@
from ..uis import get_ui from ..uis import get_ui
from ..configs import config
from .. import bibstruct from .. import bibstruct
from .. import content from .. import content
from .. import repo from .. import repo
@ -28,12 +27,12 @@ def parser(subparsers):
return parser return parser
def bibentry_from_editor(ui, rp): def bibentry_from_editor(conf, ui, rp):
again = True again = True
bibstr = templates.add_bib bibstr = templates.add_bib
while again: while again:
try: try:
bibstr = content.editor_input(config().edit_cmd, bibstr = content.editor_input(conf['main']['edit_cmd'],
bibstr, bibstr,
suffix='.bib') suffix='.bib')
if bibstr == templates.add_bib: if bibstr == templates.add_bib:
@ -57,7 +56,7 @@ def bibentry_from_editor(ui, rp):
return bibentry return bibentry
def command(args): def command(conf, args):
""" """
:param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param bibfile: bibtex file (in .bib, .bibml or .yaml format.
:param docfile: path (no url yet) to a pdf or ps file :param docfile: path (no url yet) to a pdf or ps file
@ -69,12 +68,12 @@ def command(args):
tags = args.tags tags = args.tags
citekey = args.citekey citekey = args.citekey
rp = repo.Repository(config()) rp = repo.Repository(conf)
# get bibtex entry # get bibtex entry
if bibfile is None: if bibfile is None:
if args.doi is None and args.isbn is None: if args.doi is None and args.isbn is None:
bibentry = bibentry_from_editor(ui, rp) bibentry = bibentry_from_editor(conf, ui, rp)
else: else:
if args.doi is not None: if args.doi is not None:
bibentry_raw = apis.doi2bibtex(args.doi) bibentry_raw = apis.doi2bibtex(args.doi)
@ -124,18 +123,28 @@ def command(args):
'{}, using {} instead.').format(bib_docfile, docfile)) '{}, using {} instead.').format(bib_docfile, docfile))
# create the paper # create the paper
copy = args.copy
if copy is None:
copy = conf['main']['doc_add'] in ('copy', 'move')
move = args.move
if move is None:
move = conf['main']['doc_add'] == 'move'
try: try:
rp.push_paper(p) rp.push_paper(p)
if docfile is not None: if docfile is not None:
rp.push_doc(p.citekey, docfile, copy=args.copy or args.move) rp.push_doc(p.citekey, docfile, copy=copy or args.move)
if args.copy: if copy:
if args.move: if move:
content.remove_file(docfile) content.remove_file(docfile)
# elif ui.input_yn('{} has been copied into pubs; should the original be removed?'.format(color.dye_out(docfile, 'bold'))):
# content.remove_file(docfile)
ui.message('added to pubs:\n{}'.format(pretty.paper_oneliner(p))) ui.message('added to pubs:\n{}'.format(pretty.paper_oneliner(p)))
if copy:
if move:
ui.message('{} was moved to the pubs repository.'.format(docfile))
else:
ui.message('{} was copied to the pubs repository.'.format(docfile))
except ValueError as v: except ValueError as v:
ui.error(v.message) ui.error(v.message)
ui.exit(1) ui.exit(1)

@ -1,6 +1,5 @@
from .. import repo from .. import repo
from .. import color from .. import color
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from .. import content from .. import content
@ -20,7 +19,7 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
""" """
:param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param bibfile: bibtex file (in .bib, .bibml or .yaml format.
:param docfile: path (no url yet) to a pdf or ps file :param docfile: path (no url yet) to a pdf or ps file
@ -28,7 +27,7 @@ def command(args):
ui = get_ui() ui = get_ui()
rp = repo.Repository(config()) rp = repo.Repository(conf)
paper = rp.pull_paper(args.citekey) paper = rp.pull_paper(args.citekey)
try: try:

@ -1,6 +1,6 @@
from ..paper import Paper from ..paper import Paper
from .. import repo from .. import repo
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from ..endecoder import EnDecoder from ..endecoder import EnDecoder
from ..utils import resolve_citekey from ..utils import resolve_citekey
@ -16,12 +16,12 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
meta = args.meta meta = args.meta
rp = repo.Repository(config()) rp = repo.Repository(conf)
citekey = resolve_citekey(rp, args.citekey, ui=ui, exit_on_fail=True) citekey = resolve_citekey(rp, args.citekey, ui=ui, exit_on_fail=True)
paper = rp.pull_paper(citekey) paper = rp.pull_paper(citekey)

@ -1,7 +1,6 @@
from __future__ import print_function from __future__ import print_function
from .. import repo from .. import repo
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from .. import endecoder from .. import endecoder
@ -14,14 +13,14 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
""" """
""" """
# :param bib_format (only 'bibtex' now) # :param bib_format (only 'bibtex' now)
ui = get_ui() ui = get_ui()
rp = repo.Repository(config()) rp = repo.Repository(conf)
try: try:
papers = [rp.pull_paper(c) for c in args.citekeys] papers = [rp.pull_paper(c) for c in args.citekeys]

@ -6,7 +6,7 @@ from .. import endecoder
from .. import bibstruct from .. import bibstruct
from .. import color from .. import color
from ..paper import Paper from ..paper import Paper
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from ..content import system_path, read_file from ..content import system_path, read_file
@ -58,7 +58,7 @@ def many_from_path(bibpath):
return papers return papers
def command(args): def command(conf, args):
""" """
:param bibpath: path (no url yet) to a bibliography file :param bibpath: path (no url yet) to a bibliography file
""" """
@ -66,10 +66,10 @@ def command(args):
ui = get_ui() ui = get_ui()
bibpath = args.bibpath bibpath = args.bibpath
copy = args.copy copy = args.copy
if copy is None: if copy is None:
copy = config().import_copy copy = conf['main']['doc_add'] in ('copy', 'move')
rp = repo.Repository(config())
rp = repo.Repository(conf)
# Extract papers from bib # Extract papers from bib
papers = many_from_path(bibpath) papers = many_from_path(bibpath)
keys = args.keys or papers.keys() keys = args.keys or papers.keys()
@ -85,7 +85,8 @@ def command(args):
if docfile is None: if docfile is None:
ui.warning("no file for {}.".format(p.citekey)) ui.warning("no file for {}.".format(p.citekey))
else: else:
rp.push_doc(p.citekey, docfile, copy=args.copy) rp.push_doc(p.citekey, docfile, copy=copy)
#FIXME should move the file if configured to do so.
except KeyError: except KeyError:
ui.error('no entry found for citekey {}.'.format(k)) ui.error('no entry found for citekey {}.'.format(k))
except IOError as e: except IOError as e:

@ -2,25 +2,25 @@
import os import os
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from .. import color from .. import color
from ..repo import Repository from ..repo import Repository
from ..content import system_path, check_directory from ..content import system_path, check_directory
from .. import config
def parser(subparsers): def parser(subparsers):
parser = subparsers.add_parser('init', parser = subparsers.add_parser('init',
help="initialize the pubs directory") help="initialize the pubs directory")
parser.add_argument('-p', '--pubsdir', default=None, parser.add_argument('-p', '--pubsdir', default=None,
help='path to pubs directory (if none, ~/.ubs is used)') help='directory where to put the pubs repository (if none, ~/.pubs is used)')
parser.add_argument('-d', '--docsdir', default='docsdir://', parser.add_argument('-d', '--docsdir', default='docsdir://',
help=('path to document directory (if not specified, documents will' help=('path to document directory (if not specified, documents will'
'be stored in /path/to/pubsdir/doc/)')) 'be stored in /path/to/pubsdir/doc/)'))
return parser return parser
def command(args): def command(conf, args):
"""Create a .pubs directory""" """Create a .pubs directory"""
ui = get_ui() ui = get_ui()
@ -39,8 +39,8 @@ def command(args):
ui.message('Initializing pubs in {}'.format(color.dye_out(pubsdir, color.filepath))) ui.message('Initializing pubs in {}'.format(color.dye_out(pubsdir, color.filepath)))
config().pubsdir = pubsdir conf['main']['pubsdir'] = pubsdir
config().docsdir = docsdir conf['main']['docsdir'] = docsdir
config().save() config.save_conf(conf)
Repository(config(), create=True) Repository(conf, create=True)

@ -3,7 +3,6 @@ from datetime import datetime
from .. import repo from .. import repo
from .. import pretty from .. import pretty
from .. import bibstruct from .. import bibstruct
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
@ -36,9 +35,9 @@ def date_added(p):
return p.added or datetime(1, 1, 1) return p.added or datetime(1, 1, 1)
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
rp = repo.Repository(config()) rp = repo.Repository(conf)
papers = filter(lambda p: filter_paper(p, args.query, papers = filter(lambda p: filter_paper(p, args.query,
case_sensitive=args.case_sensitive), case_sensitive=args.case_sensitive),
rp.all_papers()) rp.all_papers())

@ -1,8 +1,8 @@
from .. import repo from .. import repo
from .. import content from .. import content
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
def parser(subparsers): def parser(subparsers):
parser = subparsers.add_parser('note', parser = subparsers.add_parser('note',
help='edit the note attached to a paper') help='edit the note attached to a paper')
@ -11,17 +11,16 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
""" """
""" """
ui = get_ui() ui = get_ui()
rp = repo.Repository(conf)
rp = repo.Repository(config())
if not rp.databroker.exists(args.citekey): if not rp.databroker.exists(args.citekey):
ui.error("citekey {} not found".format(args.citekey)) ui.error("citekey {} not found".format(args.citekey))
ui.exit(1) ui.exit(1)
notepath = rp.databroker.real_notepath(args.citekey) notepath = rp.databroker.real_notepath(args.citekey)
content.edit_file(config().edit_cmd, notepath, temporary=False) content.edit_file(conf['main']['edit_cmd'], notepath, temporary=False)

@ -1,7 +1,7 @@
import subprocess import subprocess
from .. import repo from .. import repo
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from .. import color from .. import color
from ..content import system_path from ..content import system_path
@ -17,17 +17,19 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
with_command = args.with_command with_command = args.with_command
rp = repo.Repository(config()) rp = repo.Repository(conf)
citekey = resolve_citekey(rp, args.citekey, ui=ui, exit_on_fail=True) citekey = resolve_citekey(rp, args.citekey, ui=ui, exit_on_fail=True)
paper = rp.pull_paper(citekey) paper = rp.pull_paper(citekey)
if with_command is None: if with_command is None:
with_command = config().open_cmd with_command = conf['main']['open_cmd']
if with_command is None: # default in conf have not been changed
pass # TODO platform specific
if paper.docpath is None: if paper.docpath is None:
ui.error('No document associated with the entry {}.'.format( ui.error('No document associated with the entry {}.'.format(

@ -1,6 +1,5 @@
from .. import repo from .. import repo
from .. import color from .. import color
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
@ -13,11 +12,11 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
force = args.force force = args.force
rp = repo.Repository(config()) rp = repo.Repository(conf)
if force is None: if force is None:
are_you_sure = (("Are you sure you want to delete paper(s) [{}]" are_you_sure = (("Are you sure you want to delete paper(s) [{}]"

@ -1,5 +1,4 @@
from ..uis import get_ui from ..uis import get_ui
from ..configs import config
from .. import bibstruct from .. import bibstruct
from .. import content from .. import content
from .. import repo from .. import repo
@ -14,14 +13,14 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
""" """
:param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param bibfile: bibtex file (in .bib, .bibml or .yaml format.
:param docfile: path (no url yet) to a pdf or ps file :param docfile: path (no url yet) to a pdf or ps file
""" """
ui = get_ui() ui = get_ui()
rp = repo.Repository(config()) rp = repo.Repository(conf)
paper = rp.pull_paper(args.citekey) paper = rp.pull_paper(args.citekey)
rp.rename_paper(paper, args.new_citekey) rp.rename_paper(paper, args.new_citekey)

@ -20,7 +20,7 @@ The different use cases are :
import re import re
from ..repo import Repository, InvalidReference from ..repo import Repository, InvalidReference
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from .. import pretty from .. import pretty
from .. import color from .. import color
@ -72,7 +72,7 @@ def _tag_groups(tags):
minus_tags.append(tag[1:]) minus_tags.append(tag[1:])
return set(plus_tags), set(minus_tags) return set(plus_tags), set(minus_tags)
def command(args): def command(conf, args):
"""Add, remove and show tags""" """Add, remove and show tags"""
ui = get_ui() ui = get_ui()
@ -80,7 +80,7 @@ def command(args):
tags = args.tags tags = args.tags
rp = Repository(config()) rp = Repository(conf)
if citekeyOrTag is None: if citekeyOrTag is None:
ui.message(color.dye_out(' '.join(sorted(rp.get_tags())), color.tag)) ui.message(color.dye_out(' '.join(sorted(rp.get_tags())), color.tag))

@ -2,7 +2,7 @@ import sys
from .. import repo from .. import repo
from .. import color from .. import color
from ..configs import config
from ..uis import get_ui from ..uis import get_ui
from ..__init__ import __version__ from ..__init__ import __version__
@ -11,12 +11,14 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
code_version = __version__ code_version = __version__.split('.')
repo_version = int(config().version) if len(conf['internal']['version']) == 1: # support for deprecated version scheme.
conf['internal']['version'] = '0.{}.0'.format(conf['internal']['version'])
repo_version = conf['internal']['version'].split('.')
if repo_version == code_version: if repo_version == code_version:
ui.message('Your pubs repository is up-to-date.') ui.message('Your pubs repository is up-to-date.')
@ -27,11 +29,11 @@ def command(args):
sys.exit(0) sys.exit(0)
else: else:
msg = ("You should backup the pubs directory {} before continuing." msg = ("You should backup the pubs directory {} before continuing."
"Continue ?").format(color.dye_out(config().papers_dir, color.filepath)) "Continue ?").format(color.dye_out(conf['main']['pubsdir'], color.filepath))
sure = ui.input_yn(question=msg, default='n') sure = ui.input_yn(question=msg, default='n')
if not sure: if not sure:
sys.exit(0) sys.exit(0)
#TODO: update!!
# config().version = repo_version # conf['internal']['version'] = repo_version
# config().save() # conf['internal']['version']

@ -11,7 +11,7 @@ def parser(subparsers):
return parser return parser
def command(args): def command(conf, args):
ui = get_ui() ui = get_ui()
search_string = args.search_string search_string = args.search_string

@ -0,0 +1 @@
from .conf import load_default_conf, load_conf, save_conf, get_pubspath

@ -0,0 +1,49 @@
import os
import configobj
import validate
from .spec import configspec
DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc')
def load_default_conf():
"""Loads the default configuration"""
default_conf = configobj.ConfigObj(configspec=configspec)
validator = validate.Validator()
default_conf.validate(validator, copy=True)
return default_conf
def get_pubspath(verify=True):
"""Returns the pubs path.
If verify is True, verify that pubs.conf exist in the directory,
and exit with an error if not.
"""
confpath = DFT_CONFIG_PATH
if 'PUBSCONF' in os.environ:
confpath = os.path.abspath(os.path.expanduser(os.environ['PUBSCONF']))
if verify:
if not os.path.isfile(confpath):
from .. import uis
ui = uis.get_ui()
ui.error('configuration file not found at `{}`'.format(confpath))
ui.exit(error_code=1)
return confpath
def load_conf(check_conf=True):
"""Load the user config"""
pubspath = get_pubspath(verify=True)
with open(pubspath, 'r') as f:
conf = configobj.ConfigObj(f.readlines(), configspec=configspec)
if check_conf:
validator = validate.Validator()
results = conf.validate(validator, copy=True)
assert results == True, '{}'.format(results) # TODO: precise error dialog when parsing error
return conf
def save_conf(conf):
with open(get_pubspath(verify=False), 'w') as f:
conf.write(outfile=f)

@ -0,0 +1,55 @@
from .. import __version__
configspec = """
[main]
# Where the pubs repository files (bibtex, metadata, notes) are located
pubsdir = string(default='~/pubs')
# Where the documents files are located (default: $(pubsdir)/doc/)
docsdir = string(default="docsdir://")
# Specify if a document should be copied or moved in the docdir, or only
# linked when adding a publication.
doc_add = option('copy', 'move', 'link', default='move')
# if True, pubs will ask confirmation before copying/moving/linking the
# document file.
doc_add_ask = boolean(default=True)
# the command to use when opening document files
open_cmd = string(default=None)
# which editor to use when editing bibtex files.
# if using a graphical editor, use the --wait or --block option, i.e.:
# "atom --wait"
# "kate --block"
edit_cmd = string(default=None)
[formating]
# Enable bold formatting, if the terminal supports it.
bold = boolean(default=True)
# Enable italics, if the terminal supports it.
italics = boolean(default=True)
# Enable colors, if the terminal supports it.
color = boolean(default=True)
[theme]
[plugins]
# comma-separated list of the plugins to load
active = list(default=list())
[internal]
# The version of this configuration file. Do not edit.
version = string(min=5, default='{}')
""".format(__version__).split('\n')

@ -1,112 +0,0 @@
import os
import sys
import collections
from .p3 import configparser, ConfigParser, _read_config
from .content import check_file, _open
from . import __version__
# constant stuff (DFT = DEFAULT)
MAIN_SECTION = 'pubs'
DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc')
try:
DFT_EDIT_CMD = os.environ['EDITOR']
except KeyError:
DFT_EDIT_CMD = 'vi'
DFT_PLUGINS = ''
DFT_CONFIG = collections.OrderedDict([
('pubsdir', os.path.expanduser('~/.pubs')),
('docsdir', ''),
('import_copy', True),
('import_move', False),
('color', True),
('version', __version__),
('version_warning', True),
('open_cmd', 'open'),
('edit_cmd', DFT_EDIT_CMD),
('plugins', DFT_PLUGINS)
])
BOOLEANS = {'import_copy', 'import_move', 'color', 'version_warning'}
# package-shared config that can be accessed using :
# from configs import config
_config = None
def config(section=MAIN_SECTION):
if _config is None:
raise ValueError('not config instanciated yet')
_config._section = section
return _config
class Config(object):
def __init__(self, **kwargs):
object.__setattr__(self, '_section', MAIN_SECTION) # active section
object.__setattr__(self, '_cfg', ConfigParser())
self._cfg.add_section(self._section)
for name, value in DFT_CONFIG.items():
self._cfg.set(self._section, name, str(value))
for name, value in kwargs.items():
self.__setattr__(name, value)
def as_global(self):
global _config
_config = self
def load(self, path=DFT_CONFIG_PATH):
if not check_file(path, fail=False):
raise IOError(("The configuration file {} does not exist."
" Did you run 'pubs init' ?").format(path))
b_flag = ''
if sys.version_info[0] == 2: # HACK, FIXME please
b_flag = 'b'
with _open(path, 'r{}+'.format(b_flag)) as f:
_read_config(self._cfg, f)
return self
def save(self, path=DFT_CONFIG_PATH):
b_flag = ''
if sys.version_info[0] == 2: # HACK, FIXME please
b_flag = 'b'
with _open(path, 'w{}+'.format(b_flag)) as f:
self._cfg.write(f)
def __setattr__(self, name, value):
if name in ('_cfg', '_section'):
object.__setattr__(self, name, value)
else:
if type(value) is bool:
BOOLEANS.add(name)
self._cfg.set(self._section, name, str(value))
def __getattr__(self, name):
value = self._cfg.get(self._section, name)
if name in BOOLEANS:
value = str2bool(value)
return value
def get(self, name, default=None):
try:
return self.__getattr__(name)
except (configparser.NoOptionError, configparser.NoSectionError):
return default
def items(self):
for name, value in self._cfg.items(self._section):
if name in BOOLEANS:
value = str2bool(value)
yield name, value
def str2bool(s):
return str(s).lower() in ('yes', 'true', 't', 'y', '1')

@ -4,7 +4,7 @@ import argparse
import collections import collections
from . import uis from . import uis
from . import configs from . import config
from . import commands from . import commands
from . import plugins from . import plugins
from .__init__ import __version__ from .__init__ import __version__
@ -31,45 +31,43 @@ CORE_CMDS = collections.OrderedDict([
]) ])
def _update_check(config, ui): def _update_check(conf, ui):
if config.version_warning: code_version = __version__.split('.')
code_version = __version__.split('.') if len(conf['internal']['version']) == 1: # support for deprecated version scheme.
if len(config.version) == 1: # support for deprecated version scheme. conf['internal']['version'] = '0.{}.0'.format(conf['internal']['version'])
config.version = '0.{}.0'.format(config.version) repo_version = conf['internal']['version'].split('.')
repo_version = config.version.split('.')
if repo_version > code_version:
if repo_version > code_version: ui.warning(
ui.warning( 'your repository was generated with an newer version'
'your repository was generated with an newer version' ' of pubs (v{}) than the one you are using (v{}).'
' of pubs (v{}) than the one you are using (v{}).' '\n'.format(repo_version, code_version) +
'\n'.format(repo_version, code_version) + 'You should not use pubs until you install the '
'You should not use pubs until you install the ' 'newest version.')
'newest version. (use version_warning in you pubsrc ' sys.exit()
'to bypass this error)') elif repo_version < code_version:
sys.exit() ui.message(
elif repo_version < code_version: 'warning: your repository version (v{})'.format(repo_version)
ui.message( + 'must be updated to version {}.\n'.format(code_version)
'warning: your repository version (v{})'.format(repo_version) + "run 'pubs update'.")
+ 'must be updated to version {}.\n'.format(code_version) sys.exit()
+ "run 'pubs update'.")
sys.exit()
def execute(raw_args=sys.argv): def execute(raw_args=sys.argv):
# loading config # loading config
config = configs.Config()
if len(raw_args) > 1 and raw_args[1] != 'init': if len(raw_args) > 1 and raw_args[1] != 'init':
try: try:
config.load() conf = config.load_conf(check_conf=True)
except IOError as e: except IOError as e:
print('error: {}'.format(str(e))) print('error: {}'.format(str(e)))
sys.exit() sys.exit()
config.as_global() else:
conf = config.load_default_conf()
uis.init_ui(config) uis.init_ui(conf)
ui = uis.get_ui() ui = uis.get_ui()
_update_check(config, ui) _update_check(conf, ui)
parser = argparse.ArgumentParser(description="research papers repository") parser = argparse.ArgumentParser(description="research papers repository")
subparsers = parser.add_subparsers(title="valid commands", dest="command") subparsers = parser.add_subparsers(title="valid commands", dest="command")
@ -80,7 +78,7 @@ def execute(raw_args=sys.argv):
cmd_funcs[cmd_name] = cmd_mod.command cmd_funcs[cmd_name] = cmd_mod.command
# Extend with plugin commands # Extend with plugin commands
plugins.load_plugins(ui, config.plugins.split()) plugins.load_plugins(ui, conf['plugins']['active'])
for p in plugins.get_plugins().values(): for p in plugins.get_plugins().values():
cmd_funcs.update(p.get_commands(subparsers)) cmd_funcs.update(p.get_commands(subparsers))
@ -89,4 +87,4 @@ def execute(raw_args=sys.argv):
cmd = args.command cmd = args.command
del args.command del args.command
cmd_funcs[cmd](args) cmd_funcs[cmd](conf, args)

@ -22,10 +22,10 @@ class InvalidReference(Exception):
class Repository(object): class Repository(object):
def __init__(self, config, create=False): def __init__(self, conf, create=False):
self.config = config self.conf = conf
self._citekeys = None self._citekeys = None
self.databroker = DataCache(self.config.pubsdir, create=create) self.databroker = DataCache(self.conf['main']['pubsdir'], create=create)
@property @property
def citekeys(self): def citekeys(self):
@ -133,7 +133,7 @@ class Repository(object):
def push_doc(self, citekey, docfile, copy=None): def push_doc(self, citekey, docfile, copy=None):
p = self.pull_paper(citekey) p = self.pull_paper(citekey)
if copy is None: if copy is None:
copy = self.config.import_copy copy = self.conf['main']['doc_add'] in ('copy', 'move')
if copy: if copy:
docfile = self.databroker.add_doc(citekey, docfile) docfile = self.databroker.add_doc(citekey, docfile)
else: else:

@ -39,16 +39,14 @@ def init_ui(conf):
class PrintUI(object): class PrintUI(object):
def __init__(self, conf=None): def __init__(self, conf):
""" """
:param conf: if None, conservative default values are used. :param conf: if None, conservative default values are used.
Useful to instanciate the UI before parsing the config file. Useful to instanciate the UI before parsing the config file.
""" """
if conf is None: color.setup(color=conf['formating']['color'],
color.setup() bold=conf['formating']['bold'],
else: italic=conf['formating']['italics'])
color.setup(color=True, bold=True, italic=True)
# color.setup(color=conf.color, bold=conf.bold, italic=conf.italic)
self.encoding = _get_encoding(conf) self.encoding = _get_encoding(conf)
self._stdout = codecs.getwriter(self.encoding)(_get_raw_stdout(), self._stdout = codecs.getwriter(self.encoding)(_get_raw_stdout(),
errors='replace') errors='replace')
@ -77,7 +75,7 @@ class InputUI(PrintUI):
def __init__(self, conf): def __init__(self, conf):
super(InputUI, self).__init__(conf) super(InputUI, self).__init__(conf)
self.editor = conf.edit_cmd self.editor = conf['main']['edit_cmd']
def input(self): def input(self):
try: try:

@ -13,10 +13,13 @@ setup(
url = 'https://github.com/pubs/pubs', url = 'https://github.com/pubs/pubs',
description = 'command-line scientific bibliography manager', description = 'command-line scientific bibliography manager',
packages = ['pubs', 'pubs.commands', 'pubs.templates', 'pubs.plugs'], packages = ['pubs', 'pubs.config',
'pubs.commands',
'pubs.templates',
'pubs.plugs'],
scripts = ['pubs/pubs'], scripts = ['pubs/pubs'],
install_requires = ['pyyaml', 'bibtexparser', 'python-dateutil', 'requests', install_requires = ['pyyaml', 'bibtexparser', 'python-dateutil', 'requests', 'configobj',
'beautifulsoup4'], # to be made optional? 'beautifulsoup4'], # to be made optional?
classifiers=[ classifiers=[

@ -7,14 +7,15 @@ import fixtures
from pubs.repo import Repository, _base27, CiteKeyCollision, InvalidReference from pubs.repo import Repository, _base27, CiteKeyCollision, InvalidReference
from pubs.paper import Paper from pubs.paper import Paper
from pubs import configs from pubs import config
class TestRepo(fake_env.TestFakeFs): class TestRepo(fake_env.TestFakeFs):
def setUp(self): def setUp(self):
super(TestRepo, self).setUp() super(TestRepo, self).setUp()
self.repo = Repository(configs.Config(), create=True) default_conf = config.load_default_conf()
self.repo = Repository(default_conf, create=True)
self.repo.push_paper(Paper.from_bibentry(fixtures.turing_bibentry)) self.repo.push_paper(Paper.from_bibentry(fixtures.turing_bibentry))

@ -8,7 +8,9 @@ import dotdot
import fake_env import fake_env
from pubs import pubs_cmd from pubs import pubs_cmd
from pubs import color, content, filebroker, uis, p3, endecoder, configs from pubs import color, content, filebroker, uis, p3, endecoder
from pubs.config import conf
import configobj
import str_fixtures import str_fixtures
import fixtures import fixtures
@ -56,7 +58,7 @@ class CommandTestCase(unittest.TestCase):
maxDiff = 1000000 maxDiff = 1000000
def setUp(self): def setUp(self):
self.fs = fake_env.create_fake_fs([content, filebroker, configs, init_cmd, import_cmd]) self.fs = fake_env.create_fake_fs([content, filebroker, conf, init_cmd, import_cmd, configobj])
self.default_pubs_dir = self.fs['os'].path.expanduser('~/.pubs') self.default_pubs_dir = self.fs['os'].path.expanduser('~/.pubs')
def execute_cmds(self, cmds, capture_output=CAPTURE_OUTPUT): def execute_cmds(self, cmds, capture_output=CAPTURE_OUTPUT):
@ -107,7 +109,7 @@ class CommandTestCase(unittest.TestCase):
return outs return outs
def tearDown(self): def tearDown(self):
fake_env.unset_fake_fs([content, filebroker, configs, init_cmd, import_cmd]) fake_env.unset_fake_fs([content, filebroker, conf, init_cmd, import_cmd, configobj])
class DataCommandTestCase(CommandTestCase): class DataCommandTestCase(CommandTestCase):
@ -253,7 +255,8 @@ class TestUsecase(DataCommandTestCase):
def test_first(self): def test_first(self):
correct = ['Initializing pubs in /paper_first\n', correct = ['Initializing pubs in /paper_first\n',
'added to pubs:\n[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) \n', 'added to pubs:\n[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) \n'
'data/pagerank.pdf was copied to the pubs repository.\n',
'[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) \n', '[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) \n',
'\n', '\n',
'', '',

Loading…
Cancel
Save