Bug report
Bug description:
The pure-Python datetime.fromisoformat() raises a bare AssertionError for some
malformed strings, where the C accelerator correctly raises ValueError. fromisoformat
is documented to raise ValueError for invalid input only.
>>> import _pydatetime, _datetime
>>> _pydatetime.datetime.fromisoformat('2020-2020')
Traceback (most recent call last):
...
AssertionError
>>> _datetime.datetime.fromisoformat('2020-2020')
Traceback (most recent call last):
...
ValueError: Invalid isoformat string: '2020-2020'
'2020-1234' triggers the same divergence.
Because the failing check is an assert, it is stripped under python -O, so the
behaviour also differs by build flag:
$ python -O -c "import _pydatetime; _pydatetime.datetime.fromisoformat('2020-2020')"
ValueError: Invalid isoformat string: '2020-2020'
Root cause
For a 9-character input such as '2020-2020', datetime.fromisoformat() calls
_find_isoformat_datetime_separator(), which (seeing a - at index 4 and a non-W at
index 5) returns 10 — the YYYY-MM-DD branch. The date portion slice is then the full
9-character string, and _parse_isoformat_date() trips its
assert len(dtstr) in (7, 8, 10). The caller's except ValueError does not catch
AssertionError, so it escapes.
This is the sibling assert site to gh-151770 (an assert reached via the 24:00
midnight-rollover path with an out-of-range month), which was fixed in #151771. The
present site is a different location and a different input class.
Suggested fix
Replace the bare assert in _parse_isoformat_date() with an explicit ValueError whose
message matches the C implementation. date.fromisoformat() already length-checks before
calling _parse_isoformat_date(), so it is unaffected; datetime.fromisoformat()
re-wraps the ValueError with the full input string, producing the same message as the C
accelerator.
I have a patch and a regression test (added to test_fromisoformat_fails_datetime, which
runs under both the C and pure-Python test classes) ready.
CPython versions tested on:
3.16 (main, built from source)
Operating systems tested on:
macOS
Linked PRs
Bug report
Bug description:
The pure-Python
datetime.fromisoformat()raises a bareAssertionErrorfor somemalformed strings, where the C accelerator correctly raises
ValueError.fromisoformatis documented to raise
ValueErrorfor invalid input only.'2020-1234'triggers the same divergence.Because the failing check is an
assert, it is stripped underpython -O, so thebehaviour also differs by build flag:
Root cause
For a 9-character input such as
'2020-2020',datetime.fromisoformat()calls_find_isoformat_datetime_separator(), which (seeing a-at index 4 and a non-Watindex 5) returns 10 — the
YYYY-MM-DDbranch. The date portion slice is then the full9-character string, and
_parse_isoformat_date()trips itsassert len(dtstr) in (7, 8, 10). The caller'sexcept ValueErrordoes not catchAssertionError, so it escapes.This is the sibling assert site to gh-151770 (an assert reached via the
24:00midnight-rollover path with an out-of-range month), which was fixed in #151771. The
present site is a different location and a different input class.
Suggested fix
Replace the bare assert in
_parse_isoformat_date()with an explicitValueErrorwhosemessage matches the C implementation.
date.fromisoformat()already length-checks beforecalling
_parse_isoformat_date(), so it is unaffected;datetime.fromisoformat()re-wraps the
ValueErrorwith the full input string, producing the same message as the Caccelerator.
I have a patch and a regression test (added to
test_fromisoformat_fails_datetime, whichruns under both the C and pure-Python test classes) ready.
CPython versions tested on:
3.16 (main, built from source)
Operating systems tested on:
macOS
Linked PRs