diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index 2906ebe7822f52..52e1bc0f76a620 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -97,7 +97,7 @@ This module defines the following functions: .. 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) +.. function:: dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, aware_datetime=False, compact=False) Write *value* to a plist file. *Fp* should be a writable, binary file object. @@ -120,6 +120,8 @@ This module defines the following functions: is set as an :ref:`aware object `, it will convert to UTC timezone before writing it. + When *compact* is true, the XML elements will be written without indentation. + A :exc:`TypeError` will be raised if the object is of an unsupported type or a container that contains objects of unsupported types. @@ -131,8 +133,11 @@ This module defines the following functions: .. versionchanged:: 3.13 The keyword-only parameter *aware_datetime* has been added. + .. versionchanged:: 3.14 + The keyword-only parameter *compact* has been added. + -.. function:: dumps(value, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, aware_datetime=False) +.. function:: dumps(value, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, aware_datetime=False, compact=False) Return *value* as a plist-formatted bytes object. See the documentation for :func:`dump` for an explanation of the keyword diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index a6f595ccf08bf4..67db41c63e7cc5 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -413,6 +413,15 @@ pydoc (Contributed by Jelle Zijlstra in :gh:`101552`.) +plistlib +-------- + +* Add a new parameter *compact* to :func:`plistlib.dump` and + :func:`plistlib.dumps`. When *compact* is true, the XML elements will + be written without indentation. + (Contributed by Jiahao Li in :gh:`113056`.) + + symtable -------- diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 67e832db217319..6b55cf17eae24c 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -287,11 +287,12 @@ def end_date(self): class _DumbXMLWriter: - def __init__(self, file, indent_level=0, indent="\t"): + def __init__(self, file, indent_level=0, indent="\t", compact=False): self.file = file self.stack = [] self._indent_level = indent_level self.indent = indent + self.compact = compact def begin_element(self, element): self.stack.append(element) @@ -308,7 +309,6 @@ def simple_element(self, element, value=None): if value is not None: value = _escape(value) self.writeln("<%s>%s" % (element, value, element)) - else: self.writeln("<%s/>" % element) @@ -319,19 +319,22 @@ def writeln(self, line): # XXX: is this test needed? if isinstance(line, str): line = line.encode('utf-8') - self.file.write(self._indent_level * self.indent) - self.file.write(line) - self.file.write(b'\n') + if not self.compact: + self.file.write(self._indent_level * self.indent) + self.file.write(line) + self.file.write(b'\n') + else: + self.file.write(line) class _PlistWriter(_DumbXMLWriter): def __init__( self, file, indent_level=0, indent=b"\t", writeHeader=1, - sort_keys=True, skipkeys=False, aware_datetime=False): + sort_keys=True, skipkeys=False, aware_datetime=False, compact=False): if writeHeader: file.write(PLISTHEADER) - _DumbXMLWriter.__init__(self, file, indent_level, indent) + _DumbXMLWriter.__init__(self, file, indent_level, indent, compact) self._sort_keys = sort_keys self._skipkeys = skipkeys self._aware_datetime = aware_datetime @@ -642,7 +645,7 @@ def _count_to_size(count): _scalars = (str, int, float, datetime.datetime, bytes) class _BinaryPlistWriter (object): - def __init__(self, fp, sort_keys, skipkeys, aware_datetime=False): + def __init__(self, fp, sort_keys, skipkeys, aware_datetime=False, compact=False): self._fp = fp self._sort_keys = sort_keys self._skipkeys = skipkeys @@ -917,7 +920,7 @@ def loads(value, *, fmt=None, dict_type=dict, aware_datetime=False): def dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, - aware_datetime=False): + aware_datetime=False, compact=False): """Write 'value' to a .plist file. 'fp' should be a writable, binary file object. """ @@ -925,15 +928,15 @@ def dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False, raise ValueError("Unsupported format: %r"%(fmt,)) writer = _FORMATS[fmt]["writer"](fp, sort_keys=sort_keys, skipkeys=skipkeys, - aware_datetime=aware_datetime) + aware_datetime=aware_datetime, compact=compact) writer.write(value) def dumps(value, *, fmt=FMT_XML, skipkeys=False, sort_keys=True, - aware_datetime=False): + aware_datetime=False, compact=False): """Return a bytes object with the contents for a .plist file. """ fp = BytesIO() dump(value, fp, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys, - aware_datetime=aware_datetime) + aware_datetime=aware_datetime, compact=compact) return fp.getvalue() diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index b231b05f864ab9..51a743e84a5a74 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -1,4 +1,3 @@ -# Copyright (C) 2003-2013 Python Software Foundation import copy import operator import pickle @@ -900,6 +899,13 @@ def test_dump_naive_datetime_with_aware_datetime_option(self): expected = dt.astimezone(datetime.UTC).replace(tzinfo=None) self.assertEqual(parsed, expected) + def test_compact_mode(self): + pl = self._create() + for fmt in ALL_FORMATS: + with self.subTest(fmt=fmt): + data = plistlib.dumps(pl, fmt=fmt, compact=True) + pl2 = plistlib.loads(data) + self.assertEqual(dict(pl), dict(pl2)) class TestBinaryPlistlib(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2024-10-28-20-19-35.gh-issue-113056.ndF_hX.rst b/Misc/NEWS.d/next/Library/2024-10-28-20-19-35.gh-issue-113056.ndF_hX.rst new file mode 100644 index 00000000000000..71f762319dc998 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-28-20-19-35.gh-issue-113056.ndF_hX.rst @@ -0,0 +1,3 @@ +Add a new parameter *compact* to :func:`plistlib.dump` and +:func:`plistlib.dumps`. When *compact* is true, the XML elements will be +written without indentation.