Skip to content

Commit 8a105e7

Browse files
Merge pull request #7 from ClassicMiniDIY/port-357-per-node-tweak
Per-connector / per-cable tweak with name placeholder (port of upstream PR wireviz#357)
2 parents e789a70 + 39129a4 commit 8a105e7

3 files changed

Lines changed: 67 additions & 0 deletions

File tree

docs/syntax.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ 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 tweak section below
8891
```
8992
9093
## Cable attributes
@@ -148,6 +151,8 @@ tweak: # optional tweaking of .gv output
148151
show_wirecount: <bool> # defaults to true
149152
show_wirenumbers: <bool> # defaults to true for cables; false for bundles
150153

154+
# optional tweaking of .gv output executed for each instance of this cable
155+
tweak: # see tweak section below
151156
```
152157
153158
## Connection sets
@@ -457,6 +462,12 @@ Alternatively items can be added to just the BOM by putting them in the section
457462
# This feature is experimental and might change
458463
# or be removed in future versions.
459464
465+
placeholder: <str> # Substring to be replaced with the node name in
466+
# any per-connector / per-cable tweak overrides and append entries.
467+
# An empty string disables placeholder substitution for that node.
468+
# When omitted at the per-node level, the global placeholder
469+
# (in the top-level tweak: section) is used as the fallback.
470+
460471
override: # dict of .gv entries to override
461472
# Each entry is identified by its leading string
462473
# in lines beginning with a TAB character.

src/wireviz/DataClasses.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def __post_init__(self):
7979

8080
@dataclass
8181
class Tweak:
82+
placeholder: Optional[PlainText] = None
8283
override: Optional[Dict[Designator, Dict[str, Optional[str]]]] = None
8384
append: Union[str, List[str], None] = None
8485

@@ -170,10 +171,13 @@ class Connector:
170171
loops: List[List[Pin]] = field(default_factory=list)
171172
ignore_in_bom: bool = False
172173
additional_components: List[AdditionalComponent] = field(default_factory=list)
174+
tweak: Optional[Tweak] = None
173175

174176
def __post_init__(self) -> None:
175177
if isinstance(self.image, dict):
176178
self.image = Image(**self.image)
179+
if isinstance(self.tweak, dict):
180+
self.tweak = Tweak(**self.tweak)
177181

178182
self.ports_left = False
179183
self.ports_right = False
@@ -335,10 +339,13 @@ class Cable:
335339
show_wirenumbers: Optional[bool] = None
336340
ignore_in_bom: bool = False
337341
additional_components: List[AdditionalComponent] = field(default_factory=list)
342+
tweak: Optional[Tweak] = None
338343

339344
def __post_init__(self) -> None:
340345
if isinstance(self.image, dict):
341346
self.image = Image(**self.image)
347+
if isinstance(self.tweak, dict):
348+
self.tweak = Tweak(**self.tweak)
342349

343350
if isinstance(self.gauge, str): # gauge and unit specified
344351
try:

src/wireviz/Harness.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
component_table_entry,
3434
generate_bom,
3535
get_additional_component_table,
36+
make_list,
3637
pn_info_string,
3738
)
3839
from wireviz.wv_colors import get_color_hex, translate_color
@@ -132,9 +133,57 @@ def __post_init__(self):
132133
def add_connector(self, name: str, *args, **kwargs) -> None:
133134
check_old(f"Connector '{name}'", OLD_CONNECTOR_ATTR, kwargs)
134135
self.connectors[name] = Connector(name, *args, **kwargs)
136+
self._extend_tweak(self.connectors[name])
135137

136138
def add_cable(self, name: str, *args, **kwargs) -> None:
137139
self.cables[name] = Cable(name, *args, **kwargs)
140+
self._extend_tweak(self.cables[name])
141+
142+
def _extend_tweak(self, node: Union[Connector, Cable]) -> None:
143+
"""Fold ``node.tweak`` into ``self.tweak`` after substituting the
144+
node's name for the placeholder string.
145+
146+
Per-connector / per-cable ``tweak:`` entries let users author a
147+
single template and have its ``override`` keys / ``append`` lines
148+
rewritten with the actual designator at instantiation time. This
149+
is the only place the placeholder substitution happens — the
150+
global tweak is applied unchanged at graph emission time.
151+
"""
152+
if not node.tweak:
153+
return
154+
ph = node.tweak.placeholder
155+
# An empty string is a legal value to opt out of the global
156+
# placeholder; only None falls back.
157+
if ph is None:
158+
ph = self.tweak.placeholder
159+
# The replacement target may be None when an override deletes a
160+
# key (``key: null`` in YAML), so guard the str.replace call.
161+
if ph:
162+
rph = lambda s: s.replace(ph, node.name) if isinstance(s, str) else s
163+
else:
164+
rph = lambda s: s
165+
166+
n_override = node.tweak.override or {}
167+
s_override = self.tweak.override or {}
168+
for ident, n_dict in n_override.items():
169+
ident = rph(ident)
170+
s_dict = s_override.get(ident, {})
171+
for k, v in n_dict.items():
172+
k, v = rph(k), rph(v)
173+
if k in s_dict and v != s_dict[k]:
174+
raise ValueError(
175+
f"{node.name}.tweak.override.{ident}.{k} conflicts with another"
176+
)
177+
s_dict[k] = v
178+
# Keep the empty dict rather than collapsing to None — the
179+
# graph-emission code (Harness.create_graph) expects values
180+
# in self.tweak.override to be dicts, not None.
181+
s_override[ident] = s_dict
182+
self.tweak.override = s_override or None
183+
self.tweak.append = (
184+
make_list(self.tweak.append)
185+
+ [rph(v) for v in make_list(node.tweak.append)]
186+
) or None
138187

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

0 commit comments

Comments
 (0)