diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 0b1bdf4db49..439d8ae1fe8 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -22,7 +22,7 @@ jobs: - name: install Python packages run: | pip install --upgrade pip - pip install --upgrade flake8 + pip install --upgrade flake8 flake8-comprehensions - name: Run flake8 to verify PEP8-compliance of Python code run: flake8 diff --git a/easybuild/easyblocks/c/clang.py b/easybuild/easyblocks/c/clang.py index e858de75693..b1c101bc4ae 100644 --- a/easybuild/easyblocks/c/clang.py +++ b/easybuild/easyblocks/c/clang.py @@ -262,7 +262,7 @@ def find_source_dir(globpatterns, targetdir): glob_src_dirs) src_dirs[glob_src_dirs[0]] = targetdir - if any([x['name'].startswith('llvm-project') for x in self.src]): + if any(x['name'].startswith('llvm-project') for x in self.src): # if sources contain 'llvm-project*', we use the full tarball find_source_dir("../llvm-project-*", os.path.join(self.llvm_src_dir, "llvm-project-%s" % self.version)) self.cfg.update('configopts', '-DLLVM_ENABLE_PROJECTS="%s"' % ';'.join(self.cfg['llvm_projects'])) diff --git a/easybuild/easyblocks/c/cplex.py b/easybuild/easyblocks/c/cplex.py index 721c06d5c2e..91836fad5c9 100644 --- a/easybuild/easyblocks/c/cplex.py +++ b/easybuild/easyblocks/c/cplex.py @@ -142,8 +142,8 @@ def make_module_extra(self): bins = [] libs = [] - txt += self.module_generator.prepend_paths('PATH', [path for path in bins]) - txt += self.module_generator.prepend_paths('LD_LIBRARY_PATH', [path for path in bins + libs]) + txt += self.module_generator.prepend_paths('PATH', bins) + txt += self.module_generator.prepend_paths('LD_LIBRARY_PATH', bins + libs) txt += self.module_generator.set_environment('CPLEX_HOME', os.path.join(self.installdir, 'cplex')) txt += self.module_generator.set_environment('CPLEXDIR', os.path.join(self.installdir, 'cplex')) diff --git a/easybuild/easyblocks/e/easybuildmeta.py b/easybuild/easyblocks/e/easybuildmeta.py index 12ce53d0036..77f9e0872c5 100644 --- a/easybuild/easyblocks/e/easybuildmeta.py +++ b/easybuild/easyblocks/e/easybuildmeta.py @@ -230,7 +230,7 @@ def sanity_check_step(self): # order matters, e.g. setuptools before distutils eb_dirs = OrderedDict() eb_dirs['setuptools'] = [] - eb_dirs['distutils.core'] = flatten([x for x in subdirs_by_pkg.values()]) + eb_dirs['distutils.core'] = flatten(subdirs_by_pkg.values()) # determine setup tool (setuptools or distutils) setup_tool = None diff --git a/easybuild/easyblocks/f/flexiblas.py b/easybuild/easyblocks/f/flexiblas.py index c9306762f1a..9a34e2b3d96 100644 --- a/easybuild/easyblocks/f/flexiblas.py +++ b/easybuild/easyblocks/f/flexiblas.py @@ -69,7 +69,7 @@ def __init__(self, *args, **kwargs): """Easyblock constructor.""" super().__init__(*args, **kwargs) - dep_names = [dep['name'] for dep in self.cfg.dependencies()] + dep_names = self.cfg.dependency_names() if self.cfg['backends']: self.blas_libs = self.cfg['backends'][:] # make sure that all listed backends except imkl are (build)dependencies @@ -88,7 +88,7 @@ def __init__(self, *args, **kwargs): raise EasyBuildError("One or more backends not listed as (build)dependencies: %s", ', '.join(backends_nodep)) else: - build_dep_names = set(dep['name'] for dep in self.cfg.dependencies(build_only=True)) + build_dep_names = self.cfg.dependency_names(build_only=True) self.blas_libs = [x for x in dep_names if x not in build_dep_names] self.obj_builddir = os.path.join(self.builddir, 'easybuild_obj') diff --git a/easybuild/easyblocks/g/gamess_us.py b/easybuild/easyblocks/g/gamess_us.py index a82fab8272e..87ad3b382ee 100644 --- a/easybuild/easyblocks/g/gamess_us.py +++ b/easybuild/easyblocks/g/gamess_us.py @@ -494,8 +494,8 @@ def test_step(self): # verify output of tests failed_regex = re.compile(r"^.*!!FAILED\.$", re.M) - failed_tests = set([exam[0:6] for exam in failed_regex.findall(res.output)]) - done_tests = set([exam[0] for exam in target_tests]) + failed_tests = {exam[0:6] for exam in failed_regex.findall(res.output)} + done_tests = {exam[0] for exam in target_tests} if done_tests - failed_tests == done_tests: info_msg = "All target tests ran successfully!" if self.cfg['ddi_comm'] == 'mpi': diff --git a/easybuild/easyblocks/g/gcc.py b/easybuild/easyblocks/g/gcc.py index 1cabc288d0c..3ca08480a10 100644 --- a/easybuild/easyblocks/g/gcc.py +++ b/easybuild/easyblocks/g/gcc.py @@ -662,7 +662,7 @@ def configure_step(self): "libc6-dev-i386", # Debian-based "gcc-c++-32bit", # OpenSuSE, SLES ] - if not any([check_os_dependency(dep) for dep in glibc_32bit]): + if not any(check_os_dependency(dep) for dep in glibc_32bit): raise EasyBuildError("Using multilib requires 32-bit glibc (install one of %s, depending on your OS)", ', '.join(glibc_32bit)) self.configopts += " --enable-multilib --with-multilib-list=m32,m64" diff --git a/easybuild/easyblocks/g/gromacs.py b/easybuild/easyblocks/g/gromacs.py index a264a9d2f90..0f1b34edc19 100644 --- a/easybuild/easyblocks/g/gromacs.py +++ b/easybuild/easyblocks/g/gromacs.py @@ -392,7 +392,7 @@ def configure_step(self): # set regression test path prefix = 'regressiontests' - if any([src['name'].startswith(prefix) for src in self.src]): + if any(src['name'].startswith(prefix) for src in self.src): self.cfg.update('configopts', "-DREGRESSIONTEST_PATH='%%(builddir)s/%s-%%(version)s' " % prefix) # enable OpenMP support if desired diff --git a/easybuild/easyblocks/generic/cmakemake.py b/easybuild/easyblocks/generic/cmakemake.py index 584256cf6f1..1da5d9afdc7 100644 --- a/easybuild/easyblocks/generic/cmakemake.py +++ b/easybuild/easyblocks/generic/cmakemake.py @@ -333,7 +333,7 @@ def configure_step(self, srcdir=None, builddir=None, fail_on_error=True, return_ # If the cache does not exist CMake reads the environment variables cache_exists = os.path.exists('CMakeCache.txt') - env_to_options = dict() + env_to_options = {} # Setting compilers is not required unless we want absolute paths if self.cfg.get('abs_path_compilers', False) or cache_exists: diff --git a/easybuild/easyblocks/generic/pythonbundle.py b/easybuild/easyblocks/generic/pythonbundle.py index c9cdb46c2f9..332714b4c16 100644 --- a/easybuild/easyblocks/generic/pythonbundle.py +++ b/easybuild/easyblocks/generic/pythonbundle.py @@ -116,7 +116,7 @@ def make_module_extra(self, *args, **kwargs): # update $EBPYTHONPREFIXES rather than $PYTHONPATH # if this Python package was installed for multiple Python versions, or if we prefer it use_ebpythonprefixes = False - runtime_deps = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True)] + runtime_deps = self.cfg.dependency_names(runtime_only=True) if 'Python' in runtime_deps: self.log.info("Found Python runtime dependency, so considering $EBPYTHONPREFIXES...") diff --git a/easybuild/easyblocks/generic/pythonpackage.py b/easybuild/easyblocks/generic/pythonpackage.py index 5251a07b41d..12aa15c3795 100644 --- a/easybuild/easyblocks/generic/pythonpackage.py +++ b/easybuild/easyblocks/generic/pythonpackage.py @@ -635,7 +635,7 @@ def should_use_ebpythonprefixes(self) -> bool: """ use_ebpythonprefixes = False - runtime_deps = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True)] + runtime_deps = self.cfg.dependency_names(runtime_only=True) if 'Python' in runtime_deps: self.log.info("Found Python runtime dependency, so considering $EBPYTHONPREFIXES...") diff --git a/easybuild/easyblocks/generic/systemmpi.py b/easybuild/easyblocks/generic/systemmpi.py index 40a6e2b06e6..a2ba53164f8 100644 --- a/easybuild/easyblocks/generic/systemmpi.py +++ b/easybuild/easyblocks/generic/systemmpi.py @@ -139,7 +139,7 @@ def prepare_step(self, *args, **kwargs): # Extract any OpenMPI environment variables in the current environment and ensure they are added to the # final module - self.mpi_env_vars = dict((key, value) for key, value in os.environ.items() if key.startswith('OMPI_')) + self.mpi_env_vars = {key: value for key, value in os.environ.items() if key.startswith('OMPI_')} # Extract the C compiler used underneath the MPI implementation, check for the definition of OMPI_MPICC self.mpi_c_compiler = self.extract_ompi_setting("C compiler", output_of_ompi_info) diff --git a/easybuild/easyblocks/h/hypre.py b/easybuild/easyblocks/h/hypre.py index fea286cca10..04d0f29fea3 100644 --- a/easybuild/easyblocks/h/hypre.py +++ b/easybuild/easyblocks/h/hypre.py @@ -89,7 +89,7 @@ def sanity_check_step(self): """Custom sanity check for Hypre.""" # Add static and shared libs depending on configopts - hypre_libs = list() + hypre_libs = [] if self.config_shared: shlib_ext = get_shared_lib_ext() hypre_libs.append(os.path.join('lib', 'libHYPRE.%s' % shlib_ext)) diff --git a/easybuild/easyblocks/o/openmpi.py b/easybuild/easyblocks/o/openmpi.py index 560ce6fe07e..9e6f4e95044 100644 --- a/easybuild/easyblocks/o/openmpi.py +++ b/easybuild/easyblocks/o/openmpi.py @@ -80,11 +80,11 @@ def config_opt_used(key, enable_opt=False): # No entry is interpreted as no option added at all # This is to make builds reproducible even when the system libraries are changed and avoids failures # due to e.g. finding only PMIx but not libevent on the system - unused_dep_value = dict() + unused_dep_value = {} # Known options since version 3.0 (no earlier ones checked) if LooseVersion(self.version) >= LooseVersion('3.0'): # Default to disable the option with "no" - unused_dep_value = {dep: 'no' for dep in known_dependencies} + unused_dep_value = dict.fromkeys(known_dependencies, 'no') # For these the default is to use an internal copy and not using any is not supported for dep in ('hwloc', 'libevent', 'PMIx'): unused_dep_value[dep] = 'internal' @@ -229,7 +229,7 @@ def sanity_check_step(self): # Add minimal test program to sanity checks # Run with correct MPI launcher - mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, dict(), mpi_version=self.version) + mpi_cmd_tmpl, params = get_mpi_cmd_template(toolchain.OPENMPI, {}, mpi_version=self.version) # Limit number of ranks to 8 to avoid it failing due to hyperthreading ranks = min(8, self.cfg.parallel) for srcdir, src, compiler in ( diff --git a/easybuild/easyblocks/o/orca.py b/easybuild/easyblocks/o/orca.py index 4a1af348a6c..9c4827cb1ff 100644 --- a/easybuild/easyblocks/o/orca.py +++ b/easybuild/easyblocks/o/orca.py @@ -98,7 +98,7 @@ def install_step(self): # Shared builds have additional libraries libs_to_copy = (['liborca*'], 'lib') - if all([glob.glob(p) for p in libs_to_copy[0]]): + if all(glob.glob(p) for p in libs_to_copy[0]): files_to_copy.append(libs_to_copy) self.cfg['files_to_copy'] = files_to_copy diff --git a/easybuild/easyblocks/p/petsc.py b/easybuild/easyblocks/p/petsc.py index b98d9fa2d92..844c6e2a55d 100644 --- a/easybuild/easyblocks/p/petsc.py +++ b/easybuild/easyblocks/p/petsc.py @@ -147,7 +147,7 @@ def prepare_step(self, *args, **kwargs): super().prepare_step(*args, **kwargs) # build with Python support if Python is loaded as a non-build (runtime) dependency - runtime_dep_names = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True)] + runtime_dep_names = self.cfg.dependency_names(runtime_only=True) if get_software_root('Python') and 'Python' in runtime_dep_names: self.with_python = True self.module_load_environment.PYTHONPATH = self.bin_dir @@ -256,7 +256,7 @@ def configure_step(self): sep_deps = ['BLACS', 'BLAS', 'CMake', 'FFTW', 'LAPACK', 'numpy', 'mpi4py', 'papi', 'ScaLAPACK', 'SciPy-bundle', 'SCOTCH', 'SuiteSparse'] - for dep in [dep['name'] for dep in self.cfg.dependencies(runtime_only=True) if dep['name'] not in sep_deps]: + for dep in (name for name in self.cfg.dependency_names(runtime_only=True) if name not in sep_deps): if isinstance(dep, str): dep = (dep, dep) deproot = get_software_root(dep[0]) diff --git a/easybuild/easyblocks/r/rust.py b/easybuild/easyblocks/r/rust.py index db8658c7da1..0e34662ccf5 100644 --- a/easybuild/easyblocks/r/rust.py +++ b/easybuild/easyblocks/r/rust.py @@ -123,7 +123,7 @@ def configure_step(self): # don't use Ninja if it is not listed as a build dependency; # may be because Ninja requires Python, and Rust is a build dependency for cryptography # which may be included as an extension with Python - build_dep_names = set(dep['name'] for dep in self.cfg.dependencies(build_only=True)) + build_dep_names = self.cfg.dependency_names(build_only=True) if 'Ninja' not in build_dep_names: self.cfg.update('configopts', "--set=llvm.ninja=false") diff --git a/easybuild/easyblocks/s/slepc.py b/easybuild/easyblocks/s/slepc.py index f5ab35523c3..bd241a0a210 100644 --- a/easybuild/easyblocks/s/slepc.py +++ b/easybuild/easyblocks/s/slepc.py @@ -104,7 +104,7 @@ def configure_step(self): # optional dependencies dep_filter = ['PETSc', 'Python'] - deps = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True) if dep['name'] not in dep_filter] + deps = [name for name in self.cfg.dependency_names(runtime_only=True) if name not in dep_filter] for dep in deps: deproot = get_software_root(dep) if deproot: diff --git a/easybuild/easyblocks/t/tensorflow.py b/easybuild/easyblocks/t/tensorflow.py index 6da76de9e36..c20e860ee05 100644 --- a/easybuild/easyblocks/t/tensorflow.py +++ b/easybuild/easyblocks/t/tensorflow.py @@ -365,7 +365,7 @@ def get_system_libs(self): ignored_system_deps = [] # Check direct dependencies - dep_names = {dep['name'] for dep in self.cfg.dependencies()} + dep_names = self.cfg.dependency_names() for dep_name, tf_name in sorted(dependency_mapping.items(), key=lambda i: i[0].lower()): if dep_name in dep_names: if tf_name in deps_with_python_pkg: diff --git a/easybuild/easyblocks/t/tinker.py b/easybuild/easyblocks/t/tinker.py index 72df4e5d1a1..5efca2f2a9e 100644 --- a/easybuild/easyblocks/t/tinker.py +++ b/easybuild/easyblocks/t/tinker.py @@ -131,7 +131,7 @@ def test_step(self): # salt and dialinine takes too long skip_tests.extend(['salt', 'dialanine']) - tests = [t for t in tests if not any([t.endswith('%s.run' % x) for x in skip_tests])] + tests = [t for t in tests if not any(t.endswith(f'{x}.run') for x in skip_tests)] for test in tests: run_shell_cmd(test) diff --git a/easybuild/easyblocks/t/torchvision.py b/easybuild/easyblocks/t/torchvision.py index 9c82dcf37cd..5d53c582ce6 100644 --- a/easybuild/easyblocks/t/torchvision.py +++ b/easybuild/easyblocks/t/torchvision.py @@ -44,7 +44,7 @@ def __init__(self, *args, **kwargs): """Initialize torchvision easyblock.""" super().__init__(*args, **kwargs) - dep_names = set(dep['name'] for dep in self.cfg.dependencies()) + dep_names = self.cfg.dependency_names() # require that PyTorch is listed as dependency if 'PyTorch' not in dep_names: diff --git a/easybuild/easyblocks/u/ucx_plugins.py b/easybuild/easyblocks/u/ucx_plugins.py index 0876e238c2d..f963aa57bed 100644 --- a/easybuild/easyblocks/u/ucx_plugins.py +++ b/easybuild/easyblocks/u/ucx_plugins.py @@ -117,7 +117,7 @@ def make_module_extra(self, *args, **kwargs): """Add extra statements to generated module file specific to UCX plugins""" txt = super().make_module_extra(*args, **kwargs) - base_conf = dict() + base_conf = {} cmd = ['ucx_info', '-b'] full_cmd = ' '.join(cmd) self.log.info("Running command '%s'" % full_cmd) diff --git a/setup.cfg b/setup.cfg index 3b9eeded3ff..0c735045691 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,14 +5,10 @@ requires = easybuild-config [flake8] max-line-length = 120 +# C4: Comprehensions +extend-select = C4 -# Hound CI runs with Python 3 (no way around it), -# so we need to specify some Python 2 builtins to avoid that it complains about them -# cfr. https://stackoverflow.com/questions/47427916/how-to-config-hound-ci-to-support-python2-7 -builtins = - basestring, - reduce - -# ignore "Black would make changes" produced by flake8-black +# BLK100: "Black would make changes" # see also https://github.com/houndci/hound/issues/1769 -extend-ignore = BLK100 +# G002-G004,G200: Logging statement uses '%', '+', f-string, exception +extend-ignore = BLK100,G002,G003,G004,G200 diff --git a/test/easyblocks/easyblock_specific.py b/test/easyblocks/easyblock_specific.py index 6bccec0c36b..0c73fa2497c 100644 --- a/test/easyblocks/easyblock_specific.py +++ b/test/easyblocks/easyblock_specific.py @@ -536,7 +536,7 @@ def mocked_run_shell_cmd_pip(cmd, **kwargs): python.run_pip_check(python_cmd=sys.executable, unversioned_packages=('zero', )) with self.mocked_stdout_stderr(): - python.run_pip_check(python_cmd=sys.executable, unversioned_packages=set(['zero'])) + python.run_pip_check(python_cmd=sys.executable, unversioned_packages={'zero'}) # inject all possible errors def mocked_run_shell_cmd_pip(cmd, **kwargs):