feat: graceful load failure for module-loading items

A self-loading item that can't load its module/file (unittest test file
with a missing import, pytest not installed on the host, ...) no longer
aborts the whole test load. TestSet._load_item() wraps load(), warns at
load time and records item._load_error; @test_run turns it into a clean
run-time FAILURE. The rest of the campaign loads and runs.

Scoped to module-loading items (unittest; pytest once merged). Structural
action loading stays fail-fast.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 20:19:43 +02:00
parent a875828de0
commit 5cc795ebb3
3 changed files with 24 additions and 1 deletions

View File

@@ -61,6 +61,13 @@ def test_run(f):
self.run_test_init()
# The item could not be loaded (e.g. a missing module): FAIL at run.
# run_test_end -> write_footer prints the message.
if self._load_error is not None:
self.result.set(TestValue.FAILURE, self._load_error)
self.run_test_end()
return self.result
while self._is_paused:
sleep(0.2)
if self.isStopped() :
@@ -151,6 +158,7 @@ class TestItem:
self._expected_result = None
self._no_fail = None
self._is_stopped = False
self._load_error = None
self._is_running = False
self._is_breakpoint = False
self._is_paused = False

View File

@@ -451,6 +451,20 @@ class TestSet:
def rootItem(self):
return self._rootItem
def _load_item(self, item):
"""Run an item's self-load, deferring a failure (e.g. a missing module)
to a run-time FAILURE instead of aborting the whole test load."""
try:
return item.load()
except Exception as e:
msg = getattr(e, "_message", None) or str(e)
item._load_error = msg
tm.print_warn(
f"'{item.cmd()}' item '{item.name()}' could not be loaded: "
f"{msg} (it will FAIL at run)."
)
return {}
def load_test_recursively(self, tree_parent, parent_seq, file_name):
ret = {}
try:
@@ -534,7 +548,7 @@ class TestSet:
# case where the test item loads itself its descendants
if it == cst_type.TYPE_UNITTEST:
item.setTestDir(test_dir)
child = item.load()
child = self._load_item(item)
elif issubclass(it.item_class, TestItemActions):
child = item.load()
# case where the test item is an items container