From e5b7a502dc05c702a072a043e16c5adb61738f35 Mon Sep 17 00:00:00 2001 From: Adam Coddington Date: Sun, 13 Apr 2014 12:25:27 -0700 Subject: [PATCH 1/2] Merge configuration overrides into taskrc configuration. --- taskw/taskrc.py | 5 +++-- taskw/test/test_taskrc.py | 47 +++++++++++++++++++++++++++++++++++++++ taskw/warrior.py | 2 +- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/taskw/taskrc.py b/taskw/taskrc.py index 58b875b..5b2483f 100644 --- a/taskw/taskrc.py +++ b/taskw/taskrc.py @@ -28,7 +28,8 @@ class TaskRc(dict): 'string': StringField, } - def __init__(self, path=None): + def __init__(self, path=None, overrides=None): + self.overrides = overrides if overrides else {} if path: self.path = os.path.normpath( os.path.expanduser( @@ -98,7 +99,7 @@ def _read(self, path): self.path, ) - return config + return self._merge_trees(config, self.overrides) def __delitem__(self, *args): raise TypeError('TaskRc objects are immutable') diff --git a/taskw/test/test_taskrc.py b/taskw/test/test_taskrc.py index 0e8270a..049088b 100644 --- a/taskw/test/test_taskrc.py +++ b/taskw/test/test_taskrc.py @@ -56,3 +56,50 @@ def test_get_udas(self): actual_udas = self.taskrc.get_udas() self.assertEqual(actual_udas, expected_udas) + + def test_config_overrides(self): + overrides = { + 'uda': { + 'd': { + 'type': 'string', + 'label': 'Delta', + } + }, + 'alpha': { + 'two': '3', + } + } + + taskrc = TaskRc(self.path_to_taskrc, overrides=overrides) + + expected_config = { + 'data': { + 'location': '~/.task' + }, + 'alpha': { + 'one': 'yes', + 'two': '3', + }, + 'beta': { + 'one': 'FALSE', + }, + 'gamma': { + 'one': 'TRUE', + }, + 'uda': { + 'a': { + 'type': 'numeric', + 'label': 'Alpha', + }, + 'b': { + 'type': 'string', + 'label': 'Beta', + }, + 'd': { + 'type': 'string', + 'label': 'Delta', + } + } + } + + self.assertEqual(taskrc, expected_config) diff --git a/taskw/warrior.py b/taskw/warrior.py index fcb0f44..ea8b50e 100644 --- a/taskw/warrior.py +++ b/taskw/warrior.py @@ -440,7 +440,7 @@ def __init__( self.config_overrides = config_overrides if config_overrides else {} self._marshal = marshal try: - self.config = TaskRc(config_filename) + self.config = TaskRc(config_filename, overrides=config_overrides) except: logger.exception( "Error encountered while loading configuration file " From 7278ce33ea84da883d7647e10c165023b5ce7a1d Mon Sep 17 00:00:00 2001 From: Adam Coddington Date: Sun, 13 Apr 2014 12:57:14 -0700 Subject: [PATCH 2/2] Update existing use of config overrides to match new datatstructure. --- taskw/test/test_utils.py | 28 +++++++++++++++++++++++++++- taskw/utils.py | 31 +++++++++++++++++++++++++++++++ taskw/warrior.py | 14 ++++---------- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/taskw/test/test_utils.py b/taskw/test/test_utils.py index 659fcf3..4405005 100644 --- a/taskw/test/test_utils.py +++ b/taskw/test/test_utils.py @@ -7,7 +7,11 @@ import six from taskw.utils import ( - decode_task, encode_task, encode_task_experimental, DATE_FORMAT + convert_dict_to_override_args, + decode_task, + encode_task, + encode_task_experimental, + DATE_FORMAT ) TASK = {'description': "task 2 http://www.google.com/", @@ -162,3 +166,25 @@ def test_encodes_zoned_datetimes(self): actual_encoded_task, expected_encoded_task, ) + + def test_convert_dict_to_override_args(self): + overrides = { + 'one': { + 'two': 1, + 'three': { + 'alpha': 'a' + }, + 'four': 'lorem ipsum', + }, + 'two': { + } + } + + expected_overrides = [ + 'rc.one.two=1', + 'rc.one.three.alpha=a', + 'rc.one.four="lorem ipsum"', + ] + actual_overrides = convert_dict_to_override_args(overrides) + + eq_(set(actual_overrides), set(expected_overrides)) diff --git a/taskw/utils.py b/taskw/utils.py index 08589f7..56629e1 100644 --- a/taskw/utils.py +++ b/taskw/utils.py @@ -215,3 +215,34 @@ def annotation_list_to_comparison_map(annotations): comparable = make_annotation_comparable(annotation) mapping[comparable] = annotation return mapping + + +def convert_dict_to_override_args(config, prefix=''): + """ Converts a dictionary of override arguments into CLI arguments. + + * Converts leaf nodes into dot paths of key names leading to the leaf + node. + * Does not include paths to leaf nodes not being non-dictionary type. + + See `taskw.test.test_utils.TestUtils.test_convert_dict_to_override_args` + for details. + + """ + args = [] + for k, v in six.iteritems(config): + if isinstance(v, dict): + args.extend( + convert_dict_to_override_args( + v, + prefix='.'.join([ + prefix, + k, + ]) if prefix else k + ) + ) + else: + v = six.text_type(v) + left = 'rc' + (('.' + prefix) if prefix else '') + '.' + k + right = v if ' ' not in v else '"%s"' % v + args.append('='.join([left, right])) + return args diff --git a/taskw/warrior.py b/taskw/warrior.py index ea8b50e..0604452 100644 --- a/taskw/warrior.py +++ b/taskw/warrior.py @@ -425,7 +425,9 @@ class TaskWarriorShellout(TaskWarriorBase): and /~https://github.com/ralphbean/taskw/issues/30 for more. """ DEFAULT_CONFIG_OVERRIDES = { - 'json.array': 'TRUE', + 'json': { + 'array': 'TRUE' + }, 'verbose': 'nothing', 'confirmation': 'no', } @@ -449,17 +451,9 @@ def __init__( ) def get_configuration_override_args(self): - args = [] config_overrides = self.DEFAULT_CONFIG_OVERRIDES.copy() config_overrides.update(self.config_overrides) - for key, value in six.iteritems(config_overrides): - args.append( - 'rc.%s=%s' % ( - key, - value if ' ' not in value else '"%s"' % value - ) - ) - return args + return taskw.utils.convert_dict_to_override_args(config_overrides) def _execute(self, *args): """ Execute a given taskwarrior command with arguments