Skip to content

Refactor _parse_hostport: regex-based parsing, typed IP return, and IPv6 tests#55

Merged
codingjoe merged 5 commits intoipv6from
copilot/sub-pr-54
Mar 18, 2026
Merged

Refactor _parse_hostport: regex-based parsing, typed IP return, and IPv6 tests#55
codingjoe merged 5 commits intoipv6from
copilot/sub-pr-54

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 18, 2026

_parse_hostport() had manual bracket-parsing logic with no tests, silently mishandled unbracketed IPv6 literals, and returned a plain str host regardless of whether the value was a numeric IP address.

Changes

  • voip/__main__.py:
    • Replaced manual bracket/partition logic with a single HOSTPORT_PATTERN regex that handles [IPv6HOST][:PORT], HOST:PORT, and bare HOST forms.
    • Return type changed from tuple[str, int] to tuple[IPv4Address | IPv6Address | str, int] — numeric IP literals are parsed into typed address objects; hostnames remain str.
    • Unbracketed IPv6 literals (e.g. ::1) raise click.BadParameter directing the user to bracket notation.
    • _parse_stun_server converts the typed host to str for socket/asyncio compatibility.
    • _connect_sip uses str(proxy_addr[0]) when calling asyncio.create_connection.
  • voip/sip/protocol.py: outbound_proxy type updated to tuple[IPv4Address | IPv6Address | str, int] | None.
  • tests/test_main.py: New TestParseHostport class covering the three key paths:
    • [::1](IPv6Address("::1"), 5061) (default port)
    • [::1]:5061(IPv6Address("::1"), 5061) (explicit port)
    • ::1BadParameter("...enclosed in brackets...")
# Before: silently wrong, plain str host
_parse_hostport(None, None, "::1")   # → ("::", 1)
_parse_hostport(None, None, "[::1]") # → ("::1", 5061)

# After: explicit error for unbracketed IPv6, typed address objects
_parse_hostport(None, None, "::1")
# click.BadParameter: IPv6 address must be enclosed in brackets, e.g. [::1].
_parse_hostport(None, None, "[::1]")  # → (IPv6Address('::1'), 5061)
_parse_hostport(None, None, "1.2.3.4:5060")  # → (IPv4Address('1.2.3.4'), 5060)

📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.79%. Comparing base (d0ffa4d) to head (5b7b26c).

Files with missing lines Patch % Lines
voip/__main__.py 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             ipv6      #55      +/-   ##
==========================================
+ Coverage   93.11%   93.79%   +0.68%     
==========================================
  Files          24       24              
  Lines        1975     1966       -9     
==========================================
+ Hits         1839     1844       +5     
+ Misses        136      122      -14     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 18, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • releases.astral.sh
    • Triggering command: /home/REDACTED/.local/bin/uv uv run --extra=cli --extra=pygments --extra=audio pytest tests/test_main.py::TestParseHostport -v (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] [WIP] Address feedback on IPv6 support and stronger SIP types implementation Add IPv6 tests and unbracketed IPv6 error path in _parse_hostport Mar 18, 2026
Copilot AI requested a review from codingjoe March 18, 2026 23:04
Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 18, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • releases.astral.sh
    • Triggering command: /home/REDACTED/.local/bin/uv uv run --extra=cli --extra=pygments --extra=audio pytest tests/test_main.py -v (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Add IPv6 tests and unbracketed IPv6 error path in _parse_hostport Refactor _parse_hostport: regex-based parsing, typed IP return, and IPv6 tests Mar 18, 2026
Copilot AI requested a review from codingjoe March 18, 2026 23:30
voip/__main__.py Outdated
Comment on lines 64 to 69
match = HOSTPORT_PATTERN.fullmatch(value)
if not match:
if value.count(":") > 1:
raise click.BadParameter(
f"Unclosed bracket in IPv6 address: {value!r}.", param=param
f"IPv6 address must be enclosed in brackets, e.g. [{value}].", param=param
)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
match = HOSTPORT_PATTERN.fullmatch(value)
if not match:
if value.count(":") > 1:
raise click.BadParameter(
f"Unclosed bracket in IPv6 address: {value!r}.", param=param
f"IPv6 address must be enclosed in brackets, e.g. [{value}].", param=param
)
if not (match:= HOSTPORT_PATTERN.fullmatch(value)):
if value.count(":") > 1:
raise click.BadParameter(
f"IPv6 address must be enclosed in brackets, e.g. [{value}].", param=param
)

voip/__main__.py Outdated
port = int(match.group("port")) if match.group("port") else default_port
try:
return host, int(port_str)
# Parse numeric IP literals into typed address objects; hostnames stay as str.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Parse numeric IP literals into typed address objects; hostnames stay as str.

voip/__main__.py Outdated
Comment on lines +33 to +35
#: Regex that parses ``[IPv6HOST][:PORT]`` or ``HOST[:PORT]`` strings.
#: Named groups: ``ipv6`` (bare address inside brackets) or ``host`` (plain hostname /
#: IPv4 literal), and an optional ``port`` suffix.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#: Regex that parses ``[IPv6HOST][:PORT]`` or ``HOST[:PORT]`` strings.
#: Named groups: ``ipv6`` (bare address inside brackets) or ``host`` (plain hostname /
#: IPv4 literal), and an optional ``port`` suffix.

@codingjoe codingjoe marked this pull request as ready for review March 18, 2026 23:38
@codingjoe codingjoe merged commit daa1944 into ipv6 Mar 18, 2026
19 checks passed
@codingjoe codingjoe deleted the copilot/sub-pr-54 branch March 18, 2026 23:38
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.

2 participants