From 510cb33b3a7e5b05524db47a081b409069099b89 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Wed, 25 Oct 2023 11:20:49 +0200 Subject: [PATCH 1/2] add `EasyConfig.dependency_names` --- easybuild/framework/easyconfig/easyconfig.py | 9 +++++++++ test/framework/easyconfig.py | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/easybuild/framework/easyconfig/easyconfig.py b/easybuild/framework/easyconfig/easyconfig.py index 55fe3c8578..ff4ed3562c 100644 --- a/easybuild/framework/easyconfig/easyconfig.py +++ b/easybuild/framework/easyconfig/easyconfig.py @@ -1139,6 +1139,15 @@ def dependencies(self, build_only=False): return retained_deps + def dependency_names(self, build_only=False): + """ + Return a set of names of all (direct) dependencies after filtering. + Iterable builddependencies are flattened when not iterating. + + :param build_only: only return build dependencies, discard others + """ + return {dep['name'] for dep in self.dependencies(build_only=build_only) if dep['name']} + def builddependencies(self): """ Return a flat list of the parsed build dependencies diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 14ed69084b..5fde75938d 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -301,7 +301,9 @@ def test_dependency(self): self.assertEqual(det_full_ec_version(first), '1.1-GCC-4.6.3') self.assertEqual(det_full_ec_version(second), '2.2-GCC-4.6.3') + self.assertEqual(eb.dependency_names(), {'first', 'second', 'foo', 'bar'}) # same tests for builddependencies + self.assertEqual(eb.dependency_names(build_only=True), {'first', 'second'}) first = eb.builddependencies()[0] second = eb.builddependencies()[1] @@ -354,6 +356,7 @@ def test_false_dep_version(self): self.assertEqual(len(deps), 2) self.assertEqual(deps[0]['name'], 'second_build') self.assertEqual(deps[1]['name'], 'first') + self.assertEqual(eb.dependency_names(), {'first', 'second_build'}) # more realistic example: only filter dep for POWER self.contents = '\n'.join([ @@ -377,12 +380,14 @@ def test_false_dep_version(self): deps = eb.dependencies() self.assertEqual(len(deps), 1) self.assertEqual(deps[0]['name'], 'not_on_power') + self.assertEqual(eb.dependency_names(), {'not_on_power'}) # only power, dependency gets filtered st.get_cpu_architecture = lambda: POWER eb = EasyConfig(self.eb_file) deps = eb.dependencies() self.assertEqual(deps, []) + self.assertEqual(eb.dependency_names(), {}) def test_extra_options(self): """ extra_options should allow other variables to be stored """ @@ -1608,18 +1613,15 @@ def test_filter_deps(self): test_ecs_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'easyconfigs', 'test_ecs') ec_file = os.path.join(test_ecs_dir, 'f', 'foss', 'foss-2018a.eb') ec = EasyConfig(ec_file) - deps = sorted([dep['name'] for dep in ec.dependencies()]) - self.assertEqual(deps, ['FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK']) + self.assertEqual(ec.dependency_names(), {'FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK'}) # test filtering multiple deps init_config(build_options={'filter_deps': ['FFTW', 'ScaLAPACK']}) - deps = sorted([dep['name'] for dep in ec.dependencies()]) - self.assertEqual(deps, ['GCC', 'OpenBLAS', 'OpenMPI']) + self.assertEqual(ec.dependency_names(), {'GCC', 'OpenBLAS', 'OpenMPI'}) # test filtering of non-existing dep init_config(build_options={'filter_deps': ['zlib']}) - deps = sorted([dep['name'] for dep in ec.dependencies()]) - self.assertEqual(deps, ['FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK']) + self.assertEqual(ec.dependency_names(), {'FFTW', 'GCC', 'OpenBLAS', 'OpenMPI', 'ScaLAPACK'}) # test parsing of value passed to --filter-deps opts = init_config(args=[]) @@ -1653,6 +1655,7 @@ def test_filter_deps(self): init_config(build_options=build_options) ec = EasyConfig(ec_file, validate=False) self.assertEqual(ec.dependencies(), []) + self.assertEqual(ec.dependency_names(), {}) def test_replaced_easyconfig_parameters(self): """Test handling of replaced easyconfig parameters.""" @@ -1841,6 +1844,9 @@ def test_external_dependencies(self): } self.assertEqual(deps[7]['external_module_metadata'], cray_netcdf_metadata) + # External module names are omitted + self.assertEqual(ec.dependency_names(), {'intel'}) + # provide file with partial metadata for some external modules; # metadata obtained from probing modules should be added to it... metadata = os.path.join(self.test_prefix, 'external_modules_metadata.cfg') @@ -1869,6 +1875,7 @@ def test_external_dependencies(self): deps = ec.dependencies() self.assertEqual(len(deps), 8) + self.assertEqual(ec.dependency_names(), {'intel'}) for idx in [0, 1, 2, 6]: self.assertEqual(deps[idx]['external_module_metadata'], {}) From 8c9b09a994fc60cfd5a4ce9bac0f4bfdf627ff16 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Wed, 25 Oct 2023 12:31:34 +0200 Subject: [PATCH 2/2] Explicitely use `set()` instead of `{}` Some Python version may interpret the latter as an (empty) dict instead of a set --- test/framework/easyconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 5fde75938d..fe921aa52e 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -387,7 +387,7 @@ def test_false_dep_version(self): eb = EasyConfig(self.eb_file) deps = eb.dependencies() self.assertEqual(deps, []) - self.assertEqual(eb.dependency_names(), {}) + self.assertEqual(eb.dependency_names(), set()) def test_extra_options(self): """ extra_options should allow other variables to be stored """ @@ -1655,7 +1655,7 @@ def test_filter_deps(self): init_config(build_options=build_options) ec = EasyConfig(ec_file, validate=False) self.assertEqual(ec.dependencies(), []) - self.assertEqual(ec.dependency_names(), {}) + self.assertEqual(ec.dependency_names(), set()) def test_replaced_easyconfig_parameters(self): """Test handling of replaced easyconfig parameters."""