Skip to content

gh-152157: Reject empty fraction before timezone in C fromisoformat#152161

Merged
StanFromIreland merged 4 commits into
python:mainfrom
tonghuaroot:fix-c-fromisoformat-empty-fraction-tz
Jul 1, 2026
Merged

gh-152157: Reject empty fraction before timezone in C fromisoformat#152161
StanFromIreland merged 4 commits into
python:mainfrom
tonghuaroot:fix-c-fromisoformat-empty-fraction-tz

Conversation

@tonghuaroot

Copy link
Copy Markdown
Contributor

Fixes gh-152157

datetime.fromisoformat() and time.fromisoformat() accepted, in the C accelerator, a
decimal separator (. or ,) followed by zero fractional digits when a timezone
designator (+/-/Z) came next, e.g. '2020-01-01T12:34:56.+05:00' or '12:34:56.Z'.
The pure-Python implementation already raised ValueError for these. ISO 8601 §4.2.2.4 and
RFC 3339 §5.6 require at least one digit after the decimal sign, so the C side was the
lenient/incorrect one.

Divergence (before this PR)

Input C accelerator Pure-Python
'2020-01-01T12:34:56.+05:00' parses, microsecond=0 ValueError
'2020-01-01T12:34:56.Z' parses, microsecond=0 ValueError
'2020-01-01T12:34:56,+05:00' parses, microsecond=0 ValueError
'12:34:56.+05:00' parses, microsecond=0 ValueError
'12:34:56,+05:00' parses, microsecond=0 ValueError
'12:34:56.Z' parses, microsecond=0 ValueError

After this PR both implementations raise ValueError for all of the above, and all
previously-accepted valid strings (.5, .123456, comma fractions, no-fraction +offset,
Z) parse identically on both.

Fix

In parse_hh_mm_ss_ff() the decimal-separator case is now handled before the generic
end-of-substring check, so a separator with no following digit is rejected instead of being
treated as trailing content. The standalone trailing separator ('12:34:56.') remains
rejected. No change to the valid-fraction or no-fraction paths.

Note for reviewers

The spec requires ≥1 digit after the decimal sign, and the C implementation already rejects
a standalone trailing separator, so this PR fixes C to reject. The alternative direction
(making pure-Python lenient) is possible but contradicts both the spec and C's own
end-of-string behavior; happy to flip the approach if you'd rather standardize on lenient.

Tests

Added the four empty-fraction-before-tz inputs (offset, negative offset, Z, comma) to the
datetime and time fromisoformat failure tests, which run against both the C and
pure-Python implementations. Positive parity (valid fractions, comma fractions, and
no-fraction-with-offset) is already covered by the existing *_examples tests, which also
run on both implementations.

./python.exe -m test test_datetime passes (both impls), with no refleaks for the touched
tests.

…rmat

The C accelerator for datetime.fromisoformat() and time.fromisoformat()
accepted a decimal separator (. or ,) with no following digit when a
timezone designator came next, e.g. '12:34:56.+05:00', while the
pure-Python implementation correctly raised ValueError. Handle the
decimal-separator case before the generic end-of-substring check so an
empty fraction is rejected.
Comment thread Misc/NEWS.d/next/Library/2026-06-25-07-08-17.gh-issue-152157.dt5Ef0.rst Outdated
@StanFromIreland StanFromIreland added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes labels Jul 1, 2026
@StanFromIreland StanFromIreland merged commit 112c69a into python:main Jul 1, 2026
64 checks passed
@miss-islington-app

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @StanFromIreland for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Sorry, @tonghuaroot and @StanFromIreland, I could not cleanly backport this to 3.14 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 112c69a0514902af2d2f7d0503de6690ca59a10f 3.14

@bedevere-app

bedevere-app Bot commented Jul 1, 2026

Copy link
Copy Markdown

GH-152761 is a backport of this pull request to the 3.15 branch.

@miss-islington-app

Copy link
Copy Markdown

Sorry, @tonghuaroot and @StanFromIreland, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 112c69a0514902af2d2f7d0503de6690ca59a10f 3.13

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label Jul 1, 2026
@StanFromIreland

Copy link
Copy Markdown
Member

@tonghuaroot can you please do the backports?

@bedevere-app

bedevere-app Bot commented Jul 1, 2026

Copy link
Copy Markdown

GH-152765 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Jul 1, 2026
@bedevere-app

bedevere-app Bot commented Jul 1, 2026

Copy link
Copy Markdown

GH-152766 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 bugs and security fixes label Jul 1, 2026
@tonghuaroot

Copy link
Copy Markdown
Contributor Author

Done — opened #152765 for 3.14 and #152766 for 3.13 (the 3.13 accelerator lacked the i < 2 decimal-on-hour check, so that branch only gets the empty-fraction rejection). Both build cleanly and test_datetime passes locally.

StanFromIreland added a commit that referenced this pull request Jul 1, 2026
…misoformat` (GH-152161) (#152761)

(cherry picked from commit 112c69a)

Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com>
Co-authored-by: Stan Ulbrych <stan@python.org>
@StanFromIreland

Copy link
Copy Markdown
Member

We need to backport #152061 first, can you do those please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

datetime/time.fromisoformat: C accelerator accepts an empty fraction before a timezone designator

2 participants