diff --git a/src/hyperlink/_url.py b/src/hyperlink/_url.py index 8797b5c..e613167 100644 --- a/src/hyperlink/_url.py +++ b/src/hyperlink/_url.py @@ -1667,11 +1667,16 @@ def to_uri(self): new_path = _encode_path_parts( self.path, has_scheme=bool(self.scheme), rooted=False, maximal=True ) - new_host = ( - self.host - if not self.host - else idna_encode(self.host, uts46=True).decode("ascii") - ) + # IP literals must not be IDNA-encoded (colons fail idna). + if not self.host: + new_host = self.host + else: + family, _ = parse_host(self.host) + new_host = ( + self.host + if family is not None + else idna_encode(self.host, uts46=True).decode("ascii") + ) return self.replace( userinfo=new_userinfo, host=new_host, diff --git a/src/hyperlink/test/test_url.py b/src/hyperlink/test/test_url.py index 37c9172..b912b1a 100644 --- a/src/hyperlink/test/test_url.py +++ b/src/hyperlink/test/test_url.py @@ -1132,6 +1132,15 @@ def test_idna(self): self.assertEqual(u2.to_text(), "https://xn--bcher-kva.ch") self.assertEqual(u2.to_iri().to_text(), "https://bücher.ch") + def test_to_uri_ip_literal(self): + # type: () -> None + ipv6 = URL.from_text("http://[::1]/") + self.assertEqual(ipv6.to_uri().to_text(), "http://[::1]/") + self.assertEqual(ipv6.to_uri().host, "::1") + ipv4 = URL.from_text("http://127.0.0.1/") + self.assertEqual(ipv4.to_uri().to_text(), "http://127.0.0.1/") + self.assertEqual(ipv4.to_uri().host, "127.0.0.1") + def test_netloc_slashes(self): # type: () -> None