Skip to content

Commit 49b717c

Browse files
authored
stdlib/xml/sax: Add type annotations (#10606)
* stdlib/xml/sax: Type annotations for commonly used methods. * stdlib/xml/sax: More annotations. It turns out SAX's definition of a "qname" is exactly the opposite of ElementTree's. With that understanding, let's annotate the Attributes*Impl classes too. * stdlib/xml/sax: I better understand what AttributesNSImpl is doing now. * Update third-party library stubs to agree with the new SAX annotations.
1 parent 41bfc12 commit 49b717c

File tree

6 files changed

+108
-92
lines changed

6 files changed

+108
-92
lines changed

stdlib/xml/sax/__init__.pyi

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import sys
22
from _typeshed import ReadableBuffer, StrPath, SupportsRead, _T_co
33
from collections.abc import Iterable
44
from typing import Any, NoReturn, Protocol
5+
from typing_extensions import TypeAlias
56
from xml.sax.handler import ContentHandler as ContentHandler, ErrorHandler as ErrorHandler
67
from xml.sax.xmlreader import Locator, XMLReader
78

89
class _SupportsReadClose(SupportsRead[_T_co], Protocol[_T_co]):
910
def close(self) -> None: ...
1011

12+
if sys.version_info >= (3, 8):
13+
_Source: TypeAlias = StrPath | _SupportsReadClose[bytes] | _SupportsReadClose[str]
14+
else:
15+
_Source: TypeAlias = str | _SupportsReadClose[bytes] | _SupportsReadClose[str]
16+
1117
class SAXException(Exception):
1218
def __init__(self, msg: str, exception: Exception | None = None) -> None: ...
1319
def getMessage(self) -> str: ...
@@ -28,20 +34,13 @@ class SAXReaderNotAvailable(SAXNotSupportedException): ...
2834
default_parser_list: list[str]
2935

3036
if sys.version_info >= (3, 8):
37+
3138
def make_parser(parser_list: Iterable[str] = ()) -> XMLReader: ...
32-
def parse(
33-
source: StrPath | _SupportsReadClose[bytes] | _SupportsReadClose[str],
34-
handler: ContentHandler,
35-
errorHandler: ErrorHandler = ...,
36-
) -> None: ...
3739

3840
else:
41+
3942
def make_parser(parser_list: list[str] = []) -> XMLReader: ...
40-
def parse(
41-
source: str | _SupportsReadClose[bytes] | _SupportsReadClose[str],
42-
handler: ContentHandler,
43-
errorHandler: ErrorHandler = ...,
44-
) -> None: ...
4543

44+
def parse(source: _Source, handler: ContentHandler, errorHandler: ErrorHandler = ...) -> None: ...
4645
def parseString(string: ReadableBuffer | str, handler: ContentHandler, errorHandler: ErrorHandler | None = ...) -> None: ...
4746
def _create_parser(parser_name: str) -> XMLReader: ...

stdlib/xml/sax/handler.pyi

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
from typing import NoReturn
3+
from xml.sax import xmlreader
34

45
version: str
56

@@ -9,19 +10,19 @@ class ErrorHandler:
910
def warning(self, exception: BaseException) -> None: ...
1011

1112
class ContentHandler:
12-
def setDocumentLocator(self, locator): ...
13-
def startDocument(self): ...
14-
def endDocument(self): ...
15-
def startPrefixMapping(self, prefix, uri): ...
16-
def endPrefixMapping(self, prefix): ...
17-
def startElement(self, name, attrs): ...
18-
def endElement(self, name): ...
19-
def startElementNS(self, name, qname, attrs): ...
20-
def endElementNS(self, name, qname): ...
21-
def characters(self, content): ...
22-
def ignorableWhitespace(self, whitespace): ...
23-
def processingInstruction(self, target, data): ...
24-
def skippedEntity(self, name): ...
13+
def setDocumentLocator(self, locator: xmlreader.Locator) -> None: ...
14+
def startDocument(self) -> None: ...
15+
def endDocument(self) -> None: ...
16+
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
17+
def endPrefixMapping(self, prefix) -> None: ...
18+
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
19+
def endElement(self, name: str) -> None: ...
20+
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
21+
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
22+
def characters(self, content: str) -> None: ...
23+
def ignorableWhitespace(self, whitespace: str) -> None: ...
24+
def processingInstruction(self, target: str, data: str) -> None: ...
25+
def skippedEntity(self, name: str) -> None: ...
2526

2627
class DTDHandler:
2728
def notationDecl(self, name, publicId, systemId): ...

stdlib/xml/sax/saxutils.pyi

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from _typeshed import SupportsWrite
22
from codecs import StreamReaderWriter, StreamWriter
33
from collections.abc import Mapping
44
from io import RawIOBase, TextIOBase
5-
from xml.sax import handler, xmlreader
5+
from xml.sax import _Source, handler, xmlreader
66

77
def escape(data: str, entities: Mapping[str, str] = {}) -> str: ...
88
def unescape(data: str, entities: Mapping[str, str] = {}) -> str: ...
@@ -15,46 +15,46 @@ class XMLGenerator(handler.ContentHandler):
1515
encoding: str = "iso-8859-1",
1616
short_empty_elements: bool = False,
1717
) -> None: ...
18-
def startDocument(self): ...
19-
def endDocument(self): ...
20-
def startPrefixMapping(self, prefix, uri): ...
21-
def endPrefixMapping(self, prefix): ...
22-
def startElement(self, name, attrs): ...
23-
def endElement(self, name): ...
24-
def startElementNS(self, name, qname, attrs): ...
25-
def endElementNS(self, name, qname): ...
26-
def characters(self, content): ...
27-
def ignorableWhitespace(self, content): ...
28-
def processingInstruction(self, target, data): ...
18+
def startDocument(self) -> None: ...
19+
def endDocument(self) -> None: ...
20+
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
21+
def endPrefixMapping(self, prefix: str | None) -> None: ...
22+
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
23+
def endElement(self, name: str) -> None: ...
24+
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
25+
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
26+
def characters(self, content: str) -> None: ...
27+
def ignorableWhitespace(self, content: str) -> None: ...
28+
def processingInstruction(self, target: str, data: str) -> None: ...
2929

3030
class XMLFilterBase(xmlreader.XMLReader):
3131
def __init__(self, parent: xmlreader.XMLReader | None = None) -> None: ...
3232
def error(self, exception): ...
3333
def fatalError(self, exception): ...
3434
def warning(self, exception): ...
35-
def setDocumentLocator(self, locator): ...
36-
def startDocument(self): ...
37-
def endDocument(self): ...
38-
def startPrefixMapping(self, prefix, uri): ...
39-
def endPrefixMapping(self, prefix): ...
40-
def startElement(self, name, attrs): ...
41-
def endElement(self, name): ...
42-
def startElementNS(self, name, qname, attrs): ...
43-
def endElementNS(self, name, qname): ...
44-
def characters(self, content): ...
45-
def ignorableWhitespace(self, chars): ...
46-
def processingInstruction(self, target, data): ...
47-
def skippedEntity(self, name): ...
35+
def setDocumentLocator(self, locator: xmlreader.Locator) -> None: ...
36+
def startDocument(self) -> None: ...
37+
def endDocument(self) -> None: ...
38+
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
39+
def endPrefixMapping(self, prefix: str | None) -> None: ...
40+
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
41+
def endElement(self, name: str) -> None: ...
42+
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
43+
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
44+
def characters(self, content: str) -> None: ...
45+
def ignorableWhitespace(self, chars: str) -> None: ...
46+
def processingInstruction(self, target: str, data: str) -> None: ...
47+
def skippedEntity(self, name: str) -> None: ...
4848
def notationDecl(self, name, publicId, systemId): ...
4949
def unparsedEntityDecl(self, name, publicId, systemId, ndata): ...
5050
def resolveEntity(self, publicId, systemId): ...
51-
def parse(self, source): ...
51+
def parse(self, source: _Source) -> None: ...
5252
def setLocale(self, locale): ...
53-
def getFeature(self, name): ...
54-
def setFeature(self, name, state): ...
55-
def getProperty(self, name): ...
56-
def setProperty(self, name, value): ...
57-
def getParent(self): ...
58-
def setParent(self, parent): ...
53+
def getFeature(self, name: str) -> object: ...
54+
def setFeature(self, name: str, state: object) -> None: ...
55+
def getProperty(self, name: str) -> object: ...
56+
def setProperty(self, name: str, value: object) -> None: ...
57+
def getParent(self) -> xmlreader.XMLReader: ...
58+
def setParent(self, parent: xmlreader.XMLReader) -> None: ...
5959

6060
def prepare_input_source(source, base=""): ...

stdlib/xml/sax/xmlreader.pyi

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
from collections.abc import Mapping
2+
from typing import overload
3+
from typing_extensions import Self, TypeAlias
4+
from xml.sax.handler import ContentHandler, DTDHandler, EntityResolver, ErrorHandler
25

36
class XMLReader:
47
def parse(self, source): ...
5-
def getContentHandler(self): ...
6-
def setContentHandler(self, handler): ...
7-
def getDTDHandler(self): ...
8-
def setDTDHandler(self, handler): ...
9-
def getEntityResolver(self): ...
10-
def setEntityResolver(self, resolver): ...
11-
def getErrorHandler(self): ...
12-
def setErrorHandler(self, handler): ...
8+
def getContentHandler(self) -> ContentHandler: ...
9+
def setContentHandler(self, handler: ContentHandler) -> None: ...
10+
def getDTDHandler(self) -> DTDHandler: ...
11+
def setDTDHandler(self, handler: DTDHandler) -> None: ...
12+
def getEntityResolver(self) -> EntityResolver: ...
13+
def setEntityResolver(self, resolver: EntityResolver) -> None: ...
14+
def getErrorHandler(self) -> ErrorHandler: ...
15+
def setErrorHandler(self, handler: ErrorHandler) -> None: ...
1316
def setLocale(self, locale): ...
14-
def getFeature(self, name): ...
15-
def setFeature(self, name, state): ...
16-
def getProperty(self, name): ...
17-
def setProperty(self, name, value): ...
17+
def getFeature(self, name: str) -> object: ...
18+
def setFeature(self, name: str, state: object) -> None: ...
19+
def getProperty(self, name: str) -> object: ...
20+
def setProperty(self, name: str, value: object) -> None: ...
1821

1922
class IncrementalParser(XMLReader):
2023
def __init__(self, bufsize: int = 65536) -> None: ...
@@ -45,27 +48,40 @@ class InputSource:
4548

4649
class AttributesImpl:
4750
def __init__(self, attrs: Mapping[str, str]) -> None: ...
48-
def getLength(self): ...
49-
def getType(self, name): ...
50-
def getValue(self, name): ...
51-
def getValueByQName(self, name): ...
52-
def getNameByQName(self, name): ...
53-
def getQNameByName(self, name): ...
54-
def getNames(self): ...
55-
def getQNames(self): ...
51+
def getLength(self) -> int: ...
52+
def getType(self, name: str) -> str: ...
53+
def getValue(self, name: str) -> str: ...
54+
def getValueByQName(self, name: str) -> str: ...
55+
def getNameByQName(self, name: str) -> str: ...
56+
def getQNameByName(self, name: str) -> str: ...
57+
def getNames(self) -> list[str]: ...
58+
def getQNames(self) -> list[str]: ...
5659
def __len__(self) -> int: ...
57-
def __getitem__(self, name): ...
58-
def keys(self): ...
59-
def __contains__(self, name): ...
60-
def get(self, name, alternative=None): ...
61-
def copy(self): ...
62-
def items(self): ...
63-
def values(self): ...
60+
def __getitem__(self, name: str) -> str: ...
61+
def keys(self) -> list[str]: ...
62+
def __contains__(self, name: str) -> bool: ...
63+
@overload
64+
def get(self, name: str, alternative: None = None) -> str | None: ...
65+
@overload
66+
def get(self, name: str, alternative: str) -> str: ...
67+
def copy(self) -> Self: ...
68+
def items(self) -> list[tuple[str, str]]: ...
69+
def values(self) -> list[str]: ...
70+
71+
_NSName: TypeAlias = tuple[str | None, str]
6472

6573
class AttributesNSImpl(AttributesImpl):
66-
def __init__(self, attrs: Mapping[tuple[str, str], str], qnames: Mapping[tuple[str, str], str]) -> None: ...
67-
def getValueByQName(self, name): ...
68-
def getNameByQName(self, name): ...
69-
def getQNameByName(self, name): ...
70-
def getQNames(self): ...
71-
def copy(self): ...
74+
def __init__(self, attrs: Mapping[_NSName, str], qnames: Mapping[_NSName, str]) -> None: ...
75+
def getType(self, name: _NSName) -> str: ... # type: ignore[override]
76+
def getValue(self, name: _NSName) -> str: ... # type: ignore[override]
77+
def getNameByQName(self, name: str) -> _NSName: ... # type: ignore[override]
78+
def getQNameByName(self, name: _NSName) -> str: ... # type: ignore[override]
79+
def getNames(self) -> list[_NSName]: ... # type: ignore[override]
80+
def __getitem__(self, name: _NSName) -> str: ... # type: ignore[override]
81+
def keys(self) -> list[_NSName]: ... # type: ignore[override]
82+
def __contains__(self, name: _NSName) -> bool: ... # type: ignore[override]
83+
@overload # type: ignore[override]
84+
def get(self, name: _NSName, alternative: None = None) -> str | None: ...
85+
@overload # type: ignore[override]
86+
def get(self, name: _NSName, alternative: str) -> str: ...
87+
def items(self) -> list[tuple[_NSName, str]]: ... # type: ignore[override]

stubs/netaddr/netaddr/ip/iana.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ from collections.abc import Callable, Mapping, MutableMapping
33
from typing import Any
44
from typing_extensions import TypeAlias
55
from xml.sax import handler
6-
from xml.sax.xmlreader import XMLReader
6+
from xml.sax.xmlreader import AttributesImpl, XMLReader
77

88
from netaddr.core import Publisher, Subscriber
99
from netaddr.ip import IPAddress, IPNetwork, IPRange
@@ -14,7 +14,7 @@ IANA_INFO: dict[str, dict[_IanaInfoKey, dict[str, str]]]
1414

1515
class SaxRecordParser(handler.ContentHandler):
1616
def __init__(self, callback: Callable[[Mapping[str, object] | None], object] | None = None) -> None: ...
17-
def startElement(self, name: str, attrs: Mapping[str, object]) -> None: ...
17+
def startElement(self, name: str, attrs: AttributesImpl) -> None: ...
1818
def endElement(self, name: str) -> None: ...
1919
def characters(self, content: str) -> None: ...
2020

stubs/untangle/untangle.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from collections.abc import Iterator, Mapping
22
from typing import Any
33
from typing_extensions import Self
4-
from xml.sax import handler
4+
from xml.sax import handler, xmlreader
55

66
def is_string(x: object) -> bool: ...
77

@@ -29,7 +29,7 @@ class Handler(handler.ContentHandler):
2929
root: Element
3030
elements: list[Element]
3131
def __init__(self) -> None: ...
32-
def startElement(self, name: str, attributes: Mapping[str, Any]) -> None: ...
32+
def startElement(self, name: str, attributes: xmlreader.AttributesImpl) -> None: ...
3333
def endElement(self, name: str) -> None: ...
3434
def characters(self, cdata: str) -> None: ...
3535

0 commit comments

Comments
 (0)