https://github.com/python/cpython/commit/33494b4d0dafc34ff4f1c118b7b3b5d8de3dd0f4
commit: 33494b4d0dafc34ff4f1c118b7b3b5d8de3dd0f4
branch: main
author: Michał Górny <mgo...@gentoo.org>
committer: vstinner <vstin...@python.org>
date: 2025-03-11T10:15:40+01:00
summary:

gh-130959: Reject whitespace in fractions, in pure Python `fromisoformat()` 
(#130962)

* 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`).

* Add the news entry

* Use a different example to fix Sphinx lint

* Apply suggestions from code review

Co-authored-by: Peter Bierma <zintensity...@gmail.com>
Co-authored-by: Paul Ganssle <1377457+pgans...@users.noreply.github.com>

* Try fixing `:func:` ref.

---------

Co-authored-by: Peter Bierma <zintensity...@gmail.com>
Co-authored-by: Paul Ganssle <1377457+pgans...@users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2025-03-07-19-24-27.gh-issue-130959.xO8vVS.rst
M Lib/_pydatetime.py
M Lib/test/datetimetester.py

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:
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..85f61ca43b2580
--- /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 :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.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to