gh-83122: Deprecate testing element truth values in `ElementTree` (#31149)

When testing element truth values, emit a DeprecationWarning in all implementations.

This had emitted a FutureWarning in the rarely used python-only implementation since ~2.7 and has always been documented as a behavior not to rely on.

Matching an element in a tree search but having it test False can be unexpected. Raising the warning enables making the choice to finally raise an exception for this ambiguous behavior in the future.
This commit is contained in:
Jacob Walls 2023-01-22 20:16:48 -05:00 committed by GitHub
parent 997073c28b
commit d717be04dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 5 deletions

View File

@ -1045,9 +1045,9 @@ Element Objects
:meth:`~object.__getitem__`, :meth:`~object.__setitem__`,
:meth:`~object.__len__`.
Caution: Elements with no subelements will test as ``False``. This behavior
will change in future versions. Use specific ``len(elem)`` or ``elem is
None`` test instead. ::
Caution: Elements with no subelements will test as ``False``. Testing the
truth value of an Element is deprecated and will raise an exception in
Python 3.14. Use specific ``len(elem)`` or ``elem is None`` test instead.::
element = root.find('foo')
@ -1057,6 +1057,9 @@ Element Objects
if element is None:
print("element not found")
.. versionchanged:: 3.12
Testing the truth value of an Element emits :exc:`DeprecationWarning`.
Prior to Python 3.8, the serialisation order of the XML attributes of
elements was artificially made predictable by sorting the attributes by
their name. Based on the now guaranteed ordering of dicts, this arbitrary

View File

@ -425,6 +425,11 @@ Deprecated
is no current event loop set and it decides to create one.
(Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.)
* The :mod:`xml.etree.ElementTree` module now emits :exc:`DeprecationWarning`
when testing the truth value of an :class:`xml.etree.ElementTree.Element`.
Before, the Python implementation emitted :exc:`FutureWarning`, and the C
implementation emitted nothing.
Pending Removal in Python 3.13
------------------------------
@ -487,6 +492,9 @@ Pending Removal in Python 3.14
* ``__package__`` and ``__cached__`` will cease to be set or taken
into consideration by the import system (:gh:`97879`).
* Testing the truth value of an :class:`xml.etree.ElementTree.Element`
is deprecated and will raise an exception in Python 3.14.
Pending Removal in Future Versions
----------------------------------

View File

@ -3957,6 +3957,25 @@ class NoAcceleratorTest(unittest.TestCase):
self.assertIsInstance(pyET.Element.__init__, types.FunctionType)
self.assertIsInstance(pyET.XMLParser.__init__, types.FunctionType)
# --------------------------------------------------------------------
class BoolTest(unittest.TestCase):
def test_warning(self):
e = ET.fromstring('<a style="new"></a>')
msg = (
r"Testing an element's truth value will raise an exception in "
r"future versions. "
r"Use specific 'len\(elem\)' or 'elem is not None' test instead.")
with self.assertWarnsRegex(DeprecationWarning, msg):
result = bool(e)
# Emulate prior behavior for now
self.assertIs(result, False)
# Element with children
ET.SubElement(e, 'b')
with self.assertWarnsRegex(DeprecationWarning, msg):
new_result = bool(e)
self.assertIs(new_result, True)
# --------------------------------------------------------------------
@ -4223,6 +4242,7 @@ def test_main(module=None):
XMLPullParserTest,
BugsTest,
KeywordArgsTest,
BoolTest,
C14NTest,
]

View File

@ -200,9 +200,10 @@ class Element:
def __bool__(self):
warnings.warn(
"The behavior of this method will change in future versions. "
"Testing an element's truth value will raise an exception in "
"future versions. "
"Use specific 'len(elem)' or 'elem is not None' test instead.",
FutureWarning, stacklevel=2
DeprecationWarning, stacklevel=2
)
return len(self._children) != 0 # emulate old behaviour, for now

View File

@ -0,0 +1,4 @@
The :mod:`xml.etree.ElementTree` module now emits :exc:`DeprecationWarning`
when testing the truth value of an :class:`xml.etree.ElementTree.Element`.
Before, the Python implementation emitted :exc:`FutureWarning`, and the C
implementation emitted nothing.

View File

@ -1449,6 +1449,23 @@ element_getitem(PyObject* self_, Py_ssize_t index)
return Py_NewRef(self->extra->children[index]);
}
static int
element_bool(PyObject* self_)
{
ElementObject* self = (ElementObject*) self_;
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"Testing an element's truth value will raise an exception "
"in future versions. Use specific 'len(elem)' or "
"'elem is not None' test instead.",
1) < 0) {
return -1;
};
if (self->extra ? self->extra->length : 0) {
return 1;
}
return 0;
}
/*[clinic input]
_elementtree.Element.insert
@ -4156,6 +4173,7 @@ static PyType_Slot element_slots[] = {
{Py_sq_length, element_length},
{Py_sq_item, element_getitem},
{Py_sq_ass_item, element_setitem},
{Py_nb_bool, element_bool},
{Py_mp_length, element_length},
{Py_mp_subscript, element_subscr},
{Py_mp_ass_subscript, element_ass_subscr},