From 0b667c661a40acd22c6b12c323d31c84541a6701 Mon Sep 17 00:00:00 2001 From: Huanyi Xie <74809554+xiehuanyi@users.noreply.github.com> Date: Mon, 12 Oct 2026 22:37:17 +0300 Subject: [PATCH] Preserve date serialization and trivia for reflected addition --- CHANGELOG.md | 2 ++ tests/test_items.py | 21 +++++++++++++++++++++ tomlkit/items.py | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0af52c54..0b2c2170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixed +- Preserve date text and temporal trivia when adding a timedelta from the left to `Date` or `DateTime` values. + - Fix valid TOML being rejected when an out-of-order table reopens an implicit super-table with a dotted key: `[a.b.c]` then `[a]` with `b.z = 1` extends the implicit `a.b` super-table rather than redefining it (stdlib `tomllib` accepts it), so it now parses and round-trips instead of raising `Redefinition of an existing table`. The concrete-table case (`[a.b]` then `[a]` `b.z = 1`) stays rejected. ([#565](https://github.com/python-poetry/tomlkit/pull/565)) - Fix appending a key to a parsed inline table that uses `", "` separators emitting a bare `","` for the new entry, leaving the table inconsistently spaced (e.g. `{x = 1, y = 2,z = 3}`). ([#595](https://github.com/python-poetry/tomlkit/pull/595)) diff --git a/tests/test_items.py b/tests/test_items.py index bbe1b2ed..a61902b6 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -803,6 +803,27 @@ def test_datetimes_behave_like_datetimes(tz_utc: tzinfo, tz_pst: tzinfo) -> None assert doc.as_string() == "dt = 2018-07-23T12:34:56-05:00" +@pytest.mark.parametrize( + "literal", ["2024-02-28", "2024-02-28T10:00:00", "2024-02-28T10:00:00Z"] +) +@pytest.mark.parametrize("delta", [timedelta(days=1), timedelta(days=-1)]) +def test_reflected_temporal_addition_preserves_serialization( + literal: str, delta: timedelta +) -> None: + doc = parse(f"when = {literal} # birthday\n") + value = doc["when"] + expected = value + delta + + result = delta + value + + assert type(result) is type(value) + assert result.unwrap() == expected.unwrap() + assert result.as_string() == expected.as_string() + assert result.trivia == expected.trivia + doc["when"] = result + assert parse(doc.as_string())["when"] == expected + + @pytest.mark.parametrize("fold", [0, 1]) def test_datetime_subtraction_preserves_input_fold(tz_fold: tzinfo, fold: int) -> None: value = datetime(2018, 11, 4, 1, 30, tzinfo=tz_fold, fold=fold) diff --git a/tomlkit/items.py b/tomlkit/items.py index 26b01097..076b5f9d 100644 --- a/tomlkit/items.py +++ b/tomlkit/items.py @@ -1151,6 +1151,8 @@ def __add__(self, other: timedelta) -> DateTime: return self._new(result) + __radd__ = __add__ + @overload # type: ignore[override] def __sub__(self, other: timedelta) -> DateTime: ... @@ -1271,6 +1273,8 @@ def __add__(self, other: timedelta) -> Date: return self._new(result) + __radd__ = __add__ + @overload # type: ignore[override] def __sub__(self, other: timedelta) -> Date: ...