Skip to content

Fix parse() crash on an ISO 8601 date + duration interval#982

Open
vineethsaivs wants to merge 1 commit into
python-pendulum:masterfrom
vineethsaivs:fix/parse-date-duration-interval
Open

Fix parse() crash on an ISO 8601 date + duration interval#982
vineethsaivs wants to merge 1 commit into
python-pendulum:masterfrom
vineethsaivs:fix/parse-date-duration-interval

Conversation

@vineethsaivs

Copy link
Copy Markdown

Fixes #881.

Problem

parse() raises on an ISO 8601 interval built from a duration and a date-only endpoint:

>>> import pendulum
>>> pendulum.parse("2021-01-01/P1DT1H")
TypeError: add() got an unexpected keyword argument 'hours'
>>> pendulum.parse("P1Y/2021-01-01")
TypeError: subtract() got an unexpected keyword argument 'hours'

base_parse returns a datetime.date for a date-only endpoint, so pendulum.instance() returns a Date. _parse then calls Date.add() / Date.subtract() with the duration's hours / minutes / seconds / microseconds, which Date does not accept. Endpoints that carry a time component (e.g. 2021-01-01T00:00/P1D) return a DateTime and already work.

Fix

Promote a date-only endpoint to a midnight datetime before pendulum.instance() in the two duration branches of _parse. The interval then has DateTime endpoints, matching the time-bearing case and the function's Interval[DateTime] return annotation, and add() / subtract() accept the duration's time components. Endpoints that are already datetimes are unchanged (the helper returns them as-is), and this also replaces the t.cast("datetime.datetime", parsed.end) on the end branch, which was papering over exactly this case.

Test

test_parse_interval_with_date_and_duration covers both the forward (add) and reverse (subtract) forms and asserts the resulting Interval has the expected DateTime endpoints. It raises the TypeError above on the current code and passes with this change; the existing test_parse_interval and the rest of test_parsing.py still pass (validated with PENDULUM_EXTENSIONS=0, the pure-Python parser). Happy to add a CHANGELOG entry if you'd like one.

When parse() is given an interval made of a duration and a date-only
endpoint (e.g. "2021-01-01/P1DT1H" or "P1Y/2021-01-01"), base_parse
returns a datetime.date for the endpoint, so pendulum.instance() returns a
Date. _parse then calls Date.add()/Date.subtract() with the duration's
hours/minutes/seconds/microseconds, which Date does not accept, raising
'TypeError: add() got an unexpected keyword argument 'hours''. Endpoints
that carry a time component return a DateTime and worked fine.

Promote a date-only endpoint to a midnight datetime before instance(), so
the interval has DateTime endpoints (matching the time-bearing case and the
function's Interval[DateTime] return type) and add()/subtract() accept the
time components. Fixes python-pendulum#881.
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.

parse of date with duration cause error

1 participant