Skip to content

Commit

Permalink
Add HTTPX url
Browse files Browse the repository at this point in the history
  • Loading branch information
07pepa committed Mar 14, 2024
1 parent f254b34 commit 2c36c05
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
70 changes: 70 additions & 0 deletions pydantic_extra_types/httpx_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""convenient URL type compatible with httpx and pydantic mostly useful in settings for base url of httpx client"""
from typing import Any

from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
from pydantic_core import core_schema

try:
from httpx import URL as URL_HTTPX
from httpx._exceptions import InvalidURL
from httpx._urlparse import MAX_URL_LENGTH
except ImportError:
raise RuntimeError(
'The `httpx` module requires "httpx" to be installed. You can install it with "pip install ' 'httpx".'
)


class URL(URL_HTTPX):
"""URL parses URL in the [httpx.URL](https://www.python-httpx.org/api/#url) format.
```py
from pydantic import BaseModel
from pydantic_extra_types.httpx_url import URL
class Website(BaseModel):
url: URL
website = Website(url='https://www.example.com')
print(website)
# > url='https://www.example.com'
```
"""

@classmethod
def _validate(cls, url: str, _: core_schema.ValidationInfo) -> 'URL':
"""
Validate a URL from the provided str value.
Args:
url: The str value to be validated.
_: The Pydantic ValidationInfo.
Returns:
The validated URL.
"""
try:
return cls(url)
except InvalidURL as e:
raise ValueError(str(e))

@classmethod
def __get_pydantic_core_schema__(cls, type: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
"""
duplicate of the `AnyUrl` schema, but with the `URL` type from httpx.
"""
return core_schema.with_info_after_validator_function(
cls._validate,
core_schema.str_schema(min_length=1, max_length=MAX_URL_LENGTH),
serialization=core_schema.to_string_ser_schema(),
)

@classmethod
def __get_pydantic_json_schema__(
cls, schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
) -> dict[str, Any]:
"""
duplicate of the `AnyUrl` schema, but with the `URL` type from httpx.
"""
json_schema = handler(schema)
return json_schema
1 change: 1 addition & 0 deletions requirements/testing.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pytest
codecov
pytest-cov
pytest-pretty
httpx
24 changes: 24 additions & 0 deletions tests/test_httpx_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest
from httpx import URL as URL_HTTPX
from pydantic import BaseModel, ValidationError

from pydantic_extra_types.httpx_url import URL

from .too_long_url import TOO_LONG_URL


class CheckingModel(BaseModel):
url: URL


def test_url_ok():
model = CheckingModel(url='https://www.example.com')
assert isinstance(model.url, URL_HTTPX)
assert model.url == 'https://www.example.com'
assert model.model_dump() == {'url': 'https://www.example.com'} # test serialization


@pytest.mark.parametrize('invalid_url', ['', '\0', TOO_LONG_URL])
def test_url_fail(invalid_url: str):
with pytest.raises(ValidationError):
CheckingModel(url='\0')
1 change: 1 addition & 0 deletions tests/too_long_url.py

Large diffs are not rendered by default.

0 comments on commit 2c36c05

Please sign in to comment.