Skip to content

Commit 79cac6b

Browse files
Fix validation against dataclasses (#212)
* Add failing test case for validating dataclasses. * Serialize back to JSON before validating. * Add newline. * Remove `overload`.
1 parent d02cddc commit 79cac6b

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

python/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ classifiers = [
2323
]
2424
dependencies = [
2525
"pydantic>=2.5.2",
26+
"pydantic_core>=2.16.3",
2627
"httpx>=0.27.0",
2728
"typing_extensions>=4.10.0",
2829
]
@@ -64,7 +65,7 @@ cov = [
6465
]
6566

6667
[[tool.hatch.envs.all.matrix]]
67-
python = ["3.11"]
68+
python = ["3.11", "3.12"]
6869

6970
[tool.hatch.envs.lint]
7071
detached = true

python/src/typechat/_internal/validator.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing_extensions import Generic, TypeVar
33

44
import pydantic
5+
import pydantic_core
56

67
from typechat._internal.result import Failure, Result, Success
78

@@ -26,14 +27,19 @@ def __init__(self, py_type: type[T]):
2627
def validate_object(self, obj: object) -> Result[T]:
2728
"""
2829
Validates the given Python object according to the associated schema type.
29-
30-
Useful for translators that may presume a non-JSON output.
3130
3231
Returns a `Success[T]` object containing the object if validation was successful.
3332
Otherwise, returns a `Failure` object with a `message` property describing the error.
3433
"""
3534
try:
36-
typed_dict = self._adapted_type.validate_python(obj, strict=True)
35+
# TODO: Switch to `validate_python` when validation modes are exposed.
36+
# https://github.com/pydantic/pydantic-core/issues/712
37+
# We'd prefer to keep `validate_object` as the core method and
38+
# allow translators to concern themselves with the JSON instead.
39+
# However, under Pydantic's `strict` mode, a `dict` isn't considered compatible
40+
# with a dataclass. So for now, jump back to JSON and validate the string.
41+
json_str = pydantic_core.to_json(obj)
42+
typed_dict = self._adapted_type.validate_json(json_str, strict=True)
3743
return Success(typed_dict)
3844
except pydantic.ValidationError as validation_error:
3945
return _handle_error(validation_error)

python/tests/test_validator.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
from dataclasses import dataclass
3+
import typechat
4+
5+
@dataclass
6+
class Example:
7+
a: str
8+
b: int
9+
c: bool
10+
11+
v = typechat.TypeChatValidator(Example)
12+
13+
def test_dict_valid_as_dataclass():
14+
r = v.validate_object({"a": "hello!", "b": 42, "c": True})
15+
assert r == typechat.Success(Example(a="hello!", b=42, c=True))
16+

0 commit comments

Comments
 (0)