diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst
index d84fcac0ef2..f71aaa2354e 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 `_
@@ -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 ` 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 ```` 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 0a0b91670ca..009a66adff7 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 04f8a87634d..a84bb57371e 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -46,9 +46,7 @@ Parse Plist example:
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 @@ PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
globals().update(PlistFormat.__members__)
-#
-#
-# Deprecated functionality
-#
-#
-
-
-@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 @@ class UID:
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 @@ class _PlistParser:
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 @@ class _PlistWriter(_DumbXMLWriter):
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 @@ class _PlistWriter(_DumbXMLWriter):
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 @@ class _BinaryPlistParser:
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 @@ class _BinaryPlistWriter (object):
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 @@ class _BinaryPlistWriter (object):
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 @@ class _BinaryPlistWriter (object):
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 @@ class _BinaryPlistWriter (object):
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 @@ _FORMATS={
}
-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 5c2d0265079..d3ef6f8ffe3 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -263,14 +263,12 @@ class TestPlistlib(unittest.TestCase):
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 @@ class TestBinaryPlistlib(unittest.TestCase):
# 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 @@ class TestBinaryPlistlib(unittest.TestCase):
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 @@ class TestBinaryPlistlib(unittest.TestCase):
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 @@ class MiscTestCase(unittest.TestCase):
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 00000000000..e516d3190f8
--- /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