From a345039382bfa5c1dbb6c876afe0764e6b11ff4f Mon Sep 17 00:00:00 2001 From: Semyon Moroz Date: Mon, 7 Jul 2025 14:37:15 +0000 Subject: [PATCH] [defusedxml] Add missing stubs (#14265) --- stubs/defusedxml/METADATA.toml | 2 - stubs/defusedxml/defusedxml/ElementTree.pyi | 57 +++++++++++++++----- stubs/defusedxml/defusedxml/cElementTree.pyi | 3 ++ stubs/defusedxml/defusedxml/common.pyi | 38 ++++++------- stubs/defusedxml/defusedxml/expatbuilder.pyi | 29 +++++++--- stubs/defusedxml/defusedxml/expatreader.pyi | 47 +++++++++++++--- stubs/defusedxml/defusedxml/lxml.pyi | 30 ++++++++--- stubs/defusedxml/defusedxml/minidom.pyi | 15 ++++-- stubs/defusedxml/defusedxml/pulldom.pyi | 13 ++--- stubs/defusedxml/defusedxml/sax.pyi | 18 ++++--- stubs/defusedxml/defusedxml/xmlrpc.pyi | 51 +++++++++++++----- 11 files changed, 216 insertions(+), 87 deletions(-) diff --git a/stubs/defusedxml/METADATA.toml b/stubs/defusedxml/METADATA.toml index 04dfe1b42..c073b5244 100644 --- a/stubs/defusedxml/METADATA.toml +++ b/stubs/defusedxml/METADATA.toml @@ -1,7 +1,5 @@ version = "0.7.*" upstream_repository = "https://github.com/tiran/defusedxml" -partial_stub = true [tool.stubtest] -ignore_missing_stub = true stubtest_requirements = ["lxml"] diff --git a/stubs/defusedxml/defusedxml/ElementTree.pyi b/stubs/defusedxml/defusedxml/ElementTree.pyi index 6328863d5..3b1027166 100644 --- a/stubs/defusedxml/defusedxml/ElementTree.pyi +++ b/stubs/defusedxml/defusedxml/ElementTree.pyi @@ -1,6 +1,18 @@ -from collections.abc import Iterator, Sequence -from typing import Any -from xml.etree.ElementTree import Element, ElementTree, ParseError as ParseError, XMLParser as _XMLParser, tostring as tostring +from _typeshed import ReadableBuffer +from collections.abc import Sequence +from typing import Final +from xml.etree.ElementTree import ( + Element, + ElementTree, + ParseError as ParseError, + XMLParser as _XMLParser, + _FileRead, + _IterParseIterator, + _Target, + tostring as tostring, +) + +__origin__: Final = "xml.etree.ElementTree" class DefusedXMLParser(_XMLParser): forbid_dtd: bool @@ -8,17 +20,30 @@ class DefusedXMLParser(_XMLParser): forbid_external: bool def __init__( self, - html=..., - target=None, + html: object = ..., # argument is deprecated, if bool(html) is True you will get TypeError + target: _Target | None = None, encoding: str | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, ) -> None: ... - def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset) -> None: ... - def defused_entity_decl(self, name, is_parameter_entity, value, base, sysid, pubid, notation_name) -> None: ... - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name) -> None: ... - def defused_external_entity_ref_handler(self, context, base, sysid, pubid) -> None: ... + def defused_start_doctype_decl(self, name: str, sysid: str | None, pubid: str | None, has_internal_subset: bool) -> None: ... + def defused_entity_decl( + self, + name: str, + is_parameter_entity: bool, + value: str | None, + base: str | None, + sysid: str, + pubid: str | None, + notation_name: str | None, + ) -> None: ... + def defused_unparsed_entity_decl( + self, name: str, base: str | None, sysid: str, pubid: str | None, notation_name: str + ) -> None: ... + def defused_external_entity_ref_handler( + self, context: str, base: str | None, sysid: str | None, pubid: str | None + ) -> None: ... XMLTreeBuilder = DefusedXMLParser XMLParse = DefusedXMLParser @@ -26,19 +51,25 @@ XMLParser = DefusedXMLParser # wrapper to xml.etree.ElementTree.parse def parse( - source, parser: XMLParser | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True + source: _FileRead, + parser: XMLParser | None = None, + forbid_dtd: bool = False, + forbid_entities: bool = True, + forbid_external: bool = True, ) -> ElementTree: ... # wrapper to xml.etree.ElementTree.iterparse def iterparse( - source, + source: _FileRead, events: Sequence[str] | None = None, parser: XMLParser | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, -) -> Iterator[tuple[str, Any]]: ... -def fromstring(text, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True) -> Element: ... +) -> _IterParseIterator: ... +def fromstring( + text: str | ReadableBuffer, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True +) -> Element: ... XML = fromstring diff --git a/stubs/defusedxml/defusedxml/cElementTree.pyi b/stubs/defusedxml/defusedxml/cElementTree.pyi index 8fe92b53a..5d096d4f1 100644 --- a/stubs/defusedxml/defusedxml/cElementTree.pyi +++ b/stubs/defusedxml/defusedxml/cElementTree.pyi @@ -1,3 +1,5 @@ +from typing import Final + from .ElementTree import ( XML as XML, ParseError as ParseError, @@ -10,4 +12,5 @@ from .ElementTree import ( tostring as tostring, ) +__origin__: Final = "xml.etree.cElementTree" __all__ = ["ParseError", "XML", "XMLParse", "XMLParser", "XMLTreeBuilder", "fromstring", "iterparse", "parse", "tostring"] diff --git a/stubs/defusedxml/defusedxml/common.pyi b/stubs/defusedxml/defusedxml/common.pyi index c4afb1901..15eb3f181 100644 --- a/stubs/defusedxml/defusedxml/common.pyi +++ b/stubs/defusedxml/defusedxml/common.pyi @@ -1,29 +1,31 @@ -from _typeshed import Incomplete +from typing import Final -PY3: bool +PY3: Final[bool] class DefusedXmlException(ValueError): ... class DTDForbidden(DefusedXmlException): - name: Incomplete - sysid: Incomplete - pubid: Incomplete - def __init__(self, name, sysid, pubid) -> None: ... + name: str + sysid: str | None + pubid: str | None + def __init__(self, name: str, sysid: str | None, pubid: str | None) -> None: ... class EntitiesForbidden(DefusedXmlException): - name: Incomplete - value: Incomplete - base: Incomplete - sysid: Incomplete - pubid: Incomplete - notation_name: Incomplete - def __init__(self, name, value, base, sysid, pubid, notation_name) -> None: ... + name: str + value: str | None + base: str | None + sysid: str | None + pubid: str | None + notation_name: str | None + def __init__( + self, name: str, value: str | None, base: str | None, sysid: str | None, pubid: str | None, notation_name: str | None + ) -> None: ... class ExternalReferenceForbidden(DefusedXmlException): - context: Incomplete - base: Incomplete - sysid: Incomplete - pubid: Incomplete - def __init__(self, context, base, sysid, pubid) -> None: ... + context: str + base: str | None + sysid: str | None + pubid: str | None + def __init__(self, context: str, base: str | None, sysid: str | None, pubid: str | None) -> None: ... class NotSupportedError(DefusedXmlException): ... diff --git a/stubs/defusedxml/defusedxml/expatbuilder.pyi b/stubs/defusedxml/defusedxml/expatbuilder.pyi index 0c6f4b7b9..8905cab7c 100644 --- a/stubs/defusedxml/defusedxml/expatbuilder.pyi +++ b/stubs/defusedxml/defusedxml/expatbuilder.pyi @@ -1,9 +1,11 @@ from _typeshed import SupportsRead +from typing import Final from xml.dom.expatbuilder import ExpatBuilder as _ExpatBuilder, Namespaces as _Namespaces from xml.dom.minidom import Document from xml.dom.xmlbuilder import Options +from xml.parsers.expat import XMLParserType -__origin__: str +__origin__: Final = "xml.dom.expatbuilder" class DefusedExpatBuilder(_ExpatBuilder): forbid_dtd: bool @@ -12,14 +14,27 @@ class DefusedExpatBuilder(_ExpatBuilder): def __init__( self, options: Options | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True ) -> None: ... - def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset) -> None: ... - def defused_entity_decl(self, name, is_parameter_entity, value, base, sysid, pubid, notation_name) -> None: ... - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name) -> None: ... - def defused_external_entity_ref_handler(self, context, base, sysid, pubid) -> None: ... - def install(self, parser) -> None: ... + def defused_start_doctype_decl(self, name: str, sysid: str | None, pubid: str | None, has_internal_subset: bool) -> None: ... + def defused_entity_decl( + self, + name: str, + is_parameter_entity: bool, + value: str | None, + base: str | None, + sysid: str, + pubid: str | None, + notation_name: str | None, + ) -> None: ... + def defused_unparsed_entity_decl( + self, name: str, base: str | None, sysid: str, pubid: str | None, notation_name: str + ) -> None: ... + def defused_external_entity_ref_handler( + self, context: str, base: str | None, sysid: str | None, pubid: str | None + ) -> None: ... + def install(self, parser: XMLParserType) -> None: ... class DefusedExpatBuilderNS(_Namespaces, DefusedExpatBuilder): - def install(self, parser) -> None: ... + def install(self, parser: XMLParserType) -> None: ... def reset(self) -> None: ... def parse( diff --git a/stubs/defusedxml/defusedxml/expatreader.pyi b/stubs/defusedxml/defusedxml/expatreader.pyi index 7453fee13..89155fba5 100644 --- a/stubs/defusedxml/defusedxml/expatreader.pyi +++ b/stubs/defusedxml/defusedxml/expatreader.pyi @@ -1,10 +1,43 @@ -from _typeshed import Incomplete +from typing import Final +from xml.sax.expatreader import ExpatParser as _ExpatParser, _BoolType -# Cannot type most things here as DefusedExpatParser is based off of -# xml.sax.expatreader, which is an undocumented module and lacks types at the moment. +__origin__: Final = "xml.sax.expatreader" -__origin__: str +class DefusedExpatParser(_ExpatParser): + forbid_dtd: bool + forbid_entities: bool + forbid_external: bool + def __init__( + self, + namespaceHandling: _BoolType = 0, + bufsize: int = 65516, + forbid_dtd: bool = False, + forbid_entities: bool = True, + forbid_external: bool = True, + ) -> None: ... + def defused_start_doctype_decl(self, name: str, sysid: str | None, pubid: str | None, has_internal_subset: bool) -> None: ... + def defused_entity_decl( + self, + name: str, + is_parameter_entity: bool, + value: str | None, + base: str | None, + sysid: str, + pubid: str | None, + notation_name: str | None, + ) -> None: ... + def defused_unparsed_entity_decl( + self, name: str, base: str | None, sysid: str, pubid: str | None, notation_name: str + ) -> None: ... + def defused_external_entity_ref_handler( + self, context: str, base: str | None, sysid: str | None, pubid: str | None + ) -> None: ... + def reset(self) -> None: ... -DefusedExpatParser = Incomplete - -def create_parser(*args, **kwargs): ... +def create_parser( + namespaceHandling: _BoolType = 0, + bufsize: int = 65516, + forbid_dtd: bool = False, + forbid_entities: bool = True, + forbid_external: bool = True, +) -> DefusedExpatParser: ... diff --git a/stubs/defusedxml/defusedxml/lxml.pyi b/stubs/defusedxml/defusedxml/lxml.pyi index 10cb30a4a..1bf8c8fd4 100644 --- a/stubs/defusedxml/defusedxml/lxml.pyi +++ b/stubs/defusedxml/defusedxml/lxml.pyi @@ -1,12 +1,27 @@ import threading from _typeshed import Incomplete +from typing import Final, Literal -# Not bothering with types here as lxml support is supposed to be dropped in a future version -# of defusedxml +# Not bothering with types here as lxml support is supposed to be dropped in a future version of defusedxml -LXML3: Incomplete -__origin__: str -tostring: Incomplete +LXML3: bool +__origin__: Final = "lxml.etree" + +def tostring( + element_or_tree, + *, + encoding: str | None = None, + method: Literal["xml", "html", "text", "c14n", "c14n2"] = "xml", + xml_declaration: bool | None = None, + pretty_print: bool = False, + with_tail: bool = True, + standalone: bool | None = None, + doctype=None, + exclusive: bool = False, + inclusive_ns_prefixes=None, + with_comments: bool = True, + strip_text: bool = False, +): ... # Should be imported from lxml.etree.ElementBase, but lxml lacks types class _ElementBase: ... @@ -28,9 +43,8 @@ class GlobalParserTLS(threading.local): def setDefaultParser(self, parser) -> None: ... def getDefaultParser(self): ... -getDefaultParser: Incomplete - -def check_docinfo(elementtree, forbid_dtd: bool = ..., forbid_entities: bool = ...) -> None: ... +def getDefaultParser(): ... +def check_docinfo(elementtree, forbid_dtd: bool = False, forbid_entities: bool = True) -> None: ... def parse( source, parser: Incomplete | None = ..., diff --git a/stubs/defusedxml/defusedxml/minidom.pyi b/stubs/defusedxml/defusedxml/minidom.pyi index 312cbe8c5..0097ebd5d 100644 --- a/stubs/defusedxml/defusedxml/minidom.pyi +++ b/stubs/defusedxml/defusedxml/minidom.pyi @@ -1,15 +1,22 @@ +from _typeshed import SupportsRead +from typing import Final from xml.dom.minidom import Document +from xml.sax.xmlreader import XMLReader -__origin__: str +__origin__: Final = "xml.dom.minidom" def parse( - file, - parser=None, + file: str | SupportsRead[bytes | str], + parser: XMLReader | None = None, bufsize: int | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, ) -> Document: ... def parseString( - string: str, parser=None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True + string: str, + parser: XMLReader | None = None, + forbid_dtd: bool = False, + forbid_entities: bool = True, + forbid_external: bool = True, ) -> Document: ... diff --git a/stubs/defusedxml/defusedxml/pulldom.pyi b/stubs/defusedxml/defusedxml/pulldom.pyi index 173065abc..706b2b876 100644 --- a/stubs/defusedxml/defusedxml/pulldom.pyi +++ b/stubs/defusedxml/defusedxml/pulldom.pyi @@ -1,12 +1,13 @@ +from typing import Final from xml.dom.pulldom import DOMEventStream +from xml.sax import _SupportsReadClose +from xml.sax.xmlreader import XMLReader -from .expatreader import DefusedExpatParser - -__origin__: str +__origin__: Final = "xml.dom.pulldom" def parse( - stream_or_string, - parser: DefusedExpatParser | None = None, + stream_or_string: str | _SupportsReadClose[str] | _SupportsReadClose[bytes], + parser: XMLReader | None = None, bufsize: int | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, @@ -14,7 +15,7 @@ def parse( ) -> DOMEventStream: ... def parseString( string: str, - parser: DefusedExpatParser | None = None, + parser: XMLReader | None = None, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, diff --git a/stubs/defusedxml/defusedxml/sax.pyi b/stubs/defusedxml/defusedxml/sax.pyi index a4c32eda5..9ecd45421 100644 --- a/stubs/defusedxml/defusedxml/sax.pyi +++ b/stubs/defusedxml/defusedxml/sax.pyi @@ -1,24 +1,26 @@ -from _typeshed import Incomplete -from xml.sax import ErrorHandler as _ErrorHandler +from _typeshed import ReadableBuffer, Unused +from typing import Final +from xml.sax import ErrorHandler as _ErrorHandler, _Source, xmlreader +from xml.sax.handler import _ContentHandlerProtocol from .expatreader import DefusedExpatParser -__origin__: str +__origin__: Final = "xml.sax" def parse( - source, - handler, + source: xmlreader.InputSource | _Source, + handler: _ContentHandlerProtocol, errorHandler: _ErrorHandler = ..., forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, ) -> None: ... def parseString( - string, - handler, + string: ReadableBuffer, + handler: _ContentHandlerProtocol, errorHandler: _ErrorHandler = ..., forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True, ) -> None: ... -def make_parser(parser_list: list[Incomplete] = []) -> DefusedExpatParser: ... +def make_parser(parser_list: Unused = []) -> DefusedExpatParser: ... diff --git a/stubs/defusedxml/defusedxml/xmlrpc.pyi b/stubs/defusedxml/defusedxml/xmlrpc.pyi index cddcb3f51..b2154123b 100644 --- a/stubs/defusedxml/defusedxml/xmlrpc.pyi +++ b/stubs/defusedxml/defusedxml/xmlrpc.pyi @@ -1,25 +1,48 @@ -from _typeshed import Incomplete -from xmlrpc.client import ExpatParser +import gzip +from _typeshed import ReadableBuffer +from typing import Final, Protocol, runtime_checkable +from xmlrpc.client import ExpatParser, Unmarshaller -__origin__: str -MAX_DATA: int = 31457280 +@runtime_checkable +class _Readable(Protocol): + def read(self, size: int | None = -1) -> bytes: ... -def defused_gzip_decode(data, limit: int | None = None): ... +__origin__: Final = "xmlrpc.client" +MAX_DATA: Final = 31457280 -# Couldn't type this as a class deriving from gzip.GzipFile -# since overwriting `read` method does not define an optional argument -# for size when the underlying class does. -DefusedGzipDecodedResponse = Incomplete +def defused_gzip_decode(data: ReadableBuffer, limit: int | None = None) -> bytes: ... + +class DefusedGzipDecodedResponse(gzip.GzipFile): + limit: int + readlength: int | None + def __init__(self, response: _Readable, limit: int | None = None) -> None: ... + def read(self, n: int) -> bytes: ... # type: ignore[override] + def close(self) -> None: ... class DefusedExpatParser(ExpatParser): forbid_dtd: bool forbid_entities: bool forbid_external: bool - def __init__(self, target, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True) -> None: ... - def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset) -> None: ... - def defused_entity_decl(self, name, is_parameter_entity, value, base, sysid, pubid, notation_name) -> None: ... - def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name) -> None: ... - def defused_external_entity_ref_handler(self, context, base, sysid, pubid) -> None: ... + def __init__( + self, target: Unmarshaller, forbid_dtd: bool = False, forbid_entities: bool = True, forbid_external: bool = True + ) -> None: ... + def defused_start_doctype_decl(self, name: str, sysid: str | None, pubid: str | None, has_internal_subset: bool) -> None: ... + def defused_entity_decl( + self, + name: str, + is_parameter_entity: bool, + value: str | None, + base: str | None, + sysid: str, + pubid: str | None, + notation_name: str | None, + ) -> None: ... + def defused_unparsed_entity_decl( + self, name: str, base: str | None, sysid: str, pubid: str | None, notation_name: str + ) -> None: ... + def defused_external_entity_ref_handler( + self, context: str, base: str | None, sysid: str | None, pubid: str | None + ) -> None: ... def monkey_patch() -> None: ... def unmonkey_patch() -> None: ...