]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-113537: support loads str in plistlib.loads (#113582)
authorAN Long <aisk@users.noreply.github.com>
Sat, 6 Jan 2024 09:26:59 +0000 (17:26 +0800)
committerGitHub <noreply@github.com>
Sat, 6 Jan 2024 09:26:59 +0000 (10:26 +0100)
Add support for loading XML plists from a string value instead of a only bytes value.

Doc/library/plistlib.rst
Lib/plistlib.py
Lib/test/test_plistlib.py
Misc/NEWS.d/next/Library/2023-12-30-20-30-05.gh-issue-113537.v1W5_X.rst [new file with mode: 0644]

index 10f1a48fc70a72bf8d21f58d536382138ef18874..7416ca2650bab4bb94c43334e80f088e55088806 100644 (file)
@@ -27,7 +27,7 @@ top level object is a dictionary.
 To write out and to parse a plist file, use the :func:`dump` and
 :func:`load` functions.
 
-To work with plist data in bytes objects, use :func:`dumps`
+To work with plist data in bytes or string objects, use :func:`dumps`
 and :func:`loads`.
 
 Values can be strings, integers, floats, booleans, tuples, lists, dictionaries
@@ -89,11 +89,13 @@ This module defines the following functions:
 
 .. function:: loads(data, *, fmt=None, dict_type=dict, aware_datetime=False)
 
-   Load a plist from a bytes object. See :func:`load` for an explanation of
-   the keyword arguments.
+   Load a plist from a bytes or string object. See :func:`load` for an
+   explanation of the keyword arguments.
 
    .. versionadded:: 3.4
 
+   .. versionchanged:: 3.13
+      *data* can be a string when *fmt* equals :data:`FMT_XML`.
 
 .. function:: dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, aware_datetime=False)
 
index 0fc1b5cbfa8c497e95ffddc029c46cbc34fca889..188a0b399b587b26676b90adbd2fe9ceaf15eb8f 100644 (file)
@@ -906,6 +906,11 @@ def loads(value, *, fmt=None, dict_type=dict, aware_datetime=False):
     """Read a .plist file from a bytes object.
     Return the unpacked root object (which usually is a dictionary).
     """
+    if isinstance(value, str):
+        if fmt == FMT_BINARY:
+            raise TypeError("value must be bytes-like object when fmt is "
+                            "FMT_BINARY")
+        value = value.encode()
     fp = BytesIO(value)
     return load(fp, fmt=fmt, dict_type=dict_type, aware_datetime=aware_datetime)
 
index 1d2e14a30c4e1318361778259bac0c490d3fd13f..f47982907def211586c87186decb45504b5d4e6d 100644 (file)
@@ -510,6 +510,19 @@ class TestPlistlib(unittest.TestCase):
         data2 = plistlib.dumps(pl2)
         self.assertEqual(data, data2)
 
+    def test_loads_str_with_xml_fmt(self):
+        pl = self._create()
+        b = plistlib.dumps(pl)
+        s = b.decode()
+        self.assertIsInstance(s, str)
+        pl2 = plistlib.loads(s)
+        self.assertEqual(pl, pl2)
+
+    def test_loads_str_with_binary_fmt(self):
+        msg = "value must be bytes-like object when fmt is FMT_BINARY"
+        with self.assertRaisesRegex(TypeError, msg):
+            plistlib.loads('test', fmt=plistlib.FMT_BINARY)
+
     def test_indentation_array(self):
         data = [[[[[[[[{'test': b'aaaaaa'}]]]]]]]]
         self.assertEqual(plistlib.loads(plistlib.dumps(data)), data)
diff --git a/Misc/NEWS.d/next/Library/2023-12-30-20-30-05.gh-issue-113537.v1W5_X.rst b/Misc/NEWS.d/next/Library/2023-12-30-20-30-05.gh-issue-113537.v1W5_X.rst
new file mode 100644 (file)
index 0000000..a615081
--- /dev/null
@@ -0,0 +1 @@
+Support loads ``str`` in :func:`plistlib.loads`.