Skip to content

Commit b82c7fe

Browse files
committed
Add optional tweak per node with name placeholder
Implements feature suggested in #349
1 parent a3281b0 commit b82c7fe

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

docs/syntax.md

+14
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ tweak: # optional tweaking of .gv output
8585
# loops
8686
loops: <List> # every list item is itself a list of exactly two pins
8787
# on the connector that are to be shorted
88+
89+
# optional tweaking of .gv output executed for each instance of this connector
90+
tweak: # see below
91+
8892
```
8993

9094
## Cable attributes
@@ -148,6 +152,9 @@ tweak: # optional tweaking of .gv output
148152
show_wirecount: <bool> # defaults to true
149153
show_wirenumbers: <bool> # defaults to true for cables; false for bundles
150154

155+
# optional tweaking of .gv output executed for each instance of this cable
156+
tweak: # see below
157+
151158
```
152159

153160
## Connection sets
@@ -446,6 +453,13 @@ Alternatively items can be added to just the BOM by putting them in the section
446453
# This feature is experimental and might change
447454
# or be removed in future versions.
448455
456+
placeholder: <str> # Substring to be replaced with node name
457+
# An empty string as placeholder disable replacements.
458+
# When placeholder is absent, the global placeholder is used.
459+
# For tweak sections in connectors and cables, all substrings
460+
# matching the placeholder text will be replaced with the name
461+
# of connector/cable in all override and append entries.
462+
449463
override: # dict of .gv entries to override
450464
# Each entry is identified by its leading string
451465
# in lines beginning with a TAB character.

src/wireviz/DataClasses.py

+7
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __post_init__(self):
7272

7373
@dataclass
7474
class Tweak:
75+
placeholder: Optional[PlainText] = None
7576
override: Optional[Dict[Designator, Dict[str, Optional[str]]]] = None
7677
append: Union[str, List[str], None] = None
7778

@@ -164,11 +165,14 @@ class Connector:
164165
loops: List[List[Pin]] = field(default_factory=list)
165166
ignore_in_bom: bool = False
166167
additional_components: List[AdditionalComponent] = field(default_factory=list)
168+
tweak: Optional[Tweak] = None
167169

168170
def __post_init__(self) -> None:
169171

170172
if isinstance(self.image, dict):
171173
self.image = Image(**self.image)
174+
if self.tweak is not None:
175+
self.tweak = Tweak(**self.tweak)
172176

173177
self.ports_left = False
174178
self.ports_right = False
@@ -274,11 +278,14 @@ class Cable:
274278
show_wirenumbers: Optional[bool] = None
275279
ignore_in_bom: bool = False
276280
additional_components: List[AdditionalComponent] = field(default_factory=list)
281+
tweak: Optional[Tweak] = None
277282

278283
def __post_init__(self) -> None:
279284

280285
if isinstance(self.image, dict):
281286
self.image = Image(**self.image)
287+
if self.tweak is not None:
288+
self.tweak = Tweak(**self.tweak)
282289

283290
if isinstance(self.gauge, str): # gauge and unit specified
284291
try:

src/wireviz/Harness.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
MatePin,
1818
Metadata,
1919
Options,
20-
Tweak,
2120
Side,
21+
Tweak,
2222
)
2323
from wireviz.svgembed import embed_svg_images_file
2424
from wireviz.wv_bom import (
@@ -29,6 +29,7 @@
2929
component_table_entry,
3030
generate_bom,
3131
get_additional_component_table,
32+
make_list,
3233
pn_info_string,
3334
)
3435
from wireviz.wv_colors import get_color_hex, translate_color
@@ -78,12 +79,42 @@ def __post_init__(self):
7879
self._bom = [] # Internal Cache for generated bom
7980
self.additional_bom_items = []
8081

82+
def extend_tweak(self, node: Union[Connector, Cable]) -> None:
83+
"""Extend self.tweak with node.tweak after replacing placeholders."""
84+
if node.tweak:
85+
ph = node.tweak.placeholder
86+
# An empty string is a legal value to avoid the global placeholder
87+
if ph is None: # This must therefore be a test for None!
88+
ph = self.tweak.placeholder # Use the global placeholder
89+
# Create function rph() to replace any placeholder with node name
90+
rph = (lambda s: s.replace(ph, node.name)) if ph else lambda s: s
91+
n_override = node.tweak.override or {}
92+
s_override = self.tweak.override or {}
93+
for id, n_dict in n_override.items():
94+
id = rph(id)
95+
s_dict = s_override.get(id, {})
96+
for k, v in n_dict.items():
97+
k, v = rph(k), rph(v)
98+
if k in s_dict and v != s_dict[k]:
99+
raise ValueError(
100+
f"{node.name}.tweak.override.{id}.{k} conflicts with another"
101+
)
102+
s_dict[k] = v
103+
s_override[id] = s_dict or None # Will never be None?
104+
self.tweak.override = s_override or None
105+
self.tweak.append = (
106+
make_list(self.tweak.append)
107+
+ [rph(v) for v in make_list(node.tweak.append)]
108+
) or None
109+
81110
def add_connector(self, name: str, *args, **kwargs) -> None:
82111
check_old(f"Connector '{name}'", OLD_CONNECTOR_ATTR, kwargs)
83112
self.connectors[name] = Connector(name, *args, **kwargs)
113+
self.extend_tweak(self.connectors[name])
84114

85115
def add_cable(self, name: str, *args, **kwargs) -> None:
86116
self.cables[name] = Cable(name, *args, **kwargs)
117+
self.extend_tweak(self.cables[name])
87118

88119
def add_mate_pin(self, from_name, from_pin, to_name, to_pin, arrow_type) -> None:
89120
self.mates.append(MatePin(from_name, from_pin, to_name, to_pin, arrow_type))

0 commit comments

Comments
 (0)