Skip to content

Commit 30ec8e8

Browse files
committed
gh-151221: Raise ValueError for invalid <date> in plistlib
plistlib._date_from_string() raised a confusing TypeError (or an AttributeError for a completely non-matching value) when an XML <date> element held an invalid or partial ISO 8601 value such as "2024-06Z" or "2024Z". It now raises ValueError, consistent with the sibling <integer> and <real> elements. The binary plist format decodes dates with struct.unpack and is unaffected.
1 parent 4084141 commit 30ec8e8

4 files changed

Lines changed: 29 additions & 4 deletions

File tree

Doc/library/plistlib.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ This module defines the following functions:
8181
.. versionchanged:: 3.13
8282
The keyword-only parameter *aware_datetime* has been added.
8383

84+
.. versionchanged:: next
85+
A :exc:`ValueError` is now raised for an invalid ``<date>`` value in an
86+
XML plist (for example ``2024-06Z``). Previously such values raised an
87+
unspecified :exc:`TypeError`.
88+
8489

8590
.. function:: loads(data, *, fmt=None, dict_type=dict, aware_datetime=False)
8691

Lib/plistlib.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,22 @@ def _decode_base64(s):
139139

140140
def _date_from_string(s, aware_datetime):
141141
order = ('year', 'month', 'day', 'hour', 'minute', 'second')
142-
gd = _dateParser.match(s).groupdict()
142+
m = _dateParser.match(s)
143+
if m is None:
144+
raise ValueError(f"invalid date string: {s!r}")
145+
gd = m.groupdict()
143146
lst = []
144147
for key in order:
145148
val = gd[key]
146149
if val is None:
147150
break
148151
lst.append(int(val))
149-
if aware_datetime:
150-
return datetime.datetime(*lst, tzinfo=datetime.UTC)
151-
return datetime.datetime(*lst)
152+
try:
153+
if aware_datetime:
154+
return datetime.datetime(*lst, tzinfo=datetime.UTC)
155+
return datetime.datetime(*lst)
156+
except (TypeError, ValueError):
157+
raise ValueError(f"invalid date string: {s!r}") from None
152158

153159

154160
def _date_to_string(d, aware_datetime):

Lib/test/test_plistlib.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,17 @@ def test_invalidreal(self):
876876
self.assertRaises(ValueError, plistlib.loads,
877877
b"<plist><integer>not real</integer></plist>")
878878

879+
def test_invaliddate(self):
880+
for xml in (b"<plist><date>not a date</date></plist>",
881+
b"<plist><date></date></plist>",
882+
b"<plist><date>2024Z</date></plist>",
883+
b"<plist><date>2024-06Z</date></plist>",
884+
b"<plist><date>2024-13-01T00:00:00Z</date></plist>"):
885+
with self.subTest(xml=xml):
886+
self.assertRaises(ValueError, plistlib.loads, xml)
887+
self.assertRaises(ValueError, plistlib.loads, xml,
888+
aware_datetime=True)
889+
879890
def test_integer_notations(self):
880891
pl = b"<plist><integer>456</integer></plist>"
881892
value = plistlib.loads(pl)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`plistlib` now raises :exc:`ValueError` instead of an obscure
2+
:exc:`TypeError` when loading an invalid ``<date>`` value (for example
3+
``2024-06Z``) from an XML plist.

0 commit comments

Comments
 (0)