diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst
index 919d4c595bf793..bbb15ce5e758c6 100644
--- a/Doc/library/xml.etree.elementtree.rst
+++ b/Doc/library/xml.etree.elementtree.rst
@@ -691,7 +691,7 @@ Functions
.. versionadded:: 3.2
-.. function:: SubElement(parent, tag, attrib={}, **extra)
+.. function:: SubElement(parent, tag, /, attrib={}, **extra)
Subelement factory. This function creates an element instance, and appends
it to an existing element.
@@ -705,6 +705,9 @@ Functions
.. versionchanged:: 3.15
*attrib* can now be a :class:`frozendict`.
+ .. versionchanged:: next
+ *parent* and *tag* are now positional-only parameters.
+
.. function:: tostring(element, encoding="us-ascii", method="xml", *, \
xml_declaration=None, default_namespace=None, \
@@ -880,7 +883,7 @@ Element Objects
:noindex:
:no-index:
-.. class:: Element(tag, attrib={}, **extra)
+.. class:: Element(tag, /, attrib={}, **extra)
Element class. This class defines the Element interface, and provides a
reference implementation of this interface.
@@ -893,6 +896,9 @@ Element Objects
.. versionchanged:: 3.15
*attrib* can now be a :class:`frozendict`.
+ .. versionchanged:: next
+ *tag* is now a positional-only parameter.
+
.. attribute:: tag
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 5b06e422672b1d..b380d0276b0169 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -381,6 +381,19 @@ def test_simpleops(self):
self.serialize_check(element,
'')
+ def test_positional_only_parameter(self):
+ # Test Element positional-only parameters (gh-144846).
+
+ # 'tag' is positional-only
+ with self.assertRaises(TypeError):
+ ET.Element(tag='fail')
+
+ # 'tag' and 'attrib' as kwarg/attribute names
+ e = ET.Element('e', attrib={'attrib': 'foo'}, tag='bar')
+ self.assertEqual(e.tag, 'e')
+ self.assertEqual(e.get('attrib'), 'foo')
+ self.assertEqual(e.get('tag'), 'bar')
+
def test_cdata(self):
# Test CDATA handling (etc).
@@ -484,6 +497,28 @@ def test_attrib(self):
self.assertEqual(ET.tostring(elem),
b'')
+ def test_subelement_positional_only_parameter(self):
+ # Test SubElement positional-only parameters (gh-144270).
+ parent = ET.Element('parent')
+
+ # 'parent' and 'tag' are positional-only
+ with self.assertRaises(TypeError):
+ ET.SubElement(parent=parent, tag='fail')
+ with self.assertRaises(TypeError):
+ ET.SubElement(parent, tag='fail')
+
+ # 'attrib' can be passed as keyword
+ sub1 = ET.SubElement(parent, 'sub1', attrib={'key': 'value'})
+ self.assertEqual(sub1.get('key'), 'value')
+
+ # 'tag' and 'parent' as kwargs become XML attributes, not func params
+ sub2 = ET.SubElement(parent, 'sub2', attrib={'attrib': 'foo'},
+ tag='bar', parent='baz')
+ self.assertEqual(sub2.tag, 'sub2')
+ self.assertEqual(sub2.get('attrib'), 'foo')
+ self.assertEqual(sub2.get('tag'), 'bar')
+ self.assertEqual(sub2.get('parent'), 'baz')
+
def test_makeelement(self):
# Test makeelement handling.
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 57c5b64ea3ba70..85766e02b531ce 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -164,7 +164,7 @@ class Element:
"""
- def __init__(self, tag, attrib={}, **extra):
+ def __init__(self, tag, /, attrib={}, **extra):
if not isinstance(attrib, (dict, frozendict)):
raise TypeError("attrib must be dict or frozendict, not %s" % (
attrib.__class__.__name__,))
@@ -416,7 +416,7 @@ def itertext(self):
yield t
-def SubElement(parent, tag, attrib={}, **extra):
+def SubElement(parent, tag, /, attrib={}, **extra):
"""Subelement factory which creates an element instance, and appends it
to an existing parent.
diff --git a/Misc/NEWS.d/next/Library/2026-02-19-16-34-18.gh-issue-144270.wJRtSr.rst b/Misc/NEWS.d/next/Library/2026-02-19-16-34-18.gh-issue-144270.wJRtSr.rst
new file mode 100644
index 00000000000000..b8a4374bc2d3ca
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-02-19-16-34-18.gh-issue-144270.wJRtSr.rst
@@ -0,0 +1,3 @@
+Made the *tag* parameter of :class:`xml.etree.ElementTree.Element` and the
+*parent* and *tag* parameters of :func:`xml.etree.ElementTree.SubElement`
+positional-only, matching the behavior of the C accelerator.