Skip to content

Commit 84709fd

Browse files
authored
Merge pull request #1643 from mvdbeek/rich_fix
Escape rich markup in failed-job error reporting
2 parents 02f2370 + e0eff05 commit 84709fd

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

planemo/galaxy/invocations/progress.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from rich.console import Group
1111
from rich.live import Live
12+
from rich.markup import escape
1213
from rich.panel import Panel
1314
from rich.progress import (
1415
BarColumn,
@@ -259,7 +260,7 @@ def print_job_errors_once(
259260
workflow_progress_display.console.print("\n".join(new_error_lines))
260261

261262
except Exception as e:
262-
error_msg = "❌ Failed to collect failed job details: {}".format(e)
263+
error_msg = "❌ Failed to collect failed job details: {}".format(escape(str(e)))
263264
workflow_progress_display.console.print(error_msg)
264265

265266
def _format_job_error_details(self, job_id, job_details):
@@ -271,23 +272,23 @@ def _format_job_error_details(self, job_id, job_details):
271272
command_line = job_details.get("command_line")
272273
tool_id = job_details.get("tool_id")
273274

274-
error_lines.append("❌ Failed job {}:".format(job_id))
275+
error_lines.append("❌ Failed job {}:".format(escape(str(job_id))))
275276
if tool_id:
276-
error_lines.append(" Tool ID: {}".format(tool_id))
277+
error_lines.append(" Tool ID: {}".format(escape(tool_id)))
277278
if exit_code is not None:
278279
error_lines.append(" Exit code: {}".format(exit_code))
279280
if command_line:
280-
error_lines.append(" Command line: {}".format(command_line))
281+
error_lines.append(" Command line: {}".format(escape(command_line)))
281282
if stdout:
282283
error_lines.append(" Stdout:")
283284
for line in stdout.split("\n"):
284285
if line.strip():
285-
error_lines.append(" {}".format(line))
286+
error_lines.append(" {}".format(escape(line)))
286287
if stderr:
287288
error_lines.append(" Stderr:")
288289
for line in stderr.split("\n"):
289290
if line.strip():
290-
error_lines.append(" {}".format(line))
291+
error_lines.append(" {}".format(escape(line)))
291292
error_lines.append("") # Empty line for spacing
292293
return error_lines
293294

tests/test_workflow_progress.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import time
2+
from io import StringIO
3+
4+
from rich.console import Console
25

36
from planemo.galaxy.invocations.progress import (
47
WorkflowProgress,
@@ -168,3 +171,37 @@ def test_workflow_progress_completed_step_state_counting():
168171
workflow_progress.step_states.get("completed") or 0
169172
)
170173
assert num_scheduled == 2
174+
175+
176+
def test_format_job_error_details_escapes_rich_markup():
177+
# Regression: failed-job stderr containing strings like Java's Arrays.toString
178+
# output (e.g. ImageJ --debug) starts with "[/tmp/..." which rich's markup parser
179+
# treats as a closing tag and rejects with MarkupError, masking the real failure.
180+
bracketed_argv = (
181+
"[/tmp/shed_dir/toolshed.g2.bx.psu.edu/repos/imgteam/imagej2_analyze_particles_binary/"
182+
"862af85a50ec/imagej2_analyze_particles_binary/imagej2_analyze_particles_binary_jython_script.py, "
183+
"/tmp/job/outputs/dataset_cc.dat, /tmp/files/dataset_99.dat, "
184+
"yes, 50-Infinity, 0.0, 1.0, Outlines, no, no, no, output.tiff, tiff, ]"
185+
)
186+
job_details = {
187+
"exit_code": 1,
188+
"tool_id": "toolshed.g2.bx.psu.edu/repos/imgteam/imagej2_analyze_particles_binary/"
189+
"imagej2_analyze_particles_binary/20240614+galaxy0",
190+
"command_line": "ImageJ --jython /tmp/shed_dir/script.py /tmp/input.dat",
191+
"stdout": "",
192+
"stderr": bracketed_argv,
193+
}
194+
195+
with WorkflowProgress(DisplayConfiguration()) as workflow_progress:
196+
lines = workflow_progress._format_job_error_details("JOB_ID_42", job_details)
197+
198+
# Render through a Console with markup parsing on (the default) to ensure
199+
# the assembled output does not blow up rich.
200+
console = Console(file=StringIO(), force_terminal=False, width=200)
201+
console.print("\n".join(lines)) # would raise MarkupError before the fix
202+
output = console.file.getvalue()
203+
204+
# Content must be preserved verbatim, not stripped.
205+
assert "/tmp/shed_dir/" in output
206+
assert "output.tiff" in output
207+
assert "20240614+galaxy0" in output

0 commit comments

Comments
 (0)