From 73200216114ecd8a4b61518d446eda6ee10c633c Mon Sep 17 00:00:00 2001 From: Wesley Collin Wright Date: Tue, 18 Apr 2023 20:47:56 +0000 Subject: [PATCH 1/8] stdlib/xml: fix return types for toxml/toprettyxml methods --- stdlib/xml/dom/minidom.pyi | 62 +++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/stdlib/xml/dom/minidom.pyi b/stdlib/xml/dom/minidom.pyi index e2880ae858d6..f572ad2b90ea 100644 --- a/stdlib/xml/dom/minidom.pyi +++ b/stdlib/xml/dom/minidom.pyi @@ -1,7 +1,7 @@ import sys import xml.dom from _typeshed import Incomplete, ReadableBuffer, SupportsRead, SupportsWrite -from typing import NoReturn, TypeVar +from typing import NoReturn, TypeVar, overload from typing_extensions import Literal, Self from xml.dom.minicompat import NodeList from xml.dom.xmlbuilder import DocumentLS, DOMImplementationLS @@ -30,13 +30,65 @@ class Node(xml.dom.Node): def localName(self) -> str | None: ... def __bool__(self) -> Literal[True]: ... if sys.version_info >= (3, 9): - def toxml(self, encoding: str | None = None, standalone: bool | None = None) -> str: ... + @overload + def toxml(self, encoding: str, standalone: bool | None = None) -> bytes: ... + @overload + def toxml(self, encoding: None = None, standalone: bool | None = None) -> str: ... + def toxml(self, + encoding: str | None = None, + standalone: bool | None = None, + ) -> str | bytes: ... + + @overload + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + encoding: str = ..., + standalone: bool | None = None, + ) -> bytes: ... + @overload def toprettyxml( - self, indent: str = "\t", newl: str = "\n", encoding: str | None = None, standalone: bool | None = None + self, + indent: str = "\t", + newl: str = "\n", + encoding: None = None, + standalone: bool | None = None, + ) -> str: ... + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + encoding: str | None = None, + standalone: bool | None = None, ) -> str: ... else: - def toxml(self, encoding: str | None = None): ... - def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: str | None = None): ... + @overload + def toxml(self, encoding: str) -> bytes: ... + @overload + def toxml(self, encoding: None = None) -> str: ... + def toxml(self, encoding: str | None = None) -> str | bytes: ... + + @overload + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + encoding: str = ..., + ) -> bytes: ... + @overload + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + encoding: None = None, + ) -> str: ... + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + encoding: str | None = None, + ) -> str | bytes: ... def hasChildNodes(self) -> bool: ... def insertBefore(self, newChild, refChild): ... From b61b4cf88a94eaad474188f2910b0e2ab63b26ae Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 21:00:17 +0000 Subject: [PATCH 2/8] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/xml/dom/minidom.pyi | 46 ++++++-------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/stdlib/xml/dom/minidom.pyi b/stdlib/xml/dom/minidom.pyi index f572ad2b90ea..1f33e0413f99 100644 --- a/stdlib/xml/dom/minidom.pyi +++ b/stdlib/xml/dom/minidom.pyi @@ -34,33 +34,17 @@ class Node(xml.dom.Node): def toxml(self, encoding: str, standalone: bool | None = None) -> bytes: ... @overload def toxml(self, encoding: None = None, standalone: bool | None = None) -> str: ... - def toxml(self, - encoding: str | None = None, - standalone: bool | None = None, - ) -> str | bytes: ... - + def toxml(self, encoding: str | None = None, standalone: bool | None = None) -> str | bytes: ... @overload def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: str = ..., - standalone: bool | None = None, + self, indent: str = "\t", newl: str = "\n", encoding: str = ..., standalone: bool | None = None ) -> bytes: ... @overload def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: None = None, - standalone: bool | None = None, + self, indent: str = "\t", newl: str = "\n", encoding: None = None, standalone: bool | None = None ) -> str: ... def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: str | None = None, - standalone: bool | None = None, + self, indent: str = "\t", newl: str = "\n", encoding: str | None = None, standalone: bool | None = None ) -> str: ... else: @overload @@ -68,27 +52,11 @@ class Node(xml.dom.Node): @overload def toxml(self, encoding: None = None) -> str: ... def toxml(self, encoding: str | None = None) -> str | bytes: ... - @overload - def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: str = ..., - ) -> bytes: ... + def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: str = ...) -> bytes: ... @overload - def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: None = None, - ) -> str: ... - def toprettyxml( - self, - indent: str = "\t", - newl: str = "\n", - encoding: str | None = None, - ) -> str | bytes: ... + def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: None = None) -> str: ... + def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: str | None = None) -> str | bytes: ... def hasChildNodes(self) -> bool: ... def insertBefore(self, newChild, refChild): ... From b8774571d7466e3a2aaf59e7df45e57b4ff66969 Mon Sep 17 00:00:00 2001 From: Wesley Collin Wright Date: Wed, 19 Apr 2023 15:27:29 +0000 Subject: [PATCH 3/8] fix stubs, add test case --- stdlib/xml/dom/minidom.pyi | 58 +++++++++++++++++++++++++++------- test_cases/stdlib/check_xml.py | 28 ++++++++++++++++ 2 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 test_cases/stdlib/check_xml.py diff --git a/stdlib/xml/dom/minidom.pyi b/stdlib/xml/dom/minidom.pyi index 1f33e0413f99..ec17f0a41497 100644 --- a/stdlib/xml/dom/minidom.pyi +++ b/stdlib/xml/dom/minidom.pyi @@ -34,29 +34,65 @@ class Node(xml.dom.Node): def toxml(self, encoding: str, standalone: bool | None = None) -> bytes: ... @overload def toxml(self, encoding: None = None, standalone: bool | None = None) -> str: ... - def toxml(self, encoding: str | None = None, standalone: bool | None = None) -> str | bytes: ... @overload def toprettyxml( - self, indent: str = "\t", newl: str = "\n", encoding: str = ..., standalone: bool | None = None - ) -> bytes: ... + self, + indent: str = "\t", + newl: str = "\n", + # Handle any case where encoding is not provided or where it is passed with None + encoding: None = None, + standalone: bool | None = None, + ) -> str: ... @overload def toprettyxml( - self, indent: str = "\t", newl: str = "\n", encoding: None = None, standalone: bool | None = None - ) -> str: ... + self, + indent: str, + newl: str, + # Handle cases where encoding is passed as str *positionally* + encoding: str, + standalone: bool | None = None, + ) -> bytes: ... + @overload def toprettyxml( - self, indent: str = "\t", newl: str = "\n", encoding: str | None = None, standalone: bool | None = None - ) -> str: ... + self, + indent: str = "\t", + newl: str = "\n", + # Handle all cases where encoding is passed as a keyword argument; because standalone + # comes after, it will also have to be a keyword arg if encoding is + *, + encoding: str, + standalone: bool | None = None, + ) -> bytes: ... else: @overload def toxml(self, encoding: str) -> bytes: ... @overload def toxml(self, encoding: None = None) -> str: ... - def toxml(self, encoding: str | None = None) -> str | bytes: ... @overload - def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: str = ...) -> bytes: ... + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + # Handle any case where encoding is not provided or where it is passed with None + encoding: None = None, + ) -> str: ... @overload - def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: None = None) -> str: ... - def toprettyxml(self, indent: str = "\t", newl: str = "\n", encoding: str | None = None) -> str | bytes: ... + def toprettyxml( + self, + indent: str, + newl: str, + # Handle cases where encoding is passed as str *positionally* + encoding: str, + ) -> bytes: ... + @overload + def toprettyxml( + self, + indent: str = "\t", + newl: str = "\n", + # Handle all cases where encoding is passed as a keyword argument + *, + encoding: str, + ) -> bytes: ... def hasChildNodes(self) -> bool: ... def insertBefore(self, newChild, refChild): ... diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py new file mode 100644 index 000000000000..6e4708a43480 --- /dev/null +++ b/test_cases/stdlib/check_xml.py @@ -0,0 +1,28 @@ +from xml.dom.minidom import Document +from typing_extensions import assert_type + +document = Document() + +assert_type(document.toxml(), str) +assert_type(document.toxml(encoding=None), str) +assert_type(document.toxml(standalone=True), str) +assert_type(document.toxml(encoding="UTF8"), bytes) +assert_type(document.toxml(encoding="UTF8", standalone=True), bytes) +assert_type(document.toxml("UTF8"), bytes) +assert_type(document.toxml("UTF8", True), bytes) + +# Because toprettyxml can mix positional and keyword variants of the "encoding" argument, which +# determines the return type, the proper stub typing isn't immediately obvious. This is a basic +# brute-force sanity check. +# Test cases like toxml +assert_type(document.toprettyxml(), str) +assert_type(document.toprettyxml(encoding=None), str) +assert_type(document.toprettyxml(standalone=True), str) +assert_type(document.toprettyxml(encoding="UTF8"), bytes) +assert_type(document.toprettyxml(encoding="UTF8", standalone=True), bytes) +# Test cases unique to toprettyxml +assert_type(document.toprettyxml(" "), str) +assert_type(document.toprettyxml(" ", "\r\n"), str) +assert_type(document.toprettyxml(" ", "\r\n", standalone=True), str) +assert_type(document.toprettyxml(" ", "\r\n", "UTF8"), bytes) +assert_type(document.toprettyxml(" ", "\r\n", "UTF8", True), bytes) From 3fca179b64d9e2b23b516f0f033b5cd53da90132 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 15:31:36 +0000 Subject: [PATCH 4/8] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/check_xml.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py index 6e4708a43480..fb89e563799d 100644 --- a/test_cases/stdlib/check_xml.py +++ b/test_cases/stdlib/check_xml.py @@ -1,5 +1,5 @@ -from xml.dom.minidom import Document from typing_extensions import assert_type +from xml.dom.minidom import Document document = Document() From 4611f56f178c50a1a788d82fc427711920f2dcf6 Mon Sep 17 00:00:00 2001 From: Wesley Collin Wright Date: Wed, 19 Apr 2023 15:48:09 +0000 Subject: [PATCH 5/8] gate standalone= tests for python 3.9+ --- test_cases/stdlib/check_xml.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py index fb89e563799d..36cc9c029acd 100644 --- a/test_cases/stdlib/check_xml.py +++ b/test_cases/stdlib/check_xml.py @@ -1,3 +1,5 @@ +import sys + from typing_extensions import assert_type from xml.dom.minidom import Document @@ -5,24 +7,28 @@ assert_type(document.toxml(), str) assert_type(document.toxml(encoding=None), str) -assert_type(document.toxml(standalone=True), str) assert_type(document.toxml(encoding="UTF8"), bytes) -assert_type(document.toxml(encoding="UTF8", standalone=True), bytes) assert_type(document.toxml("UTF8"), bytes) -assert_type(document.toxml("UTF8", True), bytes) +if sys.version_info >= (3, 9): + assert_type(document.toxml(standalone=True), str) + assert_type(document.toxml("UTF8", True), bytes) + assert_type(document.toxml(encoding="UTF8", standalone=True), bytes) + # Because toprettyxml can mix positional and keyword variants of the "encoding" argument, which # determines the return type, the proper stub typing isn't immediately obvious. This is a basic # brute-force sanity check. # Test cases like toxml -assert_type(document.toprettyxml(), str) -assert_type(document.toprettyxml(encoding=None), str) -assert_type(document.toprettyxml(standalone=True), str) -assert_type(document.toprettyxml(encoding="UTF8"), bytes) -assert_type(document.toprettyxml(encoding="UTF8", standalone=True), bytes) +assert_type(document.toxml(), str) +assert_type(document.toxml(encoding=None), str) +assert_type(document.toxml(encoding="UTF8"), bytes) +if sys.version_info >= (3, 9): + assert_type(document.toxml(standalone=True), str) + assert_type(document.toxml(encoding="UTF8", standalone=True), bytes) # Test cases unique to toprettyxml assert_type(document.toprettyxml(" "), str) assert_type(document.toprettyxml(" ", "\r\n"), str) -assert_type(document.toprettyxml(" ", "\r\n", standalone=True), str) assert_type(document.toprettyxml(" ", "\r\n", "UTF8"), bytes) -assert_type(document.toprettyxml(" ", "\r\n", "UTF8", True), bytes) +if sys.version_info >= (3, 9): + assert_type(document.toprettyxml(" ", "\r\n", "UTF8", True), bytes) + assert_type(document.toprettyxml(" ", "\r\n", standalone=True), str) From 754cdd4edefbe8079e40ac1fbfe2b44dd469530d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 15:49:41 +0000 Subject: [PATCH 6/8] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/check_xml.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py index 36cc9c029acd..755c0cc05992 100644 --- a/test_cases/stdlib/check_xml.py +++ b/test_cases/stdlib/check_xml.py @@ -1,5 +1,4 @@ import sys - from typing_extensions import assert_type from xml.dom.minidom import Document From 53f84b63d16689aeb1a429116cacc18f96a5a8a2 Mon Sep 17 00:00:00 2001 From: Wesley Collin Wright Date: Wed, 19 Apr 2023 15:56:52 +0000 Subject: [PATCH 7/8] placate warning about modern typing syntax --- test_cases/stdlib/check_xml.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py index 755c0cc05992..826d43acefeb 100644 --- a/test_cases/stdlib/check_xml.py +++ b/test_cases/stdlib/check_xml.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from typing_extensions import assert_type from xml.dom.minidom import Document From ccafb9362b09173d5854876f0115d848db358a80 Mon Sep 17 00:00:00 2001 From: Wesley Collin Wright Date: Sat, 22 Apr 2023 22:17:18 +0000 Subject: [PATCH 8/8] fix toxml => toprettyxml in test cases --- test_cases/stdlib/check_xml.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test_cases/stdlib/check_xml.py b/test_cases/stdlib/check_xml.py index 826d43acefeb..b485dac8dc29 100644 --- a/test_cases/stdlib/check_xml.py +++ b/test_cases/stdlib/check_xml.py @@ -20,12 +20,12 @@ # determines the return type, the proper stub typing isn't immediately obvious. This is a basic # brute-force sanity check. # Test cases like toxml -assert_type(document.toxml(), str) -assert_type(document.toxml(encoding=None), str) -assert_type(document.toxml(encoding="UTF8"), bytes) +assert_type(document.toprettyxml(), str) +assert_type(document.toprettyxml(encoding=None), str) +assert_type(document.toprettyxml(encoding="UTF8"), bytes) if sys.version_info >= (3, 9): - assert_type(document.toxml(standalone=True), str) - assert_type(document.toxml(encoding="UTF8", standalone=True), bytes) + assert_type(document.toprettyxml(standalone=True), str) + assert_type(document.toprettyxml(encoding="UTF8", standalone=True), bytes) # Test cases unique to toprettyxml assert_type(document.toprettyxml(" "), str) assert_type(document.toprettyxml(" ", "\r\n"), str)