diff --git a/CHANGES/1265.bugfix.rst b/CHANGES/1265.bugfix.rst new file mode 100644 index 000000000..60cd5e5b6 --- /dev/null +++ b/CHANGES/1265.bugfix.rst @@ -0,0 +1,3 @@ +Fixed :py:meth:`~yarl.URL.build` failing to validate paths must start with a ``/`` when passing ``authority`` -- by :user:`bdraco`. + +The validation only worked correctly when passing ``host``. diff --git a/tests/test_url_build.py b/tests/test_url_build.py index cc9b15f7e..a3943dc2d 100644 --- a/tests/test_url_build.py +++ b/tests/test_url_build.py @@ -140,12 +140,18 @@ def test_build_with_invalid_host(host: str, is_authority: bool): def test_build_with_authority(): - url = URL.build(scheme="http", authority="степан:bar@host.com:8000", path="path") + url = URL.build(scheme="http", authority="степан:bar@host.com:8000", path="/path") assert ( str(url) == "http://%D1%81%D1%82%D0%B5%D0%BF%D0%B0%D0%BD:bar@host.com:8000/path" ) +def test_build_with_authority_no_leading_flash(): + msg = r"Path in a URL with authority should start with a slash \('/'\) if set" + with pytest.raises(ValueError, match=msg): + URL.build(scheme="http", authority="степан:bar@host.com:8000", path="path") + + def test_build_with_authority_without_encoding(): url = URL.build( scheme="http", authority="foo:bar@host.com:8000", path="path", encoded=True diff --git a/yarl/_url.py b/yarl/_url.py index 271e0840e..37536610f 100644 --- a/yarl/_url.py +++ b/yarl/_url.py @@ -309,7 +309,8 @@ def __new__( if netloc: if "." in path: path = cls._normalize_path(path) - cls._validate_authority_uri_abs_path(host, path) + if path[0] != "/": + cls._raise_for_authority_missing_abs_path() query = cls._QUERY_REQUOTER(query) if query else query fragment = cls._FRAGMENT_REQUOTER(fragment) if fragment else fragment @@ -407,7 +408,8 @@ def build( if path and netloc: if "." in path: path = cls._normalize_path(path) - cls._validate_authority_uri_abs_path(host, path) + if path[0] != "/": + cls._raise_for_authority_missing_abs_path() query_string = ( cls._QUERY_QUOTER(query_string) if query_string else query_string @@ -947,15 +949,10 @@ def suffixes(self) -> tuple[str, ...]: return tuple(self._UNQUOTER(suffix) for suffix in self.raw_suffixes) @staticmethod - def _validate_authority_uri_abs_path(host: str, path: str) -> None: - """Ensure that path in URL with authority starts with a leading slash. - - Raise ValueError if not. - """ - if host and path and path[0] != "/": - raise ValueError( - "Path in a URL with authority should start with a slash ('/') if set" - ) + def _raise_for_authority_missing_abs_path() -> None: + """Raise when he path in URL with authority starts lacks a leading slash.""" + msg = "Path in a URL with authority should start with a slash ('/') if set" + raise ValueError(msg) def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL": """