@@ -2,6 +2,7 @@ import sys
22from collections .abc import Iterable , Mapping , Sequence
33from types import GenericAlias
44from typing import Any , AnyStr , Final , Generic , Literal , NamedTuple , Protocol , TypeAlias , overload , type_check_only
5+ from typing_extensions import TypeVar
56
67__all__ = [
78 "urlparse" ,
@@ -37,6 +38,11 @@ scheme_chars: Final[str]
3738if sys .version_info < (3 , 11 ):
3839 MAX_CACHE_SIZE : Final [int ]
3940
41+ _ResultStrT = TypeVar ("_ResultStrT" , str , bytes )
42+ _ResultComponentT = TypeVar ("_ResultComponentT" , str , bytes , str | None , bytes | None )
43+ _StrComponentT = TypeVar ("_StrComponentT" , str , str | None , default = str )
44+ _BytesComponentT = TypeVar ("_BytesComponentT" , bytes , bytes | None , default = bytes )
45+
4046class _ResultMixinStr :
4147 __slots__ = ()
4248 def encode (self , encoding : str = "ascii" , errors : str = "strict" ) -> _ResultMixinBytes : ...
@@ -63,44 +69,88 @@ class _NetlocResultMixinStr(_NetlocResultMixinBase[str], _ResultMixinStr):
6369class _NetlocResultMixinBytes (_NetlocResultMixinBase [bytes ], _ResultMixinBytes ):
6470 __slots__ = ()
6571
66- class _DefragResultBase (NamedTuple , Generic [AnyStr ]):
67- url : AnyStr
68- fragment : AnyStr
72+ # Need to duplicate the whole class because mypy rejects version-specific
73+ # branches in namedtuple bodies.
74+ if sys .version_info >= (3 , 15 ):
75+ class _DefragResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
76+ url : _ResultStrT
77+ fragment : _ResultComponentT
78+ # Ignore needed due to mypy#21453.
79+ def geturl (self ) -> _ResultStrT : ... # type: ignore[misc]
80+
81+ else :
82+ class _DefragResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
83+ url : _ResultStrT
84+ fragment : _ResultComponentT
85+
86+ if sys .version_info >= (3 , 15 ):
87+ class _SplitResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
88+ scheme : _ResultComponentT
89+ netloc : _ResultComponentT
90+ path : _ResultStrT
91+ query : _ResultComponentT
92+ fragment : _ResultComponentT
93+ # Ignore needed due to mypy#21453.
94+ def geturl (self ) -> _ResultStrT : ... # type: ignore[misc]
95+
96+ else :
97+ class _SplitResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
98+ scheme : _ResultComponentT
99+ netloc : _ResultComponentT
100+ path : _ResultStrT
101+ query : _ResultComponentT
102+ fragment : _ResultComponentT
103+
104+ if sys .version_info >= (3 , 15 ):
105+ class _ParseResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
106+ scheme : _ResultComponentT
107+ netloc : _ResultComponentT
108+ path : _ResultStrT
109+ params : _ResultComponentT
110+ query : _ResultComponentT
111+ fragment : _ResultComponentT
112+ # Ignore needed due to mypy#21453.
113+ def geturl (self ) -> _ResultStrT : ... # type: ignore[misc]
69114
70- class _SplitResultBase (NamedTuple , Generic [AnyStr ]):
71- scheme : AnyStr
72- netloc : AnyStr
73- path : AnyStr
74- query : AnyStr
75- fragment : AnyStr
115+ else :
116+ class _ParseResultBase (NamedTuple , Generic [_ResultStrT , _ResultComponentT ]):
117+ scheme : _ResultComponentT
118+ netloc : _ResultComponentT
119+ path : _ResultStrT
120+ params : _ResultComponentT
121+ query : _ResultComponentT
122+ fragment : _ResultComponentT
76123
77- class _ParseResultBase (NamedTuple , Generic [AnyStr ]):
78- scheme : AnyStr
79- netloc : AnyStr
80- path : AnyStr
81- params : AnyStr
82- query : AnyStr
83- fragment : AnyStr
124+ if sys .version_info >= (3 , 15 ):
125+ # Structured result objects for string data
126+ class DefragResult (_DefragResultBase [str , _StrComponentT ], _ResultMixinStr , Generic [_StrComponentT ]): ...
127+ class SplitResult (_SplitResultBase [str , _StrComponentT ], _NetlocResultMixinStr , Generic [_StrComponentT ]): ...
128+ class ParseResult (_ParseResultBase [str , _StrComponentT ], _NetlocResultMixinStr , Generic [_StrComponentT ]): ...
129+ # Structured result objects for bytes data
130+ class DefragResultBytes (_DefragResultBase [bytes , _BytesComponentT ], _ResultMixinBytes , Generic [_BytesComponentT ]): ...
131+ class SplitResultBytes (_SplitResultBase [bytes , _BytesComponentT ], _NetlocResultMixinBytes , Generic [_BytesComponentT ]): ...
132+ class ParseResultBytes (_ParseResultBase [bytes , _BytesComponentT ], _NetlocResultMixinBytes , Generic [_BytesComponentT ]): ...
84133
85- # Structured result objects for string data
86- class DefragResult (_DefragResultBase [str ], _ResultMixinStr ):
87- def geturl (self ) -> str : ...
134+ else :
135+ # Structured result objects for string data
136+ class DefragResult (_DefragResultBase [str , str ], _ResultMixinStr ):
137+ def geturl (self ) -> str : ...
88138
89- class SplitResult (_SplitResultBase [str ], _NetlocResultMixinStr ):
90- def geturl (self ) -> str : ...
139+ class SplitResult (_SplitResultBase [str , str ], _NetlocResultMixinStr ):
140+ def geturl (self ) -> str : ...
91141
92- class ParseResult (_ParseResultBase [str ], _NetlocResultMixinStr ):
93- def geturl (self ) -> str : ...
142+ class ParseResult (_ParseResultBase [str , str ], _NetlocResultMixinStr ):
143+ def geturl (self ) -> str : ...
94144
95- # Structured result objects for bytes data
96- class DefragResultBytes (_DefragResultBase [bytes ], _ResultMixinBytes ):
97- def geturl (self ) -> bytes : ...
145+ # Structured result objects for bytes data
146+ class DefragResultBytes (_DefragResultBase [bytes , bytes ], _ResultMixinBytes ):
147+ def geturl (self ) -> bytes : ...
98148
99- class SplitResultBytes (_SplitResultBase [bytes ], _NetlocResultMixinBytes ):
100- def geturl (self ) -> bytes : ...
149+ class SplitResultBytes (_SplitResultBase [bytes , bytes ], _NetlocResultMixinBytes ):
150+ def geturl (self ) -> bytes : ...
101151
102- class ParseResultBytes (_ParseResultBase [bytes ], _NetlocResultMixinBytes ):
103- def geturl (self ) -> bytes : ...
152+ class ParseResultBytes (_ParseResultBase [bytes , bytes ], _NetlocResultMixinBytes ):
153+ def geturl (self ) -> bytes : ...
104154
105155def parse_qs (
106156 qs : AnyStr | None ,
@@ -137,6 +187,20 @@ def urldefrag(url: str) -> DefragResult: ...
137187@overload
138188def urldefrag (url : bytes | bytearray | None ) -> DefragResultBytes : ...
139189
190+ if sys .version_info >= (3 , 15 ):
191+ @overload
192+ def urldefrag (url : str , * , missing_as_none : Literal [True ]) -> DefragResult [str | None ]: ...
193+ @overload
194+ def urldefrag (url : str , * , missing_as_none : Literal [False ] = False ) -> DefragResult [str ]: ...
195+ @overload
196+ def urldefrag (url : bytes | bytearray | None , * , missing_as_none : Literal [True ]) -> DefragResultBytes [bytes | None ]: ...
197+ @overload
198+ def urldefrag (url : bytes | bytearray | None , * , missing_as_none : Literal [False ] = False ) -> DefragResultBytes [bytes ]: ...
199+ @overload
200+ def urldefrag (url : str , * , missing_as_none : bool ) -> DefragResult [str | None ]: ...
201+ @overload
202+ def urldefrag (url : bytes | bytearray | None , * , missing_as_none : bool ) -> DefragResultBytes [bytes | None ]: ...
203+
140204# The values are passed through `str()` (unless they are bytes), so anything is valid.
141205_QueryType : TypeAlias = (
142206 Mapping [str , object ]
@@ -171,6 +235,45 @@ def urlparse(url: str, scheme: str = "", allow_fragments: bool = True) -> ParseR
171235def urlparse (
172236 url : bytes | bytearray | None , scheme : bytes | bytearray | None | Literal ["" ] = "" , allow_fragments : bool = True
173237) -> ParseResultBytes : ...
238+
239+ if sys .version_info >= (3 , 15 ):
240+ @overload
241+ def urlparse (
242+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : Literal [True ]
243+ ) -> ParseResult [str | None ]: ...
244+ @overload
245+ def urlparse (
246+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : Literal [False ] = False
247+ ) -> ParseResult [str ]: ...
248+ @overload
249+ def urlparse (
250+ url : bytes | bytearray | None ,
251+ scheme : bytes | bytearray | None | Literal ["" ] = "" ,
252+ allow_fragments : bool = True ,
253+ * ,
254+ missing_as_none : Literal [True ],
255+ ) -> ParseResultBytes [bytes | None ]: ...
256+ @overload
257+ def urlparse (
258+ url : bytes | bytearray | None ,
259+ scheme : bytes | bytearray | None | Literal ["" ] = "" ,
260+ allow_fragments : bool = True ,
261+ * ,
262+ missing_as_none : Literal [False ] = False ,
263+ ) -> ParseResultBytes [bytes ]: ...
264+ @overload
265+ def urlparse (
266+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : bool
267+ ) -> ParseResult [str | None ]: ...
268+ @overload
269+ def urlparse (
270+ url : bytes | bytearray | None ,
271+ scheme : bytes | bytearray | None | Literal ["" ] = "" ,
272+ allow_fragments : bool = True ,
273+ * ,
274+ missing_as_none : bool ,
275+ ) -> ParseResultBytes [bytes | None ]: ...
276+
174277@overload
175278def urlsplit (url : str , scheme : str = "" , allow_fragments : bool = True ) -> SplitResult : ...
176279
@@ -186,15 +289,66 @@ else:
186289 url : bytes | bytearray | None , scheme : bytes | bytearray | None | Literal ["" ] = "" , allow_fragments : bool = True
187290 ) -> SplitResultBytes : ...
188291
189- # Requires an iterable of length 6
190- @overload
191- def urlunparse (components : Iterable [None ]) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
192- @overload
193- def urlunparse (components : Iterable [AnyStr | None ]) -> AnyStr : ...
292+ if sys .version_info >= (3 , 15 ):
293+ @overload
294+ def urlsplit (
295+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : Literal [True ]
296+ ) -> SplitResult [str | None ]: ...
297+ @overload
298+ def urlsplit (
299+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : Literal [False ] = False
300+ ) -> SplitResult [str ]: ...
301+ @overload
302+ def urlsplit (
303+ url : bytes | None ,
304+ scheme : bytes | None | Literal ["" ] = "" ,
305+ allow_fragments : bool = True ,
306+ * ,
307+ missing_as_none : Literal [True ],
308+ ) -> SplitResultBytes [bytes | None ]: ...
309+ @overload
310+ def urlsplit (
311+ url : bytes | None ,
312+ scheme : bytes | None | Literal ["" ] = "" ,
313+ allow_fragments : bool = True ,
314+ * ,
315+ missing_as_none : Literal [False ] = False ,
316+ ) -> SplitResultBytes [bytes ]: ...
317+ @overload
318+ def urlsplit (
319+ url : str , scheme : str = "" , allow_fragments : bool = True , * , missing_as_none : bool
320+ ) -> SplitResult [str | None ]: ...
321+ @overload
322+ def urlsplit (
323+ url : bytes | None , scheme : bytes | None | Literal ["" ] = "" , allow_fragments : bool = True , * , missing_as_none : bool
324+ ) -> SplitResultBytes [bytes | None ]: ...
325+
326+ if sys .version_info >= (3 , 15 ):
327+ # Requires an iterable of length 6
328+ @overload
329+ def urlunparse (components : Iterable [None ], * , keep_empty : bool = ...) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
330+ @overload
331+ def urlunparse (components : Iterable [AnyStr | None ], * , keep_empty : bool = ...) -> AnyStr : ...
332+
333+ else :
334+ # Requires an iterable of length 6
335+ @overload
336+ def urlunparse (components : Iterable [None ]) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
337+ @overload
338+ def urlunparse (components : Iterable [AnyStr | None ]) -> AnyStr : ...
339+
340+ if sys .version_info >= (3 , 15 ):
341+ # Requires an iterable of length 5
342+ @overload
343+ def urlunsplit (components : Iterable [None ], * , keep_empty : bool = ...) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
344+ @overload
345+ def urlunsplit (components : Iterable [AnyStr | None ], * , keep_empty : bool = ...) -> AnyStr : ...
346+
347+ else :
348+ # Requires an iterable of length 5
349+ @overload
350+ def urlunsplit (components : Iterable [None ]) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
351+ @overload
352+ def urlunsplit (components : Iterable [AnyStr | None ]) -> AnyStr : ...
194353
195- # Requires an iterable of length 5
196- @overload
197- def urlunsplit (components : Iterable [None ]) -> Literal [b"" ]: ... # type: ignore[overload-overlap]
198- @overload
199- def urlunsplit (components : Iterable [AnyStr | None ]) -> AnyStr : ...
200354def unwrap (url : str ) -> str : ...
0 commit comments