Skip to content

Commit ff9e447

Browse files
authored
feat: enhance exception message on conversion error (#2)
* feat: enhance exception message on conversion error * chore: bump to 0.2.0
1 parent 666cc68 commit ff9e447

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "typeline"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "Write dataclasses to delimited text formats and read them back again."
55
authors = ["Clint Valentine <[email protected]>"]
66
license = "MIT"

tests/test_reader.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import get_origin
55

66
import pytest
7+
from msgspec import ValidationError
78
from typing_extensions import override
89

910
from typeline import CsvStructReader
@@ -259,3 +260,26 @@ def _decode(record_type: type[Any] | str | Any, item: Any) -> Any:
259260

260261
with SimpleListReader.from_path(tmp_path / "test.txt", MyMetric) as reader:
261262
assert list(reader) == [MyMetric(0.1, [1, 2, 3])]
263+
264+
265+
def test_reader_msgspec_validation_exception(tmp_path: Path) -> None:
266+
"""Test that we clarify when msgspec cannot decode a structure of builtins."""
267+
268+
@dataclass
269+
class MyData:
270+
field1: str
271+
field2: list[int]
272+
273+
(tmp_path / "test.txt").write_text("field1,field2\nmy-name,null\n")
274+
275+
with CsvStructReader.from_path(tmp_path / "test.txt", MyData) as reader:
276+
with pytest.raises(
277+
ValidationError,
278+
match=(
279+
r"Could not parse JSON-like object into requested structure:"
280+
+ r" \{'field1'\: 'my-name', 'field2': None\}."
281+
+ r" Requested structure: MyData. Original exception:"
282+
+ r" Expected \`array\`, got \`null\` - at \`\$.field2\`"
283+
),
284+
):
285+
list(reader)

typeline/_reader.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from typing import get_args
2121
from typing import get_origin
2222

23+
from msgspec import ValidationError
2324
from msgspec import convert
2425
from typing_extensions import Self
2526
from typing_extensions import override
@@ -164,11 +165,11 @@ def __iter__(self) -> Iterator[RecordType]:
164165
as_builtins = self._csv_dict_to_json(record)
165166
try:
166167
yield convert(as_builtins, self._record_type, strict=False)
167-
except ValueError as exception:
168-
raise ValueError(
169-
f"Could not parse {record} as {self._record_type.__name__}!"
170-
+ f" Intermediate structure formed is: {as_builtins}."
171-
+ f" Original error: {exception}"
168+
except ValidationError as exception:
169+
raise ValidationError(
170+
f"Could not parse JSON-like object into requested structure: {as_builtins}."
171+
+ f" Requested structure: {self._record_type.__name__}."
172+
+ f" Original exception: {exception}"
172173
) from exception
173174

174175
@staticmethod

0 commit comments

Comments
 (0)