diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py
index 8c07296..1cc1ec6 100644
--- a/src/wireviz/Harness.py
+++ b/src/wireviz/Harness.py
@@ -33,10 +33,12 @@ from wireviz.wv_bom import (
)
from wireviz.wv_colors import get_color_hex, translate_color
from wireviz.wv_gv_html import (
+ apply_dot_tweaks,
gv_connector_loops,
gv_node_component,
html_line_breaks,
remove_links,
+ set_dot_basics,
)
from wireviz.wv_helper import (
flatten2d,
@@ -145,27 +147,7 @@ class Harness:
def create_graph(self) -> Graph:
dot = Graph()
- dot.body.append(f"// Graph generated by {APP_NAME} {__version__}\n")
- dot.body.append(f"// {APP_URL}\n")
- dot.attr(
- "graph",
- rankdir="LR",
- ranksep="2",
- bgcolor=wv_colors.translate_color(self.options.bgcolor, "HEX"),
- nodesep="0.33",
- fontname=self.options.fontname,
- )
- dot.attr(
- "node",
- shape="none",
- width="0",
- height="0",
- margin="0", # Actual size of the node is entirely determined by the label.
- style="filled",
- fillcolor=wv_colors.translate_color(self.options.bgcolor_node, "HEX"),
- fontname=self.options.fontname,
- )
- dot.attr("edge", style="bold", fontname=self.options.fontname)
+ set_dot_basics(dot, self.options)
for connector in self.connectors.values():
# generate connector node
@@ -212,7 +194,6 @@ class Harness:
html = []
-
wirehtml = []
# conductor table
wirehtml.append('
')
@@ -405,70 +386,7 @@ class Harness:
fillcolor=translate_color(bgcolor, "HEX"),
)
- def typecheck(name: str, value: Any, expect: type) -> None:
- if not isinstance(value, expect):
- raise Exception(
- f"Unexpected value type of {name}: Expected {expect}, got {type(value)}\n{value}"
- )
-
- # TODO?: Differ between override attributes and HTML?
- if self.tweak.override is not None:
- typecheck("tweak.override", self.tweak.override, dict)
- for k, d in self.tweak.override.items():
- typecheck(f"tweak.override.{k} key", k, str)
- typecheck(f"tweak.override.{k} value", d, dict)
- for a, v in d.items():
- typecheck(f"tweak.override.{k}.{a} key", a, str)
- typecheck(f"tweak.override.{k}.{a} value", v, (str, type(None)))
-
- # Override generated attributes of selected entries matching tweak.override.
- for i, entry in enumerate(dot.body):
- if isinstance(entry, str):
- # Find a possibly quoted keyword after leading TAB(s) and followed by [ ].
- match = re.match(
- r'^\t*(")?((?(1)[^"]|[^ "])+)(?(1)") \[.*\]$', entry, re.S
- )
- keyword = match and match[2]
- if keyword in self.tweak.override.keys():
- for attr, value in self.tweak.override[keyword].items():
- if value is None:
- entry, n_subs = re.subn(
- f'( +)?{attr}=("[^"]*"|[^] ]*)(?(1)| *)', "", entry
- )
- if n_subs < 1:
- print(
- f"Harness.create_graph() warning: {attr} not found in {keyword}!"
- )
- elif n_subs > 1:
- print(
- f"Harness.create_graph() warning: {attr} removed {n_subs} times in {keyword}!"
- )
- continue
-
- if len(value) == 0 or " " in value:
- value = value.replace('"', r"\"")
- value = f'"{value}"'
- entry, n_subs = re.subn(
- f'{attr}=("[^"]*"|[^] ]*)', f"{attr}={value}", entry
- )
- if n_subs < 1:
- # If attr not found, then append it
- entry = re.sub(r"\]$", f" {attr}={value}]", entry)
- elif n_subs > 1:
- print(
- f"Harness.create_graph() warning: {attr} overridden {n_subs} times in {keyword}!"
- )
-
- dot.body[i] = entry
-
- if self.tweak.append is not None:
- if isinstance(self.tweak.append, list):
- for i, element in enumerate(self.tweak.append, 1):
- typecheck(f"tweak.append[{i}]", element, str)
- dot.body.extend(self.tweak.append)
- else:
- typecheck("tweak.append", self.tweak.append, str)
- dot.body.append(self.tweak.append)
+ apply_dot_tweaks(dot, self.tweak)
for mate in self.mates:
if mate.shape[0] == "<" and mate.shape[-1] == ">":
diff --git a/src/wireviz/wv_gv_html.py b/src/wireviz/wv_gv_html.py
index 002c8ac..af11743 100644
--- a/src/wireviz/wv_gv_html.py
+++ b/src/wireviz/wv_gv_html.py
@@ -2,8 +2,9 @@
import re
from itertools import zip_longest
-from typing import List, Optional, Union
+from typing import Any, List, Optional, Union
+from wireviz import APP_NAME, APP_URL, __version__
from wireviz.DataClasses import Cable, Color, Component, Connector, Options
from wireviz.wv_colors import get_color_hex, translate_color
from wireviz.wv_helper import pn_info_string, remove_links
@@ -356,3 +357,95 @@ def html_size_attr_dict(image):
def html_line_breaks(inp):
return remove_links(inp).replace("\n", "
") if isinstance(inp, str) else inp
+
+
+def set_dot_basics(dot, options):
+ dot.body.append(f"// Graph generated by {APP_NAME} {__version__}\n")
+ dot.body.append(f"// {APP_URL}\n")
+ dot.attr(
+ "graph",
+ rankdir="LR",
+ ranksep="2",
+ bgcolor=translate_color(options.bgcolor, "HEX"),
+ nodesep="0.33",
+ fontname=options.fontname,
+ )
+ dot.attr(
+ "node",
+ shape="none",
+ width="0",
+ height="0",
+ margin="0", # Actual size of the node is entirely determined by the label.
+ style="filled",
+ fillcolor=translate_color(options.bgcolor_node, "HEX"),
+ fontname=options.fontname,
+ )
+ dot.attr("edge", style="bold", fontname=options.fontname)
+
+
+def apply_dot_tweaks(dot, tweak):
+ def typecheck(name: str, value: Any, expect: type) -> None:
+ if not isinstance(value, expect):
+ raise Exception(
+ f"Unexpected value type of {name}: Expected {expect}, got {type(value)}\n{value}"
+ )
+
+ # TODO?: Differ between override attributes and HTML?
+ if tweak.override is not None:
+ typecheck("tweak.override", tweak.override, dict)
+ for k, d in tweak.override.items():
+ typecheck(f"tweak.override.{k} key", k, str)
+ typecheck(f"tweak.override.{k} value", d, dict)
+ for a, v in d.items():
+ typecheck(f"tweak.override.{k}.{a} key", a, str)
+ typecheck(f"tweak.override.{k}.{a} value", v, (str, type(None)))
+
+ # Override generated attributes of selected entries matching tweak.override.
+ for i, entry in enumerate(dot.body):
+ if not isinstance(entry, str):
+ continue
+ # Find a possibly quoted keyword after leading TAB(s) and followed by [ ].
+ match = re.match(r'^\t*(")?((?(1)[^"]|[^ "])+)(?(1)") \[.*\]$', entry, re.S)
+ keyword = match and match[2]
+ if not keyword in tweak.override.keys():
+ continue
+
+ for attr, value in tweak.override[keyword].items():
+ if value is None:
+ entry, n_subs = re.subn(
+ f'( +)?{attr}=("[^"]*"|[^] ]*)(?(1)| *)', "", entry
+ )
+ if n_subs < 1:
+ print(
+ f"Harness.create_graph() warning: {attr} not found in {keyword}!"
+ )
+ elif n_subs > 1:
+ print(
+ f"Harness.create_graph() warning: {attr} removed {n_subs} times in {keyword}!"
+ )
+ continue
+
+ if len(value) == 0 or " " in value:
+ value = value.replace('"', r"\"")
+ value = f'"{value}"'
+ entry, n_subs = re.subn(
+ f'{attr}=("[^"]*"|[^] ]*)', f"{attr}={value}", entry
+ )
+ if n_subs < 1:
+ # If attr not found, then append it
+ entry = re.sub(r"\]$", f" {attr}={value}]", entry)
+ elif n_subs > 1:
+ print(
+ f"Harness.create_graph() warning: {attr} overridden {n_subs} times in {keyword}!"
+ )
+
+ dot.body[i] = entry
+
+ if tweak.append is not None:
+ if isinstance(tweak.append, list):
+ for i, element in enumerate(tweak.append, 1):
+ typecheck(f"tweak.append[{i}]", element, str)
+ dot.body.extend(tweak.append)
+ else:
+ typecheck("tweak.append", tweak.append, str)
+ dot.body.append(tweak.append)