jinja2: use jinja2 for html template

This commit is contained in:
Laurier Loiselle 2023-01-23 15:47:45 -05:00
parent fc500b6d45
commit 641b44abf7
No known key found for this signature in database
GPG Key ID: 345920CC72089A3F
10 changed files with 209 additions and 204 deletions

View File

@ -4,3 +4,4 @@ pillow
pyyaml pyyaml
setuptools setuptools
tabulate tabulate
jinja2

View File

@ -23,6 +23,7 @@ setup(
"pillow", "pillow",
"pyyaml", "pyyaml",
"tabulate", "tabulate",
"jinja2",
], ],
license="GPLv3", license="GPLv3",
keywords="cable connector hardware harness wiring wiring-diagram wiring-harness", keywords="cable connector hardware harness wiring wiring-diagram wiring-harness",

View File

@ -3,12 +3,12 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="generator" content="<!-- %generator% -->"> <meta name="generator" content=" {{ generator }}">
<title><!-- %title% --></title> <title> {{ title }}</title>
<style> <style>
body { body {
font-family: <!-- %fontname% -->; font-family: {{ fontname }};
background-color: <!-- %bgcolor% -->; background-color: {{ bgcolor }};
} }
table, td, th, #frame { table, td, th, #frame {
@ -183,107 +183,29 @@
</head> </head>
<body> <body>
<div id="page"> <div id="page">
<div id="frame" class="sheetsize_default"> <div id="frame" class={{ sheetsize_default }}>
<div id="diagram"> <div id="diagram">
<div id="description"> <div id="description">
<!-- %description% --> {{ description }}
</div> </div>
<!-- %diagram% --> {{ diagram }}
<div id="notes"> <div id="notes">
<!-- %notes% --> {{ notes }}
</div> </div>
</div> </div>
<div id="bom"> <div id="bom">
<!-- %bom_reversed% --> {{ bom_reversed }}
</div> </div>
<div id="titleblock"> <div id="titleblock">
<table> {{ titleblock }}
<tr> </div>
<td class="revno"><!-- %revisions_8% --></td>
<td class="changelog"><!-- %revisions_8_changelog% --></td>
<td class="date"><!-- %revisions_8_date% --></td>
<td class="name"><!-- %revisions_8_name% --></td>
<td class="process"></td>
<td class="date">Date</td>
<td class="name">Name</td>
<td class="title" colspan="3" rowspan="5"><!-- %title% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_7% --></td>
<td><!-- %revisions_7_changelog% --></td>
<td><!-- %revisions_7_date% --></td>
<td><!-- %revisions_7_name% --></td>
<td><!-- %authors_1% --></td>
<td><!-- %authors_1_date% --></td>
<td><!-- %authors_1_name% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_6% --></td>
<td><!-- %revisions_6_changelog% --></td>
<td><!-- %revisions_6_date% --></td>
<td><!-- %revisions_6_name% --></td>
<td><!-- %authors_2% --></td>
<td><!-- %authors_2_date% --></td>
<td><!-- %authors_2_name% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_5% --></td>
<td><!-- %revisions_5_changelog% --></td>
<td><!-- %revisions_5_date% --></td>
<td><!-- %revisions_5_name% --></td>
<td><!-- %authors_3% --></td>
<td><!-- %authors_3_date% --></td>
<td><!-- %authors_3_name% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_4% --></td>
<td><!-- %revisions_4_changelog% --></td>
<td><!-- %revisions_4_date% --></td>
<td><!-- %revisions_4_name% --></td>
<td colspan="2"></td>
<td></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_3% --></td>
<td><!-- %revisions_3_changelog% --></td>
<td><!-- %revisions_3_date% --></td>
<td><!-- %revisions_3_name% --></td>
<td class="company" colspan="3" rowspan="3"><!-- %company% --></td>
<td class="partno" colspan="2" rowspan="3"><!-- %pn% --></td>
<td class="sheetno" rowspan="2">Sheet<br /><!-- %sheet_current% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_2% --></td>
<td><!-- %revisions_2_changelog% --></td>
<td><!-- %revisions_2_date% --></td>
<td><!-- %revisions_2_name% --></td>
</tr>
<tr>
<td class="revno"><!-- %revisions_1% --></td>
<td><!-- %revisions_1_changelog% --></td>
<td><!-- %revisions_1_date% --></td>
<td><!-- %revisions_1_name% --></td>
<td class="sheetno">of <!-- %sheet_total% --></td>
</tr>
<tr>
<td>Rev</td>
<td>Changelog</td>
<td>Date</td>
<td>Name</td>
<td colspan="3"></td>
<td></td>
<td colspan="2"></td>
</tr>
</table>
</div> <!-- /titleblock -->
</div> <!-- /frame --> </div> <!-- /frame -->
</div> <!-- /page --> </div> <!-- /page -->
</body> </body>

View File

@ -2,7 +2,7 @@
<html lang="en"><head> <html lang="en"><head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="generator" content="<!-- %generator% -->"> <meta name="generator" content="<!-- %generator% -->">
<title><!-- %title% --></title> <title>{{ title }}</title>
<style> <style>
#bom table, th, td { #bom table, th, td {
@ -20,26 +20,26 @@
} }
</style> </style>
</head><body style="font-family:<!-- %fontname% -->;background-color:<!-- %bgcolor% -->"> </head><body style="font-family:{{ fontname }};background-color:{{ bgcolor }}">
<h1><!-- %title% --></h1> <h1>{{ title }}</h1>
<h2>Diagram</h2> <h2>Diagram</h2>
<div id="description"> <div id="description">
<!-- %description% --> {{ description }}
</div> </div>
<div id="diagram"> <div id="diagram">
<!-- %diagram% --> {{ diagram }}
</div> </div>
<div id="notes"> <div id="notes">
<!-- %notes% --> {{ notes }}
</div> </div>
<h2>Bill of Materials</h2> <h2>Bill of Materials</h2>
<div id="bom"> <div id="bom">
<!-- %bom% --> {{ bom }}
</div> </div>
</body></html> </body></html>

78
src/wireviz/templates/titleblock.html generated Normal file
View File

@ -0,0 +1,78 @@
<table>
<tr>
<td class="revno"> {{ revisions_8 }}</td>
<td class="changelog"> {{ revisions_8_changelog }}</td>
<td class="date"> {{ revisions_8_date }}</td>
<td class="name"> {{ revisions_8_name }}</td>
<td class="process"></td>
<td class="date">Date</td>
<td class="name">Name</td>
<td class="title" colspan="3" rowspan="5"> {{ title }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_7 }}</td>
<td> {{ revisions_7_changelog }}</td>
<td> {{ revisions_7_date }}</td>
<td> {{ revisions_7_name }}</td>
<td> {{ authors_1 }}</td>
<td> {{ authors_1_date }}</td>
<td> {{ authors_1_name }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_6 }}</td>
<td> {{ revisions_6_changelog }}</td>
<td> {{ revisions_6_date }}</td>
<td> {{ revisions_6_name }}</td>
<td> {{ authors_2 }}</td>
<td> {{ authors_2_date }}</td>
<td> {{ authors_2_name }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_5 }}</td>
<td> {{ revisions_5_changelog }}</td>
<td> {{ revisions_5_date }}</td>
<td> {{ revisions_5_name }}</td>
<td> {{ authors_3 }}</td>
<td> {{ authors_3_date }}</td>
<td> {{ authors_3_name }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_4 }}</td>
<td> {{ revisions_4_changelog }}</td>
<td> {{ revisions_4_date }}</td>
<td> {{ revisions_4_name }}</td>
<td colspan="2"></td>
<td></td>
</tr>
<tr>
<td class="revno"> {{ revisions_3 }}</td>
<td> {{ revisions_3_changelog }}</td>
<td> {{ revisions_3_date }}</td>
<td> {{ revisions_3_name }}</td>
<td class="company" colspan="3" rowspan="3"> {{ company }}</td>
<td class="partno" colspan="2" rowspan="3"> {{ pn }}</td>
<td class="sheetno" rowspan="2">Sheet<br /> {{ sheet_current }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_2 }}</td>
<td> {{ revisions_2_changelog }}</td>
<td> {{ revisions_2_date }}</td>
<td> {{ revisions_2_name }}</td>
</tr>
<tr>
<td class="revno"> {{ revisions_1 }}</td>
<td> {{ revisions_1_changelog }}</td>
<td> {{ revisions_1_date }}</td>
<td> {{ revisions_1_name }}</td>
<td class="sheetno">of {{ sheet_total }}</td>
</tr>
<tr>
<td>Rev</td>
<td>Changelog</td>
<td>Date</td>
<td>Name</td>
<td colspan="3"></td>
<td></td>
<td colspan="2"></td>
</tr>
</table>

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import argparse import argparse
from click.testing import CliRunner
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
@ -9,26 +10,27 @@ from pathlib import Path
script_path = Path(__file__).absolute() script_path = Path(__file__).absolute()
sys.path.insert(0, str(script_path.parent.parent.parent)) # to find wireviz module sys.path.insert(0, str(script_path.parent.parent.parent)) # to find wireviz module
from wireviz import APP_NAME, __version__, wireviz from wireviz import APP_NAME, __version__
from wireviz.wv_cli import cli
from wireviz.wv_utils import open_file_append, open_file_read, open_file_write from wireviz.wv_utils import open_file_append, open_file_read, open_file_write
dir = script_path.parent.parent.parent.parent base_dir = script_path.parent.parent.parent.parent
readme = "readme.md" readme = "readme.md"
groups = { groups = {
"examples": { "examples": {
"path": dir / "examples", "path": base_dir / "examples",
"prefix": "ex", "prefix": "ex",
readme: [], # Include no files readme: [], # Include no files
"title": "Example Gallery", "title": "Example Gallery",
}, },
"tutorial": { "tutorial": {
"path": dir / "tutorial", "path": base_dir / "tutorial",
"prefix": "tutorial", "prefix": "tutorial",
readme: ["md", "yml"], # Include .md and .yml files readme: ["md", "yml"], # Include .md and .yml files
"title": f"{APP_NAME} Tutorial", "title": f"{APP_NAME} Tutorial",
}, },
"demos": { "demos": {
"path": dir / "examples", "path": base_dir / "examples",
"prefix": "demo", "prefix": "demo",
}, },
} }
@ -51,6 +53,7 @@ def collect_filenames(description, groupkey, ext_list):
def build_generated(groupkeys): def build_generated(groupkeys):
runner = CliRunner()
for key in groupkeys: for key in groupkeys:
# preparation # preparation
path = groups[key]["path"] path = groups[key]["path"]
@ -62,9 +65,13 @@ def build_generated(groupkeys):
out.write(f'# {groups[key]["title"]}\n\n') out.write(f'# {groups[key]["title"]}\n\n')
# collect and iterate input YAML files # collect and iterate input YAML files
for yaml_file in collect_filenames("Building", key, input_extensions): for yaml_file in collect_filenames("Building", key, input_extensions):
print(f' "{yaml_file}"') res = runner.invoke(cli, args=[
wireviz.parse(yaml_file, output_formats=("gv", "html", "png", "svg", "tsv")) '--format', 'ghpst',
str(yaml_file)
])
if res.exit_code != 0:
raise RuntimeError(f'Cli failed for {yaml_file} with result: {res}') from res.exception
if build_readme: if build_readme:
i = "".join(filter(str.isdigit, yaml_file.stem)) i = "".join(filter(str.isdigit, yaml_file.stem))

View File

@ -111,8 +111,7 @@ def bom_list(bom):
all_designators = sorted(entry["designators"]) all_designators = sorted(entry["designators"])
if len(all_designators) > MAX_DESIGNATORS: if len(all_designators) > MAX_DESIGNATORS:
all_designators = all_designators[:MAX_DESIGNATORS] + ['...'] all_designators = all_designators[:MAX_DESIGNATORS] + ["..."]
cells = [ cells = [
entry["id"], entry["id"],
@ -129,8 +128,8 @@ def bom_list(bom):
hash.partnumbers.pn, hash.partnumbers.pn,
hash.partnumbers.manufacturer, hash.partnumbers.manufacturer,
hash.partnumbers.mpn, hash.partnumbers.mpn,
None, #hash.partnumbers.supplier, None, # hash.partnumbers.supplier,
None, #hash.partnumbers.spn, None, # hash.partnumbers.spn,
] ]
) )
else: else:

View File

@ -129,11 +129,10 @@ def cli(file, format, prepend, output_dir, output_name, version):
raise Exception(f"Path is not a file:\n{file}") raise Exception(f"Path is not a file:\n{file}")
extra_metadata = {} extra_metadata = {}
extra_metadata['name'] = file.stem extra_metadata["name"] = file.stem
extra_metadata['sheet_total'] = len(filepaths) extra_metadata["sheet_total"] = len(filepaths)
extra_metadata['sheet_current'] = sheet_current extra_metadata["sheet_current"] = sheet_current
sheet_current +=1 sheet_current += 1
# file_out = file.with_suffix("") if not output_file else output_file # file_out = file.with_suffix("") if not output_file else output_file
_output_dir = file.parent if not output_dir else output_dir _output_dir = file.parent if not output_dir else output_dir

View File

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
from collections import namedtuple from collections import namedtuple
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from itertools import zip_longest from itertools import zip_longest
import logging
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Tuple, Union
from wireviz.wv_bom import ( from wireviz.wv_bom import (
@ -576,7 +576,9 @@ class Cable(TopLevelGraphicalComponent):
def gauge_str(self): def gauge_str(self):
if not self.gauge: if not self.gauge:
return None return None
number = int(self.gauge.number) if self.gauge.unit == 'AWG' else self.gauge.number number = (
int(self.gauge.number) if self.gauge.unit == "AWG" else self.gauge.number
)
actual_gauge = f"{number} {self.gauge.unit}" actual_gauge = f"{number} {self.gauge.unit}"
actual_gauge = actual_gauge.replace("mm2", "mm\u00B2") actual_gauge = actual_gauge.replace("mm2", "mm\u00B2")
return actual_gauge return actual_gauge
@ -631,59 +633,60 @@ class Cable(TopLevelGraphicalComponent):
return desc return desc
belden_color = { belden_color = {
'BN': '001', "BN": "001",
'RD': '002', "RD": "002",
'OG': '003', "OG": "003",
'YE': '004', "YE": "004",
'GN': '005', "GN": "005",
'TQ': '006', # (For Belden: light blue. For WireViz: turquoise) "TQ": "006", # (For Belden: light blue. For WireViz: turquoise)
'VT': '007', "VT": "007",
'GY': '008', "GY": "008",
'WH': '009', "WH": "009",
'BK': '010', "BK": "010",
'BG': '011', "BG": "011",
'PK': '012', "PK": "012",
'BU': '013', "BU": "013",
'BKRD':'015', # (for Belden: white/red) "BKRD": "015", # (for Belden: white/red)
'BKGN':'016', # (for Belden: white/green) "BKGN": "016", # (for Belden: white/green)
'BKYE':'017', # (for Belden: white/yellow) "BKYE": "017", # (for Belden: white/yellow)
'BKBU':'018', # (for Belden: white/blue) "BKBU": "018", # (for Belden: white/blue)
'BKBN':'019', # (for Belden: white/brown) "BKBN": "019", # (for Belden: white/brown)
'BKOG':'020', # (for Belden: white/orange) "BKOG": "020", # (for Belden: white/orange)
'BKGY':'021', # (for Belden: white/gray) "BKGY": "021", # (for Belden: white/gray)
'BKVT':'022', # (for Belden: white/purple) "BKVT": "022", # (for Belden: white/purple)
# (1) Why use BKRD instead of WHRD, since Belden only sells white/red? # (1) Why use BKRD instead of WHRD, since Belden only sells white/red?
# - WHRD is impractical to use in Wireviz (white wire sides on white background does not help with identification) # - WHRD is impractical to use in Wireviz (white wire sides on white background does not help with identification)
# - BKRD is clearly distinguishable, and comes handy to use in Wireviz, as the representation of a GND rail associated (even twisted, if applicable) with a specific RD signal wire. # - BKRD is clearly distinguishable, and comes handy to use in Wireviz, as the representation of a GND rail associated (even twisted, if applicable) with a specific RD signal wire.
# (2) For all wire colors see: # (2) For all wire colors see:
# https://www.belden.com/dfsmedia/f1e38517e0cd4caa8b1acb6619890f5e/7806-source/options/view/cabling-solutions-for-industrial-applications-catalog-belden-09-2020#page=153 # https://www.belden.com/dfsmedia/f1e38517e0cd4caa8b1acb6619890f5e/7806-source/options/view/cabling-solutions-for-industrial-applications-catalog-belden-09-2020#page=153
} }
belden_tfe_base_mpn = { belden_tfe_base_mpn = {
# Leftmost in list is the prefered MPN # Leftmost in list is the prefered MPN
# NOTE (lal 2022-12-20): this prefered MPN is arbitrary ATM # NOTE (lal 2022-12-20): this prefered MPN is arbitrary ATM
'16 AWG': ['83030', '83010'], "16 AWG": ["83030", "83010"],
'18 AWG': ['83029', '83009'], "18 AWG": ["83029", "83009"],
'20 AWG': ['83028', '83027', '83007', '83008'], "20 AWG": ["83028", "83027", "83007", "83008"],
'22 AWG': ['83025', '83026', '83005', '83006', '83049', '83050'], "22 AWG": ["83025", "83026", "83005", "83006", "83049", "83050"],
'24 AWG': ['83023', '83003', '83004', '83047', '83048'], "24 AWG": ["83023", "83003", "83004", "83047", "83048"],
'26 AWG': ['83002', '83046'], "26 AWG": ["83002", "83046"],
'28 AWG': ['83001', '83045'], "28 AWG": ["83001", "83045"],
'30 AWG': ['83000', '83043'], "30 AWG": ["83000", "83043"],
'32 AWG': ['83041'], "32 AWG": ["83041"],
# see: https://www.belden.com/dfsmedia/f1e38517e0cd4caa8b1acb6619890f5e/7806-source/options/view/cabling-solutions-for-industrial-applications-catalog-belden-09-2020#page=136 # see: https://www.belden.com/dfsmedia/f1e38517e0cd4caa8b1acb6619890f5e/7806-source/options/view/cabling-solutions-for-industrial-applications-catalog-belden-09-2020#page=136
} }
@property @property
def is_belden(self): def is_belden(self):
if 'belden' in self.manufacturer.lower(): if "belden" in self.manufacturer.lower():
return True return True
return False return False
def get_belden_color(self, color): def get_belden_color(self, color):
if color not in self.belden_color: if color not in self.belden_color:
logging.warn(f'No color found in belden colors {list(self.belden_color.keys())} matching {self.color}, defaulting to BK') logging.warn(
return self.belden_color['BK'] f"No color found in belden colors {list(self.belden_color.keys())} matching {self.color}, defaulting to BK"
)
return self.belden_color["BK"]
return self.belden_color[color] return self.belden_color[color]
def gen_belden_cable_with_alternate(self, color): def gen_belden_cable_with_alternate(self, color):
@ -691,16 +694,18 @@ class Cable(TopLevelGraphicalComponent):
try: try:
parts = self.belden_tfe_base_mpn[self.gauge_str] parts = self.belden_tfe_base_mpn[self.gauge_str]
except KeyError: except KeyError:
raise ValueError(f'Couldn\'t find a belden TFE wire for wire of {self.gauge_str}') raise ValueError(
f"Couldn't find a belden TFE wire for wire of {self.gauge_str}"
)
color = self.get_belden_color(color) color = self.get_belden_color(color)
if not color: if not color:
raise ValueError(f'Failed to find a color for property: {self.description}') raise ValueError(f"Failed to find a color for property: {self.description}")
# Create the list of mpn # Create the list of mpn
roll_length = 100 roll_length = 100
mpn_list = [f'{mpn} {color}{roll_length}' for mpn in parts] mpn_list = [f"{mpn} {color}{roll_length}" for mpn in parts]
main_part = mpn_list[0] main_part = mpn_list[0]
alternates = mpn_list[1:] if len(mpn_list) > 1 else [] alternates = mpn_list[1:] if len(mpn_list) > 1 else []
@ -712,11 +717,15 @@ class Cable(TopLevelGraphicalComponent):
main_part, alternates = self.gen_belden_cable_with_alternate(color) main_part, alternates = self.gen_belden_cable_with_alternate(color)
return main_part return main_part
if alternates: if alternates:
logging.info(f'Alternate part{"s" if len(alternates) > 1 else ""} available for {self.gauge_str}, color {self.color}: {alternates}') logging.info(
f'Alternate part{"s" if len(alternates) > 1 else ""} available for {self.gauge_str}, color {self.color}: {alternates}'
)
else: else:
logging.info(f'Not updating part for manufacturer {self.manufacturer}, only "belden" supported') logging.info(
f'Not updating part for manufacturer {self.manufacturer}, only "belden" supported'
)
else: else:
logging.info(f'Not updating part, no manufacturer provided') logging.info(f"Not updating part, no manufacturer provided")
return mpn return mpn
def _get_wire_partnumber(self, idx, color) -> PartNumberInfo: def _get_wire_partnumber(self, idx, color) -> PartNumberInfo:
@ -725,8 +734,8 @@ class Cable(TopLevelGraphicalComponent):
# TODO: possibly make more robust/elegant # TODO: possibly make more robust/elegant
if self.category == "bundle": if self.category == "bundle":
manufacturer = _get_correct_element(self.partnumbers.manufacturer, idx), manufacturer = (_get_correct_element(self.partnumbers.manufacturer, idx),)
mpn = _get_correct_element(self.partnumbers.mpn, idx), mpn = (_get_correct_element(self.partnumbers.mpn, idx),)
if color is not None: if color is not None:
mpn = self.get_mpn_if_belden(manufacturer, mpn, color.code_en) mpn = self.get_mpn_if_belden(manufacturer, mpn, color.code_en)

View File

@ -5,15 +5,12 @@ import re
from pathlib import Path from pathlib import Path
from typing import Dict, List, Union from typing import Dict, List, Union
import jinja2
import wireviz # for doing wireviz.__file__ import wireviz # for doing wireviz.__file__
from wireviz import APP_NAME, APP_URL, __version__ from wireviz import APP_NAME, APP_URL, __version__
from wireviz.wv_dataclasses import Metadata, Options from wireviz.wv_dataclasses import Metadata, Options
from wireviz.wv_utils import ( from wireviz.wv_utils import html_line_breaks, open_file_read, open_file_write
html_line_breaks,
open_file_read,
open_file_write,
smart_file_resolve,
)
mime_subtype_replacements = {"jpg": "jpeg", "tif": "tiff"} mime_subtype_replacements = {"jpg": "jpeg", "tif": "tiff"}
@ -62,27 +59,24 @@ def embed_svg_images_file(
filename_out.replace(filename_in) filename_out.replace(filename_in)
def get_template_html(template_name):
template_file_path = jinja2.FileSystemLoader(
Path(wireviz.__file__).parent / "templates"
)
jinja_env = jinja2.Environment(loader=template_file_path)
return jinja_env.get_template(template_name + ".html")
def generate_html_output( def generate_html_output(
filename: Union[str, Path], filename: Union[str, Path],
bom: List[List[str]], bom: List[List[str]],
metadata: Metadata, metadata: Metadata,
options: Options, options: Options,
): ):
print("Generating html output")
# load HTML template template_name = metadata.get("template", {}).get("name", "simple")
templatename = metadata.get("template", {}).get("name") page_template = get_template_html(template_name)
if templatename:
# if relative path to template was provided,
# check directory of YAML file first, fall back to built-in template directory
templatefile = smart_file_resolve(
f"{templatename}.html",
[Path(filename).parent, Path(__file__).parent / "templates"],
)
else:
# fall back to built-in simple template if no template was provided
templatefile = Path(wireviz.__file__).parent / "templates/simple.html"
html = open_file_read(templatefile).read()
# embed SVG diagram # embed SVG diagram
with open_file_read(f"{filename}.tmp.svg") as file: with open_file_read(f"{filename}.tmp.svg") as file:
@ -122,51 +116,46 @@ def generate_html_output(
) )
if metadata: if metadata:
sheet_current = metadata['sheet_current'] sheet_current = metadata["sheet_current"]
sheet_total = metadata['sheet_total'] sheet_total = metadata["sheet_total"]
else: else:
sheet_current = 1 sheet_current = 1
sheet_total = 1 sheet_total = 1
# prepare simple replacements
replacements = { replacements = {
"<!-- %generator% -->": f"{APP_NAME} {__version__} - {APP_URL}", "title": "pizza",
"<!-- %fontname% -->": options.fontname, "generator": f"{APP_NAME} {__version__} - {APP_URL}",
"<!-- %bgcolor% -->": options.bgcolor.html, "fontname": options.fontname,
"<!-- %diagram% -->": svgdata, "bgcolor": options.bgcolor.html,
"<!-- %bom% -->": bom_html, "diagram": svgdata,
"<!-- %bom_reversed% -->": bom_html_reversed, "bom": bom_html,
"<!-- %sheet_current% -->": sheet_current, "bom_reversed": bom_html_reversed,
"<!-- %sheet_total% -->": sheet_total, "sheet_current": sheet_current,
"sheet_total": sheet_total,
} }
# prepare metadata replacements # prepare metadata replacements
if metadata: if metadata:
for item, contents in metadata.items(): for item, contents in metadata.items():
if isinstance(contents, (str, int, float)): if isinstance(contents, (str, int, float)):
replacements[f"<!-- %{item}% -->"] = html_line_breaks(str(contents)) replacements[str(item)] = html_line_breaks(str(contents))
elif isinstance(contents, Dict): # useful for authors, revisions elif isinstance(contents, Dict): # useful for authors, revisions
for index, (category, entry) in enumerate(contents.items()): for index, (category, entry) in enumerate(contents.items()):
if isinstance(entry, Dict): if isinstance(entry, Dict):
replacements[f"<!-- %{item}_{index+1}% -->"] = str(category) replacements[f"{item}_{index+1}"] = str(category)
for entry_key, entry_value in entry.items(): for entry_key, entry_value in entry.items():
replacements[ replacements[
f"<!-- %{item}_{index+1}_{entry_key}% -->" f"{item}_{index+1}_{entry_key}"
] = html_line_breaks(str(entry_value)) ] = html_line_breaks(str(entry_value))
replacements['"sheetsize_default"'] = '"{}"'.format( replacements[
metadata.get("template", {}).get("sheetsize", "") "sheetsize_default"
) ] = f'{metadata.get("template", {}).get("sheetsize", "sheetsize_default")}'
# include quotes so no replacement happens within <style> definition # include quotes so no replacement happens within <style> definition
# perform replacements # prepare titleblock
# regex replacement adapted from: titleblock_template = get_template_html("titleblock")
# https://gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729 replacements["titleblock"] = titleblock_template.render(replacements)
# longer replacements first, just in case page_rendered = page_template.render(replacements)
replacements_sorted = sorted(replacements, key=len, reverse=True) open_file_write(f"{filename}.html").write(page_rendered)
replacements_escaped = map(re.escape, replacements_sorted)
pattern = re.compile("|".join(replacements_escaped))
html = pattern.sub(lambda match: replacements[match.group(0)], html)
open_file_write(f"{filename}.html").write(html)