Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion easybuild/tools/build_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def __init__(self, msg, *args, exit_code=EasyBuildExit.ERROR, **kwargs):

def __str__(self):
"""Return string representation of this EasyBuildError instance."""
return repr(self.msg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, there must have been a reason why we did this...

Copy link
Contributor Author

@Flamefire Flamefire Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C&P from some other code I'd say as this was introduced by renaming some other exception class in the very beginning: https://github.com/easybuilders/easybuild-framework/blame/d7f1ad2f6f09e387e121c94c9df434a07e7aaa68/easybuild/tools/buildLog.py

There is a __repr__ special method that should likely be implemented like that.

Someone notes at https://stackoverflow.com/questions/1436703/what-is-the-difference-between-str-and-repr

default for __repr__ which would act like:

return "%s(%r)" % (self.__class__, self.__dict__)

__repr__ goal is to be unambiguous
__str__ goal is to be readable
This means, in simple terms: almost every object you implement should have a functional __repr__ that’s usable for understanding the object. Implementing __str__ is optional: do that if you need a “pretty print” functionality (for example, used by a report generator).
Summary

Implement __repr__ for any class you implement. This should be second nature. Implement __str__ if you think it would be useful to have a string version which errs on the side of readability.

E.g.

def __repr__(self):
    return f'EasyBuildError({self.msg!r}, {self.exit_code})'

return self.msg


def raise_easybuilderror(msg, *args):
Expand Down
2 changes: 1 addition & 1 deletion test/framework/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def run_hooks():
"== Running pre-single_extension hook...",
"this is run before installing an extension",
"== Running fail hook...",
"EasyBuild FAIL: 'oops'",
"EasyBuild FAIL: oops",
"== Running crash hook...",
"EasyBuild CRASHED, oh no! => boom!",
"== Running post-easyblock hook...",
Expand Down
2 changes: 1 addition & 1 deletion test/framework/sandbox/easybuild/easyblocks/t/toy.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def build_step(self, name=None, cfg=None):
def test_step(self, *args, **kwargs):
"""Test toy."""
if self.cfg['runtest'] == 'RAISE_ERROR':
raise EasyBuildError("TOY_TEST_FAIL")
raise EasyBuildError("TOY_TEST_FAIL\nDescription on new line")
else:
super().test_step(*args, **kwargs)

Expand Down
6 changes: 3 additions & 3 deletions test/framework/toy_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1778,7 +1778,7 @@ def test_external_dependencies(self):
write_file(toy_ec, ectxt + extraectxt)

if isinstance(self.modtool, Lmod):
err_msg = r"Module command \\'.*load nosuchbuilddep/0.0.0\\' failed"
err_msg = r"Module command '.*load nosuchbuilddep/0.0.0' failed"
else:
err_msg = r"Unable to locate a modulefile for 'nosuchbuilddep/0.0.0'"

Expand All @@ -1791,7 +1791,7 @@ def test_external_dependencies(self):
write_file(toy_ec, ectxt + extraectxt)

if isinstance(self.modtool, Lmod):
err_msg = r"Module command \\'.*load nosuchmodule/1.2.3\\' failed"
err_msg = r"Module command '.*load nosuchmodule/1.2.3' failed"
else:
err_msg = r"Unable to locate a modulefile for 'nosuchmodule/1.2.3'"

Expand Down Expand Up @@ -4842,7 +4842,7 @@ def test_toy_failing_test_step(self):
test_ec_txt += '\nruntest = "RAISE_ERROR"'
write_file(test_ec, test_ec_txt)

error_pattern = r"An error was raised during test step: 'TOY_TEST_FAIL'"
error_pattern = "An error was raised during test step: TOY_TEST_FAIL\nDescription"
self.assertErrorRegex(EasyBuildError, error_pattern, self.run_test_toy_build_with_output,
ec_file=test_ec, raise_error=True)

Expand Down