summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2021-10-29 18:44:49 +0200
committerGitHub <noreply@github.com>2021-10-29 18:44:49 +0200
commit3eb52b48b8d0f3379e257ab0817fef4e1b7f4c5e (patch)
treee2e5c1326c3efb646388ccecb6ddef243fe1b410 /lib
parent20b7485cd4305d229219dd14a803764280c83978 (diff)
downloadspack-3eb52b48b8d0f3379e257ab0817fef4e1b7f4c5e.tar.gz
spack-3eb52b48b8d0f3379e257ab0817fef4e1b7f4c5e.tar.bz2
spack-3eb52b48b8d0f3379e257ab0817fef4e1b7f4c5e.tar.xz
spack-3eb52b48b8d0f3379e257ab0817fef4e1b7f4c5e.zip
config add: infer type based on JSON schema validation errors (#27035)
- [x] Allow dding enumerated types and types whose default value is forbidden by the schema - [x] Add a test for using enumerated types in the tests for `spack config add` - [x] Make `config add` tests use the `mutable_config` fixture so they do not affect other tests Co-authored-by: Todd Gamblin <tgamblin@llnl.gov>
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/config.py43
-rw-r--r--lib/spack/spack/test/cmd/config.py2
-rw-r--r--lib/spack/spack/test/config.py19
3 files changed, 45 insertions, 19 deletions
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index c82729b007..f3fc73e4b4 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -1067,22 +1067,36 @@ def get_valid_type(path):
path given, the priority order is ``list``, ``dict``, ``str``, ``bool``,
``int``, ``float``.
"""
+ types = {
+ 'array': list,
+ 'object': syaml.syaml_dict,
+ 'string': str,
+ 'boolean': bool,
+ 'integer': int,
+ 'number': float
+ }
+
components = process_config_path(path)
section = components[0]
- for type in (list, syaml.syaml_dict, str, bool, int, float):
- try:
- ret = type()
- test_data = ret
- for component in reversed(components):
- test_data = {component: test_data}
- validate(test_data, section_schemas[section])
- return ret
- except (ConfigFormatError, AttributeError):
- # This type won't validate, try the next one
- # Except AttributeError because undefined behavior of dict ordering
- # in python 3.5 can cause the validator to raise an AttributeError
- # instead of a ConfigFormatError.
- pass
+
+ # Use None to construct the test data
+ test_data = None
+ for component in reversed(components):
+ test_data = {component: test_data}
+
+ try:
+ validate(test_data, section_schemas[section])
+ except (ConfigFormatError, AttributeError) as e:
+ jsonschema_error = e.validation_error
+ if jsonschema_error.validator == 'type':
+ return types[jsonschema_error.validator_value]()
+ elif jsonschema_error.validator == 'anyOf':
+ for subschema in jsonschema_error.validator_value:
+ anyof_type = subschema.get('type')
+ if anyof_type is not None:
+ return types[anyof_type]()
+ else:
+ return type(None)
raise ConfigError("Cannot determine valid type for path '%s'." % path)
@@ -1301,6 +1315,7 @@ class ConfigFormatError(ConfigError):
def __init__(self, validation_error, data, filename=None, line=None):
# spack yaml has its own file/line marks -- try to find them
# we prioritize these over the inputs
+ self.validation_error = validation_error
mark = self._get_mark(validation_error, data)
if mark:
filename = mark.name
diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py
index acadbc761d..63c3cab92a 100644
--- a/lib/spack/spack/test/cmd/config.py
+++ b/lib/spack/spack/test/cmd/config.py
@@ -225,7 +225,7 @@ def test_config_with_c_argument(mutable_empty_config):
# Add the path to the config
config("add", args.config_vars[0], scope='command_line')
output = config("get", 'config')
- assert "config:\n install_root:\n - root: /path/to/config.yaml" in output
+ assert "config:\n install_root:\n root: /path/to/config.yaml" in output
def test_config_add_ordered_dict(mutable_empty_config):
diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py
index fd6af8640b..6e65eee3bf 100644
--- a/lib/spack/spack/test/config.py
+++ b/lib/spack/spack/test/config.py
@@ -279,21 +279,32 @@ repos_high = {'repos': ["/some/other/path"]}
# Test setting config values via path in filename
-def test_add_config_path():
-
+def test_add_config_path(mutable_config):
# Try setting a new install tree root
path = "config:install_tree:root:/path/to/config.yaml"
- spack.config.add(path, scope="command_line")
+ spack.config.add(path)
set_value = spack.config.get('config')['install_tree']['root']
assert set_value == '/path/to/config.yaml'
# Now a package:all setting
path = "packages:all:compiler:[gcc]"
- spack.config.add(path, scope="command_line")
+ spack.config.add(path)
compilers = spack.config.get('packages')['all']['compiler']
assert "gcc" in compilers
+@pytest.mark.regression('17543,23259')
+def test_add_config_path_with_enumerated_type(mutable_config):
+ spack.config.add("config:concretizer:clingo")
+ assert spack.config.get('config')['concretizer'] == "clingo"
+
+ spack.config.add("config:concretizer:original")
+ assert spack.config.get('config')['concretizer'] == "original"
+
+ with pytest.raises(spack.config.ConfigError):
+ spack.config.add("config:concretizer:foo")
+
+
def test_add_config_filename(mock_low_high_config, tmpdir):
config_yaml = tmpdir.join('config-filename.yaml')