This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ElementTree.Element.extend: bad error message when error occurs in generator
Type: behavior Stage:
Components: XML Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: goodmami
Priority: normal Keywords:

Created on 2021-11-02 00:50 by goodmami, last changed 2022-04-11 14:59 by admin.

Messages (1)
msg405476 - (view) Author: Michael Wayne Goodman (goodmami) * Date: 2021-11-02 00:50
Both the Python and C versions of xml.etree.ElementTree allow Element.extend() to accept a sequence or an iterable, such as a generator expression (although the docs only mention "sequence"; that's a separate problem):

>>> from xml.etree import ElementTree as ET
>>> elem = ET.Element('root')
>>> elem.extend(ET.Element('child') for _ in range(3))
>>> pyelem = ET._Element_Py('root')
>>> pyelem.extend(ET._Element_Py('child') for _ in range(3))

If the generator expression raises an Exception (for instance, by omitting the tag name as below), then the Python implementation passes up the error:

>>> pyelem.extend(ET._Element_Py() for _ in range(3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.9/xml/etree/ElementTree.py", line 253, in extend
    for element in elements:
  File "<stdin>", line 1, in <genexpr>
TypeError: __init__() missing 1 required positional argument: 'tag'

But the C implementation hides it with a misleading exception of its own:

>>> elem.extend(ET.Element() for _ in range(3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected sequence, not "generator"

Is it possible to pass up the original exception, as in the Python implementation? In the C code, the exception is raised when PySequence_Fast returns something false:

    seq = PySequence_Fast(elements, "");
    if (!seq) {
        PyErr_Format(
            PyExc_TypeError,
            "expected sequence, not \"%.200s\"", Py_TYPE(elements)->tp_name
            );
        return NULL;
    }

Otherwise, while it would be good if the error message didn't incorrectly state that Element.extend() requires a sequence and not a generator, it currently leads the programmer to the actual error. That is, when the programmer tries to make the argument a sequence by creating a list, the error will be propagated before Element.extend() is called:

>>> elem.extend([ET.Element() for _ in range(3)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
TypeError: Element() takes at least 1 argument (0 given)
History
Date User Action Args
2022-04-11 14:59:51adminsetgithub: 89849
2022-01-15 16:31:14iritkatrielsetversions: - Python 3.6, Python 3.7, Python 3.8
2021-11-02 00:50:51goodmamicreate