Coverage for functions \ flipdare \ mailer \ core \ table_email_formatter.py: 100%
44 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1#!/usr/bin/env python
2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
3#
4# This file is part of Flipdare's proprietary software and contains
5# confidential and copyrighted material. Unauthorised copying,
6# modification, distribution, or use of this file is strictly
7# prohibited without prior written permission from Flipdare Pty Ltd.
8#
9# This software includes third-party components licensed under MIT,
10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
11#
13from __future__ import annotations
15from dataclasses import dataclass
16from typing import override
17import pandas as pd
18from pandas.io.formats.style_render import CSSDict
19from flipdare.app_log import LOG
20from flipdare.app_types import ReportListType
21from flipdare.mailer.core.base_email_formatter import BaseEmailFormatter
22from flipdare.constants import IS_TRACE
23from flipdare.mailer.core.email_sanitizer import EmailPostSanitizer, EmailPreSanitizer
25__all__ = ["TableEmailFormatter"]
28@dataclass(frozen=True)
29class ExtraEmailInfo:
30 title: str
31 message: str
34class TableEmailFormatter(BaseEmailFormatter):
35 def __init__(
36 self,
37 headers: list[str],
38 data: ReportListType,
39 extra: ExtraEmailInfo | None = None,
40 ) -> None:
41 if IS_TRACE:
42 msg = f"Initializing EmailReport with {len(headers)} columns and {len(data)} rows No images."
43 LOG().trace(msg)
45 super().__init__(headers=headers, data=data)
46 self._extra = extra
48 @override
49 def tabulate_text(self) -> str:
50 table_headers = self.headers
51 pre_data = EmailPreSanitizer(self.data).format(is_html=False)
53 df = pd.DataFrame(pre_data, columns=table_headers)
54 txt = df.to_markdown(index=False)
56 extra = self._extra
57 post_data = [txt] if extra is None else [f"{extra.message}", txt]
58 headers = None if extra is None else [extra.title, "Table"]
60 return EmailPostSanitizer(data=post_data, headers=headers).format(is_html=False)
62 @override
63 def tabulate_html(self) -> str:
64 table_headers = self.headers
65 pre_data = EmailPreSanitizer(self.data).format(is_html=True)
67 df = pd.DataFrame(pre_data, columns=table_headers)
68 styler = df.style.hide(axis="index")
69 css_style: list[CSSDict] = [
70 {
71 "selector": "th",
72 "props": [
73 ("background-color", "#f2f2f2"),
74 ("padding", "8px"),
75 ("text-align", "left"),
76 ("border", "1px solid #ddd"),
77 ],
78 },
79 {"selector": "td", "props": [("padding", "8px"), ("border", "1px solid #ddd")]},
80 ]
82 html = styler.set_table_styles(css_style).to_html(index=False, render_links=True)
84 extra = self._extra
85 post_data = [html] if extra is None else [f"<p>{extra.message}</p>", html]
86 headers = None if extra is None else [extra.title, "Table"]
88 return EmailPostSanitizer(data=post_data, headers=headers).format(is_html=True)