From bc847a9b07948a20fcd06ad6c19f2e73437e957e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 21 Feb 2023 00:41:49 +0000 Subject: [PATCH] Use generic `NamedTuple`s to clean up `urllib.parse` (#9773) --- stdlib/urllib/parse.pyi | 82 ++++++++++-------------- tests/stubtest_allowlists/py3_common.txt | 1 - 2 files changed, 34 insertions(+), 49 deletions(-) diff --git a/stdlib/urllib/parse.pyi b/stdlib/urllib/parse.pyi index 50c5d44cd..8e179ca76 100644 --- a/stdlib/urllib/parse.pyi +++ b/stdlib/urllib/parse.pyi @@ -40,13 +40,10 @@ scheme_chars: str if sys.version_info < (3, 11): MAX_CACHE_SIZE: int -class _ResultMixinBase(Generic[AnyStr]): - def geturl(self) -> AnyStr: ... - -class _ResultMixinStr(_ResultMixinBase[str]): +class _ResultMixinStr: def encode(self, encoding: str = "ascii", errors: str = "strict") -> _ResultMixinBytes: ... -class _ResultMixinBytes(_ResultMixinBase[bytes]): +class _ResultMixinBytes: def decode(self, encoding: str = "ascii", errors: str = "strict") -> _ResultMixinStr: ... class _NetlocResultMixinBase(Generic[AnyStr]): @@ -64,55 +61,44 @@ class _NetlocResultMixinBase(Generic[AnyStr]): class _NetlocResultMixinStr(_NetlocResultMixinBase[str], _ResultMixinStr): ... class _NetlocResultMixinBytes(_NetlocResultMixinBase[bytes], _ResultMixinBytes): ... -# Ideally this would be a generic fixed-length tuple, -# but mypy doesn't support that yet: https://github.com/python/mypy/issues/685#issuecomment-992014179 -class _DefragResultBase(tuple[AnyStr, ...], Generic[AnyStr]): - if sys.version_info >= (3, 10): - __match_args__ = ("url", "fragment") - @property - def url(self) -> AnyStr: ... - @property - def fragment(self) -> AnyStr: ... +class _DefragResultBase(NamedTuple, Generic[AnyStr]): + url: AnyStr + fragment: AnyStr -class _SplitResultBase(NamedTuple): - scheme: str - netloc: str - path: str - query: str - fragment: str +class _SplitResultBase(NamedTuple, Generic[AnyStr]): + scheme: AnyStr + netloc: AnyStr + path: AnyStr + query: AnyStr + fragment: AnyStr -class _SplitResultBytesBase(NamedTuple): - scheme: bytes - netloc: bytes - path: bytes - query: bytes - fragment: bytes - -class _ParseResultBase(NamedTuple): - scheme: str - netloc: str - path: str - params: str - query: str - fragment: str - -class _ParseResultBytesBase(NamedTuple): - scheme: bytes - netloc: bytes - path: bytes - params: bytes - query: bytes - fragment: bytes +class _ParseResultBase(NamedTuple, Generic[AnyStr]): + scheme: AnyStr + netloc: AnyStr + path: AnyStr + params: AnyStr + query: AnyStr + fragment: AnyStr # Structured result objects for string data -class DefragResult(_DefragResultBase[str], _ResultMixinStr): ... -class SplitResult(_SplitResultBase, _NetlocResultMixinStr): ... -class ParseResult(_ParseResultBase, _NetlocResultMixinStr): ... +class DefragResult(_DefragResultBase[str], _ResultMixinStr): + def geturl(self) -> str: ... + +class SplitResult(_SplitResultBase[str], _NetlocResultMixinStr): + def geturl(self) -> str: ... + +class ParseResult(_ParseResultBase[str], _NetlocResultMixinStr): + def geturl(self) -> str: ... # Structured result objects for bytes data -class DefragResultBytes(_DefragResultBase[bytes], _ResultMixinBytes): ... -class SplitResultBytes(_SplitResultBytesBase, _NetlocResultMixinBytes): ... -class ParseResultBytes(_ParseResultBytesBase, _NetlocResultMixinBytes): ... +class DefragResultBytes(_DefragResultBase[bytes], _ResultMixinBytes): + def geturl(self) -> bytes: ... + +class SplitResultBytes(_SplitResultBase[bytes], _NetlocResultMixinBytes): + def geturl(self) -> bytes: ... + +class ParseResultBytes(_ParseResultBase[bytes], _NetlocResultMixinBytes): + def geturl(self) -> bytes: ... def parse_qs( qs: AnyStr | None, diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index 1a61c2295..a5212fbf9 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -205,7 +205,6 @@ types.SimpleNamespace.__init__ # class doesn't accept positional arguments but typing.IO.__next__ # Added because IO streams are iterable. See https://github.com/python/typeshed/commit/97bc450acd60c1bcdafef3ce8fbe3b95a9c0cac3 typing.type_check_only # typing decorator that is not available at runtime unittest.mock.patch # It's a complicated overload and I haven't been able to figure out why stubtest doesn't like it -urllib.parse._DefragResultBase.__new__ # Generic NamedTuple is problematic in mypy, so regular tuple was used. See https://github.com/python/mypy/issues/685 urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified weakref.CallableProxyType.__getattr__ # Should have all attributes of proxy weakref.ProxyType.__getattr__ # Should have all attributes of proxy