Skip to content

Commit 8d928e3

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 e924bb6 commit 8d928e3

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
@@ -86,6 +86,11 @@ This module defines the following functions:
8686
.. versionchanged:: 3.13
8787
The keyword-only parameter *aware_datetime* has been added.
8888

89+
.. versionchanged:: next
90+
A :exc:`ValueError` is now raised for an invalid ``<date>`` value in an
91+
XML plist (for example ``2024-06Z``). Previously such values raised an
92+
unspecified :exc:`TypeError`.
93+
8994

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

Lib/plistlib.py

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

143143
def _date_from_string(s, aware_datetime):
144144
order = ('year', 'month', 'day', 'hour', 'minute', 'second')
145-
gd = _dateParser.match(s).groupdict()
145+
m = _dateParser.match(s)
146+
if m is None:
147+
raise ValueError(f"invalid date string: {s!r}")
148+
gd = m.groupdict()
146149
lst = []
147150
for key in order:
148151
val = gd[key]
149152
if val is None:
150153
break
151154
lst.append(int(val))
152-
if aware_datetime:
153-
return datetime.datetime(*lst, tzinfo=datetime.UTC)
154-
return datetime.datetime(*lst)
155+
try:
156+
if aware_datetime:
157+
return datetime.datetime(*lst, tzinfo=datetime.UTC)
158+
return datetime.datetime(*lst)
159+
except (TypeError, ValueError):
160+
raise ValueError(f"invalid date string: {s!r}") from None
155161

156162

157163
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
@@ -795,6 +795,17 @@ def test_invalidreal(self):
795795
self.assertRaises(ValueError, plistlib.loads,
796796
b"<plist><integer>not real</integer></plist>")
797797

798+
def test_invaliddate(self):
799+
for xml in (b"<plist><date>not a date</date></plist>",
800+
b"<plist><date></date></plist>",
801+
b"<plist><date>2024Z</date></plist>",
802+
b"<plist><date>2024-06Z</date></plist>",
803+
b"<plist><date>2024-13-01T00:00:00Z</date></plist>"):
804+
with self.subTest(xml=xml):
805+
self.assertRaises(ValueError, plistlib.loads, xml)
806+
self.assertRaises(ValueError, plistlib.loads, xml,
807+
aware_datetime=True)
808+
798809
def test_integer_notations(self):
799810
pl = b"<plist><integer>456</integer></plist>"
800811
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)