From 30eb4290d8e193114d3780d1bf46a0416ba89bc8 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sat, 17 Oct 2026 21:43:26 +0300 Subject: [PATCH 1/2] gh-159637: Fix renaming an attribute to a prefixed name in minidom Document.renameNode() set the new prefix of an attribute before its new namespace, so the prefix was validated against the old namespace. Renaming an attribute with no namespace to a prefixed name in a namespace raised NamespaceErr after the attribute had been removed from its element. Set the namespace first, and check the prefix before removing the attribute, so that a rejected rename leaves the element unchanged. --- Lib/test/test_minidom.py | 22 ++++++++++++++++++++++ Lib/xml/dom/minidom.py | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 446bbe096bd19dc..b5028ee126ccee2 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -1880,6 +1880,28 @@ def testRenameAttribute(self): self.checkRenameNodeSharedConstraints(doc, attr) doc.unlink() + def testRenameAttributeToPrefixedName(self): + doc = parseString("") + elem = doc.documentElement + attr = elem.getAttributeNode("a") + attr = doc.renameNode(attr, "http://xml.python.org/ns", "p:c") + self.assertEqual(attr.name, "p:c") + self.assertEqual(attr.prefix, "p") + self.assertEqual(attr.localName, "c") + self.assertEqual(attr.namespaceURI, "http://xml.python.org/ns") + self.assertIsNone(elem.getAttributeNode("a")) + self.assertIs(elem.getAttributeNodeNS("http://xml.python.org/ns", "c"), + attr) + + # A rejected rename leaves the attribute on its element. + attr = elem.getAttributeNode("b") + self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr, + "http://xml.python.org/ns", "xml:lang") + self.assertEqual(attr.name, "b") + self.assertIsNone(attr.namespaceURI) + self.assertIs(elem.getAttributeNode("b"), attr) + doc.unlink() + def testRenameElement(self): doc = parseString("") elem = doc.documentElement diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index 7cb652a323dcc22..5ab58c76f032ad0 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -2129,15 +2129,17 @@ def renameNode(self, n, namespaceURI, name): prefix = None localName = None if n.nodeType == Node.ATTRIBUTE_NODE: + if prefix is not None: + _check_prefix(prefix, namespaceURI, True) element = n.ownerElement if element is not None: is_id = n._is_id element.removeAttributeNode(n) else: element = None + n.namespaceURI = namespaceURI n.prefix = prefix n._localName = localName - n.namespaceURI = namespaceURI n.nodeName = name if n.nodeType == Node.ELEMENT_NODE: n.tagName = name From 83c874608750917c992aeda68e1cea61f7ed312f Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Tue, 3 Nov 2026 17:54:07 +0200 Subject: [PATCH 2/2] Add a NEWS entry --- .../Library/2026-11-03-17-54-07.gh-issue-159637.0p15UL.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-11-03-17-54-07.gh-issue-159637.0p15UL.rst diff --git a/Misc/NEWS.d/next/Library/2026-11-03-17-54-07.gh-issue-159637.0p15UL.rst b/Misc/NEWS.d/next/Library/2026-11-03-17-54-07.gh-issue-159637.0p15UL.rst new file mode 100644 index 000000000000000..cd820a2868f52ec --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-11-03-17-54-07.gh-issue-159637.0p15UL.rst @@ -0,0 +1,4 @@ +Fix :meth:`Document.renameNode() ` in +:mod:`xml.dom.minidom` rejecting a valid rename of an attribute to a +prefixed name, and removing the attribute from its element when a rename +is rejected.