[PortList] plugged() failure shouldn't dirty the ports

This commit is contained in:
Jan Petykiewicz 2026-03-31 22:38:27 -07:00
commit 395ad4df9d
2 changed files with 26 additions and 1 deletions

View file

@ -413,6 +413,10 @@ class PortList(metaclass=ABCMeta):
if missing_b: if missing_b:
raise PortError(f'Connection destination ports were not found: {missing_b}') raise PortError(f'Connection destination ports were not found: {missing_b}')
a_names, b_names = list(zip(*connections.items(), strict=True)) a_names, b_names = list(zip(*connections.items(), strict=True))
used_names = list(chain(a_names, b_names))
duplicate_names = {name for name in used_names if used_names.count(name) > 1}
if duplicate_names:
raise PortError(f'Each port may appear in at most one connection: {duplicate_names}')
a_ports = [self.ports[pp] for pp in a_names] a_ports = [self.ports[pp] for pp in a_names]
b_ports = [self.ports[pp] for pp in b_names] b_ports = [self.ports[pp] for pp in b_names]

View file

@ -182,9 +182,30 @@ def test_port_list_plugged_missing_port_raises() -> None:
pl.plugged({"missing": "B"}) pl.plugged({"missing": "B"})
assert set(pl.ports) == {"A", "B"} assert set(pl.ports) == {"A", "B"}
def test_port_list_plugged_reused_port_raises_atomically() -> None:
class MyPorts(PortList):
def __init__(self) -> None:
self._ports = {"A": Port((0, 0), None), "B": Port((0, 0), None), "C": Port((0, 0), None)}
@property
def ports(self) -> dict[str, Port]:
return self._ports
@ports.setter
def ports(self, val: dict[str, Port]) -> None:
self._ports = val
for connections in ({"A": "A"}, {"A": "B", "C": "B"}):
pl = MyPorts()
with pytest.raises(PortError, match="Each port may appear in at most one connection"):
pl.plugged(connections)
assert set(pl.ports) == {"A", "B", "C"}
pl = MyPorts()
with pytest.raises(PortError, match="Connection destination ports were not found"): with pytest.raises(PortError, match="Connection destination ports were not found"):
pl.plugged({"A": "missing"}) pl.plugged({"A": "missing"})
assert set(pl.ports) == {"A", "B"} assert set(pl.ports) == {"A", "B", "C"}
def test_port_list_plugged_mismatch() -> None: def test_port_list_plugged_mismatch() -> None: