Add the interim `/tipc/` maddr grammar
`mk_maddr()`/`parse_maddr()` learn,
/tipc/<stype>/<instance>/<scope>
mirroring how `uds` maps onto the spec-legal `/unix`.
XXX `str`-ONLY for now: there is no registered `/tipc` proto
in the multiaddr table (upstream track gh #483 +
multiformats/py-multiaddr#107) and `Multiaddr()` rejects an
unregistered name outright. `MsgTransport.maddr`s return type
is already `Multiaddr|str` (and `MsgpackUDSStream` already
exercises the `str` branch), so this fits — but it IS why gh
`parse_maddr()` therefore special-cases the `/tipc/` prefix
BEFORE handing anything to `Multiaddr()`.
Also drive the maddr mapping-table tests off `_address_types`
instead of a hardcoded len/dict so the next backend can't
fail them for the wrong reason.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
wkt/pr493_review
parent
e0f66616cd
commit
51d7133f47
|
|
@ -19,7 +19,10 @@ from tractor.discovery._multiaddr import (
|
||||||
_tpt_proto_to_maddr,
|
_tpt_proto_to_maddr,
|
||||||
_maddr_to_tpt_proto,
|
_maddr_to_tpt_proto,
|
||||||
)
|
)
|
||||||
from tractor.discovery._addr import wrap_address
|
from tractor.discovery._addr import (
|
||||||
|
wrap_address,
|
||||||
|
_address_types,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_tpt_proto_to_maddr_mapping():
|
def test_tpt_proto_to_maddr_mapping():
|
||||||
|
|
@ -30,7 +33,12 @@ def test_tpt_proto_to_maddr_mapping():
|
||||||
'''
|
'''
|
||||||
assert _tpt_proto_to_maddr['tcp'] == 'tcp'
|
assert _tpt_proto_to_maddr['tcp'] == 'tcp'
|
||||||
assert _tpt_proto_to_maddr['uds'] == 'unix'
|
assert _tpt_proto_to_maddr['uds'] == 'unix'
|
||||||
assert len(_tpt_proto_to_maddr) == 2
|
assert _tpt_proto_to_maddr['tipc'] == 'tipc'
|
||||||
|
|
||||||
|
# NOTE, drive the expected set off the registration table
|
||||||
|
# (per the "drive-the-set-from-the-`Literal`" pattern) so
|
||||||
|
# adding a backend can't fail this for the wrong reason.
|
||||||
|
assert set(_tpt_proto_to_maddr) == set(_address_types)
|
||||||
|
|
||||||
|
|
||||||
def test_mk_maddr_tcp_ipv4():
|
def test_mk_maddr_tcp_ipv4():
|
||||||
|
|
@ -153,9 +161,12 @@ def test_maddr_to_tpt_proto_mapping():
|
||||||
|
|
||||||
'''
|
'''
|
||||||
assert _maddr_to_tpt_proto == {
|
assert _maddr_to_tpt_proto == {
|
||||||
'tcp': 'tcp',
|
maddr_proto: proto_key
|
||||||
'unix': 'uds',
|
for proto_key, maddr_proto in _tpt_proto_to_maddr.items()
|
||||||
}
|
}
|
||||||
|
assert _maddr_to_tpt_proto['tcp'] == 'tcp'
|
||||||
|
assert _maddr_to_tpt_proto['unix'] == 'uds'
|
||||||
|
assert _maddr_to_tpt_proto['tipc'] == 'tipc'
|
||||||
|
|
||||||
|
|
||||||
def test_parse_maddr_tcp_ipv4():
|
def test_parse_maddr_tcp_ipv4():
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,12 @@ import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.msg.types import Aid
|
from tractor.msg.types import Aid
|
||||||
|
from tractor.discovery import _addr
|
||||||
|
from tractor.discovery._addr import wrap_address
|
||||||
|
from tractor.discovery._multiaddr import (
|
||||||
|
mk_maddr,
|
||||||
|
parse_maddr,
|
||||||
|
)
|
||||||
from tractor.ipc import _tipc
|
from tractor.ipc import _tipc
|
||||||
from tractor.ipc._tipc import (
|
from tractor.ipc._tipc import (
|
||||||
AF_TIPC,
|
AF_TIPC,
|
||||||
|
|
@ -206,6 +212,48 @@ def test_get_random_honors_bindspace():
|
||||||
assert addr.bindspace == TIPC_NODE_SCOPE == addr._scope
|
assert addr.bindspace == TIPC_NODE_SCOPE == addr._scope
|
||||||
|
|
||||||
|
|
||||||
|
def test_wrap_address_dispatches_on_the_proto_key():
|
||||||
|
'''
|
||||||
|
The proto-keyed unwrapped form must round-trip through the
|
||||||
|
*global* `wrap_address()` — and NOT get stolen by `tcp`s
|
||||||
|
`(str(), int())` case nor `uds`s `(_, str())` one.
|
||||||
|
|
||||||
|
'''
|
||||||
|
addr: TIPCAddress = TIPCAddress.get_random()
|
||||||
|
assert wrap_address(addr.unwrap()) == addr
|
||||||
|
# ..and via the `list` form `msgpack` decodes to
|
||||||
|
assert wrap_address(list(addr.unwrap())) == addr
|
||||||
|
|
||||||
|
assert _addr._address_types['tipc'] is TIPCAddress
|
||||||
|
assert _addr.get_address_cls('tipc') is TIPCAddress
|
||||||
|
|
||||||
|
# the host-singleton registrar default is import-time cheap
|
||||||
|
# (no kernel module, no I/O) and mirrors the `1616` idiom
|
||||||
|
assert _addr._default_lo_addrs['tipc'] == (
|
||||||
|
'tipc', TRACTOR_STYPE, 1616, TIPC_CLUSTER_SCOPE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_maddr_roundtrip():
|
||||||
|
'''
|
||||||
|
Interim `str`-only `/tipc/` maddr grammar (there's no
|
||||||
|
registered `/tipc` multiaddr proto yet, gh #483), which
|
||||||
|
`parse_maddr()` special-cases before `Multiaddr()` ever sees
|
||||||
|
the string.
|
||||||
|
|
||||||
|
'''
|
||||||
|
addr: TIPCAddress = TIPCAddress.get_random()
|
||||||
|
maddr: str = mk_maddr(addr)
|
||||||
|
|
||||||
|
assert isinstance(maddr, str)
|
||||||
|
assert maddr == (
|
||||||
|
f'/tipc/{addr._stype}/{addr._instance}/{addr._scope}'
|
||||||
|
)
|
||||||
|
assert parse_maddr(maddr) == addr
|
||||||
|
# ..and through the generic entrypoint
|
||||||
|
assert wrap_address(maddr) == addr
|
||||||
|
|
||||||
|
|
||||||
def test_eafnosupport_is_actionable_connerr(
|
def test_eafnosupport_is_actionable_connerr(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,23 @@ if TYPE_CHECKING:
|
||||||
_tpt_proto_to_maddr: dict[str, str] = {
|
_tpt_proto_to_maddr: dict[str, str] = {
|
||||||
'tcp': 'tcp',
|
'tcp': 'tcp',
|
||||||
'uds': 'unix',
|
'uds': 'unix',
|
||||||
|
'tipc': 'tipc',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# XXX, there is NO `/tipc` in the multiaddr protocol table yet
|
||||||
|
# (upstream track: gh #483 + multiformats/py-multiaddr#107), and
|
||||||
|
# `Multiaddr()` rejects an unregistered proto name outright.
|
||||||
|
#
|
||||||
|
# So until that lands `tipc` maddrs stay **`str`**-only — which
|
||||||
|
# `MsgTransport.maddr`s `Multiaddr|str` return type already
|
||||||
|
# allows and `MsgpackUDSStream.maddr` already exercises — and
|
||||||
|
# `parse_maddr()` special-cases the prefix BEFORE handing
|
||||||
|
# anything to `Multiaddr()`.
|
||||||
|
#
|
||||||
|
# This is also why gh #443's "always return `Multiaddr`" item
|
||||||
|
# stays blocked.
|
||||||
|
_tipc_maddr_prefix: str = '/tipc/'
|
||||||
|
|
||||||
# reverse mapping: multiaddr protocol name -> tractor proto_key
|
# reverse mapping: multiaddr protocol name -> tractor proto_key
|
||||||
_maddr_to_tpt_proto: dict[str, str] = {
|
_maddr_to_tpt_proto: dict[str, str] = {
|
||||||
v: k for k, v in _tpt_proto_to_maddr.items()
|
v: k for k, v in _tpt_proto_to_maddr.items()
|
||||||
|
|
@ -49,7 +64,7 @@ _maddr_to_tpt_proto: dict[str, str] = {
|
||||||
|
|
||||||
def mk_maddr(
|
def mk_maddr(
|
||||||
addr: 'Address',
|
addr: 'Address',
|
||||||
) -> Multiaddr:
|
) -> Multiaddr|str:
|
||||||
'''
|
'''
|
||||||
Construct a `Multiaddr` from a tractor `Address` instance,
|
Construct a `Multiaddr` from a tractor `Address` instance,
|
||||||
dispatching on the `.proto_key` to build the correct
|
dispatching on the `.proto_key` to build the correct
|
||||||
|
|
@ -75,6 +90,18 @@ def mk_maddr(
|
||||||
f'/{net_proto}/{host}/{maddr_proto}/{port}'
|
f'/{net_proto}/{host}/{maddr_proto}/{port}'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# NOTE, interim `str`-only grammar (see the
|
||||||
|
# `_tipc_maddr_prefix` note above),
|
||||||
|
#
|
||||||
|
# /tipc/<stype>/<instance>/<scope>
|
||||||
|
#
|
||||||
|
# mirroring how `uds` maps onto the spec-legal `/unix`.
|
||||||
|
case 'tipc':
|
||||||
|
_, stype, instance, scope = addr.unwrap()
|
||||||
|
return (
|
||||||
|
f'/{maddr_proto}/{stype}/{instance}/{scope}'
|
||||||
|
)
|
||||||
|
|
||||||
case 'uds':
|
case 'uds':
|
||||||
filedir, filename = addr.unwrap()
|
filedir, filename = addr.unwrap()
|
||||||
filepath = Path(filedir) / filename
|
filepath = Path(filedir) / filename
|
||||||
|
|
@ -100,6 +127,17 @@ def parse_maddr(
|
||||||
# lazy imports to avoid circular deps
|
# lazy imports to avoid circular deps
|
||||||
from tractor.ipc._tcp import TCPAddress
|
from tractor.ipc._tcp import TCPAddress
|
||||||
from tractor.ipc._uds import UDSAddress
|
from tractor.ipc._uds import UDSAddress
|
||||||
|
from tractor.ipc._tipc import TIPCAddress
|
||||||
|
|
||||||
|
# XXX MUST come before `Multiaddr()` which rejects the
|
||||||
|
# not-yet-registered `/tipc` proto name outright.
|
||||||
|
if maddr_str.startswith(_tipc_maddr_prefix):
|
||||||
|
_, _, stype, instance, scope = maddr_str.split('/')
|
||||||
|
return TIPCAddress(
|
||||||
|
_stype=int(stype),
|
||||||
|
_instance=int(instance),
|
||||||
|
_scope=int(scope),
|
||||||
|
)
|
||||||
|
|
||||||
maddr = Multiaddr(maddr_str)
|
maddr = Multiaddr(maddr_str)
|
||||||
proto_names: list[str] = [
|
proto_names: list[str] = [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue