Skip to content

Commit 6e585f9

Browse files
Fix url serialization for unions (#11233)
1 parent 5a22e02 commit 6e585f9

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

pydantic/networks.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010
from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network
1111
from typing import TYPE_CHECKING, Any, ClassVar
1212

13-
from pydantic_core import MultiHostHost, PydanticCustomError, SchemaSerializer, core_schema
13+
from pydantic_core import (
14+
MultiHostHost,
15+
PydanticCustomError,
16+
PydanticSerializationUnexpectedValue,
17+
SchemaSerializer,
18+
core_schema,
19+
)
1420
from pydantic_core import MultiHostUrl as _CoreMultiHostUrl
1521
from pydantic_core import Url as _CoreUrl
1622
from typing_extensions import Annotated, Self, TypeAlias
@@ -283,6 +289,14 @@ def build(
283289
)
284290
)
285291

292+
@classmethod
293+
def serialize_url(cls, url: Any) -> str:
294+
if not isinstance(url, cls):
295+
raise PydanticSerializationUnexpectedValue(
296+
f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected."
297+
)
298+
return str(url)
299+
286300
@classmethod
287301
def __get_pydantic_core_schema__(
288302
cls, source: type[_BaseUrl], handler: GetCoreSchemaHandler
@@ -300,7 +314,7 @@ def wrap_val(v, h):
300314
return core_schema.no_info_wrap_validator_function(
301315
wrap_val,
302316
schema=core_schema.url_schema(**cls._constraints.defined_constraints),
303-
serialization=core_schema.to_string_ser_schema(),
317+
serialization=core_schema.plain_serializer_function_ser_schema(cls.serialize_url),
304318
)
305319

306320
@classmethod
@@ -450,6 +464,14 @@ def build(
450464
)
451465
)
452466

467+
@classmethod
468+
def serialize_url(cls, url: Any) -> str:
469+
if not isinstance(url, cls):
470+
raise PydanticSerializationUnexpectedValue(
471+
f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected."
472+
)
473+
return str(url)
474+
453475
@classmethod
454476
def __get_pydantic_core_schema__(
455477
cls, source: type[_BaseMultiHostUrl], handler: GetCoreSchemaHandler
@@ -467,7 +489,7 @@ def wrap_val(v, h):
467489
return core_schema.no_info_wrap_validator_function(
468490
wrap_val,
469491
schema=core_schema.multi_host_url_schema(**cls._constraints.defined_constraints),
470-
serialization=core_schema.to_string_ser_schema(),
492+
serialization=core_schema.plain_serializer_function_ser_schema(cls.serialize_url),
471493
)
472494

473495
@classmethod

tests/test_networks.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Any, Union
33

44
import pytest
5-
from pydantic_core import PydanticCustomError, Url
5+
from pydantic_core import PydanticCustomError, PydanticSerializationError, Url
66
from typing_extensions import Annotated
77

88
from pydantic import (
@@ -1180,3 +1180,12 @@ class Model(BaseModel):
11801180

11811181
with pytest.raises(ValidationError, match=r'Value should have at most 45 items after validation'):
11821182
Model(postgres='postgres://user:pass@localhost:5432/foobarbazfoo')
1183+
1184+
1185+
def test_unexpected_ser() -> None:
1186+
ta = TypeAdapter(HttpUrl)
1187+
with pytest.raises(
1188+
PydanticSerializationError,
1189+
match="Expected `<class 'pydantic.networks.HttpUrl'>` but got `<class 'str'>` with value `'http://example.com'`",
1190+
):
1191+
ta.dump_python('http://example.com', warnings='error')

0 commit comments

Comments
 (0)