Allow deprecating more than one property in config (#46221)

* Allow deprecating more than one property in config

This internal change allows the customization of errors
and warnings to be printed when deprecating a property.

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>

* fix

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>

* Use a list comprehension for "issues"

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>

---------

Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Massimiliano Culpo 2024-09-06 00:33:20 +02:00 committed by GitHub
parent 434a703bcf
commit 9a8bff01ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 57 deletions

View File

@ -3,22 +3,28 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""This module contains jsonschema files for all of Spack's YAML formats.""" """This module contains jsonschema files for all of Spack's YAML formats."""
import typing
import warnings import warnings
import llnl.util.lang import llnl.util.lang
class DeprecationMessage(typing.NamedTuple):
message: str
error: bool
# jsonschema is imported lazily as it is heavy to import # jsonschema is imported lazily as it is heavy to import
# and increases the start-up time # and increases the start-up time
def _make_validator(): def _make_validator():
import jsonschema import jsonschema
import spack.parser
def _validate_spec(validator, is_spec, instance, schema): def _validate_spec(validator, is_spec, instance, schema):
"""Check if the attributes on instance are valid specs.""" """Check if the attributes on instance are valid specs."""
import jsonschema import jsonschema
import spack.parser
if not validator.is_type(instance, "object"): if not validator.is_type(instance, "object"):
return return
@ -32,27 +38,31 @@ def _deprecated_properties(validator, deprecated, instance, schema):
if not (validator.is_type(instance, "object") or validator.is_type(instance, "array")): if not (validator.is_type(instance, "object") or validator.is_type(instance, "array")):
return return
# Get a list of the deprecated properties, return if there is none if not deprecated:
deprecated_properties = [x for x in instance if x in deprecated["properties"]]
if not deprecated_properties:
return return
# Retrieve the template message deprecations = {
msg_str_or_func = deprecated["message"] name: DeprecationMessage(message=x["message"], error=x["error"])
if isinstance(msg_str_or_func, str): for x in deprecated
msg = msg_str_or_func.format(properties=deprecated_properties) for name in x["names"]
else: }
msg = msg_str_or_func(instance, deprecated_properties)
if msg is None:
return
is_error = deprecated["error"] # Get a list of the deprecated properties, return if there is none
if not is_error: issues = [entry for entry in instance if entry in deprecations]
warnings.warn(msg) if not issues:
else: return
import jsonschema
yield jsonschema.ValidationError(msg) # Process issues
errors = []
for name in issues:
msg = deprecations[name].message.format(name=name)
if deprecations[name].error:
errors.append(msg)
else:
warnings.warn(msg)
if errors:
yield jsonschema.ValidationError("\n".join(errors))
return jsonschema.validators.extend( return jsonschema.validators.extend(
jsonschema.Draft4Validator, jsonschema.Draft4Validator,

View File

@ -96,12 +96,14 @@
"binary_index_ttl": {"type": "integer", "minimum": 0}, "binary_index_ttl": {"type": "integer", "minimum": 0},
"aliases": {"type": "object", "patternProperties": {r"\w[\w-]*": {"type": "string"}}}, "aliases": {"type": "object", "patternProperties": {r"\w[\w-]*": {"type": "string"}}},
}, },
"deprecatedProperties": { "deprecatedProperties": [
"properties": ["concretizer"], {
"message": "Spack supports only clingo as a concretizer from v0.23. " "names": ["concretizer"],
"The config:concretizer config option is ignored.", "message": "Spack supports only clingo as a concretizer from v0.23. "
"error": False, "The config:concretizer config option is ignored.",
}, "error": False,
}
],
} }
} }

View File

@ -140,14 +140,16 @@
}, },
"variants": variants, "variants": variants,
}, },
"deprecatedProperties": { "deprecatedProperties": [
"properties": ["version"], {
"message": "setting version preferences in the 'all' section of packages.yaml " "names": ["version"],
"is deprecated and will be removed in v0.23\n\n\tThese preferences " "message": "setting version preferences in the 'all' section of "
"will be ignored by Spack. You can set them only in package-specific sections " "packages.yaml is deprecated and will be removed in v0.23"
"of the same file.\n", "\n\n\tThese preferences will be ignored by Spack. You can "
"error": False, "set them only in package-specific sections of the same file.\n",
}, "error": False,
}
],
} }
}, },
"patternProperties": { "patternProperties": {
@ -204,18 +206,20 @@
}, },
}, },
}, },
"deprecatedProperties": { "deprecatedProperties": [
"properties": ["target", "compiler", "providers"], {
"message": "setting 'compiler:', 'target:' or 'provider:' preferences in " "names": ["target", "compiler", "providers"],
"a package-specific section of packages.yaml is deprecated, and will be " "message": "setting '{name}:' preferences in "
"removed in v0.23.\n\n\tThese preferences will be ignored by Spack, and " "a package-specific section of packages.yaml is deprecated, and will be "
"can be set only in the 'all' section of the same file. " "removed in v0.23.\n\n\tThis preferences will be ignored by Spack, and "
"You can run:\n\n\t\t$ spack audit configs\n\n\tto get better diagnostics, " "can be set only in the 'all' section of the same file. "
"including files:lines where the deprecated attributes are used.\n\n" "You can run:\n\n\t\t$ spack audit configs\n\n\tto get better "
"\tUse requirements to enforce conditions on specific packages: " "diagnostics, including files:lines where the deprecated "
f"{REQUIREMENT_URL}\n", "attributes are used.\n\n\tUse requirements to enforce conditions"
"error": False, f" on specific packages: {REQUIREMENT_URL}\n",
}, "error": False,
}
],
} }
}, },
} }

View File

@ -105,25 +105,21 @@ def test_schema_validation(meta_schema, config_name):
def test_deprecated_properties(module_suffixes_schema): def test_deprecated_properties(module_suffixes_schema):
# Test that an error is reported when 'error: True' # Test that an error is reported when 'error: True'
msg_fmt = r"deprecated properties detected [properties={properties}]" msg_fmt = r"{name} is deprecated"
module_suffixes_schema["deprecatedProperties"] = { module_suffixes_schema["deprecatedProperties"] = [
"properties": ["tcl"], {"names": ["tcl"], "message": msg_fmt, "error": True}
"message": msg_fmt, ]
"error": True,
}
v = spack.schema.Validator(module_suffixes_schema) v = spack.schema.Validator(module_suffixes_schema)
data = {"tcl": {"all": {"suffixes": {"^python": "py"}}}} data = {"tcl": {"all": {"suffixes": {"^python": "py"}}}}
expected_match = "deprecated properties detected" expected_match = "tcl is deprecated"
with pytest.raises(jsonschema.ValidationError, match=expected_match): with pytest.raises(jsonschema.ValidationError, match=expected_match):
v.validate(data) v.validate(data)
# Test that just a warning is reported when 'error: False' # Test that just a warning is reported when 'error: False'
module_suffixes_schema["deprecatedProperties"] = { module_suffixes_schema["deprecatedProperties"] = [
"properties": ["tcl"], {"names": ["tcl"], "message": msg_fmt, "error": False}
"message": msg_fmt, ]
"error": False,
}
v = spack.schema.Validator(module_suffixes_schema) v = spack.schema.Validator(module_suffixes_schema)
data = {"tcl": {"all": {"suffixes": {"^python": "py"}}}} data = {"tcl": {"all": {"suffixes": {"^python": "py"}}}}
# The next validation doesn't raise anymore # The next validation doesn't raise anymore