Skip to content

Allow pin labels in connector loop definitions (fixes #432)#493

Draft
rsp2k wants to merge 4 commits intowireviz:masterfrom
rsp2k:feature/432-loop-pin-labels
Draft

Allow pin labels in connector loop definitions (fixes #432)#493
rsp2k wants to merge 4 commits intowireviz:masterfrom
rsp2k:feature/432-loop-pin-labels

Conversation

@rsp2k
Copy link

@rsp2k rsp2k commented Feb 13, 2026

Summary

Connector loops now accept pin labels (from pinlabels) in addition to pin numbers, matching how regular connections already work.

# Before: only pin numbers worked
loops:
  - [7, 8]

# After: pin labels work too
loops:
  - [RTS, CTS]
  - [1, GND]       # mixed is fine

Also fixes two pre-existing bugs:

Changes

wv_helper.py

  • New normalize_pin() function — tries int() first, falls back to str(). Extracts the coercion logic that was already inline in expand().
  • expand() refactored — uses normalize_pin() instead of inline try/except.

DataClasses.py

  • New Connector.resolve_pin() method — resolves a pin identifier (number or label) to its canonical pin number. Handles ambiguity detection (value in both pins and pinlabels at different positions) and duplicate label detection.
  • Pin type normalization in Connector.__post_init__()pins, pinlabels, and loops are normalized via normalize_pin() before any validation. This ensures pins: ["1", "2"] and pins: [1, 2] behave identically regardless of YAML quoting.
  • Pin type normalization in Cable.__post_init__()wirelabels normalized the same way.
  • Loop validation updated — loops now resolve through resolve_pin() and store the resolved pin numbers. Self-loops (same pin on both ends) are rejected.
  • activate_pin() type annotationside parameter updated to Optional[Side] since loops pass None.

Harness.py

  • connect() refactored — pin resolution logic (previously ~20 lines duplicating the same algorithm) replaced with delegation to Connector.resolve_pin(). Behavior is unchanged, but the logic now lives in one place.
  • Loop rendering fix — loop edges now convert pin numbers to 1-based port indices via connector.pins.index(), matching how wire connections already work. Previously, pin numbers were used directly as port names, which produced silently wrong diagrams for non-sequential pins like pins: [10, 20, 30, 40].

examples/ex17_loop_labels.yml (new)

RS-232 loopback adapter example demonstrating loops with pin labels, mixed number + label, and label-based wire connections.

tests/test_resolve_pin.py (new)

31 tests covering:

  • resolve_pin() happy paths and error paths
  • Loop resolution with labels, mixed types, non-sequential pins, self-loop detection
  • GraphViz rendering with correct port indices
  • Harness.connect() delegation
  • Pin type coercion: str-to-int normalization, mixed types, leading zeros, non-numeric pins, duplicate-after-normalization, wirelabels, and full YAML integration

Test plan

  • 31/31 tests pass
  • All 17 examples render without error (including new ex17)
  • All 8 tutorials render without error
  • Non-sequential pin test verifies port indices p1/p2 (not p10/p20) in GV output
  • Regression: pins: ["1", "2", "3"] with loops: [[1, "2"]] resolves correctly
  • Reviewer: verify edge cases with non-numeric pins containing digits (e.g. "A1", "3.3V")

Notes

  • The loop rendering bug (pin numbers vs port indices) was pre-existing, not introduced by this PR. It was invisible because all existing examples use sequential pins where number == index.
  • No changes to YAML schema — loops accepts the same types as before, plus strings that match pinlabels. Existing YAML files are unaffected by pin normalization.

Loops now accept pin labels (from pinlabels) in addition to pin
numbers, matching the behavior of the connections section. Labels
are resolved to pin numbers during __post_init__ via the new
Connector.resolve_pin() method, which handles ambiguity checking.
Code review fixes for the wireviz#432 loop-pin-labels feature:

- Fix loop rendering to use port indices instead of pin numbers
  (pre-existing bug: non-sequential pins produced wrong diagram)
- Add duplicate label check to the ambiguity branch in resolve_pin()
- Prevent self-referencing loops (pin looped to itself)
- Fix activate_pin() type annotation to accept Optional[Side]
- Deduplicate pin resolution: Harness.connect() now delegates to
  Connector.resolve_pin() instead of reimplementing the logic
- Add 21-test suite covering all resolution paths and error modes
- Document return contract, resolution precedence, and type-sensitivity
  note in resolve_pin() docstring
- Add ex17_loop_labels.yml: RS-232 loopback adapter demonstrating
  loops with pin labels, mixed number+label, and label-based connections
YAML safe_load() parses unquoted 1 as int and quoted "1" as str.
Python's `in` and .index() are type-strict, so pin lookups silently
fail when users quote numeric pin values.

Extract normalize_pin() from expand()'s inline logic and call it on
pins, pinlabels, loops, and wirelabels in __post_init__() before any
validation or resolution. Downstream code sees consistent types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant