Skip to content

Commit 1f6e849

Browse files
authored
Add rich_execute_result test category (#49)
Some kernels (like evcxr) send rich output via execute_result instead of display_data. This is a valid design choice - execute_result is for final expression output, display_data is for mid-execution displays. New test: rich_execute_result - Checks for execute_result with rich MIME types (HTML, images, etc.) - Complements display_data test for kernels that use this approach New snippet field: rich_execute_result_code - Added to all language snippets - evcxr uses evcxr_display trait pattern - Python/Julia/Scala/Deno can return rich objects - SQL query results come as execute_result with text/html - Others marked as unsupported (use display_data instead) _Submitted on @rgbkrk's behalf by his agent Quill_
1 parent c0e4952 commit 1f6e849

File tree

2 files changed

+74
-3
lines changed

2 files changed

+74
-3
lines changed

src/snippets.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ pub struct LanguageSnippets {
3636
pub display_data_code: &'static str,
3737
/// Code that produces display_data with display_id then updates it
3838
pub update_display_data_code: &'static str,
39+
/// Code that produces execute_result with rich MIME types (text/html, image/*, etc.)
40+
pub rich_execute_result_code: &'static str,
3941
}
4042

4143
impl LanguageSnippets {
@@ -77,6 +79,7 @@ impl LanguageSnippets {
7779
completion_prefix: "test_variable_for_",
7880
display_data_code: "from IPython.display import display, HTML; display(HTML('<b>bold</b>'))",
7981
update_display_data_code: "from IPython.display import display, HTML, update_display; dh = display(HTML('<b>initial</b>'), display_id=True); update_display(HTML('<b>updated</b>'), display_id=dh.display_id)",
82+
rich_execute_result_code: "from IPython.display import HTML; HTML('<b>bold</b>')",
8083
}
8184
}
8285

@@ -100,6 +103,8 @@ impl LanguageSnippets {
100103
display_data_code: "plot(1:10)",
101104
// Note: update_display_data may not trigger in batch mode; Ark may optimize to single render
102105
update_display_data_code: "plot(1:10); points(5, 5, col='red', pch=19)",
106+
// R doesn't typically produce rich execute_result, uses display_data instead
107+
rich_execute_result_code: "// R uses display_data for rich output",
103108
}
104109
}
105110

@@ -119,10 +124,17 @@ impl LanguageSnippets {
119124
completion_var: "test_variable_for_completion",
120125
completion_setup: "let test_variable_for_completion = 42;",
121126
completion_prefix: "test_variable_for_",
122-
display_data_code: r#"struct Html(&'static str);
123-
impl Html { fn evcxr_display(&self) { println!("EVCXR_BEGIN_CONTENT text/html\n{}\nEVCXR_END_CONTENT", self.0); } }
124-
Html("<b>bold</b>").evcxr_display();"#,
127+
// evcxr sends rich output via execute_result, not display_data
128+
display_data_code: "// evcxr uses execute_result for rich output, not display_data",
125129
update_display_data_code: "// evcxr doesn't support update_display_data (no display_id)",
130+
// evcxr's strength: rich execute_result via evcxr_display trait
131+
rich_execute_result_code: r#"pub struct Html(pub &'static str);
132+
impl Html {
133+
pub fn evcxr_display(&self) {
134+
println!("EVCXR_BEGIN_CONTENT text/html\n{}\nEVCXR_END_CONTENT", self.0);
135+
}
136+
}
137+
Html("<b>bold</b>")"#,
126138
}
127139
}
128140

@@ -143,6 +155,8 @@ Html("<b>bold</b>").evcxr_display();"#,
143155
completion_prefix: "test_variable_for_",
144156
display_data_code: "display(\"text/html\", \"<b>bold</b>\")",
145157
update_display_data_code: "# Julia update_display varies by environment",
158+
// Julia can return rich objects that render as HTML
159+
rich_execute_result_code: "HTML(\"<b>bold</b>\")",
146160
}
147161
}
148162

@@ -164,6 +178,7 @@ Html("<b>bold</b>").evcxr_display();"#,
164178
completion_prefix: "testVariableFor",
165179
display_data_code: r#"await Deno.jupyter.broadcast("display_data", { data: { "text/html": "<b>bold</b>" }, metadata: {}, transient: {} })"#,
166180
update_display_data_code: r#"await Deno.jupyter.broadcast("display_data", { data: { "text/html": "<b>initial</b>" }, metadata: {}, transient: { display_id: "test_update" } }); await Deno.jupyter.broadcast("update_display_data", { data: { "text/html": "<b>updated</b>" }, metadata: {}, transient: { display_id: "test_update" } })"#,
181+
rich_execute_result_code: r#"Deno.jupyter.html("<b>bold</b>")"#,
167182
}
168183
}
169184

@@ -190,6 +205,8 @@ gonbui.DisplayHtml("<b>bold</b>")"#,
190205
id := gonbui.UniqueId()
191206
gonbui.UpdateHtml(id, "<b>initial</b>")
192207
gonbui.UpdateHtml(id, "<b>updated</b>")"#,
208+
// Go uses display_data for rich output, not execute_result
209+
rich_execute_result_code: "// Go uses display_data for rich output",
193210
}
194211
}
195212

@@ -211,6 +228,8 @@ gonbui.UpdateHtml(id, "<b>updated</b>")"#,
211228
completion_prefix: "testVariableFor",
212229
display_data_code: "kernel.publish.html(\"<b>bold</b>\")",
213230
update_display_data_code: r#"val id = java.util.UUID.randomUUID().toString; kernel.publish.html("<b>initial</b>", id); kernel.publish.updateHtml("<b>updated</b>", id)"#,
231+
// Almond can return HTML objects as rich execute_result
232+
rich_execute_result_code: "Html(\"<b>bold</b>\")",
214233
}
215234
}
216235

@@ -251,6 +270,8 @@ nlohmann::json mime_bundle_repr(const html_content& h) {
251270
html_content h{"<b>bold</b>"};
252271
xcpp::display(h);"#,
253272
update_display_data_code: "// xeus-cling update_display_data requires display_id handling",
273+
// C++ uses display_data for rich output
274+
rich_execute_result_code: "// C++ uses display_data for rich output",
254275
}
255276
}
256277

@@ -274,6 +295,8 @@ xcpp::display(h);"#,
274295
// xeus-sql displays query results as tables natively
275296
display_data_code: "SELECT 1 AS col1, 2 AS col2, 3 AS col3;",
276297
update_display_data_code: "-- SQL doesn't support update_display_data",
298+
// SQL query results come as execute_result with text/html table
299+
rich_execute_result_code: "SELECT 1 AS col1, 2 AS col2, 3 AS col3;",
277300
}
278301
}
279302

@@ -295,6 +318,8 @@ xcpp::display(h);"#,
295318
completion_prefix: "test_variable_for_",
296319
display_data_code: "ilua.display.html('<b>bold</b>')",
297320
update_display_data_code: "-- Lua doesn't support update_display_data",
321+
// Lua uses display_data for rich output
322+
rich_execute_result_code: "// Lua uses display_data for rich output",
298323
}
299324
}
300325

@@ -316,6 +341,8 @@ xcpp::display(h);"#,
316341
completion_prefix: "testVariableFor",
317342
display_data_code: "putStrLn \"no rich display\"",
318343
update_display_data_code: "-- Haskell doesn't support update_display_data",
344+
// Haskell doesn't have rich execute_result
345+
rich_execute_result_code: "// Haskell doesn't support rich execute_result",
319346
}
320347
}
321348

@@ -337,6 +364,8 @@ xcpp::display(h);"#,
337364
completion_prefix: "test_variable_for_",
338365
display_data_code: "% Octave plot() requires display - skip in headless CI",
339366
update_display_data_code: "% Octave update_display varies by environment",
367+
// Octave uses display_data for rich output
368+
rich_execute_result_code: "// Octave uses display_data for rich output",
340369
}
341370
}
342371

@@ -358,6 +387,8 @@ xcpp::display(h);"#,
358387
completion_prefix: "test_variable_for_",
359388
display_data_code: r#"#require "jupyter.notebook";; Jupyter_notebook.display "text/html" "<b>bold</b>""#,
360389
update_display_data_code: "(* OCaml jupyter doesn't support update_display_data *)",
390+
// OCaml uses display_data for rich output
391+
rich_execute_result_code: "(* OCaml uses display_data for rich output *)",
361392
}
362393
}
363394

@@ -379,6 +410,7 @@ xcpp::display(h);"#,
379410
completion_prefix: "x",
380411
display_data_code: "1",
381412
update_display_data_code: "// update_display not available",
413+
rich_execute_result_code: "// rich execute_result not available",
382414
}
383415
}
384416
}

src/tests.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,38 @@ fn test_execute_result(
637637
})
638638
}
639639

640+
fn test_rich_execute_result(
641+
kernel: &mut KernelUnderTest,
642+
) -> Pin<Box<dyn Future<Output = TestResult> + Send + '_>> {
643+
Box::pin(async move {
644+
let code = kernel.snippets().rich_execute_result_code.to_string();
645+
646+
// Skip if language doesn't support rich execute_result
647+
if code.contains("doesn't support") || code.contains("uses display_data") || code.contains("not available") {
648+
return TestResult::Unsupported;
649+
}
650+
651+
match kernel.execute_and_collect(&code).await {
652+
Ok((_, iopub)) => {
653+
// Look for execute_result (rich snippet should produce rich MIME types)
654+
let has_result = iopub
655+
.iter()
656+
.any(|msg| matches!(&msg.content, JupyterMessageContent::ExecuteResult(_)));
657+
658+
if has_result {
659+
TestResult::Pass
660+
} else {
661+
TestResult::Unsupported
662+
}
663+
}
664+
Err(e) => TestResult::Fail {
665+
kind: None,
666+
reason: e.to_string(),
667+
},
668+
}
669+
})
670+
}
671+
640672
// =============================================================================
641673
// TIER 4: ADVANCED FEATURES
642674
// =============================================================================
@@ -976,6 +1008,13 @@ pub fn all_tests() -> Vec<ConformanceTest> {
9761008
message_type: "execute_result",
9771009
run: test_execute_result,
9781010
},
1011+
ConformanceTest {
1012+
name: "rich_execute_result",
1013+
category: TestCategory::Tier3RichOutput,
1014+
description: "Expression evaluation produces execute_result with rich MIME types (HTML, images, etc.)",
1015+
message_type: "execute_result",
1016+
run: test_rich_execute_result,
1017+
},
9791018
// Tier 4: Advanced Features
9801019
ConformanceTest {
9811020
name: "stdin_input_request",

0 commit comments

Comments
 (0)