Skip to content

core

tit.reporting.core

Core infrastructure for TI-Toolbox reporting system.

This module provides the foundational components for building modular, self-contained HTML reports.

ReportletType

Bases: Enum

Enumeration of reportlet types.

ReportMetadata dataclass

ReportMetadata(title: str, subject_id: str | None = None, session_id: str | None = None, report_type: str = 'general', generation_time: datetime = now(), software_versions: dict[str, str] = dict(), project_dir: str | None = None, bids_version: str = '1.8.0', dataset_type: str = 'derivative')

Metadata for a generated report.

to_dict

to_dict() -> dict[str, Any]

Convert metadata to dictionary.

Source code in tit/reporting/core/protocols.py
def to_dict(self) -> dict[str, Any]:
    """Convert metadata to dictionary."""
    return {
        "title": self.title,
        "subject_id": self.subject_id,
        "session_id": self.session_id,
        "report_type": self.report_type,
        "generation_time": self.generation_time.isoformat(),
        "software_versions": self.software_versions,
        "project_dir": self.project_dir,
        "bids_version": self.bids_version,
        "dataset_type": self.dataset_type,
    }

ReportSection dataclass

ReportSection(section_id: str, title: str, reportlets: list[Any] = list(), description: str | None = None, collapsed: bool = False, order: int = 0)

A section within a report containing multiple reportlets.

add_reportlet

add_reportlet(reportlet: Any) -> None

Add a reportlet to this section.

Source code in tit/reporting/core/protocols.py
def add_reportlet(self, reportlet: Any) -> None:
    """Add a reportlet to this section."""
    self.reportlets.append(reportlet)

render_html

render_html() -> str

Render the section and all its reportlets as HTML.

Source code in tit/reporting/core/protocols.py
def render_html(self) -> str:
    """Render the section and all its reportlets as HTML."""
    collapse_class = "collapsible" if self.collapsed else ""
    content_parts = []

    for reportlet in self.reportlets:
        content_parts.append(reportlet.render_html())

    content = "\n".join(content_parts)

    description_html = ""
    if self.description:
        description_html = f'<p class="section-description">{self.description}</p>'

    return f"""
    <section id="{self.section_id}" class="report-section {collapse_class}">
        <h2 class="section-title">{self.title}</h2>
        {description_html}
        <div class="section-content">
            {content}
        </div>
    </section>
    """

to_dict

to_dict() -> dict[str, Any]

Convert section to dictionary.

Source code in tit/reporting/core/protocols.py
def to_dict(self) -> dict[str, Any]:
    """Convert section to dictionary."""
    return {
        "section_id": self.section_id,
        "title": self.title,
        "description": self.description,
        "collapsed": self.collapsed,
        "order": self.order,
        "reportlets": [r.to_dict() for r in self.reportlets],
    }

Reportlet

Bases: Protocol

Protocol defining the interface for all reportlets.

reportlet_type property

reportlet_type: ReportletType

Return the type of this reportlet.

reportlet_id property

reportlet_id: str

Return a unique identifier for this reportlet.

render_html

render_html() -> str

Render the reportlet as HTML.

Source code in tit/reporting/core/protocols.py
def render_html(self) -> str:
    """Render the reportlet as HTML."""
    ...

to_dict

to_dict() -> dict[str, Any]

Convert the reportlet to a dictionary representation.

Source code in tit/reporting/core/protocols.py
def to_dict(self) -> dict[str, Any]:
    """Convert the reportlet to a dictionary representation."""
    ...

SeverityLevel

Bases: Enum

Severity levels for errors and warnings.

StatusType

Bases: Enum

Status types for processing steps.

BaseReportlet

BaseReportlet(title: str | None = None)

Bases: ABC

Abstract base class for all reportlets.

Source code in tit/reporting/core/base.py
def __init__(self, title: str | None = None):
    self._title = title
    self._id = str(uuid.uuid4())[:8]

reportlet_type abstractmethod property

reportlet_type: ReportletType

Return the type of this reportlet.

reportlet_id property

reportlet_id: str

Return a unique identifier for this reportlet.

title property

title: str | None

Return the title of this reportlet.

render_html abstractmethod

render_html() -> str

Render the reportlet as HTML.

Source code in tit/reporting/core/base.py
@abstractmethod
def render_html(self) -> str:
    """Render the reportlet as HTML."""
    pass

to_dict abstractmethod

to_dict() -> dict[str, Any]

Convert the reportlet to a dictionary representation.

Source code in tit/reporting/core/base.py
@abstractmethod
def to_dict(self) -> dict[str, Any]:
    """Convert the reportlet to a dictionary representation."""
    pass

MetadataReportlet

MetadataReportlet(data: dict[str, Any], title: str | None = None, display_mode: str = 'table', columns: int = 2)

Bases: BaseReportlet

Reportlet for displaying metadata as key-value pairs.

Supports two display modes: - 'table': Traditional table layout - 'cards': Modern card grid layout

Source code in tit/reporting/core/base.py
def __init__(
    self,
    data: dict[str, Any],
    title: str | None = None,
    display_mode: str = "table",
    columns: int = 2,
):
    super().__init__(title)
    self.data = data
    self.display_mode = display_mode
    self.columns = columns

render_html

render_html() -> str

Render metadata as HTML table or cards.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render metadata as HTML table or cards."""
    if self.display_mode == "cards":
        return self._render_cards()
    return self._render_table()

ImageReportlet

ImageReportlet(image_source: str | Path | bytes | Any | None = None, title: str | None = None, caption: str | None = None, alt_text: str | None = None, width: str | None = None, height: str | None = None)

Bases: BaseReportlet

Reportlet for displaying images.

Supports embedding images as base64 or referencing external paths. Images can be loaded from file paths, PIL Images, or raw bytes.

Source code in tit/reporting/core/base.py
def __init__(
    self,
    image_source: str | Path | bytes | Any | None = None,
    title: str | None = None,
    caption: str | None = None,
    alt_text: str | None = None,
    width: str | None = None,
    height: str | None = None,
):
    super().__init__(title)
    self.caption = caption
    self.alt_text = alt_text or title or "Image"
    self.width = width
    self.height = height
    self._base64_data: str | None = None
    self._mime_type: str = "image/png"

    if image_source is not None:
        self._load_image(image_source)

set_base64_data

set_base64_data(data: str, mime_type: str = 'image/png') -> None

Directly set base64 encoded image data.

Source code in tit/reporting/core/base.py
def set_base64_data(self, data: str, mime_type: str = "image/png") -> None:
    """Directly set base64 encoded image data."""
    self._base64_data = data
    self._mime_type = mime_type

render_html

render_html() -> str

Render image as HTML.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render image as HTML."""
    if not self._base64_data:
        return f"""
        <div class="reportlet image-reportlet" id="{self.reportlet_id}">
            <div class="image-placeholder">
                <em>No image available</em>
            </div>
        </div>
        """

    style_parts = []
    if self.width:
        style_parts.append(f"max-width: {self.width}")
    if self.height:
        style_parts.append(f"max-height: {self.height}")
    style = "; ".join(style_parts) if style_parts else ""

    title_html = f"<h3>{self._title}</h3>" if self._title else ""
    caption_html = (
        f'<figcaption class="image-caption">{self.caption}</figcaption>'
        if self.caption
        else ""
    )

    return f"""
    <div class="reportlet image-reportlet" id="{self.reportlet_id}">
        {title_html}
        <figure class="image-figure">
            <img src="data:{self._mime_type};base64,{self._base64_data}"
                 alt="{self.alt_text}"
                 style="{style}"
                 class="report-image" />
            {caption_html}
        </figure>
    </div>
    """

TableReportlet

TableReportlet(data: list[dict] | list[list] | Any, title: str | None = None, headers: list[str] | None = None, sortable: bool = False, striped: bool = True, compact: bool = False)

Bases: BaseReportlet

Reportlet for displaying tabular data.

Supports various input formats including lists of dicts, lists of lists, and pandas DataFrames.

Source code in tit/reporting/core/base.py
def __init__(
    self,
    data: list[dict] | list[list] | Any,
    title: str | None = None,
    headers: list[str] | None = None,
    sortable: bool = False,
    striped: bool = True,
    compact: bool = False,
):
    super().__init__(title)
    self.headers: list[str] = []
    self.rows: list[list[Any]] = []
    self.sortable = sortable
    self.striped = striped
    self.compact = compact

    self._process_data(data, headers)

render_html

render_html() -> str

Render table as HTML.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render table as HTML."""
    if not self.rows and not self.headers:
        return f"""
        <div class="reportlet table-reportlet" id="{self.reportlet_id}">
            <em>No data available</em>
        </div>
        """

    classes = ["data-table"]
    if self.striped:
        classes.append("striped")
    if self.compact:
        classes.append("compact")
    if self.sortable:
        classes.append("sortable")

    header_html = ""
    if self.headers:
        header_cells = "".join(f"<th>{h}</th>" for h in self.headers)
        header_html = f"<thead><tr>{header_cells}</tr></thead>"

    body_rows = []
    for row in self.rows:
        cells = "".join(f"<td>{self._format_cell(c)}</td>" for c in row)
        body_rows.append(f"<tr>{cells}</tr>")
    body_html = f"<tbody>{''.join(body_rows)}</tbody>"

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet table-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="table-wrapper">
            <table class="{' '.join(classes)}">
                {header_html}
                {body_html}
            </table>
        </div>
    </div>
    """

TextReportlet

TextReportlet(content: str, title: str | None = None, content_type: str = 'text', copyable: bool = False, monospace: bool = False)

Bases: BaseReportlet

Reportlet for displaying text content.

Supports plain text, HTML, and markdown-style formatting. Includes optional copy-to-clipboard functionality for boilerplate text.

Source code in tit/reporting/core/base.py
def __init__(
    self,
    content: str,
    title: str | None = None,
    content_type: str = "text",
    copyable: bool = False,
    monospace: bool = False,
):
    super().__init__(title)
    self.content = content
    self.content_type = content_type  # 'text', 'html', 'code'
    self.copyable = copyable
    self.monospace = monospace

render_html

render_html() -> str

Render text content as HTML.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render text content as HTML."""
    classes = ["text-content"]
    if self.monospace:
        classes.append("monospace")
    if self.copyable:
        classes.append("copyable")

    # Format content based on type
    if self.content_type == "html":
        formatted_content = self.content
    elif self.content_type == "code":
        formatted_content = (
            f"<pre><code>{self._escape_html(self.content)}</code></pre>"
        )
    else:
        # Plain text - convert newlines to paragraphs
        paragraphs = self.content.split("\n\n")
        formatted_content = "".join(f"<p>{p}</p>" for p in paragraphs if p.strip())

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    copy_button = ""
    if self.copyable:
        copy_button = f"""
        <button class="copy-btn" onclick="copyToClipboard('{self.reportlet_id}-content')">
            Copy to Clipboard
        </button>
        """

    return f"""
    <div class="reportlet text-reportlet" id="{self.reportlet_id}">
        {title_html}
        {copy_button}
        <div class="{' '.join(classes)}" id="{self.reportlet_id}-content">
            {formatted_content}
        </div>
    </div>
    """

ErrorReportlet

ErrorReportlet(messages: list[dict[str, Any]] | None = None, title: str | None = None)

Bases: BaseReportlet

Reportlet for displaying errors and warnings.

Supports different severity levels with appropriate styling.

Source code in tit/reporting/core/base.py
def __init__(
    self,
    messages: list[dict[str, Any]] | None = None,
    title: str | None = None,
):
    super().__init__(title or "Errors and Warnings")
    self.messages: list[dict[str, Any]] = messages or []

add_message

add_message(message: str, severity: SeverityLevel = ERROR, context: str | None = None, step: str | None = None) -> None

Add an error or warning message.

Source code in tit/reporting/core/base.py
def add_message(
    self,
    message: str,
    severity: SeverityLevel = SeverityLevel.ERROR,
    context: str | None = None,
    step: str | None = None,
) -> None:
    """Add an error or warning message."""
    self.messages.append(
        {
            "message": message,
            "severity": (
                severity.value if isinstance(severity, SeverityLevel) else severity
            ),
            "context": context,
            "step": step,
        }
    )

add_error

add_error(message: str, context: str | None = None, step: str | None = None) -> None

Add an error message.

Source code in tit/reporting/core/base.py
def add_error(
    self, message: str, context: str | None = None, step: str | None = None
) -> None:
    """Add an error message."""
    self.add_message(message, SeverityLevel.ERROR, context, step)

add_warning

add_warning(message: str, context: str | None = None, step: str | None = None) -> None

Add a warning message.

Source code in tit/reporting/core/base.py
def add_warning(
    self, message: str, context: str | None = None, step: str | None = None
) -> None:
    """Add a warning message."""
    self.add_message(message, SeverityLevel.WARNING, context, step)

render_html

render_html() -> str

Render errors and warnings as HTML.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render errors and warnings as HTML."""
    if not self.messages:
        return f"""
        <div class="reportlet error-reportlet success" id="{self.reportlet_id}">
            <div class="success-message">
                <span class="status-icon">[OK]</span>
                No errors or warnings
            </div>
        </div>
        """

    message_items = []
    for msg in self.messages:
        severity = msg.get("severity", "error")
        icon = (
            "[!]"
            if severity == "warning"
            else "[X]" if severity in ("error", "critical") else "[i]"
        )
        context = msg.get("context", "")
        step = msg.get("step", "")

        context_html = (
            f'<span class="error-context">[{context}]</span>' if context else ""
        )
        step_html = f'<span class="error-step">Step: {step}</span>' if step else ""

        message_items.append(f"""
            <div class="message-item {severity}">
                <span class="severity-icon">{icon}</span>
                <div class="message-content">
                    {context_html}
                    <span class="message-text">{msg["message"]}</span>
                    {step_html}
                </div>
            </div>
            """)

    title_html = f"<h3>{self._title}</h3>" if self._title else ""

    return f"""
    <div class="reportlet error-reportlet" id="{self.reportlet_id}">
        {title_html}
        <div class="messages-list">
            {"".join(message_items)}
        </div>
    </div>
    """

ReferencesReportlet

ReferencesReportlet(references: list[dict[str, str]] | None = None, title: str | None = None)

Bases: BaseReportlet

Reportlet for displaying citations and references.

Automatically formats references in a consistent style.

Source code in tit/reporting/core/base.py
def __init__(
    self,
    references: list[dict[str, str]] | None = None,
    title: str | None = None,
):
    super().__init__(title or "References")
    self.references: list[dict[str, str]] = references or []

add_reference

add_reference(key: str, citation: str, url: str | None = None, doi: str | None = None) -> None

Add a reference.

Source code in tit/reporting/core/base.py
def add_reference(
    self,
    key: str,
    citation: str,
    url: str | None = None,
    doi: str | None = None,
) -> None:
    """Add a reference."""
    self.references.append(
        {
            "key": key,
            "citation": citation,
            "url": url,
            "doi": doi,
        }
    )

render_html

render_html() -> str

Render references as HTML.

Source code in tit/reporting/core/base.py
def render_html(self) -> str:
    """Render references as HTML."""
    if not self.references:
        return ""

    ref_items = []
    for ref in self.references:
        citation = ref["citation"]
        key = ref.get("key", "")

        # Add DOI link if available
        if ref.get("doi"):
            doi_link = (
                f'<a href="https://doi.org/{ref["doi"]}" target="_blank">[DOI]</a>'
            )
            citation = f"{citation} {doi_link}"
        elif ref.get("url"):
            url_link = f'<a href="{ref["url"]}" target="_blank">[Link]</a>'
            citation = f"{citation} {url_link}"

        ref_items.append(f"""
            <li class="reference-item" id="ref-{key}">
                <span class="ref-key">[{key}]</span>
                <span class="ref-citation">{citation}</span>
            </li>
            """)

    title_html = f"<h3>{self._title}</h3>"

    return f"""
    <div class="reportlet references-reportlet" id="{self.reportlet_id}">
        {title_html}
        <ol class="references-list">
            {"".join(ref_items)}
        </ol>
    </div>
    """

ReportAssembler

ReportAssembler(metadata: ReportMetadata | None = None, title: str | None = None)

Assembles reportlets into a complete HTML report.

The assembler manages sections, handles ordering, generates the table of contents, and renders the final HTML document.

Initialize the report assembler.

Parameters:

Name Type Description Default
metadata ReportMetadata | None

Report metadata (title, subject, etc.)

None
title str | None

Report title (overrides metadata.title if provided)

None
Source code in tit/reporting/core/assembler.py
def __init__(
    self,
    metadata: ReportMetadata | None = None,
    title: str | None = None,
):
    """
    Initialize the report assembler.

    Args:
        metadata: Report metadata (title, subject, etc.)
        title: Report title (overrides metadata.title if provided)
    """
    self.metadata = metadata or ReportMetadata(title=title or "Report")
    if title:
        self.metadata.title = title

    self.sections: list[ReportSection] = []
    self._custom_css: str = ""
    self._custom_js: str = ""

add_section

add_section(section_id: str, title: str, description: str | None = None, collapsed: bool = False, order: int | None = None) -> ReportSection

Add a new section to the report.

Parameters:

Name Type Description Default
section_id str

Unique identifier for the section

required
title str

Section title

required
description str | None

Optional section description

None
collapsed bool

Whether section starts collapsed

False
order int | None

Sort order (lower = earlier in report)

None

Returns:

Type Description
ReportSection

The created ReportSection object

Source code in tit/reporting/core/assembler.py
def add_section(
    self,
    section_id: str,
    title: str,
    description: str | None = None,
    collapsed: bool = False,
    order: int | None = None,
) -> ReportSection:
    """
    Add a new section to the report.

    Args:
        section_id: Unique identifier for the section
        title: Section title
        description: Optional section description
        collapsed: Whether section starts collapsed
        order: Sort order (lower = earlier in report)

    Returns:
        The created ReportSection object
    """
    if order is None:
        order = len(self.sections)

    section = ReportSection(
        section_id=section_id,
        title=title,
        description=description,
        collapsed=collapsed,
        order=order,
    )
    self.sections.append(section)
    return section

get_section

get_section(section_id: str) -> ReportSection | None

Get a section by its ID.

Parameters:

Name Type Description Default
section_id str

The section identifier

required

Returns:

Type Description
ReportSection | None

The ReportSection or None if not found

Source code in tit/reporting/core/assembler.py
def get_section(self, section_id: str) -> ReportSection | None:
    """
    Get a section by its ID.

    Args:
        section_id: The section identifier

    Returns:
        The ReportSection or None if not found
    """
    for section in self.sections:
        if section.section_id == section_id:
            return section
    return None

add_reportlet_to_section

add_reportlet_to_section(section_id: str, reportlet: Any, create_if_missing: bool = True, section_title: str | None = None) -> None

Add a reportlet to a specific section.

Parameters:

Name Type Description Default
section_id str

The section identifier

required
reportlet Any

The reportlet to add

required
create_if_missing bool

Create section if it doesn't exist

True
section_title str | None

Title for new section (if created)

None
Source code in tit/reporting/core/assembler.py
def add_reportlet_to_section(
    self,
    section_id: str,
    reportlet: Any,
    create_if_missing: bool = True,
    section_title: str | None = None,
) -> None:
    """
    Add a reportlet to a specific section.

    Args:
        section_id: The section identifier
        reportlet: The reportlet to add
        create_if_missing: Create section if it doesn't exist
        section_title: Title for new section (if created)
    """
    section = self.get_section(section_id)

    if section is None:
        if create_if_missing:
            title = section_title or section_id.replace("_", " ").title()
            section = self.add_section(section_id, title)
        else:
            raise ValueError(f"Section '{section_id}' not found")

    section.add_reportlet(reportlet)

set_custom_css

set_custom_css(css: str) -> None

Add custom CSS styles to the report.

Source code in tit/reporting/core/assembler.py
def set_custom_css(self, css: str) -> None:
    """Add custom CSS styles to the report."""
    self._custom_css = css

set_custom_js

set_custom_js(js: str) -> None

Add custom JavaScript to the report.

Source code in tit/reporting/core/assembler.py
def set_custom_js(self, js: str) -> None:
    """Add custom JavaScript to the report."""
    self._custom_js = js

render_toc

render_toc() -> str

Render the table of contents as HTML.

Returns:

Type Description
str

HTML string for the table of contents

Source code in tit/reporting/core/assembler.py
def render_toc(self) -> str:
    """
    Render the table of contents as HTML.

    Returns:
        HTML string for the table of contents
    """
    sorted_sections = sorted(self.sections, key=lambda s: s.order)

    links = []
    for section in sorted_sections:
        links.append(
            f'<li><a href="#{section.section_id}">{section.title}</a></li>'
        )

    return f'<ul class="toc-list">{"".join(links)}</ul>'

render_metadata

render_metadata() -> str

Render the header metadata as HTML.

Returns:

Type Description
str

HTML string for the header metadata

Source code in tit/reporting/core/assembler.py
def render_metadata(self) -> str:
    """
    Render the header metadata as HTML.

    Returns:
        HTML string for the header metadata
    """
    parts = []

    if self.metadata.subject_id:
        parts.append(
            f"<span>Subject: <strong>{self.metadata.subject_id}</strong></span>"
        )

    if self.metadata.session_id:
        parts.append(
            f"<span>Session: <strong>{self.metadata.session_id}</strong></span>"
        )

    parts.append(
        f'<span>Generated: <strong>{self.metadata.generation_time.strftime("%Y-%m-%d %H:%M:%S")}</strong></span>'
    )

    return f'<div class="header-meta">{"".join(parts)}</div>'

render_sections

render_sections() -> str

Render all sections as HTML.

Returns:

Type Description
str

HTML string for all sections

Source code in tit/reporting/core/assembler.py
def render_sections(self) -> str:
    """
    Render all sections as HTML.

    Returns:
        HTML string for all sections
    """
    sorted_sections = sorted(self.sections, key=lambda s: s.order)
    return "\n".join(section.render_html() for section in sorted_sections)

render_html

render_html() -> str

Render the complete report as HTML.

Returns:

Type Description
str

Complete HTML document as a string

Source code in tit/reporting/core/assembler.py
def render_html(self) -> str:
    """
    Render the complete report as HTML.

    Returns:
        Complete HTML document as a string
    """
    content = self.render_sections()
    toc_html = self.render_toc()
    metadata_html = self.render_metadata()

    return get_html_template(
        title=self.metadata.title,
        content=content,
        toc_html=toc_html,
        metadata_html=metadata_html,
        custom_css=self._custom_css,
        custom_js=self._custom_js,
    )

save

save(output_path: str | Path, create_dirs: bool = True) -> Path

Save the report to a file.

Parameters:

Name Type Description Default
output_path str | Path

Path to save the HTML file

required
create_dirs bool

Create parent directories if needed

True

Returns:

Type Description
Path

Path to the saved file

Source code in tit/reporting/core/assembler.py
def save(
    self,
    output_path: str | Path,
    create_dirs: bool = True,
) -> Path:
    """
    Save the report to a file.

    Args:
        output_path: Path to save the HTML file
        create_dirs: Create parent directories if needed

    Returns:
        Path to the saved file
    """
    output_path = Path(output_path)

    if create_dirs:
        output_path.parent.mkdir(parents=True, exist_ok=True)

    html_content = self.render_html()
    output_path.write_text(html_content, encoding="utf-8")

    return output_path

to_dict

to_dict() -> dict[str, Any]

Convert the report to a dictionary representation.

Returns:

Type Description
dict[str, Any]

Dictionary containing all report data

Source code in tit/reporting/core/assembler.py
def to_dict(self) -> dict[str, Any]:
    """
    Convert the report to a dictionary representation.

    Returns:
        Dictionary containing all report data
    """
    return {
        "metadata": self.metadata.to_dict(),
        "sections": [s.to_dict() for s in self.sections],
    }

from_dict classmethod

from_dict(data: dict[str, Any]) -> Self

Create a ReportAssembler from a dictionary.

Parameters:

Name Type Description Default
data dict[str, Any]

Dictionary containing report data

required

Returns:

Type Description
Self

Reconstructed ReportAssembler instance

Note

This reconstructs the structure but not the reportlet instances. Use this for loading report metadata, not for full reconstruction.

Source code in tit/reporting/core/assembler.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> Self:
    """
    Create a ReportAssembler from a dictionary.

    Args:
        data: Dictionary containing report data

    Returns:
        Reconstructed ReportAssembler instance

    Note:
        This reconstructs the structure but not the reportlet instances.
        Use this for loading report metadata, not for full reconstruction.
    """
    metadata_dict = data.get("metadata", {})
    metadata = ReportMetadata(
        title=metadata_dict.get("title", "Report"),
        subject_id=metadata_dict.get("subject_id"),
        session_id=metadata_dict.get("session_id"),
        report_type=metadata_dict.get("report_type", "general"),
        project_dir=metadata_dict.get("project_dir"),
    )

    assembler = cls(metadata=metadata)

    for section_data in data.get("sections", []):
        assembler.add_section(
            section_id=section_data["section_id"],
            title=section_data["title"],
            description=section_data.get("description"),
            collapsed=section_data.get("collapsed", False),
            order=section_data.get("order", 0),
        )

    return assembler

get_html_template

get_html_template(title: str, content: str, toc_html: str = '', metadata_html: str = '', footer_html: str = '', custom_css: str = '', custom_js: str = '') -> str

Generate a complete HTML document with the report content.

Parameters:

Name Type Description Default
title str

The report title

required
content str

The main HTML content

required
toc_html str

Table of contents HTML

''
metadata_html str

Header metadata HTML

''
footer_html str

Footer HTML

''
custom_css str

Additional CSS styles

''
custom_js str

Additional JavaScript

''

Returns:

Type Description
str

Complete HTML document as a string

Source code in tit/reporting/core/templates.py
def get_html_template(
    title: str,
    content: str,
    toc_html: str = "",
    metadata_html: str = "",
    footer_html: str = "",
    custom_css: str = "",
    custom_js: str = "",
) -> str:
    """
    Generate a complete HTML document with the report content.

    Args:
        title: The report title
        content: The main HTML content
        toc_html: Table of contents HTML
        metadata_html: Header metadata HTML
        footer_html: Footer HTML
        custom_css: Additional CSS styles
        custom_js: Additional JavaScript

    Returns:
        Complete HTML document as a string
    """
    css = DEFAULT_CSS_STYLES
    if custom_css:
        css += f"\n/* Custom Styles */\n{custom_css}"

    js = DEFAULT_JS_SCRIPTS
    if custom_js:
        js += f"\n// Custom Scripts\n{custom_js}"

    nav_html = ""
    if toc_html:
        nav_html = f"""
        <nav class="report-nav">
            <h2>Contents</h2>
            {toc_html}
        </nav>
        """

    footer = footer_html or """
        <footer class="report-footer">
            <p>Generated by <a href="https://github.com/idossha/TI-toolbox" target="_blank">TI-Toolbox</a></p>
        </footer>
    """

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{title}</title>
    <style>
{css}
    </style>
</head>
<body>
    <div class="report-container">
        <header class="report-header">
            <h1>{title}</h1>
            {metadata_html}
        </header>

        {nav_html}

        <main class="report-main">
            {content}
        </main>

        {footer}
    </div>

    <script>
{js}
    </script>
</body>
</html>
"""