Skip to content

Commit 8d81c7a

Browse files
authored
Merge pull request #3246 from justbennet/sort-list-toolchains
Adding sorting to rst output of list_toolchains to match txt and none
2 parents 6343ea2 + 2cef406 commit 8d81c7a

File tree

2 files changed

+95
-12
lines changed

2 files changed

+95
-12
lines changed

easybuild/tools/docs.py

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -744,28 +744,59 @@ def list_toolchains_rst(tcs):
744744
""" Returns overview of all toolchains in rst format """
745745
title = "List of known toolchains"
746746

747-
# figure out column names
748-
table_titles = ['name', 'compiler', 'MPI']
749-
for tc in tcs.values():
750-
table_titles.extend(tc.keys())
747+
# Specify the column names for the table
748+
table_titles = ['NAME', 'COMPILER', 'MPI', 'LINALG', 'FFT']
751749

750+
# Set up column name : display name pairs
752751
col_names = {
753-
'COMPILER_CUDA': 'CUDA compiler',
754-
'SCALAPACK': 'ScaLAPACK',
752+
'NAME': 'Name',
753+
'COMPILER': 'Compiler(s)',
754+
'LINALG': "Linear algebra",
755755
}
756756

757-
table_titles = nub(table_titles)
757+
# Create sorted list of toolchain names
758+
sorted_tc_names = sorted(tcs.keys(), key=str.lower)
758759

759-
table_values = [[] for i in range(len(table_titles))]
760-
table_values[0] = ['**%s**' % tcname for tcname in tcs.keys()]
760+
# Create text placeholder to use for missing entries
761+
none_txt = '*(none)*'
761762

762-
for idx in range(1, len(table_titles)):
763-
for tc in tcs.values():
764-
table_values[idx].append(', '.join(tc.get(table_titles[idx].upper(), [])))
763+
# Initialize an empty list of lists for the table data
764+
table_values = [[] for i in range(len(table_titles))]
765765

766+
for col_id, col_name in enumerate(table_titles):
767+
if col_name == 'NAME':
768+
# toolchain names column gets bold face entry
769+
table_values[col_id] = ['**%s**' % tcname for tcname in sorted_tc_names]
770+
else:
771+
for tc_name in sorted_tc_names:
772+
tc = tcs[tc_name]
773+
if 'cray' in tc_name.lower():
774+
if col_name == 'COMPILER':
775+
entry = ', '.join(tc[col_name.upper()])
776+
elif col_name == 'MPI':
777+
entry = 'cray-mpich'
778+
elif col_name == 'LINALG':
779+
entry = 'cray-libsci'
780+
# Combine the linear algebra libraries into a single column
781+
elif col_name == 'LINALG':
782+
linalg = []
783+
for col in ['BLAS', 'LAPACK', 'SCALAPACK']:
784+
linalg.extend(tc.get(col, []))
785+
entry = ', '.join(nub(linalg)) or none_txt
786+
else:
787+
# for other columns, we can grab the values via 'tc'
788+
# key = col_name
789+
entry = ', '.join(tc.get(col_name, [])) or none_txt
790+
table_values[col_id].append(entry)
791+
792+
# Set the table titles to the pretty ones
766793
table_titles = [col_names.get(col, col) for col in table_titles]
794+
795+
# Pass the data to the rst formatter, wich is returned as a list, each element
796+
# is an rst formatted text row.
767797
doc = rst_title_and_table(title, table_titles, table_values)
768798

799+
# Make a string with line endings suitable to write to document file
769800
return '\n'.join(doc)
770801

771802

test/framework/options.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,58 @@ def test__list_toolchains(self):
517517
if os.path.exists(dummylogfn):
518518
os.remove(dummylogfn)
519519

520+
def test_list_toolchains_rst(self):
521+
"""Test --list-toolchains --output-format=rst."""
522+
523+
args = [
524+
'--list-toolchains',
525+
'--output-format=rst',
526+
]
527+
self.mock_stderr(True)
528+
self.mock_stdout(True)
529+
self.eb_main(args, raise_error=True)
530+
stderr, stdout = self.get_stderr(), self.get_stdout().strip()
531+
self.mock_stderr(False)
532+
self.mock_stdout(False)
533+
534+
self.assertFalse(stderr)
535+
536+
title = "List of known toolchains"
537+
538+
# separator line: starts/ends with sequence of '=', 4 spaces in between columns
539+
sep_line = r'=(=+\s{4})+[=]+='
540+
541+
col_names = ['Name', r'Compiler\(s\)', 'MPI', 'Linear algebra', 'FFT']
542+
col_names_line = r'\s+'.join(col_names) + r'\s*'
543+
544+
patterns = [
545+
# title
546+
'^' + title + '\n' + '-' * len(title) + '\n',
547+
# header
548+
'\n' + '\n'.join([sep_line, col_names_line, sep_line]) + '\n',
549+
# compiler-only GCC toolchain
550+
r"\n\*\*GCC\*\*\s+GCC\s+\*\(none\)\*\s+\*\(none\)\*\s+\*\(none\)\*\s*\n",
551+
# gompi compiler + MPI toolchain
552+
r"\n\*\*gompi\*\*\s+GCC\s+OpenMPI\s+\*\(none\)\*\s+\*\(none\)\*\s*\n",
553+
# full 'foss' toolchain
554+
r"\*\*foss\*\*\s+GCC\s+OpenMPI\s+OpenBLAS,\s+ScaLAPACK\s+FFTW\s*\n",
555+
# compiler-only iccifort toolchain
556+
r"\*\*iccifort\*\*\s+icc,\s+ifort\s+\*\(none\)\*\s+\*\(none\)\*\s+\*\(none\)\*\s*\n",
557+
# full 'intel' toolchain (imkl appears twice, in linalg + FFT columns)
558+
r"\*\*intel\*\*\s+icc,\s+ifort\s+impi\s+imkl\s+imkl\s*\n",
559+
# fosscuda toolchain, also lists CUDA in compilers column
560+
r"\*\*fosscuda\*\*\s+GCC,\s+CUDA\s+OpenMPI\s+OpenBLAS,\s+ScaLAPACK\s+FFTW\s*\n",
561+
# system toolchain: 'none' in every column
562+
r"\*\*system\*\*\s+\*\(none\)\*\s+\*\(none\)\*\s+\*\(none\)\*\s+\*\(none\)\*\s*\n",
563+
# Cray special case
564+
r"\n\*\*CrayGNU\*\*\s+PrgEnv-gnu\s+cray-mpich\s+cray-libsci\s+\*\(none\)\*\s*\n",
565+
# footer
566+
'\n' + sep_line + '$',
567+
]
568+
for pattern in patterns:
569+
regex = re.compile(pattern, re.M)
570+
self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout))
571+
520572
def test_avail_lists(self):
521573
"""Test listing available values of certain types."""
522574

0 commit comments

Comments
 (0)