Commit bac98294 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Allow configuration options to be overridden by commandline flags.

When obtaining a configuration object, it is now possible to pass
certain values to be overridden no matter what settings were made in the
configuration files.

This is used to let the -t and -d flags (location of todo.txt and
archive respectively) override anything that is mentioned in
configuration files.

This fixes a bug where the edit subcommand did not respect the -t flag,
because it was simply reading the location from the configuration file.
Now the configuration is overridden when -t is passed.

Thanks to Jacek for reporting the broken 'edit' command.
parent 9ab686d6
...@@ -29,5 +29,13 @@ class ConfigTest(TopydoTest): ...@@ -29,5 +29,13 @@ class ConfigTest(TopydoTest):
def test_config3(self): def test_config3(self):
self.assertTrue(config("test/data/config2").ignore_weekends()) self.assertTrue(config("test/data/config2").ignore_weekends())
def test_config4(self):
""" Test that value in file is overridden by parameter. """
overrides = {
('topydo', 'default_command'): 'edit'
}
self.assertEqual(config("test/data/config1", p_overrides=overrides).default_command(), 'edit')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -45,7 +45,7 @@ class CLIApplication(CLIApplicationBase): ...@@ -45,7 +45,7 @@ class CLIApplication(CLIApplicationBase):
""" Main entry function. """ """ Main entry function. """
args = self._process_flags() args = self._process_flags()
self.todofile = TodoFile.TodoFile(self.path) self.todofile = TodoFile.TodoFile(config().todotxt())
self.todolist = TodoList.TodoList(self.todofile.read()) self.todolist = TodoList.TodoList(self.todofile.read())
(subcommand, args) = get_subcommand(args) (subcommand, args) = get_subcommand(args)
......
...@@ -112,11 +112,6 @@ class CLIApplicationBase(object): ...@@ -112,11 +112,6 @@ class CLIApplicationBase(object):
""" """
def __init__(self): def __init__(self):
self.todolist = TodoList.TodoList([]) self.todolist = TodoList.TodoList([])
self.config = config()
self.path = self.config.todotxt()
self.archive_path = self.config.archive()
self.todofile = None self.todofile = None
def _usage(self): def _usage(self):
...@@ -135,24 +130,25 @@ class CLIApplicationBase(object): ...@@ -135,24 +130,25 @@ class CLIApplicationBase(object):
error(str(e)) error(str(e))
sys.exit(1) sys.exit(1)
alt_path = None alt_config_path = None
alt_archive = None overrides = {}
for opt, value in opts: for opt, value in opts:
if opt == "-c": if opt == "-c":
self.config = config(value) alt_config_path = value
elif opt == "-t": elif opt == "-t":
alt_path = value overrides[('topydo', 'filename')] = value
elif opt == "-d": elif opt == "-d":
alt_archive = value overrides[('topydo', 'archive_filename')] = value
elif opt == "-v": elif opt == "-v":
version() version()
else: else:
self._usage() self._usage()
self.path = alt_path if alt_path else self.config.todotxt() if alt_config_path:
self.archive_path = alt_archive \ config(alt_config_path, overrides)
if alt_archive else self.config.archive() elif len(overrides):
config(p_overrides=overrides)
return args return args
...@@ -163,7 +159,7 @@ class CLIApplicationBase(object): ...@@ -163,7 +159,7 @@ class CLIApplicationBase(object):
This means that all completed tasks are moved to the archive file This means that all completed tasks are moved to the archive file
(defaults to done.txt). (defaults to done.txt).
""" """
archive_file = TodoFile.TodoFile(self.archive_path) archive_file = TodoFile.TodoFile(config().archive())
archive = TodoListBase.TodoListBase(archive_file.read()) archive = TodoListBase.TodoListBase(archive_file.read())
if archive: if archive:
......
...@@ -51,7 +51,7 @@ class PromptApplication(CLIApplicationBase): ...@@ -51,7 +51,7 @@ class PromptApplication(CLIApplicationBase):
""" Main entry function. """ """ Main entry function. """
args = self._process_flags() args = self._process_flags()
self.todofile = TodoFile.TodoFile(self.path) self.todofile = TodoFile.TodoFile(config().todotxt())
self.todolist = TodoList.TodoList(self.todofile.read()) self.todolist = TodoList.TodoList(self.todofile.read())
# suppress upstream issue with Python 2.7 # suppress upstream issue with Python 2.7
......
...@@ -26,12 +26,17 @@ class ConfigError(Exception): ...@@ -26,12 +26,17 @@ class ConfigError(Exception):
return self.text return self.text
class _Config: class _Config:
def __init__(self, p_path=None): def __init__(self, p_path=None, p_overrides=None):
""" """
Constructor. Constructor.
If p_path is given, that is the only configuration file that will be If p_path is given, that is the only configuration file that will be
read. read.
If p_overrides is given, some options are ultimately overridden. This
is for some command line options which override any configuration file
(such as todo.txt location passed with -t). The key is a tuple of
(section, option), the value is the option's value.
""" """
self.sections = ['topydo', 'tags', 'sort', 'ls', 'dep'] self.sections = ['topydo', 'tags', 'sort', 'ls', 'dep']
...@@ -84,6 +89,10 @@ class _Config: ...@@ -84,6 +89,10 @@ class _Config:
self._supplement_sections() self._supplement_sections()
if p_overrides:
for (section, option), value in p_overrides.items():
self.cp.set(section, option, value)
def _supplement_sections(self): def _supplement_sections(self):
for section in self.sections: for section in self.sections:
if not self.cp.has_section(section): if not self.cp.has_section(section):
...@@ -177,17 +186,21 @@ class _Config: ...@@ -177,17 +186,21 @@ class _Config:
hidden_tags = self.cp.get('ls', 'hide_tags') hidden_tags = self.cp.get('ls', 'hide_tags')
return [] if hidden_tags == '' else hidden_tags.split(',') return [] if hidden_tags == '' else hidden_tags.split(',')
def config(p_path=None): def config(p_path=None, p_overrides=None):
""" """
Retrieve the config instance. Retrieve the config instance.
If a path is given, the instance is overwritten by the one that supplies an If a path is given, the instance is overwritten by the one that supplies an
additional filename (for testability). Moreover, no other configuration additional filename (for testability). Moreover, no other configuration
files will be read when a path is given. files will be read when a path is given.
Overrides will discard a setting in any configuration file and use the
passed value instead. Structure: (section, option) => value
The previous configuration instance will be discarded.
""" """
if not config.instance or p_path != None: if not config.instance or p_path != None or p_overrides != None:
try: try:
config.instance = _Config(p_path) config.instance = _Config(p_path, p_overrides)
except configparser.ParsingError as perr: except configparser.ParsingError as perr:
raise ConfigError(str(perr)) raise ConfigError(str(perr))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment