diff --git a/starlette/datastructures.py b/starlette/datastructures.py index f5d74d25f..011efc357 100644 --- a/starlette/datastructures.py +++ b/starlette/datastructures.py @@ -107,6 +107,12 @@ def port(self) -> int | None: def is_secure(self) -> bool: return self.scheme in ("https", "wss") + def relative_url(self) -> URL: + """ + Get a URL that only includes url path, query string and fragment. + """ + return self.__class__(path=self.path, query=self.query, fragment=self.fragment) + def replace(self, **kwargs: typing.Any) -> URL: if "username" in kwargs or "password" in kwargs or "hostname" in kwargs or "port" in kwargs: hostname = kwargs.pop("hostname", None) diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py index 0e7d35c3c..8b7ed62d8 100644 --- a/tests/test_datastructures.py +++ b/tests/test_datastructures.py @@ -90,6 +90,17 @@ def test_hidden_password() -> None: assert repr(u) == "URL('https://username:********@example.org/path/to/somewhere')" +def test_relative_url() -> None: + u = URL("https://example.org/path/to/somewhere") + assert u.relative_url() == URL("/path/to/somewhere") + + u = URL("https://username:password@example.org/path/to/somewhere?abc=123") + assert u.relative_url() == URL("/path/to/somewhere?abc=123") + + u = URL("https://[fe::2]:12345/path/to/somewhere?abc=123#anchor") + assert u.relative_url() == URL("/path/to/somewhere?abc=123#anchor") + + def test_csv() -> None: csv = CommaSeparatedStrings('"localhost", "127.0.0.1", 0.0.0.0') assert list(csv) == ["localhost", "127.0.0.1", "0.0.0.0"]