Skip to content

Commit 884eb9d

Browse files
authored
Merge branch 'main' into fix-mmap-setitem-resize-reentrancy
2 parents c9b2513 + 3308360 commit 884eb9d

16 files changed

Lines changed: 476 additions & 289 deletions

Doc/library/xml.dom.minidom.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,23 @@ module documentation. This section lists the differences between the API and
187187

188188
The *standalone* argument behaves exactly as in :meth:`writexml`.
189189

190+
No indentation is added inside an element
191+
which is marked with ``xml:space="preserve"``,
192+
which is declared in the DTD as not having element content,
193+
or, in absence of such declaration, which contains text,
194+
because this would change its content.
195+
190196
.. versionchanged:: 3.8
191197
The :meth:`toprettyxml` method now preserves the attribute order specified
192198
by the user.
193199

194200
.. versionchanged:: 3.9
195201
The *standalone* parameter was added.
196202

203+
.. versionchanged:: next
204+
Whitespace is no longer added inside an element with mixed content
205+
or marked with ``xml:space="preserve"``.
206+
197207
.. _dom-example:
198208

199209
DOM Example

Doc/library/xml.etree.elementtree.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,16 @@ Functions
631631
characters by default. For indenting partial subtrees inside of an
632632
already indented tree, pass the initial indentation level as *level*.
633633

634+
No whitespace is added inside an element
635+
which is marked with ``xml:space="preserve"``
636+
or which contains text, because this would change its content.
637+
634638
.. versionadded:: 3.9
635639

640+
.. versionchanged:: next
641+
Whitespace is no longer added inside an element with mixed content
642+
or marked with ``xml:space="preserve"``.
643+
636644

637645
.. function:: iselement(element)
638646

Doc/whatsnew/3.16.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,14 @@ xml
702702
and :meth:`!Document.createEntityReference`.
703703
(Contributed by Jason Orendorff and Serhiy Storchaka in :gh:`44871`.)
704704

705+
* :meth:`~xml.dom.minidom.Node.toprettyxml` in :mod:`xml.dom.minidom`
706+
and :func:`~xml.etree.ElementTree.indent` in :mod:`xml.etree.ElementTree`
707+
no longer add whitespace inside an element
708+
which is marked with ``xml:space="preserve"`` or which contains text.
709+
:meth:`!toprettyxml` also takes into account
710+
the content model declared in the DTD.
711+
(Contributed by Serhiy Storchaka in :gh:`81623`.)
712+
705713
* Add :meth:`!GetSpecifiedAttributeCount` method
706714
to the :mod:`XML parser <xml.parsers.expat>` objects.
707715
It tells how many of the reported attributes were given in the start tag
@@ -947,6 +955,15 @@ that may require changes to your code.
947955
Attributes defaulted in the DTD are no longer omitted when parsing.
948956
(Contributed by Jason Orendorff and Serhiy Storchaka in :gh:`44871`.)
949957

958+
* :meth:`~xml.dom.minidom.Node.toprettyxml` in :mod:`xml.dom.minidom`
959+
and :func:`~xml.etree.ElementTree.indent` in :mod:`xml.etree.ElementTree`
960+
no longer add whitespace inside an element
961+
which is marked with ``xml:space="preserve"`` or which contains text,
962+
because this changed the content of the element.
963+
:meth:`!toprettyxml` also takes into account
964+
the content model declared in the DTD.
965+
(Contributed by Serhiy Storchaka in :gh:`81623`.)
966+
950967
* On Windows, seeking a pipe now fails instead of silently appearing to
951968
succeed: :func:`os.lseek` and :meth:`~io.IOBase.seek` raise :exc:`OSError`,
952969
and :meth:`~io.IOBase.seekable` returns ``False``. As a consequence,

Lib/test/test_capi/test_marshal.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import marshal
2+
import os.path
3+
import unittest
4+
5+
from test import support
6+
from test.support import import_helper
7+
from test.support import os_helper
8+
from test.test_marshal import HelperMixin, omit_last_byte
9+
10+
11+
# Skip this test if _testcapi is are not available.
12+
_testcapi = import_helper.import_module('_testcapi')
13+
14+
15+
@support.cpython_only
16+
class CAPI_TestCase(unittest.TestCase, HelperMixin):
17+
18+
def test_read_from_file_error(self):
19+
# A read error is reported as OSError, not EOFError.
20+
# A directory cannot be read (on some platforms it cannot even
21+
# be opened, which is reported as OSError as well).
22+
os.mkdir(os_helper.TESTFN)
23+
self.addCleanup(os_helper.rmdir, os_helper.TESTFN)
24+
for func in (_testcapi.pymarshal_read_short_from_file,
25+
_testcapi.pymarshal_read_long_from_file,
26+
_testcapi.pymarshal_read_object_from_file,
27+
_testcapi.pymarshal_read_last_object_from_file):
28+
with self.subTest(func=func.__name__):
29+
self.assertRaises(OSError, func, os_helper.TESTFN)
30+
31+
@unittest.skipUnless(os.path.exists('/dev/full'), 'requires /dev/full')
32+
def test_write_to_file_error(self):
33+
# A write error is reported as OSError.
34+
# The data is large enough to not fit in the stdio buffer, so that
35+
# the error is detected before the file is closed.
36+
obj = b'x' * 100000
37+
with self.assertRaises(OSError):
38+
_testcapi.pymarshal_write_object_to_file(obj, '/dev/full',
39+
marshal.version)
40+
41+
def test_write_unmarshallable_to_file(self):
42+
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
43+
with self.assertRaisesRegex(ValueError, 'unmarshallable object'):
44+
_testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN,
45+
marshal.version)
46+
47+
def test_write_long_to_file(self):
48+
for v in range(marshal.version + 1):
49+
_testcapi.pymarshal_write_long_to_file(0x12345678, os_helper.TESTFN, v)
50+
with open(os_helper.TESTFN, 'rb') as f:
51+
data = f.read()
52+
os_helper.unlink(os_helper.TESTFN)
53+
self.assertEqual(data, b'\x78\x56\x34\x12')
54+
55+
def test_write_object_to_file(self):
56+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
57+
for v in range(marshal.version + 1):
58+
_testcapi.pymarshal_write_object_to_file(obj, os_helper.TESTFN, v)
59+
with open(os_helper.TESTFN, 'rb') as f:
60+
data = f.read()
61+
os_helper.unlink(os_helper.TESTFN)
62+
self.assertEqual(marshal.loads(data), obj)
63+
64+
def test_read_short_from_file(self):
65+
with open(os_helper.TESTFN, 'wb') as f:
66+
f.write(b'\x34\x12xxxx')
67+
r, p = _testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
68+
os_helper.unlink(os_helper.TESTFN)
69+
self.assertEqual(r, 0x1234)
70+
self.assertEqual(p, 2)
71+
72+
with open(os_helper.TESTFN, 'wb') as f:
73+
f.write(b'\x12')
74+
with self.assertRaises(EOFError):
75+
_testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
76+
os_helper.unlink(os_helper.TESTFN)
77+
78+
def test_read_long_from_file(self):
79+
with open(os_helper.TESTFN, 'wb') as f:
80+
f.write(b'\x78\x56\x34\x12xxxx')
81+
r, p = _testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
82+
os_helper.unlink(os_helper.TESTFN)
83+
self.assertEqual(r, 0x12345678)
84+
self.assertEqual(p, 4)
85+
86+
with open(os_helper.TESTFN, 'wb') as f:
87+
f.write(b'\x56\x34\x12')
88+
with self.assertRaises(EOFError):
89+
_testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
90+
os_helper.unlink(os_helper.TESTFN)
91+
92+
def test_read_last_object_from_file(self):
93+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
94+
for v in range(marshal.version + 1):
95+
data = marshal.dumps(obj, v)
96+
with open(os_helper.TESTFN, 'wb') as f:
97+
f.write(data + b'xxxx')
98+
r, p = _testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
99+
os_helper.unlink(os_helper.TESTFN)
100+
self.assertEqual(r, obj)
101+
102+
with open(os_helper.TESTFN, 'wb') as f:
103+
f.write(omit_last_byte(data))
104+
with self.assertRaises(EOFError):
105+
_testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
106+
os_helper.unlink(os_helper.TESTFN)
107+
108+
def test_read_object_from_file(self):
109+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
110+
for v in range(marshal.version + 1):
111+
data = marshal.dumps(obj, v)
112+
with open(os_helper.TESTFN, 'wb') as f:
113+
f.write(data + b'xxxx')
114+
r, p = _testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
115+
os_helper.unlink(os_helper.TESTFN)
116+
self.assertEqual(r, obj)
117+
self.assertEqual(p, len(data))
118+
119+
with open(os_helper.TESTFN, 'wb') as f:
120+
f.write(omit_last_byte(data))
121+
with self.assertRaises(EOFError):
122+
_testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
123+
os_helper.unlink(os_helper.TESTFN)
124+
125+
126+
if __name__ == "__main__":
127+
unittest.main()

Lib/test/test_marshal.py

Lines changed: 0 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -797,117 +797,6 @@ def test_slice(self):
797797
with self.assertRaises(ValueError):
798798
marshal.dumps(obj, version)
799799

800-
@support.cpython_only
801-
@unittest.skipUnless(_testcapi, 'requires _testcapi')
802-
class CAPI_TestCase(unittest.TestCase, HelperMixin):
803-
804-
def test_read_from_file_error(self):
805-
# A read error is reported as OSError, not EOFError.
806-
# A directory cannot be read (on some platforms it cannot even
807-
# be opened, which is reported as OSError as well).
808-
os.mkdir(os_helper.TESTFN)
809-
self.addCleanup(os_helper.rmdir, os_helper.TESTFN)
810-
for func in (_testcapi.pymarshal_read_short_from_file,
811-
_testcapi.pymarshal_read_long_from_file,
812-
_testcapi.pymarshal_read_object_from_file,
813-
_testcapi.pymarshal_read_last_object_from_file):
814-
with self.subTest(func=func.__name__):
815-
self.assertRaises(OSError, func, os_helper.TESTFN)
816-
817-
@unittest.skipUnless(os.path.exists('/dev/full'), 'requires /dev/full')
818-
def test_write_to_file_error(self):
819-
# A write error is reported as OSError.
820-
# The data is large enough to not fit in the stdio buffer, so that
821-
# the error is detected before the file is closed.
822-
obj = b'x' * 100000
823-
with self.assertRaises(OSError):
824-
_testcapi.pymarshal_write_object_to_file(obj, '/dev/full',
825-
marshal.version)
826-
827-
def test_write_unmarshallable_to_file(self):
828-
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
829-
with self.assertRaisesRegex(ValueError, 'unmarshallable object'):
830-
_testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN,
831-
marshal.version)
832-
833-
def test_write_long_to_file(self):
834-
for v in range(marshal.version + 1):
835-
_testcapi.pymarshal_write_long_to_file(0x12345678, os_helper.TESTFN, v)
836-
with open(os_helper.TESTFN, 'rb') as f:
837-
data = f.read()
838-
os_helper.unlink(os_helper.TESTFN)
839-
self.assertEqual(data, b'\x78\x56\x34\x12')
840-
841-
def test_write_object_to_file(self):
842-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
843-
for v in range(marshal.version + 1):
844-
_testcapi.pymarshal_write_object_to_file(obj, os_helper.TESTFN, v)
845-
with open(os_helper.TESTFN, 'rb') as f:
846-
data = f.read()
847-
os_helper.unlink(os_helper.TESTFN)
848-
self.assertEqual(marshal.loads(data), obj)
849-
850-
def test_read_short_from_file(self):
851-
with open(os_helper.TESTFN, 'wb') as f:
852-
f.write(b'\x34\x12xxxx')
853-
r, p = _testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
854-
os_helper.unlink(os_helper.TESTFN)
855-
self.assertEqual(r, 0x1234)
856-
self.assertEqual(p, 2)
857-
858-
with open(os_helper.TESTFN, 'wb') as f:
859-
f.write(b'\x12')
860-
with self.assertRaises(EOFError):
861-
_testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
862-
os_helper.unlink(os_helper.TESTFN)
863-
864-
def test_read_long_from_file(self):
865-
with open(os_helper.TESTFN, 'wb') as f:
866-
f.write(b'\x78\x56\x34\x12xxxx')
867-
r, p = _testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
868-
os_helper.unlink(os_helper.TESTFN)
869-
self.assertEqual(r, 0x12345678)
870-
self.assertEqual(p, 4)
871-
872-
with open(os_helper.TESTFN, 'wb') as f:
873-
f.write(b'\x56\x34\x12')
874-
with self.assertRaises(EOFError):
875-
_testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
876-
os_helper.unlink(os_helper.TESTFN)
877-
878-
def test_read_last_object_from_file(self):
879-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
880-
for v in range(marshal.version + 1):
881-
data = marshal.dumps(obj, v)
882-
with open(os_helper.TESTFN, 'wb') as f:
883-
f.write(data + b'xxxx')
884-
r, p = _testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
885-
os_helper.unlink(os_helper.TESTFN)
886-
self.assertEqual(r, obj)
887-
888-
with open(os_helper.TESTFN, 'wb') as f:
889-
f.write(omit_last_byte(data))
890-
with self.assertRaises(EOFError):
891-
_testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
892-
os_helper.unlink(os_helper.TESTFN)
893-
894-
def test_read_object_from_file(self):
895-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
896-
for v in range(marshal.version + 1):
897-
data = marshal.dumps(obj, v)
898-
with open(os_helper.TESTFN, 'wb') as f:
899-
f.write(data + b'xxxx')
900-
r, p = _testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
901-
os_helper.unlink(os_helper.TESTFN)
902-
self.assertEqual(r, obj)
903-
self.assertEqual(p, len(data))
904-
905-
with open(os_helper.TESTFN, 'wb') as f:
906-
f.write(omit_last_byte(data))
907-
with self.assertRaises(EOFError):
908-
_testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
909-
os_helper.unlink(os_helper.TESTFN)
910-
911800

912801
if __name__ == "__main__":
913802
unittest.main()

0 commit comments

Comments
 (0)