diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index 72140e41675c350..d092fb88d98eee6 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -81,6 +81,11 @@ This module defines the following functions: .. versionchanged:: 3.13 The keyword-only parameter *aware_datetime* has been added. + .. versionchanged:: next + A :exc:`ValueError` is now raised for an invalid ```` value in an + XML plist (for example ``2024-06Z``). Previously such values raised an + unspecified :exc:`TypeError`. + .. function:: loads(data, *, fmt=None, dict_type=dict, aware_datetime=False) diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 93f3ef5e38af843..3fa548e63f84d9f 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -139,16 +139,22 @@ def _decode_base64(s): def _date_from_string(s, aware_datetime): order = ('year', 'month', 'day', 'hour', 'minute', 'second') - gd = _dateParser.match(s).groupdict() + m = _dateParser.match(s) + if m is None: + raise ValueError(f"invalid date string: {s!r}") + gd = m.groupdict() lst = [] for key in order: val = gd[key] if val is None: break lst.append(int(val)) - if aware_datetime: - return datetime.datetime(*lst, tzinfo=datetime.UTC) - return datetime.datetime(*lst) + try: + if aware_datetime: + return datetime.datetime(*lst, tzinfo=datetime.UTC) + return datetime.datetime(*lst) + except (TypeError, ValueError): + raise ValueError(f"invalid date string: {s!r}") from None def _date_to_string(d, aware_datetime): diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index b9c261310bb5670..11e754c71e2dae5 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -876,6 +876,17 @@ def test_invalidreal(self): self.assertRaises(ValueError, plistlib.loads, b"not real") + def test_invaliddate(self): + for xml in (b"not a date", + b"", + b"2024Z", + b"2024-06Z", + b"2024-13-01T00:00:00Z"): + with self.subTest(xml=xml): + self.assertRaises(ValueError, plistlib.loads, xml) + self.assertRaises(ValueError, plistlib.loads, xml, + aware_datetime=True) + def test_integer_notations(self): pl = b"456" value = plistlib.loads(pl) diff --git a/Misc/NEWS.d/next/Library/2026-07-06-11-05-00.gh-issue-151221.Kp7Qm2.rst b/Misc/NEWS.d/next/Library/2026-07-06-11-05-00.gh-issue-151221.Kp7Qm2.rst new file mode 100644 index 000000000000000..2b64f14698e11b2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-06-11-05-00.gh-issue-151221.Kp7Qm2.rst @@ -0,0 +1,3 @@ +:mod:`plistlib` now raises :exc:`ValueError` instead of an obscure +:exc:`TypeError` when loading an invalid ```` value (for example +``2024-06Z``) from an XML plist.