mirror of
https://github.com/python/cpython.git
synced 2025-09-30 20:31:52 +00:00
Issue #10131: Fixed deep copying of minidom documents. Based on patch
by Marian Ganisin.
This commit is contained in:
commit
37f5421954
4 changed files with 94 additions and 45 deletions
|
@ -1,5 +1,6 @@
|
||||||
# test for xml.dom.minidom
|
# test for xml.dom.minidom
|
||||||
|
|
||||||
|
import copy
|
||||||
import pickle
|
import pickle
|
||||||
from test.support import findfile
|
from test.support import findfile
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -11,6 +12,13 @@ from xml.dom.minidom import getDOMImplementation
|
||||||
|
|
||||||
|
|
||||||
tstfile = findfile("test.xml", subdir="xmltestdata")
|
tstfile = findfile("test.xml", subdir="xmltestdata")
|
||||||
|
sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
|
||||||
|
"<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
|
||||||
|
" 'http://xml.python.org/system' [\n"
|
||||||
|
" <!ELEMENT e EMPTY>\n"
|
||||||
|
" <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
|
||||||
|
"]><doc attr='value'> text\n"
|
||||||
|
"<?pi sample?> <!-- comment --> <e/> </doc>")
|
||||||
|
|
||||||
# The tests of DocumentType importing use these helpers to construct
|
# The tests of DocumentType importing use these helpers to construct
|
||||||
# the documents to work with, since not all DOM builders actually
|
# the documents to work with, since not all DOM builders actually
|
||||||
|
@ -1481,52 +1489,54 @@ class MinidomTest(unittest.TestCase):
|
||||||
self.confirm(e.isSameNode(doc.getElementById("w"))
|
self.confirm(e.isSameNode(doc.getElementById("w"))
|
||||||
and a2.isId)
|
and a2.isId)
|
||||||
|
|
||||||
|
def assert_recursive_equal(self, doc, doc2):
|
||||||
|
stack = [(doc, doc2)]
|
||||||
|
while stack:
|
||||||
|
n1, n2 = stack.pop()
|
||||||
|
self.assertEqual(n1.nodeType, n2.nodeType)
|
||||||
|
self.assertEqual(len(n1.childNodes), len(n2.childNodes))
|
||||||
|
self.assertEqual(n1.nodeName, n2.nodeName)
|
||||||
|
self.assertFalse(n1.isSameNode(n2))
|
||||||
|
self.assertFalse(n2.isSameNode(n1))
|
||||||
|
if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
|
||||||
|
len(n1.entities)
|
||||||
|
len(n2.entities)
|
||||||
|
len(n1.notations)
|
||||||
|
len(n2.notations)
|
||||||
|
self.assertEqual(len(n1.entities), len(n2.entities))
|
||||||
|
self.assertEqual(len(n1.notations), len(n2.notations))
|
||||||
|
for i in range(len(n1.notations)):
|
||||||
|
# XXX this loop body doesn't seem to be executed?
|
||||||
|
no1 = n1.notations.item(i)
|
||||||
|
no2 = n1.notations.item(i)
|
||||||
|
self.assertEqual(no1.name, no2.name)
|
||||||
|
self.assertEqual(no1.publicId, no2.publicId)
|
||||||
|
self.assertEqual(no1.systemId, no2.systemId)
|
||||||
|
stack.append((no1, no2))
|
||||||
|
for i in range(len(n1.entities)):
|
||||||
|
e1 = n1.entities.item(i)
|
||||||
|
e2 = n2.entities.item(i)
|
||||||
|
self.assertEqual(e1.notationName, e2.notationName)
|
||||||
|
self.assertEqual(e1.publicId, e2.publicId)
|
||||||
|
self.assertEqual(e1.systemId, e2.systemId)
|
||||||
|
stack.append((e1, e2))
|
||||||
|
if n1.nodeType != Node.DOCUMENT_NODE:
|
||||||
|
self.assertTrue(n1.ownerDocument.isSameNode(doc))
|
||||||
|
self.assertTrue(n2.ownerDocument.isSameNode(doc2))
|
||||||
|
for i in range(len(n1.childNodes)):
|
||||||
|
stack.append((n1.childNodes[i], n2.childNodes[i]))
|
||||||
|
|
||||||
def testPickledDocument(self):
|
def testPickledDocument(self):
|
||||||
doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
|
doc = parseString(sample)
|
||||||
"<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
|
|
||||||
" 'http://xml.python.org/system' [\n"
|
|
||||||
" <!ELEMENT e EMPTY>\n"
|
|
||||||
" <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
|
|
||||||
"]><doc attr='value'> text\n"
|
|
||||||
"<?pi sample?> <!-- comment --> <e/> </doc>")
|
|
||||||
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = pickle.dumps(doc, proto)
|
s = pickle.dumps(doc, proto)
|
||||||
doc2 = pickle.loads(s)
|
doc2 = pickle.loads(s)
|
||||||
stack = [(doc, doc2)]
|
self.assert_recursive_equal(doc, doc2)
|
||||||
while stack:
|
|
||||||
n1, n2 = stack.pop()
|
def testDeepcopiedDocument(self):
|
||||||
self.confirm(n1.nodeType == n2.nodeType
|
doc = parseString(sample)
|
||||||
and len(n1.childNodes) == len(n2.childNodes)
|
doc2 = copy.deepcopy(doc)
|
||||||
and n1.nodeName == n2.nodeName
|
self.assert_recursive_equal(doc, doc2)
|
||||||
and not n1.isSameNode(n2)
|
|
||||||
and not n2.isSameNode(n1))
|
|
||||||
if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
|
|
||||||
len(n1.entities)
|
|
||||||
len(n2.entities)
|
|
||||||
len(n1.notations)
|
|
||||||
len(n2.notations)
|
|
||||||
self.confirm(len(n1.entities) == len(n2.entities)
|
|
||||||
and len(n1.notations) == len(n2.notations))
|
|
||||||
for i in range(len(n1.notations)):
|
|
||||||
# XXX this loop body doesn't seem to be executed?
|
|
||||||
no1 = n1.notations.item(i)
|
|
||||||
no2 = n1.notations.item(i)
|
|
||||||
self.confirm(no1.name == no2.name
|
|
||||||
and no1.publicId == no2.publicId
|
|
||||||
and no1.systemId == no2.systemId)
|
|
||||||
stack.append((no1, no2))
|
|
||||||
for i in range(len(n1.entities)):
|
|
||||||
e1 = n1.entities.item(i)
|
|
||||||
e2 = n2.entities.item(i)
|
|
||||||
self.confirm(e1.notationName == e2.notationName
|
|
||||||
and e1.publicId == e2.publicId
|
|
||||||
and e1.systemId == e2.systemId)
|
|
||||||
stack.append((e1, e2))
|
|
||||||
if n1.nodeType != Node.DOCUMENT_NODE:
|
|
||||||
self.confirm(n1.ownerDocument.isSameNode(doc)
|
|
||||||
and n2.ownerDocument.isSameNode(doc2))
|
|
||||||
for i in range(len(n1.childNodes)):
|
|
||||||
stack.append((n1.childNodes[i], n2.childNodes[i]))
|
|
||||||
|
|
||||||
def testSerializeCommentNodeWithDoubleHyphen(self):
|
def testSerializeCommentNodeWithDoubleHyphen(self):
|
||||||
doc = create_doc_without_doctype()
|
doc = create_doc_without_doctype()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Tests for xml.dom.minicompat
|
# Tests for xml.dom.minicompat
|
||||||
|
|
||||||
|
import copy
|
||||||
import pickle
|
import pickle
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ class NodeListTestCase(unittest.TestCase):
|
||||||
node_list = NodeList()
|
node_list = NodeList()
|
||||||
pickled = pickle.dumps(node_list, proto)
|
pickled = pickle.dumps(node_list, proto)
|
||||||
unpickled = pickle.loads(pickled)
|
unpickled = pickle.loads(pickled)
|
||||||
|
self.assertIsNot(unpickled, node_list)
|
||||||
self.assertEqual(unpickled, node_list)
|
self.assertEqual(unpickled, node_list)
|
||||||
|
|
||||||
# Non-empty NodeList.
|
# Non-empty NodeList.
|
||||||
|
@ -96,7 +98,41 @@ class NodeListTestCase(unittest.TestCase):
|
||||||
node_list.append(2)
|
node_list.append(2)
|
||||||
pickled = pickle.dumps(node_list, proto)
|
pickled = pickle.dumps(node_list, proto)
|
||||||
unpickled = pickle.loads(pickled)
|
unpickled = pickle.loads(pickled)
|
||||||
|
self.assertIsNot(unpickled, node_list)
|
||||||
self.assertEqual(unpickled, node_list)
|
self.assertEqual(unpickled, node_list)
|
||||||
|
|
||||||
|
def test_nodelist_copy(self):
|
||||||
|
# Empty NodeList.
|
||||||
|
node_list = NodeList()
|
||||||
|
copied = copy.copy(node_list)
|
||||||
|
self.assertIsNot(copied, node_list)
|
||||||
|
self.assertEqual(copied, node_list)
|
||||||
|
|
||||||
|
# Non-empty NodeList.
|
||||||
|
node_list.append([1])
|
||||||
|
node_list.append([2])
|
||||||
|
copied = copy.copy(node_list)
|
||||||
|
self.assertIsNot(copied, node_list)
|
||||||
|
self.assertEqual(copied, node_list)
|
||||||
|
for x, y in zip(copied, node_list):
|
||||||
|
self.assertIs(x, y)
|
||||||
|
|
||||||
|
def test_nodelist_deepcopy(self):
|
||||||
|
# Empty NodeList.
|
||||||
|
node_list = NodeList()
|
||||||
|
copied = copy.deepcopy(node_list)
|
||||||
|
self.assertIsNot(copied, node_list)
|
||||||
|
self.assertEqual(copied, node_list)
|
||||||
|
|
||||||
|
# Non-empty NodeList.
|
||||||
|
node_list.append([1])
|
||||||
|
node_list.append([2])
|
||||||
|
copied = copy.deepcopy(node_list)
|
||||||
|
self.assertIsNot(copied, node_list)
|
||||||
|
self.assertEqual(copied, node_list)
|
||||||
|
for x, y in zip(copied, node_list):
|
||||||
|
self.assertIsNot(x, y)
|
||||||
|
self.assertEqual(x, y)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -64,10 +64,10 @@ class NodeList(list):
|
||||||
length = property(_get_length, _set_length,
|
length = property(_get_length, _set_length,
|
||||||
doc="The number of nodes in the NodeList.")
|
doc="The number of nodes in the NodeList.")
|
||||||
|
|
||||||
def __getstate__(self):
|
# For backward compatibility
|
||||||
return list(self)
|
|
||||||
|
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
|
if state is None:
|
||||||
|
state = []
|
||||||
self[:] = state
|
self[:] = state
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #10131: Fixed deep copying of minidom documents. Based on patch
|
||||||
|
by Marian Ganisin.
|
||||||
|
|
||||||
- Issue #7990: dir() on ElementTree.Element now lists properties: "tag",
|
- Issue #7990: dir() on ElementTree.Element now lists properties: "tag",
|
||||||
"text", "tail" and "attrib". Original patch by Santoso Wijaya.
|
"text", "tail" and "attrib". Original patch by Santoso Wijaya.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue