ElementTree: empty path makes find()/findall()/findtext() raise TypeError

Offen Anfängerfreundlich
#161,807 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
76/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
python
Bereich
backend

Rechercherichtung

Lies zunächst xml.etree.ElementPath.iterfind() und die im Issue beschriebenen Aufrufer von find(), findall() und findtext(). Reproduziere das Verhalten bei einem leeren Pfad mit und ohne namespaces, einschließlich des reinen Python-Fallbacks. Das Ziel ist erreicht, wenn alle Fälle konsistente Ergebnisse zurückgeben oder einen eindeutigen SyntaxError auslösen und beide Implementierungen durch Regressionstests abgedeckt sind.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

extension-modules stdlib topic-XML type-bug
Bug report
Bug description

Passing an empty path to find(), findall() or findtext() (or to xml.etree.ElementPath directly) raises a confusing TypeError instead of returning a result or a clear error. Whether it happens depends on which implementation runs and on whether namespaces is passed.

With the C accelerator:

import xml.etree.ElementTree as ET
from xml.etree import ElementPath

root = ET.Element("root")
root.findall("")                  # []
root.findall("", namespaces={})   # TypeError: 'NoneType' object is not iterable
ElementPath.findall(root, "")     # TypeError: 'NoneType' object is not iterable

With the pure-Python implementation (the fallback used when _elementtree is unavailable), all of them fail:

import sys
sys.modules["_elementtree"] = None
import xml.etree.ElementTree as ET

root = ET.Element("root")
root.findall("")                  # TypeError: 'NoneType' object is not iterable
root.find("")                     # TypeError: 'NoneType' object is not an iterator
root.findtext("", default="D")    # TypeError: 'NoneType' object is not an iterator

Cause. ElementPath.iterfind() is a plain function, not a generator. For an empty path the tokenizer yields nothing, and the function does a bare return:

        try:
            token = next()
        except StopIteration:
            return

So it returns None instead of an iterator, and findall(), find() and findtext() then call list() or next() on None. The C accelerator only avoids this for a plain path without namespaces: its fast path treats "" as a tag name and returns [], None or the default.

Expected. The same result in both implementations, with or without namespaces. That could be either an empty result ([], None, the default), matching the C fast path, or a clear SyntaxError("invalid path"), which iterfind() already raises a few lines later for other incomplete paths. A minimal fix would be return iter(()) instead of the bare return.

I'm happy to open a PR.

CPython versions tested on:

CPython main branch, 3.14, 3.13, 3.12

Operating systems tested on:

Linux

Linked PRs
  • gh-161916
Vorherrschende Sprache
Python
Sterne
78.2k
Forks
36.6k
Ø Merge
19 Std. 57 Min.
Gemergte PRs (30 T.)
630

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus python/cpython

Alle Issues in python/cpython

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.