Skip to content

Commit dd2ebf2

Browse files
committed
fix printing of RunShellCmdError to stderr by introducing print_error function that is aware of Rich
1 parent 9630c8d commit dd2ebf2

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

easybuild/tools/output.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"""
3434
import functools
3535
from collections import OrderedDict
36+
import sys
3637

3738
from easybuild.tools.build_log import EasyBuildError
3839
from easybuild.tools.config import OUTPUT_STYLE_RICH, build_option, get_output_style
@@ -328,9 +329,7 @@ def print_checks(checks_data):
328329

329330
if use_rich():
330331
console = Console()
331-
# don't use console.print, which causes SyntaxError in Python 2
332-
console_print = getattr(console, 'print') # noqa: B009
333-
console_print('')
332+
console.print('')
334333

335334
for section in checks_data:
336335
section_checks = checks_data[section]
@@ -382,11 +381,25 @@ def print_checks(checks_data):
382381
lines.append('')
383382

384383
if use_rich():
385-
console_print(table)
384+
console.print(table)
386385
else:
387386
print('\n'.join(lines))
388387

389388

389+
def print_error(error_msg, rich_highlight=True):
390+
"""
391+
Print error message, using a Rich Console instance if possible.
392+
Newlines before/after message are automatically added.
393+
394+
:param rich_highlight: boolean indicating whether automatic highlighting by Rich should be enabled
395+
"""
396+
if use_rich():
397+
console = Console(stderr=True)
398+
console.print('\n\n' + error_msg + '\n', highlight=rich_highlight)
399+
else:
400+
sys.stderr.write('\n' + error_msg + '\n\n')
401+
402+
390403
# this constant must be defined at the end, since functions used as values need to be defined
391404
PROGRESS_BAR_TYPES = {
392405
PROGRESS_BAR_DOWNLOAD_ALL: download_all_progress_bar,

easybuild/tools/run.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
from easybuild.tools.build_log import dry_run_msg, print_msg, time_str_since
6969
from easybuild.tools.config import build_option
7070
from easybuild.tools.hooks import RUN_SHELL_CMD, load_hooks, run_hook
71-
from easybuild.tools.output import COLOR_RED, COLOR_YELLOW, colorize
71+
from easybuild.tools.output import COLOR_RED, COLOR_YELLOW, colorize, print_error
7272
from easybuild.tools.utilities import trace_msg
7373

7474

@@ -125,7 +125,6 @@ def pad_4_spaces(msg, color=None):
125125
called_from_info = f"'{caller_function_name}' function in {caller_file_name} (line {caller_line_nr})"
126126

127127
error_info = [
128-
'',
129128
colorize("ERROR: Shell command failed!", COLOR_RED),
130129
pad_4_spaces(f"full command -> {self.cmd}"),
131130
pad_4_spaces(f"exit code -> {self.exit_code}"),
@@ -144,9 +143,7 @@ def pad_4_spaces(msg, color=None):
144143
if self.cmd_sh is not None:
145144
error_info.append(pad_4_spaces(f"interactive shell script -> {self.cmd_sh}", color=COLOR_YELLOW))
146145

147-
error_info.append('')
148-
149-
sys.stderr.write('\n'.join(error_info) + '\n')
146+
print_error('\n'.join(error_info), rich_highlight=False)
150147

151148

152149
def raise_run_shell_cmd_error(cmd_res):

test/framework/output.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from easybuild.tools.build_log import EasyBuildError
3636
from easybuild.tools.config import build_option, get_output_style, update_build_option
3737
from easybuild.tools.output import PROGRESS_BAR_EXTENSIONS, PROGRESS_BAR_TYPES
38-
from easybuild.tools.output import DummyRich, colorize, get_progress_bar, show_progress_bars
38+
from easybuild.tools.output import DummyRich, colorize, get_progress_bar, print_error, show_progress_bars
3939
from easybuild.tools.output import start_progress_bar, status_bar, stop_progress_bar, update_progress_bar, use_rich
4040

4141
try:
@@ -139,6 +139,26 @@ def test_colorize(self):
139139

140140
self.assertErrorRegex(EasyBuildError, "Unknown color: nosuchcolor", colorize, 'test', 'nosuchcolor')
141141

142+
def test_print_error(self):
143+
"""
144+
Test print_error function
145+
"""
146+
msg = "This is yellow: " + colorize("a banana", color='yellow')
147+
self.mock_stderr(True)
148+
self.mock_stdout(True)
149+
print_error(msg)
150+
stderr = self.get_stderr()
151+
stdout = self.get_stdout()
152+
self.mock_stderr(False)
153+
self.mock_stdout(False)
154+
self.assertEqual(stdout, '')
155+
if HAVE_RICH:
156+
# when using Rich, message printed to stderr won't have funny terminal escape characters for the color
157+
expected = '\n\nThis is yellow: a banana\n\n'
158+
else:
159+
expected = '\nThis is yellow: \x1b[1;33ma banana\x1b[0m\n\n'
160+
self.assertEqual(stderr, expected)
161+
142162
def test_get_progress_bar(self):
143163
"""
144164
Test get_progress_bar.

0 commit comments

Comments
 (0)