Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions stdlib/@tests/stubtest_allowlists/py315.txt
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ typing.Union
typing._SpecialForm.__mro_entries__
typing_extensions.__all__
typing_extensions.Protocol
urllib.parse._DefragResultBase.geturl
urllib.parse._ParseResultBase.geturl
urllib.parse._SplitResultBase.geturl
urllib.parse.urldefrag
urllib.parse.urlparse
urllib.parse.urlsplit
urllib.parse.urlunparse
urllib.parse.urlunsplit
xml.etree.ElementTree.__all__
xml.is_valid_name
xml.utils
zipimport.zipimporter.load_module

# =============================================================
# Allowlist entries that cannot or should not be fixed; >=3.15
# =============================================================

# runtime default is a list object used as a sentinel
urllib.parse.urlunparse
urllib.parse.urlunsplit
234 changes: 194 additions & 40 deletions stdlib/urllib/parse.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import sys
from collections.abc import Iterable, Mapping, Sequence
from types import GenericAlias
from typing import Any, AnyStr, Final, Generic, Literal, NamedTuple, Protocol, TypeAlias, overload, type_check_only
from typing_extensions import TypeVar

__all__ = [
"urlparse",
Expand Down Expand Up @@ -37,6 +38,11 @@ scheme_chars: Final[str]
if sys.version_info < (3, 11):
MAX_CACHE_SIZE: Final[int]

_ResultStrT = TypeVar("_ResultStrT", str, bytes)
_ResultComponentT = TypeVar("_ResultComponentT", str, bytes, str | None, bytes | None)
_StrComponentT = TypeVar("_StrComponentT", str, str | None, default=str)
_BytesComponentT = TypeVar("_BytesComponentT", bytes, bytes | None, default=bytes)

class _ResultMixinStr:
__slots__ = ()
def encode(self, encoding: str = "ascii", errors: str = "strict") -> _ResultMixinBytes: ...
Expand All @@ -63,44 +69,88 @@ class _NetlocResultMixinStr(_NetlocResultMixinBase[str], _ResultMixinStr):
class _NetlocResultMixinBytes(_NetlocResultMixinBase[bytes], _ResultMixinBytes):
__slots__ = ()

class _DefragResultBase(NamedTuple, Generic[AnyStr]):
url: AnyStr
fragment: AnyStr
# Need to duplicate the whole class because mypy rejects version-specific
# branches in namedtuple bodies.
if sys.version_info >= (3, 15):
class _DefragResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
url: _ResultStrT
fragment: _ResultComponentT
# Ignore needed due to mypy#21453.
def geturl(self) -> _ResultStrT: ... # type: ignore[misc]

else:
class _DefragResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
url: _ResultStrT
fragment: _ResultComponentT

if sys.version_info >= (3, 15):
class _SplitResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
scheme: _ResultComponentT
netloc: _ResultComponentT
path: _ResultStrT
query: _ResultComponentT
fragment: _ResultComponentT
# Ignore needed due to mypy#21453.
def geturl(self) -> _ResultStrT: ... # type: ignore[misc]

else:
class _SplitResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
scheme: _ResultComponentT
netloc: _ResultComponentT
path: _ResultStrT
query: _ResultComponentT
fragment: _ResultComponentT

if sys.version_info >= (3, 15):
class _ParseResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
scheme: _ResultComponentT
netloc: _ResultComponentT
path: _ResultStrT
params: _ResultComponentT
query: _ResultComponentT
fragment: _ResultComponentT
# Ignore needed due to mypy#21453.
def geturl(self) -> _ResultStrT: ... # type: ignore[misc]

class _SplitResultBase(NamedTuple, Generic[AnyStr]):
scheme: AnyStr
netloc: AnyStr
path: AnyStr
query: AnyStr
fragment: AnyStr
else:
class _ParseResultBase(NamedTuple, Generic[_ResultStrT, _ResultComponentT]):
scheme: _ResultComponentT
netloc: _ResultComponentT
path: _ResultStrT
params: _ResultComponentT
query: _ResultComponentT
fragment: _ResultComponentT

class _ParseResultBase(NamedTuple, Generic[AnyStr]):
scheme: AnyStr
netloc: AnyStr
path: AnyStr
params: AnyStr
query: AnyStr
fragment: AnyStr
if sys.version_info >= (3, 15):
# Structured result objects for string data
class DefragResult(_DefragResultBase[str, _StrComponentT], _ResultMixinStr, Generic[_StrComponentT]): ...
class SplitResult(_SplitResultBase[str, _StrComponentT], _NetlocResultMixinStr, Generic[_StrComponentT]): ...
class ParseResult(_ParseResultBase[str, _StrComponentT], _NetlocResultMixinStr, Generic[_StrComponentT]): ...
# Structured result objects for bytes data
class DefragResultBytes(_DefragResultBase[bytes, _BytesComponentT], _ResultMixinBytes, Generic[_BytesComponentT]): ...
class SplitResultBytes(_SplitResultBase[bytes, _BytesComponentT], _NetlocResultMixinBytes, Generic[_BytesComponentT]): ...
class ParseResultBytes(_ParseResultBase[bytes, _BytesComponentT], _NetlocResultMixinBytes, Generic[_BytesComponentT]): ...

# Structured result objects for string data
class DefragResult(_DefragResultBase[str], _ResultMixinStr):
def geturl(self) -> str: ...
else:
# Structured result objects for string data
class DefragResult(_DefragResultBase[str, str], _ResultMixinStr):
def geturl(self) -> str: ...

class SplitResult(_SplitResultBase[str], _NetlocResultMixinStr):
def geturl(self) -> str: ...
class SplitResult(_SplitResultBase[str, str], _NetlocResultMixinStr):
def geturl(self) -> str: ...

class ParseResult(_ParseResultBase[str], _NetlocResultMixinStr):
def geturl(self) -> str: ...
class ParseResult(_ParseResultBase[str, str], _NetlocResultMixinStr):
def geturl(self) -> str: ...

# Structured result objects for bytes data
class DefragResultBytes(_DefragResultBase[bytes], _ResultMixinBytes):
def geturl(self) -> bytes: ...
# Structured result objects for bytes data
class DefragResultBytes(_DefragResultBase[bytes, bytes], _ResultMixinBytes):
def geturl(self) -> bytes: ...

class SplitResultBytes(_SplitResultBase[bytes], _NetlocResultMixinBytes):
def geturl(self) -> bytes: ...
class SplitResultBytes(_SplitResultBase[bytes, bytes], _NetlocResultMixinBytes):
def geturl(self) -> bytes: ...

class ParseResultBytes(_ParseResultBase[bytes], _NetlocResultMixinBytes):
def geturl(self) -> bytes: ...
class ParseResultBytes(_ParseResultBase[bytes, bytes], _NetlocResultMixinBytes):
def geturl(self) -> bytes: ...

def parse_qs(
qs: AnyStr | None,
Expand Down Expand Up @@ -137,6 +187,20 @@ def urldefrag(url: str) -> DefragResult: ...
@overload
def urldefrag(url: bytes | bytearray | None) -> DefragResultBytes: ...

if sys.version_info >= (3, 15):
@overload
def urldefrag(url: str, *, missing_as_none: Literal[True]) -> DefragResult[str | None]: ...
@overload
def urldefrag(url: str, *, missing_as_none: Literal[False] = False) -> DefragResult[str]: ...
@overload
def urldefrag(url: bytes | bytearray | None, *, missing_as_none: Literal[True]) -> DefragResultBytes[bytes | None]: ...
@overload
def urldefrag(url: bytes | bytearray | None, *, missing_as_none: Literal[False] = False) -> DefragResultBytes[bytes]: ...
@overload
def urldefrag(url: str, *, missing_as_none: bool) -> DefragResult[str | None]: ...
@overload
def urldefrag(url: bytes | bytearray | None, *, missing_as_none: bool) -> DefragResultBytes[bytes | None]: ...

# The values are passed through `str()` (unless they are bytes), so anything is valid.
_QueryType: TypeAlias = (
Mapping[str, object]
Expand Down Expand Up @@ -171,6 +235,45 @@ def urlparse(url: str, scheme: str = "", allow_fragments: bool = True) -> ParseR
def urlparse(
url: bytes | bytearray | None, scheme: bytes | bytearray | None | Literal[""] = "", allow_fragments: bool = True
) -> ParseResultBytes: ...

if sys.version_info >= (3, 15):
@overload
def urlparse(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: Literal[True]
) -> ParseResult[str | None]: ...
@overload
def urlparse(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: Literal[False] = False
) -> ParseResult[str]: ...
@overload
def urlparse(
url: bytes | bytearray | None,
scheme: bytes | bytearray | None | Literal[""] = "",
allow_fragments: bool = True,
*,
missing_as_none: Literal[True],
) -> ParseResultBytes[bytes | None]: ...
@overload
def urlparse(
url: bytes | bytearray | None,
scheme: bytes | bytearray | None | Literal[""] = "",
allow_fragments: bool = True,
*,
missing_as_none: Literal[False] = False,
) -> ParseResultBytes[bytes]: ...
@overload
def urlparse(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: bool
) -> ParseResult[str | None]: ...
@overload
def urlparse(
url: bytes | bytearray | None,
scheme: bytes | bytearray | None | Literal[""] = "",
allow_fragments: bool = True,
*,
missing_as_none: bool,
) -> ParseResultBytes[bytes | None]: ...

@overload
def urlsplit(url: str, scheme: str = "", allow_fragments: bool = True) -> SplitResult: ...

Expand All @@ -186,15 +289,66 @@ else:
url: bytes | bytearray | None, scheme: bytes | bytearray | None | Literal[""] = "", allow_fragments: bool = True
) -> SplitResultBytes: ...

# Requires an iterable of length 6
@overload
def urlunparse(components: Iterable[None]) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunparse(components: Iterable[AnyStr | None]) -> AnyStr: ...
if sys.version_info >= (3, 15):
@overload
def urlsplit(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: Literal[True]
) -> SplitResult[str | None]: ...
@overload
def urlsplit(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: Literal[False] = False
) -> SplitResult[str]: ...
@overload
def urlsplit(
url: bytes | None,
scheme: bytes | None | Literal[""] = "",
allow_fragments: bool = True,
*,
missing_as_none: Literal[True],
) -> SplitResultBytes[bytes | None]: ...
@overload
def urlsplit(
url: bytes | None,
scheme: bytes | None | Literal[""] = "",
allow_fragments: bool = True,
*,
missing_as_none: Literal[False] = False,
) -> SplitResultBytes[bytes]: ...
@overload
def urlsplit(
url: str, scheme: str = "", allow_fragments: bool = True, *, missing_as_none: bool
) -> SplitResult[str | None]: ...
@overload
def urlsplit(
url: bytes | None, scheme: bytes | None | Literal[""] = "", allow_fragments: bool = True, *, missing_as_none: bool
) -> SplitResultBytes[bytes | None]: ...

if sys.version_info >= (3, 15):
# Requires an iterable of length 6
@overload
def urlunparse(components: Iterable[None], *, keep_empty: bool = ...) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunparse(components: Iterable[AnyStr | None], *, keep_empty: bool = ...) -> AnyStr: ...

else:
# Requires an iterable of length 6
@overload
def urlunparse(components: Iterable[None]) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunparse(components: Iterable[AnyStr | None]) -> AnyStr: ...

if sys.version_info >= (3, 15):
# Requires an iterable of length 5
@overload
def urlunsplit(components: Iterable[None], *, keep_empty: bool = ...) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunsplit(components: Iterable[AnyStr | None], *, keep_empty: bool = ...) -> AnyStr: ...

else:
# Requires an iterable of length 5
@overload
def urlunsplit(components: Iterable[None]) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunsplit(components: Iterable[AnyStr | None]) -> AnyStr: ...

# Requires an iterable of length 5
@overload
def urlunsplit(components: Iterable[None]) -> Literal[b""]: ... # type: ignore[overload-overlap]
@overload
def urlunsplit(components: Iterable[AnyStr | None]) -> AnyStr: ...
def unwrap(url: str) -> str: ...
Loading