Skip to content

Commit

Permalink
stdlib/xml/sax: Add type annotations (#10606)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
Screwtapello committed Sep 23, 2023
1 parent 41bfc12 commit 49b717c
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 92 deletions.
19 changes: 9 additions & 10 deletions stdlib/xml/sax/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import sys
from _typeshed import ReadableBuffer, StrPath, SupportsRead, _T_co
from collections.abc import Iterable
from typing import Any, NoReturn, Protocol
from typing_extensions import TypeAlias
from xml.sax.handler import ContentHandler as ContentHandler, ErrorHandler as ErrorHandler
from xml.sax.xmlreader import Locator, XMLReader

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

if sys.version_info >= (3, 8):
_Source: TypeAlias = StrPath | _SupportsReadClose[bytes] | _SupportsReadClose[str]
else:
_Source: TypeAlias = str | _SupportsReadClose[bytes] | _SupportsReadClose[str]

class SAXException(Exception):
def __init__(self, msg: str, exception: Exception | None = None) -> None: ...
def getMessage(self) -> str: ...
Expand All @@ -28,20 +34,13 @@ class SAXReaderNotAvailable(SAXNotSupportedException): ...
default_parser_list: list[str]

if sys.version_info >= (3, 8):

def make_parser(parser_list: Iterable[str] = ()) -> XMLReader: ...
def parse(
source: StrPath | _SupportsReadClose[bytes] | _SupportsReadClose[str],
handler: ContentHandler,
errorHandler: ErrorHandler = ...,
) -> None: ...

else:

def make_parser(parser_list: list[str] = []) -> XMLReader: ...
def parse(
source: str | _SupportsReadClose[bytes] | _SupportsReadClose[str],
handler: ContentHandler,
errorHandler: ErrorHandler = ...,
) -> None: ...

def parse(source: _Source, handler: ContentHandler, errorHandler: ErrorHandler = ...) -> None: ...
def parseString(string: ReadableBuffer | str, handler: ContentHandler, errorHandler: ErrorHandler | None = ...) -> None: ...
def _create_parser(parser_name: str) -> XMLReader: ...
27 changes: 14 additions & 13 deletions stdlib/xml/sax/handler.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
from typing import NoReturn
from xml.sax import xmlreader

version: str

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

class ContentHandler:
def setDocumentLocator(self, locator): ...
def startDocument(self): ...
def endDocument(self): ...
def startPrefixMapping(self, prefix, uri): ...
def endPrefixMapping(self, prefix): ...
def startElement(self, name, attrs): ...
def endElement(self, name): ...
def startElementNS(self, name, qname, attrs): ...
def endElementNS(self, name, qname): ...
def characters(self, content): ...
def ignorableWhitespace(self, whitespace): ...
def processingInstruction(self, target, data): ...
def skippedEntity(self, name): ...
def setDocumentLocator(self, locator: xmlreader.Locator) -> None: ...
def startDocument(self) -> None: ...
def endDocument(self) -> None: ...
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
def endPrefixMapping(self, prefix) -> None: ...
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
def endElement(self, name: str) -> None: ...
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
def characters(self, content: str) -> None: ...
def ignorableWhitespace(self, whitespace: str) -> None: ...
def processingInstruction(self, target: str, data: str) -> None: ...
def skippedEntity(self, name: str) -> None: ...

class DTDHandler:
def notationDecl(self, name, publicId, systemId): ...
Expand Down
64 changes: 32 additions & 32 deletions stdlib/xml/sax/saxutils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from _typeshed import SupportsWrite
from codecs import StreamReaderWriter, StreamWriter
from collections.abc import Mapping
from io import RawIOBase, TextIOBase
from xml.sax import handler, xmlreader
from xml.sax import _Source, handler, xmlreader

def escape(data: str, entities: Mapping[str, str] = {}) -> str: ...
def unescape(data: str, entities: Mapping[str, str] = {}) -> str: ...
Expand All @@ -15,46 +15,46 @@ class XMLGenerator(handler.ContentHandler):
encoding: str = "iso-8859-1",
short_empty_elements: bool = False,
) -> None: ...
def startDocument(self): ...
def endDocument(self): ...
def startPrefixMapping(self, prefix, uri): ...
def endPrefixMapping(self, prefix): ...
def startElement(self, name, attrs): ...
def endElement(self, name): ...
def startElementNS(self, name, qname, attrs): ...
def endElementNS(self, name, qname): ...
def characters(self, content): ...
def ignorableWhitespace(self, content): ...
def processingInstruction(self, target, data): ...
def startDocument(self) -> None: ...
def endDocument(self) -> None: ...
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
def endPrefixMapping(self, prefix: str | None) -> None: ...
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
def endElement(self, name: str) -> None: ...
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
def characters(self, content: str) -> None: ...
def ignorableWhitespace(self, content: str) -> None: ...
def processingInstruction(self, target: str, data: str) -> None: ...

class XMLFilterBase(xmlreader.XMLReader):
def __init__(self, parent: xmlreader.XMLReader | None = None) -> None: ...
def error(self, exception): ...
def fatalError(self, exception): ...
def warning(self, exception): ...
def setDocumentLocator(self, locator): ...
def startDocument(self): ...
def endDocument(self): ...
def startPrefixMapping(self, prefix, uri): ...
def endPrefixMapping(self, prefix): ...
def startElement(self, name, attrs): ...
def endElement(self, name): ...
def startElementNS(self, name, qname, attrs): ...
def endElementNS(self, name, qname): ...
def characters(self, content): ...
def ignorableWhitespace(self, chars): ...
def processingInstruction(self, target, data): ...
def skippedEntity(self, name): ...
def setDocumentLocator(self, locator: xmlreader.Locator) -> None: ...
def startDocument(self) -> None: ...
def endDocument(self) -> None: ...
def startPrefixMapping(self, prefix: str | None, uri: str) -> None: ...
def endPrefixMapping(self, prefix: str | None) -> None: ...
def startElement(self, name: str, attrs: xmlreader.AttributesImpl) -> None: ...
def endElement(self, name: str) -> None: ...
def startElementNS(self, name: tuple[str, str], qname: str, attrs: xmlreader.AttributesNSImpl) -> None: ...
def endElementNS(self, name: tuple[str, str], qname: str) -> None: ...
def characters(self, content: str) -> None: ...
def ignorableWhitespace(self, chars: str) -> None: ...
def processingInstruction(self, target: str, data: str) -> None: ...
def skippedEntity(self, name: str) -> None: ...
def notationDecl(self, name, publicId, systemId): ...
def unparsedEntityDecl(self, name, publicId, systemId, ndata): ...
def resolveEntity(self, publicId, systemId): ...
def parse(self, source): ...
def parse(self, source: _Source) -> None: ...
def setLocale(self, locale): ...
def getFeature(self, name): ...
def setFeature(self, name, state): ...
def getProperty(self, name): ...
def setProperty(self, name, value): ...
def getParent(self): ...
def setParent(self, parent): ...
def getFeature(self, name: str) -> object: ...
def setFeature(self, name: str, state: object) -> None: ...
def getProperty(self, name: str) -> object: ...
def setProperty(self, name: str, value: object) -> None: ...
def getParent(self) -> xmlreader.XMLReader: ...
def setParent(self, parent: xmlreader.XMLReader) -> None: ...

def prepare_input_source(source, base=""): ...
82 changes: 49 additions & 33 deletions stdlib/xml/sax/xmlreader.pyi
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from collections.abc import Mapping
from typing import overload
from typing_extensions import Self, TypeAlias
from xml.sax.handler import ContentHandler, DTDHandler, EntityResolver, ErrorHandler

class XMLReader:
def parse(self, source): ...
def getContentHandler(self): ...
def setContentHandler(self, handler): ...
def getDTDHandler(self): ...
def setDTDHandler(self, handler): ...
def getEntityResolver(self): ...
def setEntityResolver(self, resolver): ...
def getErrorHandler(self): ...
def setErrorHandler(self, handler): ...
def getContentHandler(self) -> ContentHandler: ...
def setContentHandler(self, handler: ContentHandler) -> None: ...
def getDTDHandler(self) -> DTDHandler: ...
def setDTDHandler(self, handler: DTDHandler) -> None: ...
def getEntityResolver(self) -> EntityResolver: ...
def setEntityResolver(self, resolver: EntityResolver) -> None: ...
def getErrorHandler(self) -> ErrorHandler: ...
def setErrorHandler(self, handler: ErrorHandler) -> None: ...
def setLocale(self, locale): ...
def getFeature(self, name): ...
def setFeature(self, name, state): ...
def getProperty(self, name): ...
def setProperty(self, name, value): ...
def getFeature(self, name: str) -> object: ...
def setFeature(self, name: str, state: object) -> None: ...
def getProperty(self, name: str) -> object: ...
def setProperty(self, name: str, value: object) -> None: ...

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

class AttributesImpl:
def __init__(self, attrs: Mapping[str, str]) -> None: ...
def getLength(self): ...
def getType(self, name): ...
def getValue(self, name): ...
def getValueByQName(self, name): ...
def getNameByQName(self, name): ...
def getQNameByName(self, name): ...
def getNames(self): ...
def getQNames(self): ...
def getLength(self) -> int: ...
def getType(self, name: str) -> str: ...
def getValue(self, name: str) -> str: ...
def getValueByQName(self, name: str) -> str: ...
def getNameByQName(self, name: str) -> str: ...
def getQNameByName(self, name: str) -> str: ...
def getNames(self) -> list[str]: ...
def getQNames(self) -> list[str]: ...
def __len__(self) -> int: ...
def __getitem__(self, name): ...
def keys(self): ...
def __contains__(self, name): ...
def get(self, name, alternative=None): ...
def copy(self): ...
def items(self): ...
def values(self): ...
def __getitem__(self, name: str) -> str: ...
def keys(self) -> list[str]: ...
def __contains__(self, name: str) -> bool: ...
@overload
def get(self, name: str, alternative: None = None) -> str | None: ...
@overload
def get(self, name: str, alternative: str) -> str: ...
def copy(self) -> Self: ...
def items(self) -> list[tuple[str, str]]: ...
def values(self) -> list[str]: ...

_NSName: TypeAlias = tuple[str | None, str]

class AttributesNSImpl(AttributesImpl):
def __init__(self, attrs: Mapping[tuple[str, str], str], qnames: Mapping[tuple[str, str], str]) -> None: ...
def getValueByQName(self, name): ...
def getNameByQName(self, name): ...
def getQNameByName(self, name): ...
def getQNames(self): ...
def copy(self): ...
def __init__(self, attrs: Mapping[_NSName, str], qnames: Mapping[_NSName, str]) -> None: ...
def getType(self, name: _NSName) -> str: ... # type: ignore[override]
def getValue(self, name: _NSName) -> str: ... # type: ignore[override]
def getNameByQName(self, name: str) -> _NSName: ... # type: ignore[override]
def getQNameByName(self, name: _NSName) -> str: ... # type: ignore[override]
def getNames(self) -> list[_NSName]: ... # type: ignore[override]
def __getitem__(self, name: _NSName) -> str: ... # type: ignore[override]
def keys(self) -> list[_NSName]: ... # type: ignore[override]
def __contains__(self, name: _NSName) -> bool: ... # type: ignore[override]
@overload # type: ignore[override]
def get(self, name: _NSName, alternative: None = None) -> str | None: ...
@overload # type: ignore[override]
def get(self, name: _NSName, alternative: str) -> str: ...
def items(self) -> list[tuple[_NSName, str]]: ... # type: ignore[override]
4 changes: 2 additions & 2 deletions stubs/netaddr/netaddr/ip/iana.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ from collections.abc import Callable, Mapping, MutableMapping
from typing import Any
from typing_extensions import TypeAlias
from xml.sax import handler
from xml.sax.xmlreader import XMLReader
from xml.sax.xmlreader import AttributesImpl, XMLReader

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

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

Expand Down
4 changes: 2 additions & 2 deletions stubs/untangle/untangle.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections.abc import Iterator, Mapping
from typing import Any
from typing_extensions import Self
from xml.sax import handler
from xml.sax import handler, xmlreader

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

Expand Down Expand Up @@ -29,7 +29,7 @@ class Handler(handler.ContentHandler):
root: Element
elements: list[Element]
def __init__(self) -> None: ...
def startElement(self, name: str, attributes: Mapping[str, Any]) -> None: ...
def startElement(self, name: str, attributes: xmlreader.AttributesImpl) -> None: ...
def endElement(self, name: str) -> None: ...
def characters(self, cdata: str) -> None: ...

Expand Down

0 comments on commit 49b717c

Please sign in to comment.