Skip to content

Commit 38ad421

Browse files
authored
Fix return type of ElementTree.iterparse() (#14213)
1 parent 2c79d47 commit 38ad421

2 files changed

Lines changed: 28 additions & 12 deletions

File tree

stdlib/xml/etree/ElementTree.pyi

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -249,28 +249,42 @@ def dump(elem: Element[Any] | ElementTree[Any]) -> None: ...
249249
def indent(tree: Element[Any] | ElementTree[Any], space: str = " ", level: int = 0) -> None: ...
250250
def parse(source: _FileRead, parser: XMLParser[Any] | None = None) -> ElementTree[Element]: ...
251251

252-
# This class is defined inside the body of iterparse
252+
# The type of the second element of the tuple yielded by iterparse depends
253+
# on the event type in the first element of the tuple:
254+
# * start, end: Element[str]
255+
# * comment, pi: Element[_ElementCallable]
256+
# * start-ns: tuple[str, str] (prefix, uri)
257+
# * end-ns: None
258+
_EventT_co = TypeVar("_EventT_co", bound=Element[str] | Element[_ElementCallable] | tuple[str, str] | None, covariant=True)
259+
_EventType: TypeAlias = Literal["start", "end", "comment", "pi", "start-ns", "end-ns"]
260+
261+
# This class is defined inside the body of iterparse.
253262
@type_check_only
254-
class _IterParseIterator(Iterator[tuple[str, Element]], Protocol):
255-
def __next__(self) -> tuple[str, Element]: ...
263+
class _IterParseIterator(Iterator[tuple[_EventType, _EventT_co]], Protocol[_EventT_co]):
256264
if sys.version_info >= (3, 13):
257265
def close(self) -> None: ...
258266
if sys.version_info >= (3, 11):
259267
def __del__(self) -> None: ...
260268

269+
# See the comment for _EventT_co above for possible iterator types.
270+
@overload
271+
def iterparse(source: _FileRead, events: Iterable[_EventType]) -> _IterParseIterator[Any]: ...
261272
@overload
262-
def iterparse(source: _FileRead, events: Sequence[str] | None = None) -> _IterParseIterator: ...
273+
def iterparse(source: _FileRead, events: None = None) -> _IterParseIterator[Element[str]]: ...
274+
275+
# In case a custom parser is passed, the type of the second element of the tuple
276+
# yielded by iterparse depends on the parser.
263277
@overload
264278
@deprecated("The `parser` parameter is deprecated since Python 3.4.")
265-
def iterparse(source: _FileRead, events: Sequence[str] | None = None, parser: XMLParser | None = None) -> _IterParseIterator: ...
279+
def iterparse(source: _FileRead, events: Iterable[_EventType], parser: XMLParser | None = None) -> _IterParseIterator[Any]: ...
266280

267281
_EventQueue: TypeAlias = tuple[str] | tuple[str, tuple[str, str]] | tuple[str, None]
268282

269-
class XMLPullParser(Generic[_E]):
270-
def __init__(self, events: Sequence[str] | None = None, *, _parser: XMLParser[_E] | None = None) -> None: ...
283+
class XMLPullParser(Generic[_EventT_co]):
284+
def __init__(self, events: Iterable[_EventType] | None = None, *, _parser: XMLParser[_EventT_co] | None = None) -> None: ...
271285
def feed(self, data: str | ReadableBuffer) -> None: ...
272286
def close(self) -> None: ...
273-
def read_events(self) -> Iterator[_EventQueue | tuple[str, _E]]: ...
287+
def read_events(self) -> Iterator[_EventQueue | tuple[_EventType, _EventT_co]]: ...
274288
def flush(self) -> None: ...
275289

276290
def XML(text: str | ReadableBuffer, parser: XMLParser | None = None) -> Element: ...

stubs/defusedxml/defusedxml/ElementTree.pyi

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from _typeshed import ReadableBuffer
22
from collections.abc import Sequence
3-
from typing import Final
3+
from typing import Any, Final
44
from xml.etree.ElementTree import (
55
Element,
66
ElementTree,
@@ -49,7 +49,7 @@ XMLTreeBuilder = DefusedXMLParser
4949
XMLParse = DefusedXMLParser
5050
XMLParser = DefusedXMLParser
5151

52-
# wrapper to xml.etree.ElementTree.parse
52+
# Wrapper to xml.etree.ElementTree.parse
5353
def parse(
5454
source: _FileRead,
5555
parser: XMLParser | None = None,
@@ -58,15 +58,17 @@ def parse(
5858
forbid_external: bool = True,
5959
) -> ElementTree: ...
6060

61-
# wrapper to xml.etree.ElementTree.iterparse
61+
# Wrapper to xml.etree.ElementTree.iterparse
62+
#
63+
# See there for possible return types.
6264
def iterparse(
6365
source: _FileRead,
6466
events: Sequence[str] | None = None,
6567
parser: XMLParser | None = None,
6668
forbid_dtd: bool = False,
6769
forbid_entities: bool = True,
6870
forbid_external: bool = True,
69-
) -> _IterParseIterator: ...
71+
) -> _IterParseIterator[Any]: ...
7072
def fromstring(
7173
text: str | ReadableBuffer, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True
7274
) -> Element: ...

0 commit comments

Comments
 (0)