From 87509e4d03e6ebb97cd0f750d3f35850eab09cca Mon Sep 17 00:00:00 2001 From: mayuriphad Date: Fri, 23 Oct 2026 09:18:09 +0530 Subject: [PATCH] Fix ParseResultBytes.authority for references without an authority ParseResultBytes.authority called encode() on None, so unsplit() and copy_with() raised AttributeError for any reference with no authority, while ParseResult returned None. Return None in that case. Fixes #163. Signed-off-by: mayuriphad --- docs/source/release-notes/unreleased.rst | 3 ++- src/rfc3986/parseresult.py | 7 +++++-- tests/test_parseresult.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/source/release-notes/unreleased.rst b/docs/source/release-notes/unreleased.rst index 09b03b4..a094250 100644 --- a/docs/source/release-notes/unreleased.rst +++ b/docs/source/release-notes/unreleased.rst @@ -1,6 +1,7 @@ 2.x.y - 202z-aa-bb ------------------ -- *Add Items here* +- Fix ``ParseResultBytes.unsplit()`` raising ``AttributeError`` for + references without an authority, such as ``/a`` or ``mailto:x``. .. links below here diff --git a/src/rfc3986/parseresult.py b/src/rfc3986/parseresult.py index 551d1c6..168045f 100644 --- a/src/rfc3986/parseresult.py +++ b/src/rfc3986/parseresult.py @@ -404,9 +404,12 @@ def from_string( ) @property - def authority(self) -> bytes: + def authority(self) -> t.Optional[bytes]: """Return the normalized authority.""" - return self.reference.authority.encode(self.encoding) + authority = self.reference.authority + if authority is None: + return None + return authority.encode(self.encoding) def copy_with( self, diff --git a/tests/test_parseresult.py b/tests/test_parseresult.py index 5788448..3217898 100644 --- a/tests/test_parseresult.py +++ b/tests/test_parseresult.py @@ -166,6 +166,18 @@ def test_unsplit(self): idna_encoded = SNOWMAN_IDNA_HOST.encode("utf-8") + b"/path" assert uri.unsplit(use_idna=True) == idna_encoded + @pytest.mark.parametrize( + "reference", [b"/a", b"a", b"mailto:x", b"?q", b"#f"] + ) + def test_unsplit_reference_without_authority(self, reference): + uri = pr.ParseResultBytes.from_string(reference) + assert uri.authority is None + assert uri.unsplit() == reference + assert ( + pr.ParseResult.from_string(reference.decode()).unsplit() + == reference.decode() + ) + def test_eager_normalization_from_string(self): uri = pr.ParseResultBytes.from_string( b"http://" + SNOWMAN + b".com/path",