From bfbc3b9dc4128beffff5e6cf825fbce833a93ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Fri, 7 Mar 2025 19:16:02 +0100 Subject: [PATCH 1/5] gh-130959: Reject whitespace in fractions, in pure Python `fromisoformat()` Fix the pure Python implementation of `fromisoformat()` to reject any non-digit characters, including whitespace, in the fractional part of time specification. This makes the behavior consistent with the C implementation, and prevents incorrect parsing of these fractions (e.g. `.400 ` would be misinterpreted as `.04`). --- Lib/_pydatetime.py | 5 ++--- Lib/test/datetimetester.py | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index fcf4416f331092..26bcd1e491d78c 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -436,6 +436,8 @@ def _parse_hh_mm_ss_ff(tstr): raise ValueError("Invalid microsecond separator") else: pos += 1 + if not all(map(_is_ascii_digit, tstr[pos:])): + raise ValueError("Non-digit values in fraction") len_remainder = len_str - pos @@ -447,9 +449,6 @@ def _parse_hh_mm_ss_ff(tstr): time_comps[3] = int(tstr[pos:(pos+to_parse)]) if to_parse < 6: time_comps[3] *= _FRACTION_CORRECTION[to_parse-1] - if (len_remainder > to_parse - and not all(map(_is_ascii_digit, tstr[(pos+to_parse):]))): - raise ValueError("Non-digit values in unparsed fraction") return time_comps diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index ceeac9435dcb85..84eb872f964ba1 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -3556,6 +3556,9 @@ def test_fromisoformat_fails_datetime(self): '9999-12-31T24:00:00.000000', # Year is invalid after wrapping due to 24:00 '2009-04-19T12:30Z12:00', # Extra time zone info after Z '2009-04-19T12:30:45:334034', # Invalid microsecond separator + '2009-04-19T12:30:45.400 +02:30', # Space between ms and timezone (gh-130959) + '2009-04-19T12:30:45.400 ', # Trailing space (gh-130959) + '2009-04-19T12:30:45. 400', # Space before fraction (gh-130959) ] for bad_str in bad_strs: @@ -4773,6 +4776,9 @@ def test_fromisoformat_fails(self): '12:30,5', # Decimal mark at end of minute '12:30:45.123456Z12:00', # Extra time zone info after Z '12:30:45:334034', # Invalid microsecond separator + '12:30:45.400 +02:30', # Space between ms and timezone (gh-130959) + '12:30:45.400 ', # Trailing space (gh-130959) + '12:30:45. 400', # Space before fraction (gh-130959) ] for bad_str in bad_strs: From 86abd944ac9dfdeca80a9a10e03a3771656d3e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Fri, 7 Mar 2025 19:24:29 +0100 Subject: [PATCH 2/5] Add the news entry --- .../Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst diff --git a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst new file mode 100644 index 00000000000000..279174f8765e5e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst @@ -0,0 +1,3 @@ +Fix pure Python implementation of ``time.fromisoformat()`` to reject times +with spaces in fractional part (for example, ``12:34:56.400 ``), matching +the C implementation. From 0ea0ae1abdaa4e21b0a21b83e49f431d21b4b5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Fri, 7 Mar 2025 19:39:28 +0100 Subject: [PATCH 3/5] Use a different example to fix Sphinx lint --- .../next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst index 279174f8765e5e..7c2aed1344fec7 100644 --- a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst +++ b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst @@ -1,3 +1,3 @@ Fix pure Python implementation of ``time.fromisoformat()`` to reject times -with spaces in fractional part (for example, ``12:34:56.400 ``), matching +with spaces in fractional part (for example, ``12:34:56.400 +02:00``), matching the C implementation. From 1a98d89c3e992196f957541981b9d545ffafbf99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 8 Mar 2025 16:16:46 +0000 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Peter Bierma Co-authored-by: Paul Ganssle <1377457+pganssle@users.noreply.github.com> --- .../Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst index 7c2aed1344fec7..84f512905dd425 100644 --- a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst +++ b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst @@ -1,3 +1,3 @@ -Fix pure Python implementation of ``time.fromisoformat()`` to reject times +Fix pure-Python implementation of :func:`time.fromisoformat` to reject times with spaces in fractional part (for example, ``12:34:56.400 +02:00``), matching -the C implementation. +the C implementation. Patch by Michał Gorny. From 4d444bec1595c5519781337952e7b9f4370800de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 8 Mar 2025 17:45:48 +0100 Subject: [PATCH 5/5] Try fixing `:func:` ref. --- .../Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst index 84f512905dd425..85f61ca43b2580 100644 --- a/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst +++ b/Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst @@ -1,3 +1,3 @@ -Fix pure-Python implementation of :func:`time.fromisoformat` to reject times -with spaces in fractional part (for example, ``12:34:56.400 +02:00``), matching -the C implementation. Patch by Michał Gorny. +Fix pure-Python implementation of :func:`datetime.time.fromisoformat` to reject +times with spaces in fractional part (for example, ``12:34:56.400 +02:00``), +matching the C implementation. Patch by Michał Gorny.