diff --git a/snakemake/utils.py b/snakemake/utils.py index 3cc81c28b..0d427c3fc 100644 --- a/snakemake/utils.py +++ b/snakemake/utils.py @@ -479,7 +479,7 @@ def min_version(version): def update_config(config, overwrite_config): - """Recursively update dictionary config with overwrite_config. + """Recursively update dictionary config with overwrite_config in-place. See https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth @@ -488,18 +488,25 @@ def update_config(config, overwrite_config): Args: config (dict): dictionary to update overwrite_config (dict): dictionary whose items will overwrite those in config - """ - def _update(d, u): - for key, value in u.items(): + def _update_config(config, overwrite_config): + """Necessary as recursive calls require a return value, + but `update_config()` has no return value. + """ + for key, value in overwrite_config.items(): + if not isinstance(config, collections.abc.Mapping): + # the config cannot be updated as it is no dict + # -> just overwrite it with the new value + config = {} if isinstance(value, collections.abc.Mapping): - d[key] = _update(d.get(key, {}), value) + sub_config = config.get(key, {}) + config[key] = _update_config(sub_config, value) else: - d[key] = value - return d + config[key] = value + return config - _update(config, overwrite_config) + _update_config(config, overwrite_config) def available_cpu_count(): diff --git a/tests/common.py b/tests/common.py index 8d1a0328a..383aa2930 100644 --- a/tests/common.py +++ b/tests/common.py @@ -33,9 +33,9 @@ def dpath(path): def md5sum(filename, ignore_newlines=False): if ignore_newlines: with open(filename, "r", encoding="utf-8", errors="surrogateescape") as f: - data = f.read().encode("utf8", errors="surrogateescape") + data = f.read().strip().encode("utf8", errors="surrogateescape") else: - data = open(filename, "rb").read() + data = open(filename, "rb").read().strip() return hashlib.md5(data).hexdigest() @@ -285,9 +285,9 @@ def run( md5target = md5sum(targetfile, ignore_newlines=ON_WINDOWS) if md5target != md5expected: with open(expectedfile) as expected: - expected_content = expected.read() + expected_content = expected.read().strip() with open(targetfile) as target: - content = target.read() + content = target.read().strip() assert ( False ), "wrong result produced for file '{resultfile}':\n------found------\n{content}\n-----expected-----\n{expected_content}\n-----------------".format( diff --git a/tests/test_config_merging/config_cmdline_01.yaml b/tests/test_config_merging/config_cmdline_01.yaml index fc731e9b5..7f8c8e018 100644 --- a/tests/test_config_merging/config_cmdline_01.yaml +++ b/tests/test_config_merging/config_cmdline_01.yaml @@ -2,3 +2,5 @@ block: foo: cfg01_foo bar: cfg01_bar baz: cfg01_baz + foobar: + cfg01_key: cfg01_val diff --git a/tests/test_config_merging/config_snakefile.yaml b/tests/test_config_merging/config_snakefile.yaml index c5fbe0a86..fd951ab16 100644 --- a/tests/test_config_merging/config_snakefile.yaml +++ b/tests/test_config_merging/config_snakefile.yaml @@ -1,3 +1,4 @@ block: bar: snake_bar fubar: snake_fubar + foobar: null diff --git a/tests/test_config_merging/expected-results/test.out b/tests/test_config_merging/expected-results/test.out index 967372364..96229e319 100644 --- a/tests/test_config_merging/expected-results/test.out +++ b/tests/test_config_merging/expected-results/test.out @@ -1 +1 @@ -{"block": {"bar": "cfg01_bar", "baz": "cfg01_baz", "bowser": "cmdline_bowser", "foo": "cfg02_foo", "fubar": "snake_fubar", "qux": "cfg02_qux", "toad": "cmdline_toad"}} \ No newline at end of file +{"block": {"bar": "cfg01_bar", "baz": "cfg01_baz", "bowser": "cmdline_bowser", "foo": "cfg02_foo", "foobar": {"cfg01_key": "cfg01_val"}, "fubar": "snake_fubar", "qux": "cfg02_qux", "toad": "cmdline_toad"}}