diff --git a/docs/api.md b/docs/api.md index d01cc649ba..f56a34c856 100644 --- a/docs/api.md +++ b/docs/api.md @@ -112,6 +112,12 @@ what gets sent over the wire.* >>> url = URL("https://example.org/") >>> url.host 'example.org' + +>>> from pydantic import HttpUrl +>>> pydantic_url = HttpUrl("https://example.org/") +>>> url = URL(pydantic_url) +>>> url.host +'example.org' ``` * `def __init__(url, **kwargs)` diff --git a/httpx/_urls.py b/httpx/_urls.py index 147a8fa333..64c264cc77 100644 --- a/httpx/_urls.py +++ b/httpx/_urls.py @@ -6,12 +6,16 @@ import idna from ._types import QueryParamTypes -from ._urlparse import urlparse +from ._urlparse import ParseResult, urlparse from ._utils import primitive_value_to_str __all__ = ["URL", "QueryParams"] +class HasDunderStr(typing.Protocol): + def __str__(self) -> str: ... + + class URL: """ url = httpx.URL("HTTPS://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink") @@ -74,7 +78,9 @@ class URL: themselves. """ - def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None: + def __init__( + self, url: URL | str | HasDunderStr = "", **kwargs: typing.Any + ) -> None: if kwargs: allowed = { "scheme": str, @@ -113,15 +119,11 @@ def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None: params = kwargs.pop("params") kwargs["query"] = None if not params else str(QueryParams(params)) - if isinstance(url, str): - self._uri_reference = urlparse(url, **kwargs) - elif isinstance(url, URL): + self._uri_reference: ParseResult + if isinstance(url, URL): self._uri_reference = url._uri_reference.copy_with(**kwargs) else: - raise TypeError( - "Invalid type for url. Expected str or httpx.URL," - f" got {type(url)}: {url!r}" - ) + self._uri_reference = urlparse(str(url), **kwargs) @property def scheme(self) -> str: diff --git a/tests/models/test_url.py b/tests/models/test_url.py index 03072e8f5c..493be272e8 100644 --- a/tests/models/test_url.py +++ b/tests/models/test_url.py @@ -452,19 +452,17 @@ def test_url_set(): assert all(url in urls for url in url_set) -# Tests for TypeErrors when instantiating `httpx.URL`. - +def test_custom_object_url(): + class ExternalURLClass: + def __str__(self): + return "https://www.example.com/" -def test_url_invalid_type(): - """ - Ensure that invalid types on `httpx.URL()` raise a `TypeError`. - """ + url = ExternalURLClass() + httpx_url = httpx.URL(url) + assert httpx_url == "https://www.example.com/" - class ExternalURLClass: # representing external URL class - pass - with pytest.raises(TypeError): - httpx.URL(ExternalURLClass()) # type: ignore +# Tests for TypeErrors when instantiating `httpx.URL`. def test_url_with_invalid_component():