Skip to content

datetime.fromisoformat() raises AssertionError instead of ValueError in the pure-Python implementation #152060

Description

@tonghuaroot

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions