From c7771c5c5c25d70ca9e4f4d05b91ed0f78696f7b Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Wed, 13 Nov 2019 19:53:16 +0100 Subject: [PATCH 1/2] add support for is_mandatory_key method in EasyConfig class --- easybuild/framework/easyconfig/easyconfig.py | 4 ++ test/framework/easyconfig.py | 42 ++++++++++++-------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/easybuild/framework/easyconfig/easyconfig.py b/easybuild/framework/easyconfig/easyconfig.py index 32d7faf942..f0295d1423 100644 --- a/easybuild/framework/easyconfig/easyconfig.py +++ b/easybuild/framework/easyconfig/easyconfig.py @@ -1514,6 +1514,10 @@ def __getitem__(self, key): return value + def is_mandatory_param(self, key): + """Check whether specified easyconfig parameter is mandatory.""" + return key in self.mandatory + def get_ref(self, key): """ Obtain reference to original/untemplated value of specified easyconfig parameter diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 9a33ac3865..4829280991 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -148,13 +148,18 @@ def test_mandatory(self): ]) self.prep() - eb = EasyConfig(self.eb_file) + ec = EasyConfig(self.eb_file) - self.assertEqual(eb['name'], "pi") - self.assertEqual(eb['version'], "3.14") - self.assertEqual(eb['homepage'], "http://example.com") - self.assertEqual(eb['toolchain'], {"name": "system", "version": "system"}) - self.assertEqual(eb['description'], "test easyconfig") + self.assertEqual(ec['name'], "pi") + self.assertEqual(ec['version'], "3.14") + self.assertEqual(ec['homepage'], "http://example.com") + self.assertEqual(ec['toolchain'], {"name": "system", "version": "system"}) + self.assertEqual(ec['description'], "test easyconfig") + + for key in ['name', 'version', 'homepage', 'toolchain', 'description']: + self.assertTrue(ec.is_mandatory_param(key)) + for key in ['buildopts', 'dependencies', 'easyblock', 'sources']: + self.assertFalse(ec.is_mandatory_param(key)) def test_validation(self): """ test other validations beside mandatory parameters """ @@ -318,24 +323,26 @@ def test_extra_options(self): extra_vars = {'custom_key': ['default', "This is a default key", easyconfig.CUSTOM]} - eb = EasyConfig(self.eb_file, extra_options=extra_vars) - self.assertEqual(eb['custom_key'], 'default') + ec = EasyConfig(self.eb_file, extra_options=extra_vars) + self.assertEqual(ec['custom_key'], 'default') + + self.assertFalse(ec.is_mandatory_param('custom_key')) - eb['custom_key'] = "not so default" - self.assertEqual(eb['custom_key'], 'not so default') + ec['custom_key'] = "not so default" + self.assertEqual(ec['custom_key'], 'not so default') self.contents += "\ncustom_key = 'test'" self.prep() - eb = EasyConfig(self.eb_file, extra_options=extra_vars) - self.assertEqual(eb['custom_key'], 'test') + ec = EasyConfig(self.eb_file, extra_options=extra_vars) + self.assertEqual(ec['custom_key'], 'test') - eb['custom_key'] = "not so default" - self.assertEqual(eb['custom_key'], 'not so default') + ec['custom_key'] = "not so default" + self.assertEqual(ec['custom_key'], 'not so default') # test if extra toolchain options are being passed - self.assertEqual(eb.toolchain.options['static'], True) + self.assertEqual(ec.toolchain.options['static'], True) # test extra mandatory parameters extra_vars.update({'mandatory_key': ['default', 'another mandatory key', easyconfig.MANDATORY]}) @@ -345,9 +352,10 @@ def test_extra_options(self): self.contents += '\nmandatory_key = "value"' self.prep() - eb = EasyConfig(self.eb_file, extra_options=extra_vars) + ec = EasyConfig(self.eb_file, extra_options=extra_vars) - self.assertEqual(eb['mandatory_key'], 'value') + self.assertEqual(ec['mandatory_key'], 'value') + self.assertTrue(ec.is_mandatory_param('mandatory_key')) def test_exts_list(self): """Test handling of list of extensions.""" From bf71ba1809be8e14adf20e9167233a5519115838 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Wed, 13 Nov 2019 20:03:13 +0100 Subject: [PATCH 2/2] always include mandatory easyconfig parameters in dumped easyconfig file, regardless of whether default value is used or not --- easybuild/framework/easyconfig/format/one.py | 4 +++- test/framework/easyconfig.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/easybuild/framework/easyconfig/format/one.py b/easybuild/framework/easyconfig/format/one.py index cce218ab8a..612c17f988 100644 --- a/easybuild/framework/easyconfig/format/one.py +++ b/easybuild/framework/easyconfig/format/one.py @@ -286,7 +286,9 @@ def dump(self, ecfg, default_values, templ_const, templ_val): # print other easyconfig parameters at the end keys_to_ignore = printed_keys + LAST_PARAMS for key in default_values: - if key not in keys_to_ignore and ecfg[key] != default_values[key]: + mandatory = ecfg.is_mandatory_param(key) + non_default_value = ecfg[key] != default_values[key] + if key not in keys_to_ignore and (mandatory or non_default_value): dump.extend(self._find_param_with_comments(key, quote_py_str(ecfg[key]), templ_const, templ_val)) dump.append('') diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 4829280991..061a324641 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -357,6 +357,19 @@ def test_extra_options(self): self.assertEqual(ec['mandatory_key'], 'value') self.assertTrue(ec.is_mandatory_param('mandatory_key')) + # check whether mandatory key is retained in dumped easyconfig file, even if it's set to the default value + ec['mandatory_key'] = 'default' + test_ecfile = os.path.join(self.test_prefix, 'test_dump_mandatory.eb') + ec.dump(test_ecfile) + + regex = re.compile("^mandatory_key = 'default'$", re.M) + ectxt = read_file(test_ecfile) + self.assertTrue(regex.search(ectxt), "Pattern '%s' found in: %s" % (regex.pattern, ectxt)) + + # parsing again should work fine (if mandatory easyconfig parameters are indeed retained) + ec = EasyConfig(test_ecfile, extra_options=extra_vars) + self.assertEqual(ec['mandatory_key'], 'default') + def test_exts_list(self): """Test handling of list of extensions.""" topdir = os.path.dirname(os.path.abspath(__file__))