Skip to content

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

Open

Description

@ines-besrour

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

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Nov 11, 2026
  2. picnixz commented on Nov 11, 2026

    @picnixz
    Member

    I think we should return a list for findall() and the default for findtext(). But I don't want to complicate the code too much. OTOH, we can document that empty path shold not be given and leave that as a doc issue only,.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directorytopic-XMLtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions