Skip to content

Commit ac01d32

Browse files
authored
Merge pull request #3586 from boegel/cuda_templates_avail_easyconfig_templates
include %(mpi_cmd_prefix)s and %(cuda_*)s templates in output of --avail-easyconfig-templates
2 parents 7979cb9 + c8ed201 commit ac01d32

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed

easybuild/framework/easyconfig/templates.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646

4747
# derived from easyconfig, but not from ._config directly
4848
TEMPLATE_NAMES_EASYCONFIG = [
49-
('arch', "System architecture (e.g. x86_64, aarch64, ppc64le, ...)"),
5049
('module_name', "Module name"),
5150
('nameletter', "First letter of software name"),
5251
('toolchain_name', "Toolchain name"),
@@ -86,6 +85,18 @@
8685
('Python', 'py'),
8786
('R', 'r'),
8887
]
88+
# template values which are only generated dynamically
89+
TEMPLATE_NAMES_DYNAMIC = [
90+
('arch', "System architecture (e.g. x86_64, aarch64, ppc64le, ...)"),
91+
('mpi_cmd_prefix', "Prefix command for running MPI programs (with default number of ranks)"),
92+
('cuda_compute_capabilities', "Comma-separated list of CUDA compute capabilities, as specified via "
93+
"--cuda-compute-capabilities configuration option or via cuda_compute_capabilities easyconfig parameter"),
94+
('cuda_cc_space_sep', "Space-separated list of CUDA compute capabilities"),
95+
('cuda_cc_semicolon_sep', "Semicolon-separated list of CUDA compute capabilities"),
96+
('cuda_sm_comma_sep', "Comma-separated list of sm_* values that correspond with CUDA compute capabilities"),
97+
('cuda_sm_space_sep', "Space-separated list of sm_* values that correspond with CUDA compute capabilities"),
98+
]
99+
89100
# constant templates that can be used in easyconfigs
90101
TEMPLATE_CONSTANTS = [
91102
# source url constants
@@ -300,6 +311,10 @@ def template_constant_dict(config, ignore=None, skip_lower=None, toolchain=None)
300311
except Exception:
301312
_log.warning("Failed to get .lower() for name %s value %s (type %s)", name, value, type(value))
302313

314+
# keep track of names of defined templates until now,
315+
# so we can check whether names of additional dynamic template values are all known
316+
common_template_names = set(template_values.keys())
317+
303318
# step 5. add additional conditional templates
304319
if toolchain is not None and hasattr(toolchain, 'mpi_cmd_prefix'):
305320
try:
@@ -322,6 +337,14 @@ def template_constant_dict(config, ignore=None, skip_lower=None, toolchain=None)
322337
template_values['cuda_sm_comma_sep'] = ','.join(sm_values)
323338
template_values['cuda_sm_space_sep'] = ' '.join(sm_values)
324339

340+
unknown_names = []
341+
for key in template_values:
342+
dynamic_template_names = set(x for (x, _) in TEMPLATE_NAMES_DYNAMIC)
343+
if not (key in common_template_names or key in dynamic_template_names):
344+
unknown_names.append(key)
345+
if unknown_names:
346+
raise EasyBuildError("One or more template values found with unknown name: %s", ','.join(unknown_names))
347+
325348
return template_values
326349

327350

easybuild/tools/docs.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
from easybuild.framework.easyconfig.easyconfig import get_easyblock_class, process_easyconfig
4747
from easybuild.framework.easyconfig.licenses import EASYCONFIG_LICENSES_DICT
4848
from easybuild.framework.easyconfig.parser import EasyConfigParser
49-
from easybuild.framework.easyconfig.templates import TEMPLATE_NAMES_CONFIG, TEMPLATE_NAMES_EASYCONFIG
49+
from easybuild.framework.easyconfig.templates import TEMPLATE_CONSTANTS, TEMPLATE_NAMES_CONFIG, TEMPLATE_NAMES_DYNAMIC
50+
from easybuild.framework.easyconfig.templates import TEMPLATE_NAMES_EASYBLOCK_RUN_STEP, TEMPLATE_NAMES_EASYCONFIG
5051
from easybuild.framework.easyconfig.templates import TEMPLATE_NAMES_LOWER, TEMPLATE_NAMES_LOWER_TEMPLATE
51-
from easybuild.framework.easyconfig.templates import TEMPLATE_NAMES_EASYBLOCK_RUN_STEP, TEMPLATE_CONSTANTS
5252
from easybuild.framework.easyconfig.templates import TEMPLATE_SOFTWARE_VERSIONS, template_constant_dict
5353
from easybuild.framework.easyconfig.tools import avail_easyblocks
5454
from easybuild.framework.easyconfig.tweak import find_matching_easyconfigs
@@ -344,6 +344,12 @@ def avail_easyconfig_templates_txt():
344344
for name in TEMPLATE_NAMES_EASYBLOCK_RUN_STEP:
345345
doc.append("%s%%(%s)s: %s" % (INDENT_4SPACES, name[0], name[1]))
346346

347+
# some template values are only defined dynamically,
348+
# see template_constant_dict function in easybuild.framework.easyconfigs.templates
349+
doc.append('Template values which are defined dynamically')
350+
for name in TEMPLATE_NAMES_DYNAMIC:
351+
doc.append("%s%%(%s)s: %s" % (INDENT_4SPACES, name[0], name[1]))
352+
347353
doc.append('Template constants that can be used in easyconfigs')
348354
for cst in TEMPLATE_CONSTANTS:
349355
doc.append('%s%s: %s (%s)' % (INDENT_4SPACES, cst[0], cst[2], cst[1]))
@@ -395,6 +401,13 @@ def avail_easyconfig_templates_rst():
395401
]
396402
doc.extend(rst_title_and_table(title, table_titles, table_values))
397403

404+
title = 'Template values which are defined dynamically'
405+
table_values = [
406+
['``%%(%s)s``' % name[0] for name in TEMPLATE_NAMES_DYNAMIC],
407+
[name[1] for name in TEMPLATE_NAMES_DYNAMIC],
408+
]
409+
doc.extend(rst_title_and_table(title, table_titles, table_values))
410+
398411
title = 'Template constants that can be used in easyconfigs'
399412
titles = ['Constant', 'Template value', 'Template name']
400413
table_values = [

test/framework/easyconfig.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,7 @@ def test_templating_doc(self):
11281128
easyconfig.templates.TEMPLATE_NAMES_CONFIG,
11291129
easyconfig.templates.TEMPLATE_NAMES_LOWER,
11301130
easyconfig.templates.TEMPLATE_NAMES_EASYBLOCK_RUN_STEP,
1131+
easyconfig.templates.TEMPLATE_NAMES_DYNAMIC,
11311132
easyconfig.templates.TEMPLATE_CONSTANTS,
11321133
]
11331134

test/framework/options.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,55 @@ def run_test(fmt=None):
509509
for fmt in [None, 'txt', 'rst']:
510510
run_test(fmt=fmt)
511511

512+
def test_avail_easyconfig_templates(self):
513+
"""Test listing available easyconfig file templates."""
514+
515+
def run_test(fmt=None):
516+
"""Helper function to test --avail-easyconfig-templates."""
517+
518+
args = ['--avail-easyconfig-templates']
519+
if fmt is not None:
520+
args.append('--output-format=%s' % fmt)
521+
522+
self.mock_stderr(True)
523+
self.mock_stdout(True)
524+
self.eb_main(args, verbose=True, raise_error=True)
525+
stderr, stdout = self.get_stderr(), self.get_stdout()
526+
self.mock_stderr(False)
527+
self.mock_stdout(False)
528+
529+
self.assertFalse(stderr)
530+
531+
if fmt == 'rst':
532+
pattern_lines = [
533+
r'^``%\(version_major\)s``\s+Major version\s*$',
534+
r'^``%\(cudaver\)s``\s+full version for CUDA\s*$',
535+
r'^``%\(pyshortver\)s``\s+short version for Python \(<major>.<minor>\)\s*$',
536+
r'^\* ``%\(name\)s``$',
537+
r'^``%\(namelower\)s``\s+lower case of value of name\s*$',
538+
r'^``%\(arch\)s``\s+System architecture \(e.g. x86_64, aarch64, ppc64le, ...\)\s*$',
539+
r'^``%\(cuda_cc_space_sep\)s``\s+Space-separated list of CUDA compute capabilities\s*$',
540+
r'^``SOURCE_TAR_GZ``\s+Source \.tar\.gz bundle\s+``%\(name\)s-%\(version\)s.tar.gz``\s*$',
541+
]
542+
else:
543+
pattern_lines = [
544+
r'^\s+%\(version_major\)s: Major version$',
545+
r'^\s+%\(cudaver\)s: full version for CUDA$',
546+
r'^\s+%\(pyshortver\)s: short version for Python \(<major>.<minor>\)$',
547+
r'^\s+%\(name\)s$',
548+
r'^\s+%\(namelower\)s: lower case of value of name$',
549+
r'^\s+%\(arch\)s: System architecture \(e.g. x86_64, aarch64, ppc64le, ...\)$',
550+
r'^\s+%\(cuda_cc_space_sep\)s: Space-separated list of CUDA compute capabilities$',
551+
r'^\s+SOURCE_TAR_GZ: Source \.tar\.gz bundle \(%\(name\)s-%\(version\)s.tar.gz\)$',
552+
]
553+
554+
for pattern_line in pattern_lines:
555+
regex = re.compile(pattern_line, re.M)
556+
self.assertTrue(regex.search(stdout), "Pattern '%s' should match in: %s" % (regex.pattern, stdout))
557+
558+
for fmt in [None, 'txt', 'rst']:
559+
run_test(fmt=fmt)
560+
512561
def test_avail_easyconfig_params(self):
513562
"""Test listing available easyconfig parameters."""
514563

0 commit comments

Comments
 (0)