From 432e76698e81adbc951842100a2ac948e715dc70 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 20:32:42 -0500 Subject: [PATCH 01/16] update unittests for new syntax --- tests/test_config.py | 5 +++-- tests/test_parse_args.py | 36 +++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 20e1236a..fa0009a1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,3 +1,4 @@ +import shlex import pytest import mock @@ -43,7 +44,7 @@ def test_override_configured_editor( mock_load_or_install.return_value = minimal_config mock_isatty.return_value = True - cli_args = ["--config-override", '{"editor": "nano"}'] + cli_args = shlex.split('--config-override editor:"nano"') parser = parse_args(cli_args) assert parser.config_override.__len__() == 1 assert "editor" in parser.config_override.keys() @@ -84,7 +85,7 @@ def test_override_configured_colors( ): mock_load_or_install.return_value = minimal_config - cli_args = ["--config-override", '{"colors.body": "blue"}'] + cli_args = shlex.split('--config-override colors.body:blue') parser = parse_args(cli_args) assert "colors.body" in parser.config_override.keys() with mock.patch.object( diff --git a/tests/test_parse_args.py b/tests/test_parse_args.py index 6ce40338..e1df5c29 100644 --- a/tests/test_parse_args.py +++ b/tests/test_parse_args.py @@ -36,7 +36,7 @@ def expected_args(**kwargs): "strict": False, "tags": False, "text": [], - "config_override": {}, + "config_override": None, } return {**default_args, **kwargs} @@ -206,28 +206,46 @@ def test_version_alone(): assert cli_as_dict("--version") == expected_args(preconfig_cmd=preconfig_version) +@pytest.mark.parametrize( + "input_str", + [ + 'editor:"nano", colors.title:blue, default:"/tmp/egg.txt"', + 'editor:"vi -c startinsert", colors.title:blue, default:"/tmp/egg.txt"', + 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"' + ] +) +def test_deserialize_config_args(input_str): + from jrnl.args import deserialize_config_args + + runtime_config = deserialize_config_args(input_str) + assert runtime_config.__class__ == dict + assert "editor" in runtime_config.keys() + assert "colors.title" in runtime_config.keys() + assert "default" in runtime_config.keys() def test_editor_override(): - assert cli_as_dict('--config-override \'{"editor": "nano"}\'') == expected_args( + parsed_args = cli_as_dict('--config-override editor:"nano"') + assert parsed_args == expected_args( config_override={"editor": "nano"} ) def test_color_override(): assert cli_as_dict( - '--config-override \'{"colors.body": "blue"}\'' + '--config-override colors.body:blue' ) == expected_args(config_override={"colors.body": "blue"}) def test_multiple_overrides(): - assert cli_as_dict( - '--config-override \'{"colors.title": "green", "editor":"", "journal.scratchpad": "/tmp/scratchpad"}\'' - ) == expected_args( + parsed_args = cli_as_dict( + '--config-override colors.title:green,editor:"nano",journal.scratchpad:"/tmp/scratchpad"' + ) + assert parsed_args == expected_args( config_override={ - "colors.title": "green", - "journal.scratchpad": "/tmp/scratchpad", - "editor": "", + 'colors.title': 'green', + 'journal.scratchpad': '/tmp/scratchpad', + 'editor': 'nano', } ) From 0b61c6d699cb44cef9968f3ee1728db4cf718d42 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 20:33:01 -0500 Subject: [PATCH 02/16] update integ tests for new syntax --- features/overrides.feature | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/features/overrides.feature b/features/overrides.feature index 0aa84d8c..3ad42b60 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -2,18 +2,23 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys Scenario: Override configured editor with built-in input === editor:'' Given we use the config "editor-args.yaml" -When we run "jrnl --config-override '{"editor": ""}'" +When we run jrnl with --config-override editor:"" Then the editor "" should have been called -Scenario: Override configured editor with 'nano' +Scenario Outline: Override configured editor Given we use the config "editor.yaml" -When we run "jrnl --config-override '{"editor": "nano"}'" -Then the editor "nano" should have been called +When we run jrnl with --config-override editor:"" +Then the editor "" should have been called +Examples: Editor Commands +|editor| +|nano| +|vi -c startinsert| +|code -w - | @skip_win Scenario: Override configured linewrap with a value of 23 Given we use the config "editor.yaml" -When we run "jrnl -2 --config-override '{"linewrap": 23}' --format fancy" +When we run "jrnl -2 --config-override linewrap:23 --format fancy" Then the output should be """ ┎─────╮2013-06-09 15:39 @@ -34,12 +39,12 @@ Then the output should be @skip_win Scenario: Override color selections with runtime overrides Given we use the config "tiny.yaml" -When we run jrnl with -1 --config-override '{"colors.body": "blue"}' +When we run jrnl with -1 --config-override colors.body:blue' Then the runtime config should have colors.body set to blue @skip_win Scenario: Apply multiple config overrides Given we use the config "tiny.yaml" -When we run jrnl with -1 --config-override '{"colors.body": "green", "editor": "nano"}' +When we run jrnl with -1 --config-override colors.body:green,editor:"nano" Then the runtime config should have colors.body set to green And the runtime config should have editor set to nano From 1578fef220a2406685d0a057d9aa41ed9babda55 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 21:02:39 -0500 Subject: [PATCH 03/16] update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5e11d85b..629a9504 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,5 @@ site/ .vscode/settings.json coverage.xml .vscode/launch.json -.coverage \ No newline at end of file +.coverage +.vscode/tasks.json \ No newline at end of file From 9ac21b84481727b295855ac76fcc9c1c250b08a5 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 21:03:19 -0500 Subject: [PATCH 04/16] guard override application --- jrnl/jrnl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py index fdc8c87b..25fd191a 100644 --- a/jrnl/jrnl.py +++ b/jrnl/jrnl.py @@ -16,6 +16,7 @@ from .editor import get_text_from_editor from .editor import get_text_from_stdin from .exception import UserAbort from . import time +from .override import apply_overrides def run(args): @@ -51,9 +52,8 @@ def run(args): # Apply config overrides overrides = args.config_override - from .override import apply_overrides - - config = apply_overrides(overrides, config) + if overrides: + config = apply_overrides(overrides, config) # --- All the standalone commands are now done --- # From bf891095255149f352ecb9fef74835418e21c236 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 21:04:10 -0500 Subject: [PATCH 05/16] deserialize function as return type --- jrnl/args.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/jrnl/args.py b/jrnl/args.py index 99489b74..2c11952f 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -17,7 +17,14 @@ from .plugins import EXPORT_FORMATS from .plugins import IMPORT_FORMATS from .plugins import util - +def deserialize_config_args(input: str) -> dict: + _kvpairs = input.strip(' ').split(',') + runtime_modifications = {} + for _p in _kvpairs: + l,r = _p.strip().split(':') + runtime_modifications[l] = r + return runtime_modifications + class WrappingFormatter(argparse.RawTextHelpFormatter): """Used in help screen""" @@ -323,9 +330,9 @@ def parse_args(args=[]): "--config-override", dest="config_override", action="store", - type=json.loads, + type=deserialize_config_args, nargs="?", - default={}, + default=None, metavar="CONFIG_KV_PAIR", help=""" Override configured key-value pairs with CONFIG_KV_PAIR for this command invocation only. @@ -342,4 +349,6 @@ def parse_args(args=[]): num = re.compile(r"^-(\d+)$") args = [num.sub(r"-n \1", arg) for arg in args] - return parser.parse_intermixed_args(args) + + parsed_args = parser.parse_intermixed_args(args) + return parsed_args From 3b74c2dec0312331632d00e5a1926fa1138ff6f3 Mon Sep 17 00:00:00 2001 From: Suhas Date: Mon, 25 Jan 2021 21:04:47 -0500 Subject: [PATCH 06/16] make format --- jrnl/args.py | 15 ++++++++------- tests/test_config.py | 2 +- tests/test_parse_args.py | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/jrnl/args.py b/jrnl/args.py index 2c11952f..3d2ecaf9 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -17,14 +17,16 @@ from .plugins import EXPORT_FORMATS from .plugins import IMPORT_FORMATS from .plugins import util -def deserialize_config_args(input: str) -> dict: - _kvpairs = input.strip(' ').split(',') - runtime_modifications = {} - for _p in _kvpairs: - l,r = _p.strip().split(':') + +def deserialize_config_args(input: str) -> dict: + _kvpairs = input.strip(" ").split(",") + runtime_modifications = {} + for _p in _kvpairs: + l, r = _p.strip().split(":") runtime_modifications[l] = r return runtime_modifications - + + class WrappingFormatter(argparse.RawTextHelpFormatter): """Used in help screen""" @@ -349,6 +351,5 @@ def parse_args(args=[]): num = re.compile(r"^-(\d+)$") args = [num.sub(r"-n \1", arg) for arg in args] - parsed_args = parser.parse_intermixed_args(args) return parsed_args diff --git a/tests/test_config.py b/tests/test_config.py index fa0009a1..aa4d7079 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -85,7 +85,7 @@ def test_override_configured_colors( ): mock_load_or_install.return_value = minimal_config - cli_args = shlex.split('--config-override colors.body:blue') + cli_args = shlex.split("--config-override colors.body:blue") parser = parse_args(cli_args) assert "colors.body" in parser.config_override.keys() with mock.patch.object( diff --git a/tests/test_parse_args.py b/tests/test_parse_args.py index e1df5c29..5b02fbfc 100644 --- a/tests/test_parse_args.py +++ b/tests/test_parse_args.py @@ -206,35 +206,35 @@ def test_version_alone(): assert cli_as_dict("--version") == expected_args(preconfig_cmd=preconfig_version) + @pytest.mark.parametrize( "input_str", [ 'editor:"nano", colors.title:blue, default:"/tmp/egg.txt"', 'editor:"vi -c startinsert", colors.title:blue, default:"/tmp/egg.txt"', - 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"' - ] + 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"', + ], ) -def test_deserialize_config_args(input_str): - from jrnl.args import deserialize_config_args - +def test_deserialize_config_args(input_str): + from jrnl.args import deserialize_config_args + runtime_config = deserialize_config_args(input_str) assert runtime_config.__class__ == dict assert "editor" in runtime_config.keys() assert "colors.title" in runtime_config.keys() assert "default" in runtime_config.keys() + def test_editor_override(): parsed_args = cli_as_dict('--config-override editor:"nano"') - assert parsed_args == expected_args( - config_override={"editor": "nano"} - ) + assert parsed_args == expected_args(config_override={"editor": "nano"}) def test_color_override(): - assert cli_as_dict( - '--config-override colors.body:blue' - ) == expected_args(config_override={"colors.body": "blue"}) + assert cli_as_dict("--config-override colors.body:blue") == expected_args( + config_override={"colors.body": "blue"} + ) def test_multiple_overrides(): @@ -243,9 +243,9 @@ def test_multiple_overrides(): ) assert parsed_args == expected_args( config_override={ - 'colors.title': 'green', - 'journal.scratchpad': '/tmp/scratchpad', - 'editor': 'nano', + "colors.title": "green", + "journal.scratchpad": "/tmp/scratchpad", + "editor": "nano", } ) From abbb2c502f2a5546fb8f1f8ee4a0812cc2652c3c Mon Sep 17 00:00:00 2001 From: Suhas Date: Wed, 27 Jan 2021 18:09:10 -0500 Subject: [PATCH 07/16] organize deserialization unittests --- tests/test_parse_args.py | 44 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/tests/test_parse_args.py b/tests/test_parse_args.py index 5b02fbfc..8e314aad 100644 --- a/tests/test_parse_args.py +++ b/tests/test_parse_args.py @@ -4,7 +4,7 @@ import shlex import pytest from jrnl.args import parse_args - +from jrnl.args import deserialize_config_args def cli_as_dict(str): cli = shlex.split(str) @@ -206,24 +206,36 @@ def test_version_alone(): assert cli_as_dict("--version") == expected_args(preconfig_cmd=preconfig_version) +class TestDeserialization: + @pytest.mark.parametrize( + "input_str", + [ + 'editor:"nano", colors.title:blue, default:"/tmp/egg.txt"', + 'editor:"vi -c startinsert", colors.title:blue, default:"/tmp/egg.txt"', + 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"', + ], + ) + def test_deserialize_multiword_strings(self,input_str): + -@pytest.mark.parametrize( - "input_str", - [ - 'editor:"nano", colors.title:blue, default:"/tmp/egg.txt"', - 'editor:"vi -c startinsert", colors.title:blue, default:"/tmp/egg.txt"', - 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"', - ], -) -def test_deserialize_config_args(input_str): - from jrnl.args import deserialize_config_args + runtime_config = deserialize_config_args(input_str) + assert runtime_config.__class__ == dict + assert "editor" in runtime_config.keys() + assert "colors.title" in runtime_config.keys() + assert "default" in runtime_config.keys() - runtime_config = deserialize_config_args(input_str) - assert runtime_config.__class__ == dict - assert "editor" in runtime_config.keys() - assert "colors.title" in runtime_config.keys() - assert "default" in runtime_config.keys() + def test_deserialize_int(self): + input = 'linewrap: 23, default_hour: 19' + runtime_config = deserialize_config_args(input) + assert runtime_config['linewrap'] == 23 + assert runtime_config['default_hour'] == 19 + def test_deserialize_multiple_datatypes(self): + input = 'linewrap: 23, encrypt: false, editor:"vi -c startinsert"' + cfg = deserialize_config_args(input) + assert cfg['encrypt'] == False + assert cfg['linewrap'] == 23 + assert cfg['editor'] == '"vi -c startinsert"' def test_editor_override(): From 0f5dfade18ea3378a441a01530cf1da16644cafa Mon Sep 17 00:00:00 2001 From: Suhas Date: Wed, 27 Jan 2021 18:13:10 -0500 Subject: [PATCH 08/16] better, more specific behave tests --- features/steps/override.py | 81 +++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/features/steps/override.py b/features/steps/override.py index 6ecbc8dc..b0edc864 100644 --- a/features/steps/override.py +++ b/features/steps/override.py @@ -1,3 +1,5 @@ +from tests.test_config import expected_override +from jrnl.editor import get_text_from_stdin from jrnl.jrnl import run from jrnl.os_compat import split_args from unittest import mock @@ -10,7 +12,16 @@ import yaml from yaml.loader import FullLoader import jrnl -from jrnl.cli import cli +def _mock_time_parse(context): + original_parse = jrnl.time.parse + if "now" not in context: + return original_parse + + def wrapper(input, *args, **kwargs): + input = context.now if input == "now" else input + return original_parse(input, *args, **kwargs) + + return wrapper @given("we use the config {config_file}") @@ -31,13 +42,9 @@ def run_command(context, args): @then("the runtime config should have {key_as_dots} set to {override_value}") def config_override(context, key_as_dots: str, override_value: str): key_as_vec = key_as_dots.split(".") - expected_call_args_list = [ - (context.cfg, key_as_vec, override_value), - (context.cfg[key_as_vec[0]], key_as_vec[1], override_value), - ] - with open(context.config_path) as f: - loaded_cfg = yaml.load(f, Loader=yaml.FullLoader) - loaded_cfg["journal"] = "features/journals/simple.journal" + # with open(context.config_path) as f: + # loaded_cfg = yaml.load(f, Loader=yaml.FullLoader) + # loaded_cfg["journal"] = "features/journals/simple.journal" def _mock_callback(**args): print("callback executed") @@ -45,16 +52,20 @@ def config_override(context, key_as_dots: str, override_value: str): # fmt: off try: with \ + mock.patch("jrnl.jrnl.search_mode"), \ mock.patch.object(jrnl.override,"_recursively_apply",wraps=jrnl.override._recursively_apply) as mock_recurse, \ mock.patch('jrnl.install.load_or_install_jrnl', return_value=context.cfg), \ + mock.patch('jrnl.time.parse', side_effect=_mock_time_parse(context)), \ mock.patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \ mock.patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \ : run(context.parser) - - assert mock_recurse.call_count >= 2 - mock_recurse.call_args_list = expected_call_args_list - + runtime_cfg = mock_recurse.call_args_list[0][0][0] + assert mock_recurse.call_count == key_as_vec.__len__() + for k in key_as_vec: + runtime_cfg = runtime_cfg['%s'%k] + + assert runtime_cfg == override_value except SystemExit as e : context.exit_status = e.code # fmt: on @@ -62,27 +73,49 @@ def config_override(context, key_as_dots: str, override_value: str): @then("the editor {editor} should have been called") def editor_override(context, editor): - def _mock_editor(command_and_journal_file): - editor = command_and_journal_file[0] - tmpfile = command_and_journal_file[-1] - context.tmpfile = tmpfile - print("%s has been launched" % editor) - return tmpfile - + + def _mock_write_in_editor(config): + editor = config['editor'] + journal = '/tmp/journal.jrnl' + context.tmpfile = journal + print("%s has been launched"%editor) + return journal + + # fmt: off # see: https://github.com/psf/black/issues/664 with \ - mock.patch("subprocess.call", side_effect=_mock_editor) as mock_editor, \ + mock.patch("jrnl.jrnl._write_in_editor", side_effect=_mock_write_in_editor(context.cfg)) as mock_write_in_editor, \ mock.patch("sys.stdin.isatty", return_value=True), \ - mock.patch("jrnl.time.parse"), \ + mock.patch("jrnl.time.parse", side_effect = _mock_time_parse(context)), \ mock.patch("jrnl.config.get_config_path", side_effect=lambda: context.config_path), \ mock.patch("jrnl.install.get_config_path", side_effect=lambda: context.config_path) \ : try : - cli(['--config-override','{"editor": "%s"}'%editor]) + run(context.parser) context.exit_status = 0 - context.editor = mock_editor - assert mock_editor.assert_called_once_with(editor, context.tmpfile) + context.editor = mock_write_in_editor + expected_config = context.cfg + expected_config['editor'] = '%s'%editor + expected_config['journal'] ='/tmp/journal.jrnl' + + assert mock_write_in_editor.call_count == 1 + assert mock_write_in_editor.call_args[0][0]['editor']==editor except SystemExit as e: context.exit_status = e.code # fmt: on + +@then("the stdin prompt must be launched") +def override_editor_to_use_stdin(context): + + try: + with \ + mock.patch('sys.stdin.read', return_value='Zwei peanuts walk into a bar und one of zem was a-salted')as mock_stdin_read, \ + mock.patch("jrnl.install.load_or_install_jrnl", return_value=context.cfg), \ + mock.patch("jrnl.Journal.open_journal", spec=False, return_value='/tmp/journal.jrnl'): + run(context.parser) + context.exit_status = 0 + mock_stdin_read.assert_called_once() + + except SystemExit as e : + context.exit_status = e.code \ No newline at end of file From b2a60fd297e620f441d76bbce8e6f38c51f491db Mon Sep 17 00:00:00 2001 From: Suhas Date: Wed, 27 Jan 2021 18:14:00 -0500 Subject: [PATCH 09/16] test different editor launch commands --- features/overrides.feature | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/overrides.feature b/features/overrides.feature index 3ad42b60..1f8b3036 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -48,3 +48,12 @@ Given we use the config "tiny.yaml" When we run jrnl with -1 --config-override colors.body:green,editor:"nano" Then the runtime config should have colors.body set to green And the runtime config should have editor set to nano + Scenario Outline: Override configured editor + Given we use the config "tiny.yaml" + When we run jrnl with --config-override editor:"" + Then the editor should have been called + Examples: Editor Commands + | editor | + | nano | + | vi -c startinsert | + | code -w - | From e85300eced5644fd525efdc6f2de5e80e379c6bb Mon Sep 17 00:00:00 2001 From: Suhas Date: Wed, 27 Jan 2021 18:14:08 -0500 Subject: [PATCH 10/16] formatting --- features/overrides.feature | 82 ++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/features/overrides.feature b/features/overrides.feature index 1f8b3036..80fdf47c 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -1,53 +1,47 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys -Scenario: Override configured editor with built-in input === editor:'' -Given we use the config "editor-args.yaml" -When we run jrnl with --config-override editor:"" -Then the editor "" should have been called + Scenario: Override configured editor with built-in input === editor:'' + Given we use the config "tiny.yaml" + When we run jrnl with --config-override editor:'' + Then the stdin prompt must be launched -Scenario Outline: Override configured editor -Given we use the config "editor.yaml" -When we run jrnl with --config-override editor:"" -Then the editor "" should have been called -Examples: Editor Commands -|editor| -|nano| -|vi -c startinsert| -|code -w - | + @skip_win + Scenario: Override configured linewrap with a value of 23 + Given we use the config "tiny.yaml" + When we run "jrnl -2 --config-override linewrap:23 --format fancy" + Then the output should be -@skip_win -Scenario: Override configured linewrap with a value of 23 -Given we use the config "editor.yaml" -When we run "jrnl -2 --config-override linewrap:23 --format fancy" -Then the output should be -""" -┎─────╮2013-06-09 15:39 -┃ My ╘═══════════════╕ -┃ fir st ent ry. │ -┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ -┃ Everything is │ -┃ alright │ -┖─────────────────────┘ -┎─────╮2013-06-10 15:40 -┃ Lif ╘═══════════════╕ -┃ e is goo d. │ -┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ -┃ But I'm better. │ -┖─────────────────────┘ -""" + """ + ┎─────╮2013-06-09 15:39 + ┃ My ╘═══════════════╕ + ┃ fir st ent ry. │ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ Everything is │ + ┃ alright │ + ┖─────────────────────┘ + ┎─────╮2013-06-10 15:40 + ┃ Lif ╘═══════════════╕ + ┃ e is goo d. │ + ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ + ┃ But I'm better. │ + ┖─────────────────────┘ + """ + + @skip_win + @wip + Scenario: Override color selections with runtime overrides + Given we use the config "tiny.yaml" + When we run jrnl with -1 --config-override colors.body:blue + Then the runtime config should have colors.body set to blue + + @skip_win + Scenario: Apply multiple config overrides + Given we use the config "tiny.yaml" + When we run jrnl with -1 --config-override colors.body:green,editor:"nano" + Then the runtime config should have colors.body set to green + And the runtime config should have editor set to nano -@skip_win -Scenario: Override color selections with runtime overrides -Given we use the config "tiny.yaml" -When we run jrnl with -1 --config-override colors.body:blue' -Then the runtime config should have colors.body set to blue -@skip_win -Scenario: Apply multiple config overrides -Given we use the config "tiny.yaml" -When we run jrnl with -1 --config-override colors.body:green,editor:"nano" -Then the runtime config should have colors.body set to green -And the runtime config should have editor set to nano Scenario Outline: Override configured editor Given we use the config "tiny.yaml" When we run jrnl with --config-override editor:"" From 6daf4fb2eeff9712ac4ba59c012b12d4048b3680 Mon Sep 17 00:00:00 2001 From: Suhas Date: Wed, 27 Jan 2021 18:14:42 -0500 Subject: [PATCH 11/16] handle datatypes in deserialization and update helptext --- jrnl/args.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/jrnl/args.py b/jrnl/args.py index 3d2ecaf9..e1d73a8c 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -23,6 +23,13 @@ def deserialize_config_args(input: str) -> dict: runtime_modifications = {} for _p in _kvpairs: l, r = _p.strip().split(":") + r = r.strip() + if r.isdigit(): + r = int(r) + elif r.lower() == "true": + r = True + elif r.lower() == "false": + r = False runtime_modifications[l] = r return runtime_modifications @@ -341,9 +348,9 @@ def parse_args(args=[]): Examples: \n \t - Use a different editor for this jrnl entry, call: \n - \t jrnl --config-override '{"editor": "nano"}' \n + \t jrnl --config-override editor: "nano" \n \t - Override color selections\n - \t jrnl --config-override '{"colors.body":"blue", "colors.title": "green"} + \t jrnl --config-override colors.body: blue, colors.title: green """, ) From b8b56124eeb5ffad6f32a2f6bf22428b07b63ddb Mon Sep 17 00:00:00 2001 From: Suhas Date: Thu, 28 Jan 2021 08:36:44 -0500 Subject: [PATCH 12/16] stick to config convention in testbed --- features/data/configs/tiny.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/data/configs/tiny.yaml b/features/data/configs/tiny.yaml index e9da7943..578cd234 100644 --- a/features/data/configs/tiny.yaml +++ b/features/data/configs/tiny.yaml @@ -1,7 +1,8 @@ journals: - default: /tmp/journal.jrnl + default: features/journals/simple.journal colors: body: none title: green editor: "vim" encrypt: false +# \ No newline at end of file From 983c9c8c4b720ea75aa281f7de49b8c56c02f1ae Mon Sep 17 00:00:00 2001 From: Suhas Date: Thu, 28 Jan 2021 08:36:58 -0500 Subject: [PATCH 13/16] update tests ith better verifications --- features/overrides.feature | 1 - features/steps/override.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/features/overrides.feature b/features/overrides.feature index 80fdf47c..eef89eec 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -28,7 +28,6 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys """ @skip_win - @wip Scenario: Override color selections with runtime overrides Given we use the config "tiny.yaml" When we run jrnl with -1 --config-override colors.body:blue diff --git a/features/steps/override.py b/features/steps/override.py index b0edc864..df7d444c 100644 --- a/features/steps/override.py +++ b/features/steps/override.py @@ -61,7 +61,7 @@ def config_override(context, key_as_dots: str, override_value: str): : run(context.parser) runtime_cfg = mock_recurse.call_args_list[0][0][0] - assert mock_recurse.call_count == key_as_vec.__len__() + for k in key_as_vec: runtime_cfg = runtime_cfg['%s'%k] @@ -76,7 +76,7 @@ def editor_override(context, editor): def _mock_write_in_editor(config): editor = config['editor'] - journal = '/tmp/journal.jrnl' + journal = 'features/journals/journal.jrnl' context.tmpfile = journal print("%s has been launched"%editor) return journal @@ -97,7 +97,7 @@ def editor_override(context, editor): context.editor = mock_write_in_editor expected_config = context.cfg expected_config['editor'] = '%s'%editor - expected_config['journal'] ='/tmp/journal.jrnl' + expected_config['journal'] ='features/journals/journal.jrnl' assert mock_write_in_editor.call_count == 1 assert mock_write_in_editor.call_args[0][0]['editor']==editor @@ -112,7 +112,7 @@ def override_editor_to_use_stdin(context): with \ mock.patch('sys.stdin.read', return_value='Zwei peanuts walk into a bar und one of zem was a-salted')as mock_stdin_read, \ mock.patch("jrnl.install.load_or_install_jrnl", return_value=context.cfg), \ - mock.patch("jrnl.Journal.open_journal", spec=False, return_value='/tmp/journal.jrnl'): + mock.patch("jrnl.Journal.open_journal", spec=False, return_value='features/journals/journal.jrnl'): run(context.parser) context.exit_status = 0 mock_stdin_read.assert_called_once() From 528ce1efe227273ee4468d70acdbfcfd58396873 Mon Sep 17 00:00:00 2001 From: Suhas Date: Thu, 28 Jan 2021 08:40:28 -0500 Subject: [PATCH 14/16] make format --- features/overrides.feature | 2 +- features/steps/override.py | 53 +++++++++++++++++++++----------------- jrnl/args.py | 11 ++++---- tests/test_config.py | 1 - tests/test_parse_args.py | 25 +++++++++--------- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/features/overrides.feature b/features/overrides.feature index eef89eec..ec3a2d1b 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -36,7 +36,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys @skip_win Scenario: Apply multiple config overrides Given we use the config "tiny.yaml" - When we run jrnl with -1 --config-override colors.body:green,editor:"nano" + When we run jrnl with -1 --config-override colors.body:green, editor:"nano" Then the runtime config should have colors.body set to green And the runtime config should have editor set to nano diff --git a/features/steps/override.py b/features/steps/override.py index df7d444c..4c241eb4 100644 --- a/features/steps/override.py +++ b/features/steps/override.py @@ -1,5 +1,3 @@ -from tests.test_config import expected_override -from jrnl.editor import get_text_from_stdin from jrnl.jrnl import run from jrnl.os_compat import split_args from unittest import mock @@ -12,16 +10,18 @@ import yaml from yaml.loader import FullLoader import jrnl + + def _mock_time_parse(context): - original_parse = jrnl.time.parse - if "now" not in context: - return original_parse + original_parse = jrnl.time.parse + if "now" not in context: + return original_parse - def wrapper(input, *args, **kwargs): - input = context.now if input == "now" else input - return original_parse(input, *args, **kwargs) + def wrapper(input, *args, **kwargs): + input = context.now if input == "now" else input + return original_parse(input, *args, **kwargs) - return wrapper + return wrapper @given("we use the config {config_file}") @@ -73,15 +73,13 @@ def config_override(context, key_as_dots: str, override_value: str): @then("the editor {editor} should have been called") def editor_override(context, editor): - def _mock_write_in_editor(config): - editor = config['editor'] - journal = 'features/journals/journal.jrnl' + editor = config["editor"] + journal = "features/journals/journal.jrnl" context.tmpfile = journal - print("%s has been launched"%editor) + print("%s has been launched" % editor) return journal - - + # fmt: off # see: https://github.com/psf/black/issues/664 with \ @@ -105,17 +103,24 @@ def editor_override(context, editor): context.exit_status = e.code # fmt: on -@then("the stdin prompt must be launched") -def override_editor_to_use_stdin(context): - try: - with \ - mock.patch('sys.stdin.read', return_value='Zwei peanuts walk into a bar und one of zem was a-salted')as mock_stdin_read, \ - mock.patch("jrnl.install.load_or_install_jrnl", return_value=context.cfg), \ - mock.patch("jrnl.Journal.open_journal", spec=False, return_value='features/journals/journal.jrnl'): +@then("the stdin prompt must be launched") +def override_editor_to_use_stdin(context): + + try: + with mock.patch( + "sys.stdin.read", + return_value="Zwei peanuts walk into a bar und one of zem was a-salted", + ) as mock_stdin_read, mock.patch( + "jrnl.install.load_or_install_jrnl", return_value=context.cfg + ), mock.patch( + "jrnl.Journal.open_journal", + spec=False, + return_value="features/journals/journal.jrnl", + ): run(context.parser) context.exit_status = 0 mock_stdin_read.assert_called_once() - except SystemExit as e : - context.exit_status = e.code \ No newline at end of file + except SystemExit as e: + context.exit_status = e.code diff --git a/jrnl/args.py b/jrnl/args.py index e1d73a8c..f2ea288c 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -4,7 +4,6 @@ import argparse import re import textwrap -import json from .commands import postconfig_decrypt from .commands import postconfig_encrypt @@ -24,11 +23,11 @@ def deserialize_config_args(input: str) -> dict: for _p in _kvpairs: l, r = _p.strip().split(":") r = r.strip() - if r.isdigit(): - r = int(r) - elif r.lower() == "true": - r = True - elif r.lower() == "false": + if r.isdigit(): + r = int(r) + elif r.lower() == "true": + r = True + elif r.lower() == "false": r = False runtime_modifications[l] = r return runtime_modifications diff --git a/tests/test_config.py b/tests/test_config.py index aa4d7079..dc2650a8 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,7 +2,6 @@ import shlex import pytest import mock -import yaml from jrnl.args import parse_args from jrnl.jrnl import run diff --git a/tests/test_parse_args.py b/tests/test_parse_args.py index 8e314aad..a49c99cb 100644 --- a/tests/test_parse_args.py +++ b/tests/test_parse_args.py @@ -1,4 +1,3 @@ -from features.steps.override import config_override import shlex import pytest @@ -6,6 +5,7 @@ import pytest from jrnl.args import parse_args from jrnl.args import deserialize_config_args + def cli_as_dict(str): cli = shlex.split(str) args = parse_args(cli) @@ -206,6 +206,7 @@ def test_version_alone(): assert cli_as_dict("--version") == expected_args(preconfig_cmd=preconfig_version) + class TestDeserialization: @pytest.mark.parametrize( "input_str", @@ -215,8 +216,7 @@ class TestDeserialization: 'editor:"nano", colors.title:blue, default:"/tmp/eg\ g.txt"', ], ) - def test_deserialize_multiword_strings(self,input_str): - + def test_deserialize_multiword_strings(self, input_str): runtime_config = deserialize_config_args(input_str) assert runtime_config.__class__ == dict @@ -224,18 +224,19 @@ class TestDeserialization: assert "colors.title" in runtime_config.keys() assert "default" in runtime_config.keys() - def test_deserialize_int(self): - input = 'linewrap: 23, default_hour: 19' + def test_deserialize_int(self): + input = "linewrap: 23, default_hour: 19" runtime_config = deserialize_config_args(input) - assert runtime_config['linewrap'] == 23 - assert runtime_config['default_hour'] == 19 + assert runtime_config["linewrap"] == 23 + assert runtime_config["default_hour"] == 19 - def test_deserialize_multiple_datatypes(self): + def test_deserialize_multiple_datatypes(self): input = 'linewrap: 23, encrypt: false, editor:"vi -c startinsert"' - cfg = deserialize_config_args(input) - assert cfg['encrypt'] == False - assert cfg['linewrap'] == 23 - assert cfg['editor'] == '"vi -c startinsert"' + cfg = deserialize_config_args(input) + assert cfg["encrypt"] == False + assert cfg["linewrap"] == 23 + assert cfg["editor"] == '"vi -c startinsert"' + def test_editor_override(): From 52e146d12c7308b59f7dca5e28fe85a7e5b06d31 Mon Sep 17 00:00:00 2001 From: Suhas Date: Thu, 28 Jan 2021 08:42:20 -0500 Subject: [PATCH 15/16] space --- features/overrides.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/overrides.feature b/features/overrides.feature index ec3a2d1b..eef89eec 100644 --- a/features/overrides.feature +++ b/features/overrides.feature @@ -36,7 +36,7 @@ Feature: Implementing Runtime Overrides for Select Configuration Keys @skip_win Scenario: Apply multiple config overrides Given we use the config "tiny.yaml" - When we run jrnl with -1 --config-override colors.body:green, editor:"nano" + When we run jrnl with -1 --config-override colors.body:green,editor:"nano" Then the runtime config should have colors.body set to green And the runtime config should have editor set to nano From 31577ad0fc1ace170a1966a323fd0970a0a59484 Mon Sep 17 00:00:00 2001 From: Suhas Date: Thu, 28 Jan 2021 08:51:09 -0500 Subject: [PATCH 16/16] review feedbac --- features/steps/override.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/features/steps/override.py b/features/steps/override.py index 4c241eb4..ac531235 100644 --- a/features/steps/override.py +++ b/features/steps/override.py @@ -42,10 +42,7 @@ def run_command(context, args): @then("the runtime config should have {key_as_dots} set to {override_value}") def config_override(context, key_as_dots: str, override_value: str): key_as_vec = key_as_dots.split(".") - # with open(context.config_path) as f: - # loaded_cfg = yaml.load(f, Loader=yaml.FullLoader) - # loaded_cfg["journal"] = "features/journals/simple.journal" - + def _mock_callback(**args): print("callback executed")