diff --git a/easybuild/framework/easyconfig/easyconfig.py b/easybuild/framework/easyconfig/easyconfig.py index 4916d776ff..c95ab7dafe 100644 --- a/easybuild/framework/easyconfig/easyconfig.py +++ b/easybuild/framework/easyconfig/easyconfig.py @@ -2075,8 +2075,8 @@ def resolve_template(value, tmpl_dict, expect_resolved=True): ver) except KeyError: if expect_resolved: - msg = ('Failed to resolve template value %s with dict %s. ' % (value, tmpl_dict) + - 'This might cause failures or unexpected behavior, ' + + msg = (f'Failed to resolve all templates in "{value}" using template dictionary: {tmpl_dict}. ' + 'This might cause failures or unexpected behavior, ' 'check for correct escaping if this is intended!') if build_option('allow_unresolved_templates'): print_warning(msg) diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index d5cb550b0c..95e72d5c25 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -5148,6 +5148,43 @@ def test_easyconfigs_caches(self): regex = re.compile(r"libtoy/0\.0 is already installed", re.M) self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout)) + def test_templates(self): + """ + Test use of template values like %(version)s + """ + test_ecs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs', 'test_ecs') + toy_ec = os.path.join(test_ecs_dir, 't', 'toy', 'toy-0.0.eb') + + test_ec_txt = read_file(toy_ec) + test_ec_txt += '\ndescription = "name: %(name)s, version: %(version)s"' + + test_ec = os.path.join(self.test_prefix, 'test.eb') + write_file(test_ec, test_ec_txt) + ec = EasyConfig(test_ec) + + # get_ref provides access to non-templated raw value + self.assertEqual(ec.get_ref('description'), "name: %(name)s, version: %(version)s") + self.assertEqual(ec['description'], "name: toy, version: 0.0") + + # error when using wrong template value or using template value that can not be resolved yet too early + test_ec_txt += '\ndescription = "name: %(name)s, version: %(version)s, pyshortver: %(pyshortver)s"' + write_file(test_ec, test_ec_txt) + ec = EasyConfig(test_ec) + + self.assertEqual(ec.get_ref('description'), "name: %(name)s, version: %(version)s, pyshortver: %(pyshortver)s") + error_pattern = "Failed to resolve all templates in.* %\(pyshortver\)s.* using template dictionary:" + self.assertErrorRegex(EasyBuildError, error_pattern, ec.__getitem__, 'description') + + # EasyBuild can be configured to allow unresolved templates + update_build_option('allow_unresolved_templates', True) + self.assertEqual(ec.get_ref('description'), "name: %(name)s, version: %(version)s, pyshortver: %(pyshortver)s") + with self.mocked_stdout_stderr() as (stdout, stderr): + self.assertEqual(ec['description'], "name: %(name)s, version: %(version)s, pyshortver: %(pyshortver)s") + + self.assertFalse(stdout.getvalue()) + regex = re.compile(r"WARNING: Failed to resolve all templates.* %\(pyshortver\)s", re.M) + self.assertRegex(stderr, regex) + def suite(): """ returns all the testcases in this module """