From cd1e8bd59141316c09a27a49dfe2d8947295501f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:50:47 +0000 Subject: [PATCH 1/2] Make browser summary reports single-file Co-authored-by: uriahf <11351434+uriahf@users.noreply.github.com> --- src/rtichoke/_report_browser.py | 7 +++--- tests/test_calibration_v2.py | 11 ++++++++- tests/test_report_browser.py | 35 +++++++++++++++++++++++++--- tests/test_summary_report_browser.py | 16 +++++++++---- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/rtichoke/_report_browser.py b/src/rtichoke/_report_browser.py index d3d628db..a4441022 100644 --- a/src/rtichoke/_report_browser.py +++ b/src/rtichoke/_report_browser.py @@ -33,20 +33,21 @@ def write_html(self, path: str | Path) -> Path: output.parent.mkdir(parents=True, exist_ok=True) vendor = files("rtichoke").joinpath("_vendor", "rtichoke_viz") - for asset in ("rtichoke-viz.js", "rtichoke-viz.css"): - (output.parent / asset).write_bytes(vendor.joinpath(asset).read_bytes()) sanitized_spec = _sanitize_nan_values(self.spec) spec_json = json.dumps(sanitized_spec, separators=(",", ":")).replace( " - + rtichoke report diff --git a/tests/test_calibration_v2.py b/tests/test_calibration_v2.py index 22d8d094..9abf80b8 100644 --- a/tests/test_calibration_v2.py +++ b/tests/test_calibration_v2.py @@ -17,6 +17,8 @@ create_calibration_curve, ) from rtichoke.performance_data.performance_data import prepare_performance_data +from importlib.resources import files + from rtichoke.processing.evaluation_semantics import ( _SHARED_POPULATION, _build_evaluation_metadata, @@ -280,7 +282,9 @@ def test_real_performance_table_roc_calibration_report_uses_shared_renderer(tmp_ tmp_path / "report.html" ) html = output.read_text(encoding="utf-8") - viz_js = (tmp_path / "rtichoke-viz.js").read_text(encoding="utf-8") + vendor = files("rtichoke").joinpath("_vendor", "rtichoke_viz") + viz_js = vendor.joinpath("rtichoke-viz.js").read_text(encoding="utf-8") + viz_css = vendor.joinpath("rtichoke-viz.css").read_text(encoding="utf-8") assert [item["id"] for item in report["sections"][0]["items"]] == [ "performance-table", @@ -291,6 +295,11 @@ def test_real_performance_table_roc_calibration_report_uses_shared_renderer(tmp_ assert _embedded_report(html) == report assert 'import { renderReport } from "./rtichoke-viz.js";' not in html assert viz_js in html + assert viz_css in html + assert '' not in html + assert [f.name for f in sorted(tmp_path.iterdir())] == ["report.html"] + assert not (tmp_path / "rtichoke-viz.js").exists() + assert not (tmp_path / "rtichoke-viz.css").exists() assert 'sectionGroupPresentation: "tabs"' in html diff --git a/tests/test_report_browser.py b/tests/test_report_browser.py index ca41d2e5..9ed6d997 100644 --- a/tests/test_report_browser.py +++ b/tests/test_report_browser.py @@ -1,4 +1,5 @@ import json +from importlib.resources import files from typing import Any, cast import numpy as np @@ -54,10 +55,14 @@ def test_browser_report_uses_real_producers_and_only_shared_render_report(tmp_pa tmp_path / "report.html" ) html = output.read_text(encoding="utf-8") - viz_js = (tmp_path / "rtichoke-viz.js").read_text(encoding="utf-8") + vendor = files("rtichoke").joinpath("_vendor", "rtichoke_viz") + viz_js = vendor.joinpath("rtichoke-viz.js").read_text(encoding="utf-8") + viz_css = vendor.joinpath("rtichoke-viz.css").read_text(encoding="utf-8") assert 'import { renderReport } from "./rtichoke-viz.js";' not in html assert viz_js in html + assert viz_css in html + assert '' not in html assert 'sectionGroupPresentation: "tabs"' in html assert 'groupPresentation: "stacked"' in html assert _embedded_report(html) == report @@ -66,8 +71,9 @@ def test_browser_report_uses_real_producers_and_only_shared_render_report(tmp_pa "roc", "gains", ] - assert (tmp_path / "rtichoke-viz.js").exists() - assert (tmp_path / "rtichoke-viz.css").exists() + assert [f.name for f in sorted(tmp_path.iterdir())] == ["report.html"] + assert not (tmp_path / "rtichoke-viz.js").exists() + assert not (tmp_path / "rtichoke-viz.css").exists() def test_browser_report_preserves_component_local_evaluation_ids_and_time_context( @@ -126,3 +132,26 @@ def test_browser_report_preserves_component_local_evaluation_ids_and_time_contex tmp_path / "time-report.html" ) assert _embedded_report(output.read_text(encoding="utf-8")) == report + + +def test_browser_report_does_not_delete_or_overwrite_preexisting_assets(tmp_path): + existing_js = tmp_path / "rtichoke-viz.js" + existing_css = tmp_path / "rtichoke-viz.css" + existing_js.write_text("// custom preexisting js", encoding="utf-8") + existing_css.write_text("/* custom preexisting css */", encoding="utf-8") + + probs = {"Model A": np.array([0.05, 0.2, 0.7, 0.95])} + reals = np.array([0, 0, 1, 1]) + performance_data = prepare_performance_data(probs, reals, by=0.25) + metadata = _build_evaluation_metadata(probs, reals, np.array([])) + table = _performance_table_spec_from_performance_data(performance_data, metadata) + report = _build_report_spec_v11( + [{"id": "sec-1", "components": [{"id": "performance-table", "spec": table}]}] + ) + + RtichokeBrowserReport(cast(dict[str, Any], report)).write_html( + tmp_path / "report.html" + ) + + assert existing_js.read_text(encoding="utf-8") == "// custom preexisting js" + assert existing_css.read_text(encoding="utf-8") == "/* custom preexisting css */" diff --git a/tests/test_summary_report_browser.py b/tests/test_summary_report_browser.py index 1586f0af..968a5608 100644 --- a/tests/test_summary_report_browser.py +++ b/tests/test_summary_report_browser.py @@ -17,6 +17,8 @@ from rtichoke._report_browser import RtichokeBrowserReport from rtichoke._report_spec import _build_report_spec_v11 from rtichoke.performance_data.performance_data import prepare_performance_data +from importlib.resources import files + from rtichoke.processing.evaluation_semantics import _build_evaluation_metadata from rtichoke.summary_report import summary_report as summary_report_module from rtichoke.summary_report.summary_report import create_summary_report @@ -170,9 +172,9 @@ def test_browser_summary_report_is_opt_in_and_uses_real_canonical_components( assert result == output assert output.exists() - viz_js_path = tmp_path / "rtichoke-viz.js" - assert viz_js_path.exists() - assert (tmp_path / "rtichoke-viz.css").exists() + assert [f.name for f in sorted(tmp_path.iterdir())] == ["canonical-summary.html"] + assert not (tmp_path / "rtichoke-viz.js").exists() + assert not (tmp_path / "rtichoke-viz.css").exists() html = output.read_text(encoding="utf-8") report = _embedded_report(html) @@ -187,7 +189,13 @@ def test_browser_summary_report_is_opt_in_and_uses_real_canonical_components( "performance-table", ] assert 'import { renderReport } from "./rtichoke-viz.js";' not in html - assert viz_js_path.read_text(encoding="utf-8") in html + vendor = files("rtichoke").joinpath("_vendor", "rtichoke_viz") + viz_js = vendor.joinpath("rtichoke-viz.js").read_text(encoding="utf-8") + viz_css = vendor.joinpath("rtichoke-viz.css").read_text(encoding="utf-8") + assert viz_js in html + assert viz_css in html + assert '' not in html + assert '