Skip to content

Commit 506c066

Browse files
fix: validate address format in _parse_address with clear errors
Previously, bare hostnames without port caused confusing ValueError about unpacking. Now raises clear messages for missing port, invalid port, and malformed IPv6 brackets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9cfb939 commit 506c066

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

src/dqliteclient/connection.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,28 @@ def _parse_address(address: str) -> tuple[str, int]:
1313
"""Parse a host:port address string, handling IPv6 brackets."""
1414
if address.startswith("["):
1515
# Bracketed IPv6: [host]:port
16+
if "]:" not in address:
17+
raise ValueError(
18+
f"Invalid IPv6 address format: expected '[host]:port', got {address!r}"
19+
)
1620
bracket_end = address.index("]")
1721
host = address[1:bracket_end]
1822
port_str = address[bracket_end + 2:] # Skip ']:
1923
else:
24+
if ":" not in address:
25+
raise ValueError(
26+
f"Invalid address format: expected 'host:port', got {address!r}"
27+
)
2028
host, port_str = address.rsplit(":", 1)
21-
return host, int(port_str)
29+
30+
try:
31+
port = int(port_str)
32+
except ValueError:
33+
raise ValueError(
34+
f"Invalid port in address {address!r}: {port_str!r} is not a number"
35+
) from None
36+
37+
return host, port
2238

2339

2440
class DqliteConnection:

tests/test_connection.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ def test_ipv6_full_bracketed(self) -> None:
2929

3030
assert _parse_address("[2001:db8::1]:9001") == ("2001:db8::1", 9001)
3131

32+
def test_bare_hostname_raises(self) -> None:
33+
from dqliteclient.connection import _parse_address
34+
35+
with pytest.raises(ValueError, match="expected.*host:port"):
36+
_parse_address("localhost")
37+
38+
def test_invalid_port_raises(self) -> None:
39+
from dqliteclient.connection import _parse_address
40+
41+
with pytest.raises(ValueError, match="not a number"):
42+
_parse_address("localhost:abc")
43+
44+
def test_ipv6_no_port_raises(self) -> None:
45+
from dqliteclient.connection import _parse_address
46+
47+
with pytest.raises(ValueError, match="expected.*host.*port"):
48+
_parse_address("[::1]")
49+
3250

3351
class TestDqliteConnection:
3452
def test_init(self) -> None:

0 commit comments

Comments
 (0)