Skip to content

Commit

Permalink
fix printing of RunShellCmdError to stderr by introducing print_error…
Browse files Browse the repository at this point in the history
… function that is aware of Rich
  • Loading branch information
boegel committed Oct 14, 2024
1 parent 9630c8d commit dd2ebf2
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 10 deletions.
21 changes: 17 additions & 4 deletions easybuild/tools/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"""
import functools
from collections import OrderedDict
import sys

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

if use_rich():
console = Console()
# don't use console.print, which causes SyntaxError in Python 2
console_print = getattr(console, 'print') # noqa: B009
console_print('')
console.print('')

for section in checks_data:
section_checks = checks_data[section]
Expand Down Expand Up @@ -382,11 +381,25 @@ def print_checks(checks_data):
lines.append('')

if use_rich():
console_print(table)
console.print(table)
else:
print('\n'.join(lines))


def print_error(error_msg, rich_highlight=True):
"""
Print error message, using a Rich Console instance if possible.
Newlines before/after message are automatically added.
:param rich_highlight: boolean indicating whether automatic highlighting by Rich should be enabled
"""
if use_rich():
console = Console(stderr=True)
console.print('\n\n' + error_msg + '\n', highlight=rich_highlight)
else:
sys.stderr.write('\n' + error_msg + '\n\n')


# this constant must be defined at the end, since functions used as values need to be defined
PROGRESS_BAR_TYPES = {
PROGRESS_BAR_DOWNLOAD_ALL: download_all_progress_bar,
Expand Down
7 changes: 2 additions & 5 deletions easybuild/tools/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
from easybuild.tools.build_log import dry_run_msg, print_msg, time_str_since
from easybuild.tools.config import build_option
from easybuild.tools.hooks import RUN_SHELL_CMD, load_hooks, run_hook
from easybuild.tools.output import COLOR_RED, COLOR_YELLOW, colorize
from easybuild.tools.output import COLOR_RED, COLOR_YELLOW, colorize, print_error
from easybuild.tools.utilities import trace_msg


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

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

error_info.append('')

sys.stderr.write('\n'.join(error_info) + '\n')
print_error('\n'.join(error_info), rich_highlight=False)


def raise_run_shell_cmd_error(cmd_res):
Expand Down
22 changes: 21 additions & 1 deletion test/framework/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.config import build_option, get_output_style, update_build_option
from easybuild.tools.output import PROGRESS_BAR_EXTENSIONS, PROGRESS_BAR_TYPES
from easybuild.tools.output import DummyRich, colorize, get_progress_bar, show_progress_bars
from easybuild.tools.output import DummyRich, colorize, get_progress_bar, print_error, show_progress_bars
from easybuild.tools.output import start_progress_bar, status_bar, stop_progress_bar, update_progress_bar, use_rich

try:
Expand Down Expand Up @@ -139,6 +139,26 @@ def test_colorize(self):

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

def test_print_error(self):
"""
Test print_error function
"""
msg = "This is yellow: " + colorize("a banana", color='yellow')
self.mock_stderr(True)
self.mock_stdout(True)
print_error(msg)
stderr = self.get_stderr()
stdout = self.get_stdout()
self.mock_stderr(False)
self.mock_stdout(False)
self.assertEqual(stdout, '')
if HAVE_RICH:
# when using Rich, message printed to stderr won't have funny terminal escape characters for the color
expected = '\n\nThis is yellow: a banana\n\n'
else:
expected = '\nThis is yellow: \x1b[1;33ma banana\x1b[0m\n\n'
self.assertEqual(stderr, expected)

def test_get_progress_bar(self):
"""
Test get_progress_bar.
Expand Down

0 comments on commit dd2ebf2

Please sign in to comment.