Skip to content

Commit e08aa98

Browse files
committed
pythongh-113537: support loads str in plistlib.loads (python#113582)
Add support for loading XML plists from a string value instead of a only bytes value.
1 parent ecf56a5 commit e08aa98

File tree

4 files changed

+24
-3
lines changed

4 files changed

+24
-3
lines changed

Doc/library/plistlib.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ top level object is a dictionary.
2727
To write out and to parse a plist file, use the :func:`dump` and
2828
:func:`load` functions.
2929

30-
To work with plist data in bytes objects, use :func:`dumps`
30+
To work with plist data in bytes or string objects, use :func:`dumps`
3131
and :func:`loads`.
3232

3333
Values can be strings, integers, floats, booleans, tuples, lists, dictionaries
@@ -89,11 +89,13 @@ This module defines the following functions:
8989

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

92-
Load a plist from a bytes object. See :func:`load` for an explanation of
93-
the keyword arguments.
92+
Load a plist from a bytes or string object. See :func:`load` for an
93+
explanation of the keyword arguments.
9494

9595
.. versionadded:: 3.4
9696

97+
.. versionchanged:: 3.13
98+
*data* can be a string when *fmt* equals :data:`FMT_XML`.
9799

98100
.. function:: dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, aware_datetime=False)
99101

Lib/plistlib.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,11 @@ def loads(value, *, fmt=None, dict_type=dict, aware_datetime=False):
906906
"""Read a .plist file from a bytes object.
907907
Return the unpacked root object (which usually is a dictionary).
908908
"""
909+
if isinstance(value, str):
910+
if fmt == FMT_BINARY:
911+
raise TypeError("value must be bytes-like object when fmt is "
912+
"FMT_BINARY")
913+
value = value.encode()
909914
fp = BytesIO(value)
910915
return load(fp, fmt=fmt, dict_type=dict_type, aware_datetime=aware_datetime)
911916

Lib/test/test_plistlib.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,19 @@ def test_bytes(self):
510510
data2 = plistlib.dumps(pl2)
511511
self.assertEqual(data, data2)
512512

513+
def test_loads_str_with_xml_fmt(self):
514+
pl = self._create()
515+
b = plistlib.dumps(pl)
516+
s = b.decode()
517+
self.assertIsInstance(s, str)
518+
pl2 = plistlib.loads(s)
519+
self.assertEqual(pl, pl2)
520+
521+
def test_loads_str_with_binary_fmt(self):
522+
msg = "value must be bytes-like object when fmt is FMT_BINARY"
523+
with self.assertRaisesRegex(TypeError, msg):
524+
plistlib.loads('test', fmt=plistlib.FMT_BINARY)
525+
513526
def test_indentation_array(self):
514527
data = [[[[[[[[{'test': b'aaaaaa'}]]]]]]]]
515528
self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support loads ``str`` in :func:`plistlib.loads`.

0 commit comments

Comments
 (0)