From b211b8de0bdb95c6b5dd732dd2f1564db5c0b0c2 Mon Sep 17 00:00:00 2001 From: mmerkel Date: Wed, 21 Feb 2024 15:47:22 -0500 Subject: [PATCH] Added check that no new keys can be introduced --- python/solid_dmft/CMakeLists.txt | 4 +- python/solid_dmft/io_tools/default.toml | 1 + .../solid_dmft/io_tools/postproc_toml_dict.py | 15 ++++++-- test/python/test_postproc_toml_dict.py | 38 ++++++++++++++++--- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/python/solid_dmft/CMakeLists.txt b/python/solid_dmft/CMakeLists.txt index 72fbf5ad..1e72ff7f 100644 --- a/python/solid_dmft/CMakeLists.txt +++ b/python/solid_dmft/CMakeLists.txt @@ -1,8 +1,8 @@ # Configure the version configure_file(version.py.in version.py) -# All Python files. Copy them in the build dir to have a complete package for the tests. -file(GLOB_RECURSE python_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.py) +# All Python and toml files. Copy them in the build dir to have a complete package for the tests. +file(GLOB_RECURSE python_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.py *.toml) foreach(file ${python_sources}) configure_file(${file} ${file} COPYONLY) endforeach() diff --git a/python/solid_dmft/io_tools/default.toml b/python/solid_dmft/io_tools/default.toml index f1f5b7ec..7ca6b495 100644 --- a/python/solid_dmft/io_tools/default.toml +++ b/python/solid_dmft/io_tools/default.toml @@ -12,6 +12,7 @@ csc = false dc = true dc_dmft = "" dc_type = "" +dft_mu = "" diag_delta = false enforce_off_diag = false fixed_mu_value = "" diff --git a/python/solid_dmft/io_tools/postproc_toml_dict.py b/python/solid_dmft/io_tools/postproc_toml_dict.py index 46615bfa..9d9ccb27 100644 --- a/python/solid_dmft/io_tools/postproc_toml_dict.py +++ b/python/solid_dmft/io_tools/postproc_toml_dict.py @@ -27,7 +27,7 @@ def _verify_dict_is_full_config(d: Dict[str, Any]) -> None: else: _verify_dict_is_param_dict(section) -def _verify_restrictions_on_default_and_config(cfg_def: Dict[str, Any], cfg_inp: Dict[str, Any], match_key: Dict[str, str]) -> None: +def _verify_restrictions_on_default_and_config(cfg_inp: Dict[str, Any], cfg_def: Dict[str, Any], match_key: Dict[str, str]) -> None: """ Checks that the restrictions described in the docstring of merge_config_with_default are met. """ # Checks that type of cfg_def dict is FullConfig _verify_dict_is_full_config(cfg_def) @@ -74,10 +74,19 @@ def _apply_default_values(cfg_inp: FullConfig, cfg_def: FullConfig, match_key: D else: raise ValueError(f'No matching section with same "{section_name}.{key}"="{entry[key]}" found in defaults.') # Updates config values in output + unknown_keys = set(entry.keys()) - set(output[section_name][-1].keys()) + if unknown_keys: + raise ValueError(f'Unknown keys {unknown_keys} found in section "{section_name}". ' + 'All valid keys have to be in the default config.') output[section_name][-1].update(entry) else: + entry = cfg_inp.get(section_name, {}) output[section_name] = copy.deepcopy(section) - output[section_name].update(cfg_inp.get(section_name, {})) + unknown_keys = set(entry.keys()) - set(output[section_name].keys()) + if unknown_keys: + raise ValueError(f'Unknown keys {unknown_keys} found in section "{section_name}". ' + 'All valid keys have to be in the default config.') + output[section_name].update(entry) return output @@ -124,7 +133,7 @@ def merge_config_with_default(cfg_inp: Dict[str, Any], cfg_def: Dict[str, Any], """ # Check restrictions and makes sure that config and default are of type FullConfig - _verify_restrictions_on_default_and_config(cfg_def, cfg_inp, match_key) + _verify_restrictions_on_default_and_config(cfg_inp, cfg_def, match_key) # Checks that keys not listed in match_key are dicts # The others can be lists or dicts. This differs from cfg_def diff --git a/test/python/test_postproc_toml_dict.py b/test/python/test_postproc_toml_dict.py index cc3c28b8..4e930e93 100644 --- a/test/python/test_postproc_toml_dict.py +++ b/test/python/test_postproc_toml_dict.py @@ -1,10 +1,10 @@ import pytest -from solid_dmft.io_tools.postproc_toml_dict import _apply_default_values, _verify_restrictions_on_default_and_config, _resolve_references +from solid_dmft.io_tools.postproc_toml_dict import merge_config_with_default, _apply_default_values, _verify_restrictions_on_default_and_config, _resolve_references -def test_verify_restrictions_invalid_key(): +def test_verify_restrictions_invalid_section(): config = { 'section1': {'key1': 'newval11', 'key2': 'newval12'}, - 'section4': {'key1': 'newval31'}, + 'section4': {'key1': 'newval41'}, } default = { 'section1': {'key1': 'defval11', 'key2': 'defval12', 'key3': 'defval13'}, @@ -17,7 +17,7 @@ def test_verify_restrictions_invalid_key(): def test_verify_restrictions_key_outside_section_default(): config = { 'section1': {'key1': 'newval11', 'key2': 'newval12'}, - 'section4': {'key1': 'newval31'}, + 'section2': {'key1': 'newval31'}, } default = { 'section1': {'key1': 'defval11', 'key2': 'defval12', 'key3': 'defval13'}, @@ -52,7 +52,7 @@ def test_verify_restriction_missing_listed_section(): with pytest.raises(ValueError): _verify_restrictions_on_default_and_config(default, config, {'section1': 'match'}) -def test_verify_restrictions_nonexistent_listed_section(): +def test_merge_config_nonexistent_listed_section(): config = { 'section1': {'key1': 'newval11', 'key2': 'newval12'}, 'section2': [{'key1': 'newval31'}], @@ -63,7 +63,7 @@ def test_verify_restrictions_nonexistent_listed_section(): 'section3': {'key1': 'defval31', 'key2': 'defval32', 'key3': 'defval33'}, } with pytest.raises(ValueError): - _verify_restrictions_on_default_and_config(config, default, {}) + merge_config_with_default(config, default, {}) def test_resolve_references_simple(): config = { @@ -137,3 +137,29 @@ def test_apply_default_values_partial_listed_config(): 'section3': {'key1': 'newval31', 'key2': 'defval32', 'key3': 'defval33'}, } assert _apply_default_values(config, default, {'section2': 'match'}) == expected_output + +def test_apply_default_values_invalid_key(): + config = { + 'section1': {'key1': 'newval11', 'key2': 'newval12'}, + 'section2': {'key4': 'newval24'}, + } + default = { + 'section1': {'key1': 'defval11', 'key2': 'defval12', 'key3': 'defval13'}, + 'section2': {'key1': 'defval21', 'key2': 'defval22', 'key3': 'defval23'}, + 'section3': {'key1': 'defval31', 'key2': 'defval32', 'key3': 'defval33'}, + } + with pytest.raises(ValueError): + _apply_default_values(config, default, {}) + +def test_apply_default_values_invalid_listed_key(): + config = { + 'section1': {'key1': 'newval11', 'key2': 'newval12'}, + 'section2': [{'match': 'matchval', 'key4': 'newval24'}], + } + default = { + 'section1': {'key1': 'defval11', 'key2': 'defval12', 'key3': 'defval13'}, + 'section2': [{'match': 'matchval', 'key2': 'defval22', 'key3': 'defval23'}], + 'section3': {'key1': 'defval31', 'key2': 'defval32', 'key3': 'defval33'}, + } + with pytest.raises(ValueError): + _apply_default_values(config, default, {'section2': 'match'})