Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions pydantic_ai_slim/pydantic_ai/format_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from collections.abc import Iterable, Iterator, Mapping
from dataclasses import asdict, dataclass, field, fields, is_dataclass
from datetime import date
from datetime import date, time, timedelta
from enum import Enum
from typing import Any, Literal
from xml.etree import ElementTree
Expand All @@ -27,7 +27,7 @@ def format_as_xml(
This is useful since LLMs often find it easier to read semi-structured data (e.g. examples) as XML,
rather than JSON etc.

Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `Enum`,
Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `time`, `timedelta`, `Enum`,
`Mapping`, `Iterable`, `dataclass`, and `BaseModel`.

Args:
Expand Down Expand Up @@ -104,8 +104,10 @@ def _to_xml(self, value: Any, path: str, tag: str | None = None) -> ElementTree.
element.text = value.decode(errors='ignore')
elif isinstance(value, bool | int | float | Enum):
element.text = str(value)
elif isinstance(value, date):
elif isinstance(value, date | time):
element.text = value.isoformat()
elif isinstance(value, timedelta):
element.text = str(value)
elif isinstance(value, Mapping):
if tag is None and path in self._element_names:
element.tag = self._element_names[path]
Expand Down Expand Up @@ -165,7 +167,7 @@ def _parse_data_structures(
path: str = '',
):
"""Parse data structures as dataclasses or Pydantic models to extract element names and attributes."""
if value is None or isinstance(value, (str | int | float | date | bytearray | bytes | bool)):
if value is None or isinstance(value, (str | int | float | date | time | timedelta | bytearray | bytes | bool)):
return
elif isinstance(value, Mapping):
for k, v in value.items(): # pyright: ignore[reportUnknownVariableType]
Expand Down
18 changes: 17 additions & 1 deletion tests/test_format_as_xml.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations as _annotations

from dataclasses import dataclass, field
from datetime import date, datetime
from datetime import date, datetime, time, timedelta
from enum import Enum
from typing import Any

Expand Down Expand Up @@ -567,6 +567,22 @@ class DataItem2:
"""),
id='list[date]',
),
pytest.param(
[time(12, 30, 45), time(8, 15)],
snapshot("""\
<item>12:30:45</item>
<item>08:15:00</item>\
"""),
id='list[time]',
),
pytest.param(
[timedelta(days=1, hours=2, minutes=30), timedelta(seconds=90)],
snapshot("""\
<item>1 day, 2:30:00</item>
<item>0:01:30</item>\
"""),
id='list[timedelta]',
),
],
)
def test_no_root(input_obj: Any, output: str):
Expand Down