https://github.com/python/cpython/commit/6447fa3f1997cfdbc3d87b3cdcee25d851278c29 commit: 6447fa3f1997cfdbc3d87b3cdcee25d851278c29 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-01-12T09:08:52Z summary:
[3.14] gh-143346: Fix calculation of the line width for wrapped Base64 in plistlib (GH-143347) (GH-143719) It was incorrect in case of mixed tabs and spaces in indentation. (cherry picked from commit 5f28aa2f372339ba0c70373b96d33ec4d2879e04) Co-authored-by: Serhiy Storchaka <[email protected]> files: A Misc/NEWS.d/next/Library/2026-01-02-12-55-52.gh-issue-143346.iTekce.rst M Lib/plistlib.py M Lib/test/test_plistlib.py diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 655c51eea3da5d..5b2b4e42c95a83 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -384,7 +384,7 @@ def write_bytes(self, data): self._indent_level -= 1 maxlinelength = max( 16, - 76 - len(self.indent.replace(b"\t", b" " * 8) * self._indent_level)) + 76 - len((self.indent * self._indent_level).expandtabs())) for line in _encode_base64(data, maxlinelength).split(b"\n"): if line: diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index de2a2fd1fc34bf..d9216be4d95658 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -509,6 +509,69 @@ def test_bytes(self): data2 = plistlib.dumps(pl2) self.assertEqual(data, data2) + def test_bytes_indent(self): + header = ( + b'<?xml version="1.0" encoding="UTF-8"?>\n' + b'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n' + b'<plist version="1.0">\n') + data = [{'bytes': bytes(range(50))}] + pl = plistlib.dumps(data) + self.assertEqual(pl, header + + b'<array>\n' + b'\t<dict>\n' + b'\t\t<key>bytes</key>\n' + b'\t\t<data>\n' + b'\t\tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss\n' + b'\t\tLS4vMDE=\n' + b'\t\t</data>\n' + b'\t</dict>\n' + b'</array>\n' + b'</plist>\n') + + def dumps_with_indent(data, indent): + fp = BytesIO() + writer = plistlib._PlistWriter(fp, indent=indent) + writer.write(data) + return fp.getvalue() + + pl = dumps_with_indent(data, b' ') + self.assertEqual(pl, header + + b'<array>\n' + b' <dict>\n' + b' <key>bytes</key>\n' + b' <data>\n' + b' AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDE=\n' + b' </data>\n' + b' </dict>\n' + b'</array>\n' + b'</plist>\n') + + pl = dumps_with_indent(data, b' \t') + self.assertEqual(pl, header + + b'<array>\n' + b' \t<dict>\n' + b' \t \t<key>bytes</key>\n' + b' \t \t<data>\n' + b' \t \tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss\n' + b' \t \tLS4vMDE=\n' + b' \t \t</data>\n' + b' \t</dict>\n' + b'</array>\n' + b'</plist>\n') + + pl = dumps_with_indent(data, b'\t ') + self.assertEqual(pl, header + + b'<array>\n' + b'\t <dict>\n' + b'\t \t <key>bytes</key>\n' + b'\t \t <data>\n' + b'\t \t AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp\n' + b'\t \t KissLS4vMDE=\n' + b'\t \t </data>\n' + b'\t </dict>\n' + b'</array>\n' + b'</plist>\n') + def test_loads_str_with_xml_fmt(self): pl = self._create() b = plistlib.dumps(pl) @@ -581,7 +644,6 @@ def test_appleformatting(self): self.assertEqual(data, TESTDATA[fmt], "generated data was not identical to Apple's output") - def test_appleformattingfromliteral(self): self.maxDiff = None for fmt in ALL_FORMATS: diff --git a/Misc/NEWS.d/next/Library/2026-01-02-12-55-52.gh-issue-143346.iTekce.rst b/Misc/NEWS.d/next/Library/2026-01-02-12-55-52.gh-issue-143346.iTekce.rst new file mode 100644 index 00000000000000..93c45eefe373d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-02-12-55-52.gh-issue-143346.iTekce.rst @@ -0,0 +1,2 @@ +Fix incorrect wrapping of the Base64 data in :class:`!plistlib._PlistWriter` +when the indent contains a mix of tabs and spaces. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
