[Python-checkins] bpo-35052: Fix handler on xml.dom.minidom.cloneNode() (GH-11061)

Victor Stinner webhook-mailer at python.org
Mon Dec 10 05:12:56 EST 2018


https://github.com/python/cpython/commit/8e0418688906206fe59bd26344320c0fc026849e
commit: 8e0418688906206fe59bd26344320c0fc026849e
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2018-12-10T11:12:53+01:00
summary:

bpo-35052: Fix handler on xml.dom.minidom.cloneNode() (GH-11061)

Fix xml.dom.minidom cloneNode() on a document with an entity: pass
the correct arguments to the user data handler of an entity (fix an
old copy/paste mistake).

Bug spotted and fix proposed by Charalampos Stratakis, initial
reproducer written by Petr Viktorin.

Co-Authored-By: Charalampos Stratakis <cstratak at redhat.com>
Co-Authored-By: Petr Viktorin <encukou at gmail.com>

files:
A Misc/NEWS.d/next/Library/2018-12-10-09-48-27.bpo-35052.xE1ymg.rst
M Lib/test/test_minidom.py
M Lib/xml/dom/minidom.py

diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py
index e626e14a5622..f3ef958b5353 100644
--- a/Lib/test/test_minidom.py
+++ b/Lib/test/test_minidom.py
@@ -3,7 +3,7 @@
 import copy
 import pickle
 import io
-from test.support import findfile
+from test import support
 import unittest
 
 import xml.dom.minidom
@@ -12,7 +12,7 @@
 from xml.dom.minidom import getDOMImplementation
 
 
-tstfile = findfile("test.xml", subdir="xmltestdata")
+tstfile = support.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"
@@ -837,6 +837,57 @@ def testClonePIShallow(self):
     def testClonePIDeep(self):
         self.check_clone_pi(1, "testClonePIDeep")
 
+    def check_clone_node_entity(self, clone_document):
+        # bpo-35052: Test user data handler in cloneNode() on a document with
+        # an entity
+        document = xml.dom.minidom.parseString("""
+            <?xml version="1.0" ?>
+            <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+                "http://www.w3.org/TR/html4/strict.dtd"
+                [ <!ENTITY smile "☺"> ]
+            >
+            <doc>Don't let entities make you frown ⌣</doc>
+        """.strip())
+
+        class Handler:
+            def handle(self, operation, key, data, src, dst):
+                self.operation = operation
+                self.key = key
+                self.data = data
+                self.src = src
+                self.dst = dst
+
+        handler = Handler()
+        doctype = document.doctype
+        entity = doctype.entities['smile']
+        entity.setUserData("key", "data", handler)
+
+        if clone_document:
+            # clone Document
+            clone = document.cloneNode(deep=True)
+
+            self.assertEqual(clone.documentElement.firstChild.wholeText,
+                             "Don't let entities make you frown ☺")
+            operation = xml.dom.UserDataHandler.NODE_IMPORTED
+            dst = clone.doctype.entities['smile']
+        else:
+            # clone DocumentType
+            with support.swap_attr(doctype, 'ownerDocument', None):
+                clone = doctype.cloneNode(deep=True)
+
+            operation = xml.dom.UserDataHandler.NODE_CLONED
+            dst = clone.entities['smile']
+
+        self.assertEqual(handler.operation, operation)
+        self.assertEqual(handler.key, "key")
+        self.assertEqual(handler.data, "data")
+        self.assertIs(handler.src, entity)
+        self.assertIs(handler.dst, dst)
+
+    def testCloneNodeEntity(self):
+        self.check_clone_node_entity(False)
+        self.check_clone_node_entity(True)
+
     def testNormalize(self):
         doc = parseString("<doc/>")
         root = doc.documentElement
diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py
index 469c51735e03..43569ddcbeac 100644
--- a/Lib/xml/dom/minidom.py
+++ b/Lib/xml/dom/minidom.py
@@ -1318,7 +1318,7 @@ def cloneNode(self, deep):
                     entity.encoding = e.encoding
                     entity.version = e.version
                     clone.entities._seq.append(entity)
-                    e._call_user_data_handler(operation, n, entity)
+                    e._call_user_data_handler(operation, e, entity)
             self._call_user_data_handler(operation, self, clone)
             return clone
         else:
@@ -1921,7 +1921,7 @@ def _clone_node(node, deep, newOwnerDocument):
                 entity.ownerDocument = newOwnerDocument
                 clone.entities._seq.append(entity)
                 if hasattr(e, '_call_user_data_handler'):
-                    e._call_user_data_handler(operation, n, entity)
+                    e._call_user_data_handler(operation, e, entity)
     else:
         # Note the cloning of Document and DocumentType nodes is
         # implementation specific.  minidom handles those cases
diff --git a/Misc/NEWS.d/next/Library/2018-12-10-09-48-27.bpo-35052.xE1ymg.rst b/Misc/NEWS.d/next/Library/2018-12-10-09-48-27.bpo-35052.xE1ymg.rst
new file mode 100644
index 000000000000..4877188a2944
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-12-10-09-48-27.bpo-35052.xE1ymg.rst
@@ -0,0 +1,2 @@
+Fix xml.dom.minidom cloneNode() on a document with an entity: pass the
+correct arguments to the user data handler of an entity.



More information about the Python-checkins mailing list