113 lines
4.2 KiB
Python
Executable File
113 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import csv
|
|
import sys
|
|
import logging
|
|
from typing import Optional
|
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
components_csv_path = sys.argv[1]
|
|
|
|
MIN_TEMP_C: int = -10
|
|
MAX_TEMP_C: int = 70
|
|
|
|
class ComponentsWarning:
|
|
def __init__(self):
|
|
self.part_number: Optional[str] = None
|
|
self.refs: list[str] = []
|
|
self.warnings: list[str] = []
|
|
|
|
report_context = {
|
|
"component_warnings": [],
|
|
"warning_count": 0,
|
|
"total_components": 0,
|
|
"min_temp": MIN_TEMP_C,
|
|
"max_temp": MAX_TEMP_C,
|
|
}
|
|
|
|
class CustomFormatter(logging.Formatter):
|
|
grey = "\x1b[38;20m"
|
|
yellow = "\x1b[33;20m"
|
|
red = "\x1b[31;20m"
|
|
reset = "\x1b[0m"
|
|
format = "%(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
|
|
|
|
FORMATS = {
|
|
logging.DEBUG: grey + format + reset,
|
|
logging.INFO: grey + format + reset,
|
|
logging.WARNING: yellow + format + reset,
|
|
logging.ERROR: red + format + reset,
|
|
}
|
|
|
|
def format(self, record):
|
|
log_fmt = self.FORMATS.get(record.levelno)
|
|
formatter = logging.Formatter(log_fmt)
|
|
return formatter.format(record)
|
|
|
|
# Add formatted logging
|
|
logger = logging.getLogger()
|
|
logger.setLevel(logging.INFO)
|
|
ch = logging.StreamHandler()
|
|
|
|
ch.setFormatter(CustomFormatter())
|
|
logger.addHandler(ch)
|
|
|
|
with open(components_csv_path, newline="") as components_csv:
|
|
spamreader = csv.DictReader(components_csv, delimiter=",")
|
|
|
|
component_count = 0
|
|
|
|
for row in spamreader:
|
|
component_count += 1
|
|
component = ComponentsWarning()
|
|
component.refs = row['Designator'].split(', ')
|
|
if row["Part Number"] == '':
|
|
component.warnings.append("No `Part Number` attribute!")
|
|
elif row["Part Number"] == "NA":
|
|
logger.warning(f"Designators(s) {row['Designator']} have `NA` Part Number!")
|
|
component.warnings.append("`NA` `Part Number` attribute!")
|
|
elif row["Part Number"].startswith("TMP"):
|
|
logger.warning(
|
|
f"Designator(s) {row['Designator']} have temporary Part Number!"
|
|
)
|
|
component.warnings.append("`TMP*` `Part Number` attribute!")
|
|
else:
|
|
component.part_number = row["Part Number"]
|
|
if row["Temperature"] == "":
|
|
logger.warning(
|
|
f"Designators(s) {row['Designator']} have no `Temperature` attribute!"
|
|
)
|
|
component.warnings.append("No `Temperature` attribute!")
|
|
else:
|
|
try:
|
|
min_temp, max_temp = [int(x.strip("¡ãC ")) for x in row["Temperature"].split(" to ")]
|
|
except ValueError:
|
|
logger.warning(
|
|
f"Designators(s) {row['Designator']} have malformed `Temperature` attribute: !"
|
|
)
|
|
component.warnings.append(f"Malformed `Temperature` attribute: `{row['Temperature']}`!")
|
|
else:
|
|
if min_temp > MIN_TEMP_C:
|
|
logger.warning(
|
|
f"Designators(s) {row['Designator']} minimum operating temperate `{min_temp}°C` exceeds requirement of `{MIN_TEMP_C}°C`!"
|
|
)
|
|
component.warnings.append(f"Minimum operating temperate `{min_temp}°C` exceeds requirement of `{MIN_TEMP_C}°C`!")
|
|
if max_temp < MAX_TEMP_C:
|
|
logger.warning(
|
|
f"Designators(s) {row['Designator']} maximum operating temperate `{max_temp}°C` doesn't meet requirement of `{MAX_TEMP_C}°C`!"
|
|
)
|
|
component.warnings.append(f"Maximum operating temperate `{max_temp}°C` doesn't meet requirement of `{MAX_TEMP_C}°C`!")
|
|
if len(component.warnings):
|
|
report_context["component_warnings"].append(component)
|
|
report_context["warning_count"] += 1
|
|
|
|
report_context["total_components"] = component_count
|
|
|
|
# Load Jinja with output HTML template
|
|
template_env = Environment(loader=FileSystemLoader("./.allspice/report_template/"), trim_blocks=True, lstrip_blocks=True)
|
|
template = template_env.get_template("report.template.md")
|
|
|
|
with open("./.allspice/report.md", mode="w", encoding="utf-8") as report_file:
|
|
report_file.write(template.render(report_context))
|