Source code for pyicat_plus.metadata.drac_report_builder

import base64
import html
import json
import os
import tempfile
import time
from typing import Any
from typing import Dict
from typing import List
from typing import Optional

import PIL.Image

from ..utils import html_utils

REPORT_VERSION = 1.0


[docs] class DracReportBuilder(object): """Build a json and/or html file compatible with Drac dataset reports. Example: report = DracReportBuilder( dataset_type="Characterisation", dataset_title="Characterisation Results", ) report.add_info("This is a demo info item.") report.add_table( title="Sample Table", columns=["Name", "Value"], data=[["Alpha", 1], ["Beta", 2]], ) report.add_image("/path/to/image.png", image_title="Preview") report.render_json("report.json") """ def __init__(self, dataset_type: str, dataset_title: str = "") -> None: self.image_list: Optional[Dict[str, Any]] = None self.dict_report: Dict[str, Any] = {} self.dict_report["version"] = REPORT_VERSION self.dict_report["type"] = dataset_type self.dict_report["title"] = dataset_title self.dict_report["items"] = []
[docs] def set_title(self, dataset_title: str) -> None: self.dict_report["title"] = dataset_title
[docs] def add_info(self, info_text: str) -> None: self.dict_report["items"].append({"type": "info", "value": info_text})
[docs] def add_warning(self, info_text: str) -> None: self.dict_report["items"].append({"type": "warning", "value": info_text})
[docs] def start_image_list(self) -> None: self.image_list = {} self.image_list["type"] = "images" self.image_list["items"] = []
[docs] def end_image_list(self) -> None: self.dict_report["items"].append(self.image_list) self.image_list = None
def _create_image_item( self, path_to_image: str, image_title: str, path_to_thumbnail_image: Optional[str] = None, thumbnail_height: Optional[int] = None, thumbnail_width: Optional[int] = None, ) -> Dict[str, Any]: item: Dict[str, Any] = {} item["type"] = "image" item["suffix"] = path_to_image.split(".")[-1] item["title"] = image_title with PIL.Image.open(path_to_image) as image: item["xsize"] = image.size[0] item["ysize"] = image.size[1] with open(path_to_image, "rb") as image_file: item["value"] = base64.b64encode(image_file.read()).decode("utf-8") if path_to_thumbnail_image is None: if thumbnail_height is not None and thumbnail_width is not None: item["thumbnailSuffix"] = path_to_image.split(".")[-1] item["thumbnailXsize"] = thumbnail_height item["thumbnailYsize"] = thumbnail_width with open(path_to_image, "rb") as image_file: item["thumbnailValue"] = base64.b64encode(image_file.read()) else: item["thumbnailSuffix"] = path_to_thumbnail_image.split(".")[-1] with PIL.Image.open(path_to_thumbnail_image) as thumbnail_im: item["thumbnailXsize"] = thumbnail_im.size[0] item["thumbnailYsize"] = thumbnail_im.size[1] with open(path_to_thumbnail_image, "rb") as thumbnail_file: item["thumbnailValue"] = base64.b64encode(thumbnail_file.read()).decode( "utf-8" ) return item
[docs] def add_image( self, path_to_image: str, image_title: str = "", path_to_thumbnail_image: Optional[str] = None, thumbnail_height: Optional[int] = None, thumbnail_width: Optional[int] = None, ) -> None: if self.image_list is None: self.dict_report["items"].append( self._create_image_item( path_to_image, image_title, path_to_thumbnail_image, thumbnail_height, thumbnail_width, ) ) else: self.image_list["items"].append( self._create_image_item( path_to_image, image_title, path_to_thumbnail_image, thumbnail_height, thumbnail_width, ) )
[docs] def add_table( self, title: str, columns: List[str], data: List[List[Any]], orientation: str = "horizontal", ) -> None: item: Dict[str, Any] = {} item["type"] = "table" item["title"] = title item["columns"] = columns item["data"] = data item["orientation"] = orientation self.dict_report["items"].append(item)
[docs] def add_log_file(self, title: str, link_text: str, path_to_log_file: str) -> None: item: Dict[str, Any] = {} item["type"] = "logFile" item["title"] = title item["link_text"] = link_text with open(path_to_log_file, "r", encoding="utf-8", errors="ignore") as log_file: item["logText"] = log_file.read() self.dict_report["items"].append(item)
[docs] def get_dict_report(self) -> Dict[str, Any]: return self.dict_report
[docs] def render_json(self, path_to_json_dir: str) -> str: path_to_json_file = os.path.join(path_to_json_dir, "report.json") with open(path_to_json_file, "w") as json_file: json_file.write(json.dumps(self.dict_report, indent=4)) return path_to_json_file
[docs] def escape_characters(self, str_value: str) -> str: str_value = html.escape(str_value) str_value = str_value.replace(str("Å"), "&Aring;") str_value = str_value.replace(str("°"), "&deg;") str_value = str_value.replace("\n", "<br>") return str_value
[docs] def render_html( self, path_to_html_dir: str, name_of_index_file: str = "index.html" ) -> str: page = html_utils.HtmlPage(mode="loose_html") page.init( title=self.dict_report["title"], footer="Generated on %s" % time.asctime() ) page.div(align_="LEFT") page.h1() page.strong(self.dict_report["title"]) page.h1.close() page.div.close() for item in self.dict_report["items"]: if "value" in item: item_value = item["value"] if "title" in item: item_title = self.escape_characters(item["title"]) if item["type"] == "info": page.p(item_value) if item["type"] == "warning": page.font(_color="red", size="+1") page.p() page.strong(item_value) page.p.close() page.font.close() elif item["type"] == "image": self._render_image(page, item, path_to_html_dir) page.br() page.p(item_title) elif item["type"] == "images": page.table() page.tr(align_="CENTER") for item in item["items"]: item_title = self.escape_characters(item["title"]) page.td() page.table() page.tr() page.td() self._render_image(page, item, path_to_html_dir) page.td.close() page.tr.close() page.tr(align_="CENTER") page.td(item_title) page.tr.close() page.table.close() page.td.close() page.tr.close() page.table.close() page.br() elif item["type"] == "table": title_bg_colour = "#99c2ff" column_title_bg_colour = "#ffffff" data_bg_colour = "#e6f0ff" page.table( border_="1", cellpadding_="2", width="100%", style_=( "border: 1px solid black; border-collapse: collapse; margin:" " 0px; font-size: 12px" ), ) page.tr(align_="LEFT") # page.strong(item_title) page.th( item_title, bgcolor_=title_bg_colour, align_="LEFT", style_=( "border: 1px solid black; border-collapse: collapse; padding:" " 5px;" ), colspan_=str(len(item["columns"])), ) page.tr.close() if "orientation" in item and item["orientation"] == "vertical": for index1 in range(len(item["columns"])): item_column = self.escape_characters(item["columns"][index1]) page.tr(align_="LEFT") page.th( item_column, bgcolor_=column_title_bg_colour, align_="LEFT", style_=( "border: 1px solid black; border-collapse: collapse;" " padding: 5px;" ), ) for index2 in range(len(item["data"])): item_data = self.escape_characters( str(item["data"][index2][index1]) ) page.th( item_data, bgcolor_=data_bg_colour, style_="padding: 5px;", ) page.tr.close() else: page.tr( align_="LEFT", bgcolor_=column_title_bg_colour, style_=( "border: 1px solid black; border-collapse: collapse;" " padding: 5px;" ), ) for column in item["columns"]: item_column = self.escape_characters(column) page.th( item_column, style_=( "border: 1px solid black; border-collapse: collapse;" " padding: 5px;" ), ) page.tr.close() for list_row in item["data"]: page.tr( align_="LEFT", bgcolor_=data_bg_colour, style_="border-collapse: collapse; padding: 5px;", ) for cell in list_row: item_cell = self.escape_characters(str(cell)) page.th( item_cell, style_=( "border: 1px solid black; border-collapse:" " collapse; padding: 5px;" ), ) page.tr.close() page.table.close() page.br() elif item["type"] == "logFile": path_to_log_html = os.path.join(path_to_html_dir, item_title + ".html") if os.path.exists(path_to_log_html): fd, path_to_log_html = tempfile.mkstemp( suffix=".html", prefix=item_title.replace(" ", "_") + "_", dir=path_to_html_dir, ) os.close(fd) page_log_html = html_utils.HtmlPage() page_log_html.h1(item_title) page_log_html.pre(page.escape(item["logText"])) with open(path_to_log_html, "w") as log_html_file: log_html_file.write(str(page_log_html)) os.chmod(path_to_log_html, 0o644) page.p() page.a(item["link_text"], href_=os.path.basename(path_to_log_html)) page.p.close() html = str(page) page_path = os.path.join(path_to_html_dir, name_of_index_file) with open(page_path, "w") as file_page: file_page.write(html) return page_path
def _render_image( self, page: Any, item: Dict[str, Any], path_to_html_dir: str ) -> None: image_name = item["title"].replace(" ", "_") path_to_image = os.path.join( path_to_html_dir, "{0}.{1}".format(image_name, item["suffix"]) ) if os.path.exists(path_to_image): fd, path_to_image = tempfile.mkstemp( suffix="." + item["suffix"], prefix=image_name + "_", dir=path_to_html_dir, ) os.close(fd) with open(path_to_image, "wb") as image_file: image_file.write(base64.b64decode(item["value"])) os.chmod(path_to_image, 0o644) if "thumbnailValue" in item: thumbnail_image_name = image_name + "_thumbnail" path_to_thumbnail_image = os.path.join( path_to_html_dir, "{0}.{1}".format(thumbnail_image_name, item["suffix"]) ) if os.path.exists(path_to_thumbnail_image): fd, path_to_thumbnail_image = tempfile.mkstemp( suffix="." + item["suffix"], prefix=thumbnail_image_name + "_", dir=path_to_html_dir, ) os.close(fd) with open(path_to_thumbnail_image, "wb") as thumbnail_file: thumbnail_file.write(base64.b64decode(item["thumbnailValue"])) os.chmod(path_to_thumbnail_image, 0o644) page_reference_image = html_utils.HtmlPage(mode="loose_html") page_reference_image.init( title=image_name, footer="Generated on %s" % time.asctime() ) page_reference_image.h1(image_name) page_reference_image.br() page_reference_image.img( src=os.path.basename(path_to_image), title=image_name, width=item["xsize"], height=item["ysize"], ) page_reference_image.br() path_page_reference_image = os.path.join( path_to_html_dir, "{0}.html".format(image_name) ) with open(path_page_reference_image, "w") as file_page: file_page.write(str(page_reference_image)) page.a(href=os.path.basename(path_page_reference_image)) page.img( src=os.path.basename(path_to_thumbnail_image), title=image_name, width=item["thumbnailXsize"], height=item["thumbnailYsize"], ) page.a.close() else: page.img( src=os.path.basename(path_to_image), title=item["title"], width=item["xsize"], height=item["ysize"], )