Skip to content

Commit 8ab8bd0

Browse files
authored
Add support for datetime.time/timedelta to format_as_xml (#3087)
Co-authored-by: nurikk <[email protected]>
1 parent ef4e0b9 commit 8ab8bd0

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

pydantic_ai_slim/pydantic_ai/format_prompt.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from collections.abc import Iterable, Iterator, Mapping
44
from dataclasses import asdict, dataclass, field, fields, is_dataclass
5-
from datetime import date
5+
from datetime import date, time, timedelta
66
from enum import Enum
77
from typing import Any, Literal
88
from xml.etree import ElementTree
@@ -27,7 +27,7 @@ def format_as_xml(
2727
This is useful since LLMs often find it easier to read semi-structured data (e.g. examples) as XML,
2828
rather than JSON etc.
2929
30-
Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `Enum`,
30+
Supports: `str`, `bytes`, `bytearray`, `bool`, `int`, `float`, `date`, `datetime`, `time`, `timedelta`, `Enum`,
3131
`Mapping`, `Iterable`, `dataclass`, and `BaseModel`.
3232
3333
Args:
@@ -104,8 +104,10 @@ def _to_xml(self, value: Any, path: str, tag: str | None = None) -> ElementTree.
104104
element.text = value.decode(errors='ignore')
105105
elif isinstance(value, bool | int | float | Enum):
106106
element.text = str(value)
107-
elif isinstance(value, date):
107+
elif isinstance(value, date | time):
108108
element.text = value.isoformat()
109+
elif isinstance(value, timedelta):
110+
element.text = str(value)
109111
elif isinstance(value, Mapping):
110112
if tag is None and path in self._element_names:
111113
element.tag = self._element_names[path]
@@ -165,7 +167,7 @@ def _parse_data_structures(
165167
path: str = '',
166168
):
167169
"""Parse data structures as dataclasses or Pydantic models to extract element names and attributes."""
168-
if value is None or isinstance(value, (str | int | float | date | bytearray | bytes | bool)):
170+
if value is None or isinstance(value, (str | int | float | date | time | timedelta | bytearray | bytes | bool)):
169171
return
170172
elif isinstance(value, Mapping):
171173
for k, v in value.items(): # pyright: ignore[reportUnknownVariableType]

tests/test_format_as_xml.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations as _annotations
22

33
from dataclasses import dataclass, field
4-
from datetime import date, datetime
4+
from datetime import date, datetime, time, timedelta
55
from enum import Enum
66
from typing import Any
77

@@ -567,6 +567,22 @@ class DataItem2:
567567
"""),
568568
id='list[date]',
569569
),
570+
pytest.param(
571+
[time(12, 30, 45), time(8, 15)],
572+
snapshot("""\
573+
<item>12:30:45</item>
574+
<item>08:15:00</item>\
575+
"""),
576+
id='list[time]',
577+
),
578+
pytest.param(
579+
[timedelta(days=1, hours=2, minutes=30), timedelta(seconds=90)],
580+
snapshot("""\
581+
<item>1 day, 2:30:00</item>
582+
<item>0:01:30</item>\
583+
"""),
584+
id='list[timedelta]',
585+
),
570586
],
571587
)
572588
def test_no_root(input_obj: Any, output: str):

0 commit comments

Comments
 (0)