@@ -213,6 +213,19 @@ def pre_encoded_url(url_str: str) -> "URL":
213
213
return self
214
214
215
215
216
+ @lru_cache
217
+ def from_parts (scheme : str , netloc : str , path : str , query : str , fragment : str ) -> "URL" :
218
+ """Create a new URL from parts."""
219
+ self = object .__new__ (URL )
220
+ self ._scheme = scheme
221
+ self ._netloc = netloc
222
+ self ._path = path
223
+ self ._query = query
224
+ self ._fragment = fragment
225
+ self ._cache = {}
226
+ return self
227
+
228
+
216
229
@rewrite_module
217
230
class URL :
218
231
# Don't derive from str
@@ -308,10 +321,7 @@ def __new__(
308
321
if type (val ) is SplitResult :
309
322
if not encoded :
310
323
raise ValueError ("Cannot apply decoding to SplitResult" )
311
- self = object .__new__ (URL )
312
- self ._scheme , self ._netloc , self ._path , self ._query , self ._fragment = val
313
- self ._cache = {}
314
- return self
324
+ return from_parts (* val )
315
325
if isinstance (val , str ):
316
326
return pre_encoded_url (str (val )) if encoded else encode_url (str (val ))
317
327
if val is UNDEFINED :
@@ -421,20 +431,6 @@ def build(
421
431
url ._cache = {}
422
432
return url
423
433
424
- @classmethod
425
- def _from_parts (
426
- cls , scheme : str , netloc : str , path : str , query : str , fragment : str
427
- ) -> "URL" :
428
- """Create a new URL from parts."""
429
- self = object .__new__ (cls )
430
- self ._scheme = scheme
431
- self ._netloc = netloc
432
- self ._path = path
433
- self ._query = query
434
- self ._fragment = fragment
435
- self ._cache = {}
436
- return self
437
-
438
434
def __init_subclass__ (cls ):
439
435
raise TypeError (f"Inheriting a class { cls !r} from URL is forbidden" )
440
436
@@ -587,7 +583,7 @@ def _origin(self) -> "URL":
587
583
netloc = make_netloc (None , None , encoded_host , self .explicit_port )
588
584
elif not self ._path and not self ._query and not self ._fragment :
589
585
return self
590
- return self . _from_parts (scheme , netloc , "" , "" , "" )
586
+ return from_parts (scheme , netloc , "" , "" , "" )
591
587
592
588
def relative (self ) -> "URL" :
593
589
"""Return a relative part of the URL.
@@ -597,7 +593,7 @@ def relative(self) -> "URL":
597
593
"""
598
594
if not self ._netloc :
599
595
raise ValueError ("URL should be absolute" )
600
- return self . _from_parts ("" , "" , self ._path , self ._query , self ._fragment )
596
+ return from_parts ("" , "" , self ._path , self ._query , self ._fragment )
601
597
602
598
@cached_property
603
599
def absolute (self ) -> bool :
@@ -916,12 +912,10 @@ def parent(self) -> "URL":
916
912
path = self ._path
917
913
if not path or path == "/" :
918
914
if self ._fragment or self ._query :
919
- return self . _from_parts (self ._scheme , self ._netloc , path , "" , "" )
915
+ return from_parts (self ._scheme , self ._netloc , path , "" , "" )
920
916
return self
921
917
parts = path .split ("/" )
922
- return self ._from_parts (
923
- self ._scheme , self ._netloc , "/" .join (parts [:- 1 ]), "" , ""
924
- )
918
+ return from_parts (self ._scheme , self ._netloc , "/" .join (parts [:- 1 ]), "" , "" )
925
919
926
920
@cached_property
927
921
def raw_name (self ) -> str :
@@ -998,13 +992,13 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL":
998
992
999
993
parsed .reverse ()
1000
994
if not netloc or not needs_normalize :
1001
- return self . _from_parts (self ._scheme , netloc , "/" .join (parsed ), "" , "" )
995
+ return from_parts (self ._scheme , netloc , "/" .join (parsed ), "" , "" )
1002
996
1003
997
path = "/" .join (normalize_path_segments (parsed ))
1004
998
# If normalizing the path segments removed the leading slash, add it back.
1005
999
if path and path [0 ] != "/" :
1006
1000
path = f"/{ path } "
1007
- return self . _from_parts (self ._scheme , netloc , path , "" , "" )
1001
+ return from_parts (self ._scheme , netloc , path , "" , "" )
1008
1002
1009
1003
def with_scheme (self , scheme : str ) -> "URL" :
1010
1004
"""Return a new URL with scheme replaced."""
@@ -1019,9 +1013,7 @@ def with_scheme(self, scheme: str) -> "URL":
1019
1013
f"relative URLs for the { lower_scheme } scheme"
1020
1014
)
1021
1015
raise ValueError (msg )
1022
- return self ._from_parts (
1023
- lower_scheme , netloc , self ._path , self ._query , self ._fragment
1024
- )
1016
+ return from_parts (lower_scheme , netloc , self ._path , self ._query , self ._fragment )
1025
1017
1026
1018
def with_user (self , user : Union [str , None ]) -> "URL" :
1027
1019
"""Return a new URL with user replaced.
@@ -1043,9 +1035,7 @@ def with_user(self, user: Union[str, None]) -> "URL":
1043
1035
raise ValueError ("user replacement is not allowed for relative URLs" )
1044
1036
encoded_host = self .host_subcomponent or ""
1045
1037
netloc = make_netloc (user , password , encoded_host , self .explicit_port )
1046
- return self ._from_parts (
1047
- self ._scheme , netloc , self ._path , self ._query , self ._fragment
1048
- )
1038
+ return from_parts (self ._scheme , netloc , self ._path , self ._query , self ._fragment )
1049
1039
1050
1040
def with_password (self , password : Union [str , None ]) -> "URL" :
1051
1041
"""Return a new URL with password replaced.
@@ -1067,9 +1057,7 @@ def with_password(self, password: Union[str, None]) -> "URL":
1067
1057
encoded_host = self .host_subcomponent or ""
1068
1058
port = self .explicit_port
1069
1059
netloc = make_netloc (self .raw_user , password , encoded_host , port )
1070
- return self ._from_parts (
1071
- self ._scheme , netloc , self ._path , self ._query , self ._fragment
1072
- )
1060
+ return from_parts (self ._scheme , netloc , self ._path , self ._query , self ._fragment )
1073
1061
1074
1062
def with_host (self , host : str ) -> "URL" :
1075
1063
"""Return a new URL with host replaced.
@@ -1090,9 +1078,7 @@ def with_host(self, host: str) -> "URL":
1090
1078
encoded_host = _encode_host (host , validate_host = True ) if host else ""
1091
1079
port = self .explicit_port
1092
1080
netloc = make_netloc (self .raw_user , self .raw_password , encoded_host , port )
1093
- return self ._from_parts (
1094
- self ._scheme , netloc , self ._path , self ._query , self ._fragment
1095
- )
1081
+ return from_parts (self ._scheme , netloc , self ._path , self ._query , self ._fragment )
1096
1082
1097
1083
def with_port (self , port : Union [int , None ]) -> "URL" :
1098
1084
"""Return a new URL with port replaced.
@@ -1110,9 +1096,7 @@ def with_port(self, port: Union[int, None]) -> "URL":
1110
1096
raise ValueError ("port replacement is not allowed for relative URLs" )
1111
1097
encoded_host = self .host_subcomponent or ""
1112
1098
netloc = make_netloc (self .raw_user , self .raw_password , encoded_host , port )
1113
- return self ._from_parts (
1114
- self ._scheme , netloc , self ._path , self ._query , self ._fragment
1115
- )
1099
+ return from_parts (self ._scheme , netloc , self ._path , self ._query , self ._fragment )
1116
1100
1117
1101
def with_path (
1118
1102
self ,
@@ -1132,7 +1116,7 @@ def with_path(
1132
1116
path = f"/{ path } "
1133
1117
query = self ._query if keep_query else ""
1134
1118
fragment = self ._fragment if keep_fragment else ""
1135
- return self . _from_parts (self ._scheme , netloc , path , query , fragment )
1119
+ return from_parts (self ._scheme , netloc , path , query , fragment )
1136
1120
1137
1121
@overload
1138
1122
def with_query (self , query : Query ) -> "URL" : ...
@@ -1155,9 +1139,7 @@ def with_query(self, *args: Any, **kwargs: Any) -> "URL":
1155
1139
"""
1156
1140
# N.B. doesn't cleanup query/fragment
1157
1141
query = get_str_query (* args , ** kwargs ) or ""
1158
- return self ._from_parts (
1159
- self ._scheme , self ._netloc , self ._path , query , self ._fragment
1160
- )
1142
+ return from_parts (self ._scheme , self ._netloc , self ._path , query , self ._fragment )
1161
1143
1162
1144
@overload
1163
1145
def extend_query (self , query : Query ) -> "URL" : ...
@@ -1183,9 +1165,7 @@ def extend_query(self, *args: Any, **kwargs: Any) -> "URL":
1183
1165
query += new_query if query [- 1 ] == "&" else f"&{ new_query } "
1184
1166
else :
1185
1167
query = new_query
1186
- return self ._from_parts (
1187
- self ._scheme , self ._netloc , self ._path , query , self ._fragment
1188
- )
1168
+ return from_parts (self ._scheme , self ._netloc , self ._path , query , self ._fragment )
1189
1169
1190
1170
@overload
1191
1171
def update_query (self , query : Query ) -> "URL" : ...
@@ -1242,9 +1222,7 @@ def update_query(self, *args: Any, **kwargs: Any) -> "URL":
1242
1222
"Invalid query type: only str, mapping or "
1243
1223
"sequence of (key, value) pairs is allowed"
1244
1224
)
1245
- return self ._from_parts (
1246
- self ._scheme , self ._netloc , self ._path , query , self ._fragment
1247
- )
1225
+ return from_parts (self ._scheme , self ._netloc , self ._path , query , self ._fragment )
1248
1226
1249
1227
def without_query_params (self , * query_params : str ) -> "URL" :
1250
1228
"""Remove some keys from query part and return new URL."""
@@ -1276,7 +1254,7 @@ def with_fragment(self, fragment: Union[str, None]) -> "URL":
1276
1254
raw_fragment = FRAGMENT_QUOTER (fragment )
1277
1255
if self ._fragment == raw_fragment :
1278
1256
return self
1279
- return self . _from_parts (
1257
+ return from_parts (
1280
1258
self ._scheme , self ._netloc , self ._path , self ._query , raw_fragment
1281
1259
)
1282
1260
@@ -1316,7 +1294,7 @@ def with_name(
1316
1294
1317
1295
query = self ._query if keep_query else ""
1318
1296
fragment = self ._fragment if keep_fragment else ""
1319
- return self . _from_parts (self ._scheme , netloc , "/" .join (parts ), query , fragment )
1297
+ return from_parts (self ._scheme , netloc , "/" .join (parts ), query , fragment )
1320
1298
1321
1299
def with_suffix (
1322
1300
self ,
@@ -1364,9 +1342,7 @@ def join(self, url: "URL") -> "URL":
1364
1342
1365
1343
# scheme is in uses_authority as uses_authority is a superset of uses_relative
1366
1344
if (join_netloc := url ._netloc ) and scheme in USES_AUTHORITY :
1367
- return self ._from_parts (
1368
- scheme , join_netloc , url ._path , url ._query , url ._fragment
1369
- )
1345
+ return from_parts (scheme , join_netloc , url ._path , url ._query , url ._fragment )
1370
1346
1371
1347
orig_path = self ._path
1372
1348
if join_path := url ._path :
@@ -1389,16 +1365,13 @@ def join(self, url: "URL") -> "URL":
1389
1365
else :
1390
1366
path = orig_path
1391
1367
1392
- new_url = object .__new__ (URL )
1393
- new_url ._scheme = scheme
1394
- new_url ._netloc = self ._netloc
1395
- new_url ._path = path
1396
- new_url ._query = url ._query if join_path or url ._query else self ._query
1397
- new_url ._fragment = (
1398
- url ._fragment if join_path or url ._fragment else self ._fragment
1368
+ return from_parts (
1369
+ scheme ,
1370
+ self ._netloc ,
1371
+ path ,
1372
+ url ._query if join_path or url ._query else self ._query ,
1373
+ url ._fragment if join_path or url ._fragment else self ._fragment ,
1399
1374
)
1400
- new_url ._cache = {}
1401
- return new_url
1402
1375
1403
1376
def joinpath (self , * other : str , encoded : bool = False ) -> "URL" :
1404
1377
"""Return a new URL with the elements in other appended to the path."""
0 commit comments