Skip to content

Commit ce1220a

Browse files
committed
Make empty durations an error in pure-Python parser
Some of Debian's test runners noticed that the pydantic-extra-types tests are failing on 32-bit architectures: ______________________ test_invalid_zero_duration_string _______________________ def test_invalid_zero_duration_string(): """'P' is not a valid ISO 8601 duration and should raise a validation error.""" > with pytest.raises(ValidationError): E Failed: DID NOT RAISE <class 'pydantic_core._pydantic_core.ValidationError'> tests/test_pendulum_dt.py:447: Failed Debian currently has pendulum 3.0.0, which disabled the Rust extensions if `struct.calcsize("P") == 4`, and the Rust and Python parsers disagree about how to handle an empty duration: the Rust parser reports an error, while the Python parser returns `Duration()`. 3.1.0 removes that particular limitation on using Rust extensions on 32-bit architectures, but the parser discrepancy still seems to be present. I don't have access to the full text of the standard, but Wikipedia's summary says 'However, at least one element must be present, thus "P" is not a valid representation for a duration of 0 seconds', so I think the Rust parser is correct. Adjust the Python parser to match.
1 parent fc386be commit ce1220a

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

src/pendulum/parsing/iso8601.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def parse_iso8601(
265265

266266
def _parse_iso8601_duration(text: str, **options: str) -> Duration | None:
267267
m = ISO8601_DURATION.fullmatch(text)
268-
if not m:
268+
if not m or (not m.group("w") and not m.group("ymd") and not m.group("hms")):
269269
return None
270270

271271
years = 0

tests/parsing/test_parse_iso8601.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_parse_iso8601(text: str, expected: date) -> None:
9090
assert parse_iso8601(text) == expected
9191

9292

93-
def test_parse_ios8601_invalid():
93+
def test_parse_iso8601_invalid():
9494
# Invalid month
9595
with pytest.raises(ValueError):
9696
parse_iso8601("20161306T123456")
@@ -193,7 +193,7 @@ def test_parse_ios8601_invalid():
193193
("P2Y30M4DT5H6M7S", (2, 30, 0, 4, 5, 6, 7, 0)),
194194
],
195195
)
196-
def test_parse_ios8601_duration(
196+
def test_parse_iso8601_duration(
197197
text: str, expected: tuple[int, int, int, int, int, int, int, int]
198198
) -> None:
199199
parsed = parse_iso8601(text)
@@ -208,3 +208,9 @@ def test_parse_ios8601_duration(
208208
parsed.remaining_seconds,
209209
parsed.microseconds,
210210
) == expected
211+
212+
213+
def test_parse_iso8601_duration_invalid():
214+
# Must include at least one element
215+
with pytest.raises(ValueError):
216+
parse_iso8601("P")

0 commit comments

Comments
 (0)