[Python-checkins] bpo-36409: Remove old plistlib API deprecated in 3.4 (GH-15615)

Ronald Oussoren webhook-mailer at python.org
Thu Sep 5 04:11:39 EDT 2019


https://github.com/python/cpython/commit/ce81a925ef2d466b0d801deaba9af44a0dfc2aa1
commit: ce81a925ef2d466b0d801deaba9af44a0dfc2aa1
branch: master
author: Jon Janzen <jjjonjanzen at gmail.com>
committer: Ronald Oussoren <ronaldoussoren at mac.com>
date: 2019-09-05T10:11:35+02:00
summary:

bpo-36409: Remove old plistlib API deprecated in 3.4 (GH-15615)

* Remove implementation for old plistlib API deprecated in 3.4

files:
A Misc/NEWS.d/next/Library/2019-03-23-16-42-46.bpo-36409.ZYVKao.rst
M Doc/library/plistlib.rst
M Doc/whatsnew/3.9.rst
M Lib/plistlib.py
M Lib/test/test_plistlib.py

diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst
index d84fcac0ef23..f71aaa2354e9 100644
--- a/Doc/library/plistlib.rst
+++ b/Doc/library/plistlib.rst
@@ -30,7 +30,7 @@ To work with plist data in bytes objects, use :func:`dumps`
 and :func:`loads`.
 
 Values can be strings, integers, floats, booleans, tuples, lists, dictionaries
-(but only with string keys), :class:`Data`, :class:`bytes`, :class:`bytesarray`
+(but only with string keys), :class:`bytes`, :class:`bytearray`
 or :class:`datetime.datetime` objects.
 
 .. versionchanged:: 3.4
@@ -40,6 +40,9 @@ or :class:`datetime.datetime` objects.
    Support added for reading and writing :class:`UID` tokens in binary plists as used
    by NSKeyedArchiver and NSKeyedUnarchiver.
 
+.. versionchanged:: 3.9
+   Old API removed.
+
 .. seealso::
 
    `PList manual page <https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/>`_
@@ -48,7 +51,7 @@ or :class:`datetime.datetime` objects.
 
 This module defines the following functions:
 
-.. function:: load(fp, \*, fmt=None, use_builtin_types=True, dict_type=dict)
+.. function:: load(fp, \*, fmt=None, dict_type=dict)
 
    Read a plist file. *fp* should be a readable and binary file object.
    Return the unpacked root object (which usually is a
@@ -62,10 +65,6 @@ This module defines the following functions:
 
    * :data:`FMT_BINARY`: Binary plist format
 
-   If *use_builtin_types* is true (the default) binary data will be returned
-   as instances of :class:`bytes`, otherwise it is returned as instances of
-   :class:`Data`.
-
    The *dict_type* is the type used for dictionaries that are read from the
    plist file.
 
@@ -80,7 +79,7 @@ This module defines the following functions:
    .. versionadded:: 3.4
 
 
-.. function:: loads(data, \*, fmt=None, use_builtin_types=True, dict_type=dict)
+.. function:: loads(data, \*, fmt=None, dict_type=dict)
 
    Load a plist from a bytes object. See :func:`load` for an explanation of
    the keyword arguments.
@@ -124,75 +123,6 @@ This module defines the following functions:
 
    .. versionadded:: 3.4
 
-The following functions are deprecated:
-
-.. function:: readPlist(pathOrFile)
-
-   Read a plist file. *pathOrFile* may be either a file name or a (readable
-   and binary) file object. Returns the unpacked root object (which usually
-   is a dictionary).
-
-   This function calls :func:`load` to do the actual work, see the documentation
-   of :func:`that function <load>` for an explanation of the keyword arguments.
-
-   .. deprecated:: 3.4 Use :func:`load` instead.
-
-   .. versionchanged:: 3.7
-      Dict values in the result are now normal dicts.  You no longer can use
-      attribute access to access items of these dictionaries.
-
-
-.. function:: writePlist(rootObject, pathOrFile)
-
-   Write *rootObject* to an XML plist file. *pathOrFile* may be either a file name
-   or a (writable and binary) file object
-
-   .. deprecated:: 3.4 Use :func:`dump` instead.
-
-
-.. function:: readPlistFromBytes(data)
-
-   Read a plist data from a bytes object.  Return the root object.
-
-   See :func:`load` for a description of the keyword arguments.
-
-   .. deprecated:: 3.4 Use :func:`loads` instead.
-
-   .. versionchanged:: 3.7
-      Dict values in the result are now normal dicts.  You no longer can use
-      attribute access to access items of these dictionaries.
-
-
-.. function:: writePlistToBytes(rootObject)
-
-   Return *rootObject* as an XML plist-formatted bytes object.
-
-   .. deprecated:: 3.4 Use :func:`dumps` instead.
-
-
-The following classes are available:
-
-.. class:: Data(data)
-
-   Return a "data" wrapper object around the bytes object *data*.  This is used
-   in functions converting from/to plists to represent the ``<data>`` type
-   available in plists.
-
-   It has one attribute, :attr:`data`, that can be used to retrieve the Python
-   bytes object stored in it.
-
-   .. deprecated:: 3.4 Use a :class:`bytes` object instead.
-
-.. class:: UID(data)
-
-   Wraps an :class:`int`.  This is used when reading or writing NSKeyedArchiver
-   encoded data, which contains UID (see PList manual).
-
-   It has one attribute, :attr:`data` which can be used to retrieve the int value
-   of the UID.  :attr:`data` must be in the range `0 <= data <= 2**64`.
-
-   .. versionadded:: 3.8
-
 
 The following constants are available:
 
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 0a0b91670ca5..009a66adff7d 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -213,6 +213,12 @@ Removed
   instead.  The ``xml.etree.cElementTree`` module has been removed.
   (Contributed by Serhiy Storchaka in :issue:`36543`.)
 
+* The old :mod:`plistlib` API has been removed, it was deprecated since Python
+  3.4. Use the :func:`load`, :func:`loads`, :func:`dump`, and :func:`dumps`
+  functions. Additionally, the ``use_builtin_types`` parameter was removed,
+  standard :class:`bytes` objects are always used.
+  (Contributed by Jon Janzen in :issue:`36409`.)
+
 
 Porting to Python 3.9
 =====================
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index 04f8a87634d3..a84bb57371ef 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -46,9 +46,7 @@
     print(pl["aKey"])
 """
 __all__ = [
-    "readPlist", "writePlist", "readPlistFromBytes", "writePlistToBytes",
-    "Data", "InvalidFileException", "FMT_XML", "FMT_BINARY",
-    "load", "dump", "loads", "dumps", "UID"
+    "InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps", "UID"
 ]
 
 import binascii
@@ -69,112 +67,6 @@
 globals().update(PlistFormat.__members__)
 
 
-#
-#
-# Deprecated functionality
-#
-#
-
-
- at contextlib.contextmanager
-def _maybe_open(pathOrFile, mode):
-    if isinstance(pathOrFile, str):
-        with open(pathOrFile, mode) as fp:
-            yield fp
-
-    else:
-        yield pathOrFile
-
-
-def readPlist(pathOrFile):
-    """
-    Read a .plist from a path or file. pathOrFile should either
-    be a file name, or a readable binary file object.
-
-    This function is deprecated, use load instead.
-    """
-    warn("The readPlist function is deprecated, use load() instead",
-        DeprecationWarning, 2)
-
-    with _maybe_open(pathOrFile, 'rb') as fp:
-        return load(fp, fmt=None, use_builtin_types=False)
-
-def writePlist(value, pathOrFile):
-    """
-    Write 'value' to a .plist file. 'pathOrFile' may either be a
-    file name or a (writable) file object.
-
-    This function is deprecated, use dump instead.
-    """
-    warn("The writePlist function is deprecated, use dump() instead",
-        DeprecationWarning, 2)
-    with _maybe_open(pathOrFile, 'wb') as fp:
-        dump(value, fp, fmt=FMT_XML, sort_keys=True, skipkeys=False)
-
-
-def readPlistFromBytes(data):
-    """
-    Read a plist data from a bytes object. Return the root object.
-
-    This function is deprecated, use loads instead.
-    """
-    warn("The readPlistFromBytes function is deprecated, use loads() instead",
-        DeprecationWarning, 2)
-    return load(BytesIO(data), fmt=None, use_builtin_types=False)
-
-
-def writePlistToBytes(value):
-    """
-    Return 'value' as a plist-formatted bytes object.
-
-    This function is deprecated, use dumps instead.
-    """
-    warn("The writePlistToBytes function is deprecated, use dumps() instead",
-        DeprecationWarning, 2)
-    f = BytesIO()
-    dump(value, f, fmt=FMT_XML, sort_keys=True, skipkeys=False)
-    return f.getvalue()
-
-
-class Data:
-    """
-    Wrapper for binary data.
-
-    This class is deprecated, use a bytes object instead.
-    """
-
-    def __init__(self, data):
-        if not isinstance(data, bytes):
-            raise TypeError("data must be as bytes")
-        self.data = data
-
-    @classmethod
-    def fromBase64(cls, data):
-        # base64.decodebytes just calls binascii.a2b_base64;
-        # it seems overkill to use both base64 and binascii.
-        return cls(_decode_base64(data))
-
-    def asBase64(self, maxlinelength=76):
-        return _encode_base64(self.data, maxlinelength)
-
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.data == other.data
-        elif isinstance(other, bytes):
-            return self.data == other
-        else:
-            return NotImplemented
-
-    def __repr__(self):
-        return "%s(%s)" % (self.__class__.__name__, repr(self.data))
-
-#
-#
-# End of deprecated functionality
-#
-#
-
-
 class UID:
     def __init__(self, data):
         if not isinstance(data, int):
@@ -202,7 +94,6 @@ def __eq__(self, other):
     def __hash__(self):
         return hash(self.data)
 
-
 #
 # XML support
 #
@@ -273,11 +164,10 @@ def _escape(text):
     return text
 
 class _PlistParser:
-    def __init__(self, use_builtin_types, dict_type):
+    def __init__(self, dict_type):
         self.stack = []
         self.current_key = None
         self.root = None
-        self._use_builtin_types = use_builtin_types
         self._dict_type = dict_type
 
     def parse(self, fileobj):
@@ -366,11 +256,7 @@ def end_string(self):
         self.add_object(self.get_data())
 
     def end_data(self):
-        if self._use_builtin_types:
-            self.add_object(_decode_base64(self.get_data()))
-
-        else:
-            self.add_object(Data.fromBase64(self.get_data()))
+        self.add_object(_decode_base64(self.get_data()))
 
     def end_date(self):
         self.add_object(_date_from_string(self.get_data()))
@@ -452,9 +338,6 @@ def write_value(self, value):
         elif isinstance(value, dict):
             self.write_dict(value)
 
-        elif isinstance(value, Data):
-            self.write_data(value)
-
         elif isinstance(value, (bytes, bytearray)):
             self.write_bytes(value)
 
@@ -467,9 +350,6 @@ def write_value(self, value):
         else:
             raise TypeError("unsupported type: %s" % type(value))
 
-    def write_data(self, data):
-        self.write_bytes(data.data)
-
     def write_bytes(self, data):
         self.begin_element("data")
         self._indent_level -= 1
@@ -563,8 +443,7 @@ class _BinaryPlistParser:
 
     see also: http://opensource.apple.com/source/CF/CF-744.18/CFBinaryPList.c
     """
-    def __init__(self, use_builtin_types, dict_type):
-        self._use_builtin_types = use_builtin_types
+    def __init__(self, dict_type):
         self._dict_type = dict_type
 
     def parse(self, fp):
@@ -664,10 +543,7 @@ def _read_object(self, ref):
 
         elif tokenH == 0x40:  # data
             s = self._get_size(tokenL)
-            if self._use_builtin_types:
-                result = self._fp.read(s)
-            else:
-                result = Data(self._fp.read(s))
+            result = self._fp.read(s)
 
         elif tokenH == 0x50:  # ascii string
             s = self._get_size(tokenL)
@@ -783,10 +659,6 @@ def _flatten(self, value):
             if (type(value), value) in self._objtable:
                 return
 
-        elif isinstance(value, Data):
-            if (type(value.data), value.data) in self._objtable:
-                return
-
         elif id(value) in self._objidtable:
             return
 
@@ -795,8 +667,6 @@ def _flatten(self, value):
         self._objlist.append(value)
         if isinstance(value, _scalars):
             self._objtable[(type(value), value)] = refnum
-        elif isinstance(value, Data):
-            self._objtable[(type(value.data), value.data)] = refnum
         else:
             self._objidtable[id(value)] = refnum
 
@@ -826,8 +696,6 @@ def _flatten(self, value):
     def _getrefnum(self, value):
         if isinstance(value, _scalars):
             return self._objtable[(type(value), value)]
-        elif isinstance(value, Data):
-            return self._objtable[(type(value.data), value.data)]
         else:
             return self._objidtable[id(value)]
 
@@ -885,10 +753,6 @@ def _write_object(self, value):
             f = (value - datetime.datetime(2001, 1, 1)).total_seconds()
             self._fp.write(struct.pack('>Bd', 0x33, f))
 
-        elif isinstance(value, Data):
-            self._write_size(0x40, len(value.data))
-            self._fp.write(value.data)
-
         elif isinstance(value, (bytes, bytearray)):
             self._write_size(0x40, len(value))
             self._fp.write(value)
@@ -970,7 +834,7 @@ def _is_fmt_binary(header):
 }
 
 
-def load(fp, *, fmt=None, use_builtin_types=True, dict_type=dict):
+def load(fp, *, fmt=None, dict_type=dict):
     """Read a .plist file. 'fp' should be a readable and binary file object.
     Return the unpacked root object (which usually is a dictionary).
     """
@@ -988,17 +852,16 @@ def load(fp, *, fmt=None, use_builtin_types=True, dict_type=dict):
     else:
         P = _FORMATS[fmt]['parser']
 
-    p = P(use_builtin_types=use_builtin_types, dict_type=dict_type)
+    p = P(dict_type=dict_type)
     return p.parse(fp)
 
 
-def loads(value, *, fmt=None, use_builtin_types=True, dict_type=dict):
+def loads(value, *, fmt=None, dict_type=dict):
     """Read a .plist file from a bytes object.
     Return the unpacked root object (which usually is a dictionary).
     """
     fp = BytesIO(value)
-    return load(
-        fp, fmt=fmt, use_builtin_types=use_builtin_types, dict_type=dict_type)
+    return load(fp, fmt=fmt, dict_type=dict_type)
 
 
 def dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False):
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
index 5c2d0265079a..d3ef6f8ffe3a 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -263,14 +263,12 @@ def test_uid_copy(self):
         self.assertEqual(copy.deepcopy(UID(1)), UID(1))
 
     def test_appleformatting(self):
-        for use_builtin_types in (True, False):
-            for fmt in ALL_FORMATS:
-                with self.subTest(fmt=fmt, use_builtin_types=use_builtin_types):
-                    pl = plistlib.loads(TESTDATA[fmt],
-                        use_builtin_types=use_builtin_types)
-                    data = plistlib.dumps(pl, fmt=fmt)
-                    self.assertEqual(data, TESTDATA[fmt],
-                        "generated data was not identical to Apple's output")
+        for fmt in ALL_FORMATS:
+            with self.subTest(fmt=fmt):
+                pl = plistlib.loads(TESTDATA[fmt])
+                data = plistlib.dumps(pl, fmt=fmt)
+                self.assertEqual(data, TESTDATA[fmt],
+                    "generated data was not identical to Apple's output")
 
 
     def test_appleformattingfromliteral(self):
@@ -524,8 +522,7 @@ def test_dump_duplicates(self):
         # Test effectiveness of saving duplicated objects
         for x in (None, False, True, 12345, 123.45, 'abcde', b'abcde',
                   datetime.datetime(2004, 10, 26, 10, 33, 33),
-                  plistlib.Data(b'abcde'), bytearray(b'abcde'),
-                  [12, 345], (12, 345), {'12': 345}):
+                  bytearray(b'abcde'), [12, 345], (12, 345), {'12': 345}):
             with self.subTest(x=x):
                 data = plistlib.dumps([x]*1000, fmt=plistlib.FMT_BINARY)
                 self.assertLess(len(data), 1100, repr(data))
@@ -533,8 +530,7 @@ def test_dump_duplicates(self):
     def test_identity(self):
         for x in (None, False, True, 12345, 123.45, 'abcde', b'abcde',
                   datetime.datetime(2004, 10, 26, 10, 33, 33),
-                  plistlib.Data(b'abcde'), bytearray(b'abcde'),
-                  [12, 345], (12, 345), {'12': 345}):
+                  bytearray(b'abcde'), [12, 345], (12, 345), {'12': 345}):
             with self.subTest(x=x):
                 data = plistlib.dumps([x]*2, fmt=plistlib.FMT_BINARY)
                 a, b = plistlib.loads(data)
@@ -621,95 +617,6 @@ def test_invalid_binary(self):
                 plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
 
 
-class TestPlistlibDeprecated(unittest.TestCase):
-    def test_io_deprecated(self):
-        pl_in = {
-            'key': 42,
-            'sub': {
-                'key': 9,
-                'alt': 'value',
-                'data': b'buffer',
-            }
-        }
-        pl_out = {
-            'key': 42,
-            'sub': {
-                'key': 9,
-                'alt': 'value',
-                'data': plistlib.Data(b'buffer'),
-            }
-        }
-
-        self.addCleanup(support.unlink, support.TESTFN)
-        with self.assertWarns(DeprecationWarning):
-            plistlib.writePlist(pl_in, support.TESTFN)
-
-        with self.assertWarns(DeprecationWarning):
-            pl2 = plistlib.readPlist(support.TESTFN)
-
-        self.assertEqual(pl_out, pl2)
-
-        os.unlink(support.TESTFN)
-
-        with open(support.TESTFN, 'wb') as fp:
-            with self.assertWarns(DeprecationWarning):
-                plistlib.writePlist(pl_in, fp)
-
-        with open(support.TESTFN, 'rb') as fp:
-            with self.assertWarns(DeprecationWarning):
-                pl2 = plistlib.readPlist(fp)
-
-        self.assertEqual(pl_out, pl2)
-
-    def test_bytes_deprecated(self):
-        pl = {
-            'key': 42,
-            'sub': {
-                'key': 9,
-                'alt': 'value',
-                'data': b'buffer',
-            }
-        }
-        with self.assertWarns(DeprecationWarning):
-            data = plistlib.writePlistToBytes(pl)
-
-        with self.assertWarns(DeprecationWarning):
-            pl2 = plistlib.readPlistFromBytes(data)
-
-        self.assertIsInstance(pl2, dict)
-        self.assertEqual(pl2, dict(
-            key=42,
-            sub=dict(
-                key=9,
-                alt='value',
-                data=plistlib.Data(b'buffer'),
-            )
-        ))
-
-        with self.assertWarns(DeprecationWarning):
-            data2 = plistlib.writePlistToBytes(pl2)
-        self.assertEqual(data, data2)
-
-    def test_dataobject_deprecated(self):
-        in_data = { 'key': plistlib.Data(b'hello') }
-        out_data = { 'key': b'hello' }
-
-        buf = plistlib.dumps(in_data)
-
-        cur = plistlib.loads(buf)
-        self.assertEqual(cur, out_data)
-        self.assertEqual(cur, in_data)
-
-        cur = plistlib.loads(buf, use_builtin_types=False)
-        self.assertEqual(cur, out_data)
-        self.assertEqual(cur, in_data)
-
-        with self.assertWarns(DeprecationWarning):
-            cur = plistlib.readPlistFromBytes(buf)
-        self.assertEqual(cur, out_data)
-        self.assertEqual(cur, in_data)
-
-
 class TestKeyedArchive(unittest.TestCase):
     def test_keyed_archive_data(self):
         # This is the structure of a NSKeyedArchive packed plist
@@ -749,7 +656,7 @@ def test__all__(self):
 
 
 def test_main():
-    support.run_unittest(TestPlistlib, TestPlistlibDeprecated, TestKeyedArchive, MiscTestCase)
+    support.run_unittest(TestPlistlib, TestKeyedArchive, MiscTestCase)
 
 
 if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Library/2019-03-23-16-42-46.bpo-36409.ZYVKao.rst b/Misc/NEWS.d/next/Library/2019-03-23-16-42-46.bpo-36409.ZYVKao.rst
new file mode 100644
index 000000000000..e516d3190f81
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-03-23-16-42-46.bpo-36409.ZYVKao.rst
@@ -0,0 +1 @@
+Remove the old plistlib API deprecated in Python 3.4
\ No newline at end of file



More information about the Python-checkins mailing list