Skip to content

Commit d956c30

Browse files
committed
gh-144270: make SubElement parent and tag positional-only
The C accelerator in _elementtree.c uses PyArg_ParseTuple, which makes parent and tag positional-only. The Python fallback in ElementTree.py allowed them as keyword arguments, creating an inconsistency. Most users never noticed because the C version overrides the Python version via "from _elementtree import *". Add "/" after tag in the Python signature to match the C behavior. The attrib parameter remains keyword-capable since the C version accepts it via get_attrib_from_keywords().
1 parent 645f5c4 commit d956c30

File tree

3 files changed

+25
-2
lines changed

3 files changed

+25
-2
lines changed

Doc/library/xml.etree.elementtree.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ Functions
693693
.. versionadded:: 3.2
694694

695695

696-
.. function:: SubElement(parent, tag, attrib={}, **extra)
696+
.. function:: SubElement(parent, tag, /, attrib={}, **extra)
697697

698698
Subelement factory. This function creates an element instance, and appends
699699
it to an existing element.
@@ -704,6 +704,9 @@ Functions
704704
attributes. *extra* contains additional attributes, given as keyword
705705
arguments. Returns an element instance.
706706

707+
.. versionchanged:: 3.15
708+
*parent* and *tag* are now positional-only parameters.
709+
707710

708711
.. function:: tostring(element, encoding="us-ascii", method="xml", *, \
709712
xml_declaration=None, default_namespace=None, \

Lib/test/test_xml_etree.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,26 @@ def test_attrib(self):
484484
self.assertEqual(ET.tostring(elem),
485485
b'<test a="&#13;" b="&#13;&#10;" c="&#09;&#10;&#13; " d="&#10;&#10;&#13;&#13;&#09;&#09; " />')
486486

487+
def test_subelement(self):
488+
# Test SubElement positional-only parameters (gh-144270).
489+
parent = ET.Element('parent')
490+
491+
# 'parent' and 'tag' are positional-only
492+
with self.assertRaises(TypeError):
493+
ET.SubElement(parent=parent, tag='fail')
494+
with self.assertRaises(TypeError):
495+
ET.SubElement(parent, tag='fail')
496+
497+
# 'attrib' can be passed as keyword
498+
sub1 = ET.SubElement(parent, 'sub1', attrib={'key': 'value'})
499+
self.assertEqual(sub1.get('key'), 'value')
500+
501+
# 'tag' and 'parent' as kwargs become XML attributes, not func params
502+
sub2 = ET.SubElement(parent, 'sub2', tag='foo', parent='bar')
503+
self.assertEqual(sub2.tag, 'sub2')
504+
self.assertEqual(sub2.get('tag'), 'foo')
505+
self.assertEqual(sub2.get('parent'), 'bar')
506+
487507
def test_makeelement(self):
488508
# Test makeelement handling.
489509

Lib/xml/etree/ElementTree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def itertext(self):
416416
yield t
417417

418418

419-
def SubElement(parent, tag, attrib={}, **extra):
419+
def SubElement(parent, tag, /, attrib={}, **extra):
420420
"""Subelement factory which creates an element instance, and appends it
421421
to an existing parent.
422422

0 commit comments

Comments
 (0)