• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neurospin-deepinsight / brainprep / 19471672015

18 Nov 2025 03:32PM UTC coverage: 79.472% (+0.02%) from 79.449%
19471672015

push

github

AGrigis
doc: fix documentation.

1444 of 1817 relevant lines covered (79.47%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.37
/brainprep/reporting/html_reporting.py
1
##########################################################################
2
# NSAp - Copyright (C) CEA, 2022 - 2025
3
# Distributed under the terms of the CeCILL-B license, as published by
4
# the CEA-CNRS-INRIA. Refer to the LICENSE file or to
5
# http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
6
# for details.
7
##########################################################################
8

9
"""
10
Module that implements a HTML reporting tool.
11
"""
12

13
import uuid
1✔
14
from html import escape
1✔
15
from pathlib import Path
1✔
16
from typing import Self
1✔
17

18
from .utils import (
1✔
19
    dataframe_to_html,
20
    inject_with_jinja,
21
    png_image_to_base64,
22
)
23

24

25
class HTMLReport:
1✔
26
    """
27
    Render and manage HTML content for display in web pages or Jupyter
28
    notebooks.
29

30
    This class encapsulates HTML content and provides utilities for rendering
31
    it inline (e.g., in Jupyter), resizing the display area, and exporting to
32
    an HTML file.
33
    It supports iframe embedding and integrates with notebook display
34
    protocols.
35

36
    The different rendering are available as follows:
37

38
    - print the object to get the content of the web page.
39
    - from a Jupyter notebook, the plot will be displayed inline if this object
40
      is the output of a cell.
41
    - use :meth:`~brainprep.reporting.html_reporting.HTMLReport.save_as_html`
42
      to save it as an html file.
43
    - use :meth:`~brainprep.reporting.html_reporting.HTMLReport.get_iframe`
44
      to have it wrapped in an iframe.
45

46
    Parameters
47
    ----------
48
    html : str
49
        The HTML content to be rendered.
50
    width : int
51
        Width of the display area in pixels. Default 800.
52
    height : int
53
        Height of the display area in pixels. Default 800.
54

55
    Examples
56
    --------
57
    >>> html = "<h1>Hello, world!</h1>"
58
    >>> report = HTMLReport(html)
59
    >>> print(report)
60
    <h1>Hello, world!</h1>
61
    >>> report.save_as_html("output.html")
62
    """
63

64
    def __init__(
1✔
65
            self,
66
            html: str,
67
            width: int = 800,
68
            height: int = 800) -> None:
69
        self.html = html
1✔
70
        self.width = width
1✔
71
        self.height = height
1✔
72
        self._temp_file = None
1✔
73
        self._temp_file_removing_proc = None
1✔
74

75
    def resize(
1✔
76
            self,
77
            width: int,
78
            height: int) -> Self:
79
        """
80
        Resize the document displayed.
81

82
        Parameters
83
        ----------
84
        width: int
85
            New width of the document.
86
        height: int
87
            New height of the document.
88

89
        Returns
90
        -------
91
        Self
92
        """
93
        self.width = width
×
94
        self.height = height
×
95
        return self
×
96

97
    def get_iframe(
1✔
98
            self,
99
            width: int | None,
100
            height: int | None) -> str:
101
        """
102
        Get the document wrapped in an inline frame.
103

104
        Notes
105
        -----
106
        Useful for inserting the document content in another HTML page,
107
        i.e. in a Jupyter notebook.
108

109
        Parameters
110
        ----------
111
        width: int | None
112
            Width of the inline frame. Default None.
113
        height: int | None
114
            Height of the inline frame. Default None.
115

116
        Returns
117
        -------
118
        wrapped: str
119
            Raw HTML code for the inline frame.
120
        """
121
        if width is None:
×
122
            width = self.width
×
123
        if height is None:
×
124
            height = self.height
×
125
        escaped = escape(self.html, quote=True)
×
126
        wrapped = (
×
127
            f"<iframe srcdoc='{escaped}' "
128
            f"width='{width}' height='{height}' "
129
            "frameBorder='0'></iframe>"
130
        )
131
        return wrapped
×
132

133
    def _repr_html_(self) -> str:
1✔
134
        """
135
         Return iframe-wrapped HTML for Jupyter notebook rendering.
136

137
        Notes
138
        -----
139
        Used by the Jupyter notebook.
140
        See the jupyter documentation:
141
        https://ipython.readthedocs.io/en/stable/config/integrating.html
142
        """
143
        return self.get_iframe()
×
144

145
    def _repr_mimebundle_(
1✔
146
            self,
147
            include=None,
148
            exclude=None) -> dict:
149
        """
150
        Return html representation of the plot.
151

152
        Notes
153
        -----
154
        Used by the Jupyter notebook.
155
        See the jupyter documentation:
156
        https://ipython.readthedocs.io/en/stable/config/integrating.html
157
        """
158
        del include, exclude
×
159
        return {"text/html": self.get_iframe()}
×
160

161
    def __str__(self):
1✔
162
        return self.html
1✔
163

164
    def save_as_html(
1✔
165
            self,
166
            file_name: str) -> None:
167
        """
168
        Save the plot in an HTML file, that can later be opened in a browser.
169

170
        Parameters
171
        ----------
172
        file_name: str
173
            Path to the HTML file used for saving.
174
        """
175
        with Path(file_name).open("wb") as of:
1✔
176
            of.write(self.html.encode("utf-8"))
1✔
177

178

179
def generate_qc_report(
1✔
180
        title: str,
181
        docstring: str,
182
        version: str,
183
        date: str,
184
        data: list[dict]) -> HTMLReport:
185
    """
186
    Generate a quality control (QC) report as an interactive HTML document.
187

188
    This function compiles visual and tabular data into a structured HTML
189
    report using a predefined template. It is useful for documenting and
190
    reviewing steps in a data processing workflow.
191

192
    Parameters
193
    ----------
194
    title : str
195
        The title displayed at the top of the report.
196
    docstring : str
197
        A descriptive introduction or summary of the report's purpose.
198
    version : str
199
        Version identifier for the report or associated software.
200
    date : str
201
        Timestamp indicating when the report was generated.
202
    data : list[dict]
203
        A list of dictionaries, each representing a workflow step. Each
204
        dictionary must contain the following keys:
205
        - name (str): Title of the step.
206
        - content (Path or list of Path): Image(s) to display.
207
        - overlay (Path): Image(s) to show on hover.
208
        - tables (DataFrame or list of DataFrame): Tabular data to include.
209

210
    Returns
211
    -------
212
    report : HTMLReport
213
        An instance of `HTMLReport` containing the rendered HTML content.
214

215
    Notes
216
    -----
217
    - Images are converted to base64 for inline embedding.
218
    - Tables are rendered as HTML using `dataframe_to_html`.
219

220
    Examples
221
    --------
222
    >>> from pathlib import Path
223
    >>> from pandas import DataFrame
224
    >>>
225
    >>> data = [{
226
    ...     "name": "Step 1",
227
    ...     "content": Path("/tmp/image1.png"),
228
    ...     "overlay": Path("/tmp/image1_overlay.png"),
229
    ...     "tables": DataFrame({"A": [1, 2], "B": [3, 4]})
230
    ... }]
231
    >>> report = generate_qc_report(
232
    ...     title="QC Summary",
233
    ...     docstring="Overview of preprocessing steps.",
234
    ...     version="1.0",
235
    ...     date="2025-10-03",
236
    ...     data=data
237
    ... ) # doctest: +SKIP
238
    >>> report.save_as_html("/tmp/qc_report.html") # doctest: +SKIP
239
    """
240
    template_path = Path(__file__).parent / "data" / "body.html"
1✔
241
    css_path = Path(__file__).parent / "data" / "style.css"
1✔
242
    with css_path.open(encoding="utf-8") as css_file:
1✔
243
        css = css_file.read()
1✔
244
    js_path = Path(__file__).parent / "data" / "script.js"
1✔
245
    with js_path.open(encoding="utf-8") as js_file:
1✔
246
        js = js_file.read()
1✔
247
    unique_id = str(uuid.uuid4()).replace("-", "")
1✔
248
    for counter, item in enumerate(data):
1✔
249
        item["id"] = counter
1✔
250
        content = item.get("content")
1✔
251
        overlay = item.get("overlay")
1✔
252
        tables = item.get("tables")
1✔
253
        if content is not None:
1✔
254
            if not isinstance(content, (tuple, list)):
1✔
255
                content = [content]
1✔
256
            item["content"] = [
1✔
257
                png_image_to_base64(img) for img in content
258
            ]
259
        if overlay is not None:
1✔
260
            if not isinstance(overlay, (tuple, list)):
1✔
261
                overlay = [overlay]
1✔
262
            item["overlay"] = [
1✔
263
                png_image_to_base64(img) for img in overlay
264
            ]
265
        if tables is not None:
1✔
266
            if not isinstance(tables, (tuple, list)):
1✔
267
                tables = [tables]
1✔
268
            item["tables"] = [
1✔
269
                dataframe_to_html(
270
                    tab,
271
                    precision=2,
272
                    header=True,
273
                    index=False,
274
                    sparsify=False,
275
                ) for tab in tables
276
            ]
277
    html = inject_with_jinja(
1✔
278
        template_file=template_path,
279
        css=css,
280
        js=js,
281
        uuid=unique_id,
282
        title=title,
283
        docstring=docstring,
284
        version=version,
285
        date=date,
286
        workflows=data,
287
    )
288
    html = html.replace(".pure-g &gt; div", ".pure-g > div")
1✔
289

290
    return HTMLReport(html=html)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc