From 1bdc30979d6db631e69335847b9b0ef38c3ebad0 Mon Sep 17 00:00:00 2001 From: Jordan Galby <67924449+Jordan474@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:42:04 +0200 Subject: [PATCH] Fix regression in spec format string for indiviual variants (#46206) Fix a regression in {variants.X} and {variants.X.value} spec format strings. --- lib/spack/spack/spec.py | 7 +++++-- lib/spack/spack/test/spec_semantics.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 5b7ad3e881..055be1508b 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -4420,9 +4420,12 @@ def format_attribute(match_object: Match) -> str: if part.startswith("_"): raise SpecFormatStringError("Attempted to format private attribute") else: - if part == "variants" and isinstance(current, vt.VariantMap): + if isinstance(current, vt.VariantMap): # subscript instead of getattr for variant names - current = current[part] + try: + current = current[part] + except KeyError: + raise SpecFormatStringError(f"Variant '{part}' does not exist") else: # aliases if part == "arch": diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index b21f0e7ac9..084f8953c3 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -672,6 +672,13 @@ def test_spec_formatting(self, default_mock_concretization): ("{/hash}", "/", lambda s: "/" + s.dag_hash()), ] + variants_segments = [ + ("{variants.debug}", spec, "debug"), + ("{variants.foo}", spec, "foo"), + ("{^pkg-a.variants.bvv}", spec["pkg-a"], "bvv"), + ("{^pkg-a.variants.foo}", spec["pkg-a"], "foo"), + ] + other_segments = [ ("{spack_root}", spack.paths.spack_root), ("{spack_install}", spack.store.STORE.layout.root), @@ -699,6 +706,12 @@ def check_prop(check_spec, fmt_str, prop, getter): callpath, fmt_str = depify("callpath", named_str, sigil) assert spec.format(fmt_str) == getter(callpath) + for named_str, test_spec, variant_name in variants_segments: + assert test_spec.format(named_str) == str(test_spec.variants[variant_name]) + assert test_spec.format(named_str[:-1] + ".value}") == str( + test_spec.variants[variant_name].value + ) + for named_str, expected in other_segments: actual = spec.format(named_str) assert expected == actual @@ -731,6 +744,7 @@ def test_spec_formatting_sigil_mismatches(self, default_mock_concretization, fmt r"{dag_hash}", r"{foo}", r"{+variants.debug}", + r"{variants.this_variant_does_not_exist}", ], ) def test_spec_formatting_bad_formats(self, default_mock_concretization, fmt_str):