From 93c54939b3d5937bf1d552ccd808691f5963ba19 Mon Sep 17 00:00:00 2001 From: Fabien Benureau Date: Fri, 4 Dec 2015 20:42:56 +0100 Subject: [PATCH] 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 --- pubs/commands/add_cmd.py | 31 +++++---- pubs/commands/attach_cmd.py | 5 +- pubs/commands/edit_cmd.py | 6 +- pubs/commands/export_cmd.py | 5 +- pubs/commands/import_cmd.py | 13 ++-- pubs/commands/init_cmd.py | 16 ++--- pubs/commands/list_cmd.py | 5 +- pubs/commands/note_cmd.py | 9 ++- pubs/commands/open_cmd.py | 10 +-- pubs/commands/remove_cmd.py | 5 +- pubs/commands/rename_cmd.py | 5 +- pubs/commands/tag_cmd.py | 6 +- pubs/commands/update_cmd.py | 18 +++--- pubs/commands/websearch_cmd.py | 2 +- pubs/config/__init__.py | 1 + pubs/config/conf.py | 49 +++++++++++++++ pubs/config/spec.py | 55 ++++++++++++++++ pubs/configs.py | 112 --------------------------------- pubs/pubs_cmd.py | 58 +++++++++-------- pubs/repo.py | 8 +-- pubs/uis.py | 12 ++-- setup.py | 7 ++- tests/test_repo.py | 5 +- tests/test_usecase.py | 11 ++-- 24 files changed, 229 insertions(+), 225 deletions(-) create mode 100644 pubs/config/__init__.py create mode 100644 pubs/config/conf.py create mode 100644 pubs/config/spec.py delete mode 100644 pubs/configs.py diff --git a/pubs/commands/add_cmd.py b/pubs/commands/add_cmd.py index 9c2ea28..6267a47 100644 --- a/pubs/commands/add_cmd.py +++ b/pubs/commands/add_cmd.py @@ -1,5 +1,4 @@ from ..uis import get_ui -from ..configs import config from .. import bibstruct from .. import content from .. import repo @@ -28,12 +27,12 @@ def parser(subparsers): return parser -def bibentry_from_editor(ui, rp): +def bibentry_from_editor(conf, ui, rp): again = True bibstr = templates.add_bib while again: try: - bibstr = content.editor_input(config().edit_cmd, + bibstr = content.editor_input(conf['main']['edit_cmd'], bibstr, suffix='.bib') if bibstr == templates.add_bib: @@ -57,7 +56,7 @@ def bibentry_from_editor(ui, rp): return bibentry -def command(args): +def command(conf, args): """ :param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param docfile: path (no url yet) to a pdf or ps file @@ -69,12 +68,12 @@ def command(args): tags = args.tags citekey = args.citekey - rp = repo.Repository(config()) + rp = repo.Repository(conf) # get bibtex entry if bibfile 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: if args.doi is not None: bibentry_raw = apis.doi2bibtex(args.doi) @@ -124,18 +123,28 @@ def command(args): '{}, using {} instead.').format(bib_docfile, docfile)) # 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: rp.push_paper(p) if docfile is not None: - rp.push_doc(p.citekey, docfile, copy=args.copy or args.move) - if args.copy: - if args.move: + rp.push_doc(p.citekey, docfile, copy=copy or args.move) + if copy: + if move: 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))) + 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: ui.error(v.message) ui.exit(1) diff --git a/pubs/commands/attach_cmd.py b/pubs/commands/attach_cmd.py index d0ea5bf..41bcdea 100644 --- a/pubs/commands/attach_cmd.py +++ b/pubs/commands/attach_cmd.py @@ -1,6 +1,5 @@ from .. import repo from .. import color -from ..configs import config from ..uis import get_ui from .. import content @@ -20,7 +19,7 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): """ :param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param docfile: path (no url yet) to a pdf or ps file @@ -28,7 +27,7 @@ def command(args): ui = get_ui() - rp = repo.Repository(config()) + rp = repo.Repository(conf) paper = rp.pull_paper(args.citekey) try: diff --git a/pubs/commands/edit_cmd.py b/pubs/commands/edit_cmd.py index 497665f..522b837 100644 --- a/pubs/commands/edit_cmd.py +++ b/pubs/commands/edit_cmd.py @@ -1,6 +1,6 @@ from ..paper import Paper from .. import repo -from ..configs import config + from ..uis import get_ui from ..endecoder import EnDecoder from ..utils import resolve_citekey @@ -16,12 +16,12 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): ui = get_ui() meta = args.meta - rp = repo.Repository(config()) + rp = repo.Repository(conf) citekey = resolve_citekey(rp, args.citekey, ui=ui, exit_on_fail=True) paper = rp.pull_paper(citekey) diff --git a/pubs/commands/export_cmd.py b/pubs/commands/export_cmd.py index 0e87296..a55a791 100644 --- a/pubs/commands/export_cmd.py +++ b/pubs/commands/export_cmd.py @@ -1,7 +1,6 @@ from __future__ import print_function from .. import repo -from ..configs import config from ..uis import get_ui from .. import endecoder @@ -14,14 +13,14 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): """ """ # :param bib_format (only 'bibtex' now) ui = get_ui() - rp = repo.Repository(config()) + rp = repo.Repository(conf) try: papers = [rp.pull_paper(c) for c in args.citekeys] diff --git a/pubs/commands/import_cmd.py b/pubs/commands/import_cmd.py index c34de89..30d200e 100644 --- a/pubs/commands/import_cmd.py +++ b/pubs/commands/import_cmd.py @@ -6,7 +6,7 @@ from .. import endecoder from .. import bibstruct from .. import color from ..paper import Paper -from ..configs import config + from ..uis import get_ui from ..content import system_path, read_file @@ -58,7 +58,7 @@ def many_from_path(bibpath): return papers -def command(args): +def command(conf, args): """ :param bibpath: path (no url yet) to a bibliography file """ @@ -66,10 +66,10 @@ def command(args): ui = get_ui() bibpath = args.bibpath copy = args.copy - if copy is None: - copy = config().import_copy - rp = repo.Repository(config()) + copy = conf['main']['doc_add'] in ('copy', 'move') + + rp = repo.Repository(conf) # Extract papers from bib papers = many_from_path(bibpath) keys = args.keys or papers.keys() @@ -85,7 +85,8 @@ def command(args): if docfile is None: ui.warning("no file for {}.".format(p.citekey)) 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: ui.error('no entry found for citekey {}.'.format(k)) except IOError as e: diff --git a/pubs/commands/init_cmd.py b/pubs/commands/init_cmd.py index 416f535..0bfaa0c 100644 --- a/pubs/commands/init_cmd.py +++ b/pubs/commands/init_cmd.py @@ -2,25 +2,25 @@ import os -from ..configs import config + from ..uis import get_ui from .. import color from ..repo import Repository from ..content import system_path, check_directory - +from .. import config def parser(subparsers): parser = subparsers.add_parser('init', help="initialize the pubs directory") 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://', help=('path to document directory (if not specified, documents will' 'be stored in /path/to/pubsdir/doc/)')) return parser -def command(args): +def command(conf, args): """Create a .pubs directory""" ui = get_ui() @@ -39,8 +39,8 @@ def command(args): ui.message('Initializing pubs in {}'.format(color.dye_out(pubsdir, color.filepath))) - config().pubsdir = pubsdir - config().docsdir = docsdir - config().save() + conf['main']['pubsdir'] = pubsdir + conf['main']['docsdir'] = docsdir + config.save_conf(conf) - Repository(config(), create=True) + Repository(conf, create=True) diff --git a/pubs/commands/list_cmd.py b/pubs/commands/list_cmd.py index 5b648aa..a382672 100644 --- a/pubs/commands/list_cmd.py +++ b/pubs/commands/list_cmd.py @@ -3,7 +3,6 @@ from datetime import datetime from .. import repo from .. import pretty from .. import bibstruct -from ..configs import config from ..uis import get_ui @@ -36,9 +35,9 @@ def date_added(p): return p.added or datetime(1, 1, 1) -def command(args): +def command(conf, args): ui = get_ui() - rp = repo.Repository(config()) + rp = repo.Repository(conf) papers = filter(lambda p: filter_paper(p, args.query, case_sensitive=args.case_sensitive), rp.all_papers()) diff --git a/pubs/commands/note_cmd.py b/pubs/commands/note_cmd.py index ad2a3eb..77be6d2 100644 --- a/pubs/commands/note_cmd.py +++ b/pubs/commands/note_cmd.py @@ -1,8 +1,8 @@ from .. import repo from .. import content -from ..configs import config from ..uis import get_ui + def parser(subparsers): parser = subparsers.add_parser('note', help='edit the note attached to a paper') @@ -11,17 +11,16 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): """ """ ui = get_ui() - - rp = repo.Repository(config()) + rp = repo.Repository(conf) if not rp.databroker.exists(args.citekey): ui.error("citekey {} not found".format(args.citekey)) ui.exit(1) 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) diff --git a/pubs/commands/open_cmd.py b/pubs/commands/open_cmd.py index 7f47a4a..fa4cec0 100644 --- a/pubs/commands/open_cmd.py +++ b/pubs/commands/open_cmd.py @@ -1,7 +1,7 @@ import subprocess from .. import repo -from ..configs import config + from ..uis import get_ui from .. import color from ..content import system_path @@ -17,17 +17,19 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): ui = get_ui() 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) paper = rp.pull_paper(citekey) 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: ui.error('No document associated with the entry {}.'.format( diff --git a/pubs/commands/remove_cmd.py b/pubs/commands/remove_cmd.py index a4245c2..47e20d8 100644 --- a/pubs/commands/remove_cmd.py +++ b/pubs/commands/remove_cmd.py @@ -1,6 +1,5 @@ from .. import repo from .. import color -from ..configs import config from ..uis import get_ui @@ -13,11 +12,11 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): ui = get_ui() force = args.force - rp = repo.Repository(config()) + rp = repo.Repository(conf) if force is None: are_you_sure = (("Are you sure you want to delete paper(s) [{}]" diff --git a/pubs/commands/rename_cmd.py b/pubs/commands/rename_cmd.py index 0540544..bc2df2d 100644 --- a/pubs/commands/rename_cmd.py +++ b/pubs/commands/rename_cmd.py @@ -1,5 +1,4 @@ from ..uis import get_ui -from ..configs import config from .. import bibstruct from .. import content from .. import repo @@ -14,14 +13,14 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): """ :param bibfile: bibtex file (in .bib, .bibml or .yaml format. :param docfile: path (no url yet) to a pdf or ps file """ ui = get_ui() - rp = repo.Repository(config()) + rp = repo.Repository(conf) paper = rp.pull_paper(args.citekey) rp.rename_paper(paper, args.new_citekey) diff --git a/pubs/commands/tag_cmd.py b/pubs/commands/tag_cmd.py index 34485b8..fb8e9a2 100644 --- a/pubs/commands/tag_cmd.py +++ b/pubs/commands/tag_cmd.py @@ -20,7 +20,7 @@ The different use cases are : import re from ..repo import Repository, InvalidReference -from ..configs import config + from ..uis import get_ui from .. import pretty from .. import color @@ -72,7 +72,7 @@ def _tag_groups(tags): minus_tags.append(tag[1:]) return set(plus_tags), set(minus_tags) -def command(args): +def command(conf, args): """Add, remove and show tags""" ui = get_ui() @@ -80,7 +80,7 @@ def command(args): tags = args.tags - rp = Repository(config()) + rp = Repository(conf) if citekeyOrTag is None: ui.message(color.dye_out(' '.join(sorted(rp.get_tags())), color.tag)) diff --git a/pubs/commands/update_cmd.py b/pubs/commands/update_cmd.py index bc1d899..0457f6a 100644 --- a/pubs/commands/update_cmd.py +++ b/pubs/commands/update_cmd.py @@ -2,7 +2,7 @@ import sys from .. import repo from .. import color -from ..configs import config + from ..uis import get_ui from ..__init__ import __version__ @@ -11,12 +11,14 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): ui = get_ui() - code_version = __version__ - repo_version = int(config().version) + code_version = __version__.split('.') + 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: ui.message('Your pubs repository is up-to-date.') @@ -27,11 +29,11 @@ def command(args): sys.exit(0) else: 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') if not sure: sys.exit(0) - -# config().version = repo_version -# config().save() + #TODO: update!! +# conf['internal']['version'] = repo_version +# conf['internal']['version'] diff --git a/pubs/commands/websearch_cmd.py b/pubs/commands/websearch_cmd.py index e3e1c76..ee7ee20 100644 --- a/pubs/commands/websearch_cmd.py +++ b/pubs/commands/websearch_cmd.py @@ -11,7 +11,7 @@ def parser(subparsers): return parser -def command(args): +def command(conf, args): ui = get_ui() search_string = args.search_string diff --git a/pubs/config/__init__.py b/pubs/config/__init__.py new file mode 100644 index 0000000..d7ea4b7 --- /dev/null +++ b/pubs/config/__init__.py @@ -0,0 +1 @@ +from .conf import load_default_conf, load_conf, save_conf, get_pubspath diff --git a/pubs/config/conf.py b/pubs/config/conf.py new file mode 100644 index 0000000..b891fd3 --- /dev/null +++ b/pubs/config/conf.py @@ -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) diff --git a/pubs/config/spec.py b/pubs/config/spec.py new file mode 100644 index 0000000..6f8be61 --- /dev/null +++ b/pubs/config/spec.py @@ -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') diff --git a/pubs/configs.py b/pubs/configs.py deleted file mode 100644 index 305b58c..0000000 --- a/pubs/configs.py +++ /dev/null @@ -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') diff --git a/pubs/pubs_cmd.py b/pubs/pubs_cmd.py index 2cae25a..16d7a80 100644 --- a/pubs/pubs_cmd.py +++ b/pubs/pubs_cmd.py @@ -4,7 +4,7 @@ import argparse import collections from . import uis -from . import configs +from . import config from . import commands from . import plugins from .__init__ import __version__ @@ -31,45 +31,43 @@ CORE_CMDS = collections.OrderedDict([ ]) -def _update_check(config, ui): - if config.version_warning: - code_version = __version__.split('.') - if len(config.version) == 1: # support for deprecated version scheme. - config.version = '0.{}.0'.format(config.version) - repo_version = config.version.split('.') - - if repo_version > code_version: - ui.warning( - 'your repository was generated with an newer version' - ' of pubs (v{}) than the one you are using (v{}).' - '\n'.format(repo_version, code_version) + - 'You should not use pubs until you install the ' - 'newest version. (use version_warning in you pubsrc ' - 'to bypass this error)') - sys.exit() - elif repo_version < code_version: - ui.message( - 'warning: your repository version (v{})'.format(repo_version) - + 'must be updated to version {}.\n'.format(code_version) - + "run 'pubs update'.") - sys.exit() +def _update_check(conf, ui): + code_version = __version__.split('.') + 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: + ui.warning( + 'your repository was generated with an newer version' + ' of pubs (v{}) than the one you are using (v{}).' + '\n'.format(repo_version, code_version) + + 'You should not use pubs until you install the ' + 'newest version.') + sys.exit() + elif repo_version < code_version: + ui.message( + 'warning: your repository version (v{})'.format(repo_version) + + 'must be updated to version {}.\n'.format(code_version) + + "run 'pubs update'.") + sys.exit() def execute(raw_args=sys.argv): # loading config - config = configs.Config() if len(raw_args) > 1 and raw_args[1] != 'init': try: - config.load() + conf = config.load_conf(check_conf=True) except IOError as e: print('error: {}'.format(str(e))) sys.exit() - config.as_global() + else: + conf = config.load_default_conf() - uis.init_ui(config) + uis.init_ui(conf) ui = uis.get_ui() - _update_check(config, ui) + _update_check(conf, ui) parser = argparse.ArgumentParser(description="research papers repository") 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 # 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(): cmd_funcs.update(p.get_commands(subparsers)) @@ -89,4 +87,4 @@ def execute(raw_args=sys.argv): cmd = args.command del args.command - cmd_funcs[cmd](args) + cmd_funcs[cmd](conf, args) diff --git a/pubs/repo.py b/pubs/repo.py index a2cdfcc..d08caaa 100644 --- a/pubs/repo.py +++ b/pubs/repo.py @@ -22,10 +22,10 @@ class InvalidReference(Exception): class Repository(object): - def __init__(self, config, create=False): - self.config = config + def __init__(self, conf, create=False): + self.conf = conf self._citekeys = None - self.databroker = DataCache(self.config.pubsdir, create=create) + self.databroker = DataCache(self.conf['main']['pubsdir'], create=create) @property def citekeys(self): @@ -133,7 +133,7 @@ class Repository(object): def push_doc(self, citekey, docfile, copy=None): p = self.pull_paper(citekey) if copy is None: - copy = self.config.import_copy + copy = self.conf['main']['doc_add'] in ('copy', 'move') if copy: docfile = self.databroker.add_doc(citekey, docfile) else: diff --git a/pubs/uis.py b/pubs/uis.py index c019105..82e8744 100644 --- a/pubs/uis.py +++ b/pubs/uis.py @@ -39,16 +39,14 @@ def init_ui(conf): class PrintUI(object): - def __init__(self, conf=None): + def __init__(self, conf): """ :param conf: if None, conservative default values are used. Useful to instanciate the UI before parsing the config file. """ - if conf is None: - color.setup() - else: - color.setup(color=True, bold=True, italic=True) -# color.setup(color=conf.color, bold=conf.bold, italic=conf.italic) + color.setup(color=conf['formating']['color'], + bold=conf['formating']['bold'], + italic=conf['formating']['italics']) self.encoding = _get_encoding(conf) self._stdout = codecs.getwriter(self.encoding)(_get_raw_stdout(), errors='replace') @@ -77,7 +75,7 @@ class InputUI(PrintUI): def __init__(self, conf): super(InputUI, self).__init__(conf) - self.editor = conf.edit_cmd + self.editor = conf['main']['edit_cmd'] def input(self): try: diff --git a/setup.py b/setup.py index a0a29ba..145a58d 100644 --- a/setup.py +++ b/setup.py @@ -13,10 +13,13 @@ setup( url = 'https://github.com/pubs/pubs', 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'], - install_requires = ['pyyaml', 'bibtexparser', 'python-dateutil', 'requests', + install_requires = ['pyyaml', 'bibtexparser', 'python-dateutil', 'requests', 'configobj', 'beautifulsoup4'], # to be made optional? classifiers=[ diff --git a/tests/test_repo.py b/tests/test_repo.py index b651caf..86e175d 100644 --- a/tests/test_repo.py +++ b/tests/test_repo.py @@ -7,14 +7,15 @@ import fixtures from pubs.repo import Repository, _base27, CiteKeyCollision, InvalidReference from pubs.paper import Paper -from pubs import configs +from pubs import config class TestRepo(fake_env.TestFakeFs): def setUp(self): 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)) diff --git a/tests/test_usecase.py b/tests/test_usecase.py index 5464d21..38e31cf 100644 --- a/tests/test_usecase.py +++ b/tests/test_usecase.py @@ -8,7 +8,9 @@ import dotdot import fake_env 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 fixtures @@ -56,7 +58,7 @@ class CommandTestCase(unittest.TestCase): maxDiff = 1000000 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') def execute_cmds(self, cmds, capture_output=CAPTURE_OUTPUT): @@ -107,7 +109,7 @@ class CommandTestCase(unittest.TestCase): return outs 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): @@ -253,7 +255,8 @@ class TestUsecase(DataCommandTestCase): def test_first(self): 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', '\n', '',