@@ -213,6 +213,39 @@ def pre_encoded_url(url_str: str) -> "URL":
213213 return self
214214
215215
216+ @lru_cache
217+ def build_pre_encoded_url (
218+ scheme : str ,
219+ authority : str ,
220+ user : Union [str , None ],
221+ password : Union [str , None ],
222+ host : str ,
223+ port : Union [int , None ],
224+ path : str ,
225+ query_string : str ,
226+ fragment : str ,
227+ ) -> "URL" :
228+ """Build a pre-encoded URL from parts."""
229+ self = object .__new__ (URL )
230+ self ._scheme = scheme
231+ if authority :
232+ self ._netloc = authority
233+ elif host :
234+ if port is not None :
235+ port = None if port == DEFAULT_PORTS .get (scheme ) else port
236+ if user is None and password is None :
237+ self ._netloc = host if port is None else f"{ host } :{ port } "
238+ else :
239+ self ._netloc = make_netloc (user , password , host , port )
240+ else :
241+ self ._netloc = ""
242+ self ._path = path
243+ self ._query = query_string
244+ self ._fragment = fragment
245+ self ._cache = {}
246+ return self
247+
248+
216249@lru_cache
217250def from_parts (scheme : str , netloc : str , path : str , query : str , fragment : str ) -> "URL" :
218251 """Create a new URL from parts."""
@@ -375,61 +408,59 @@ def build(
375408 '"query_string", and "fragment" args, use empty string instead.'
376409 )
377410
411+ if query :
412+ query_string = get_str_query (query ) or ""
413+
378414 if encoded :
379- if authority :
380- netloc = authority
381- elif host :
382- if port is not None :
383- port = None if port == DEFAULT_PORTS .get (scheme ) else port
384- if user is None and password is None :
385- netloc = host if port is None else f"{ host } :{ port } "
386- else :
387- netloc = make_netloc (user , password , host , port )
388- else :
389- netloc = ""
390- else : # not encoded
391- _host : Union [str , None ] = None
392- if authority :
393- user , password , _host , port = split_netloc (authority )
394- _host = _encode_host (_host , validate_host = False ) if _host else ""
395- elif host :
396- _host = _encode_host (host , validate_host = True )
415+ return build_pre_encoded_url (
416+ scheme ,
417+ authority ,
418+ user ,
419+ password ,
420+ host ,
421+ port ,
422+ path ,
423+ query_string ,
424+ fragment ,
425+ )
426+
427+ self = object .__new__ (URL )
428+ self ._scheme = scheme
429+ _host : Union [str , None ] = None
430+ if authority :
431+ user , password , _host , port = split_netloc (authority )
432+ _host = _encode_host (_host , validate_host = False ) if _host else ""
433+ elif host :
434+ _host = _encode_host (host , validate_host = True )
435+ else :
436+ self ._netloc = ""
437+
438+ if _host is not None :
439+ if port is not None :
440+ port = None if port == DEFAULT_PORTS .get (scheme ) else port
441+ if user is None and password is None :
442+ self ._netloc = _host if port is None else f"{ _host } :{ port } "
397443 else :
398- netloc = ""
399-
400- if _host is not None :
401- if port is not None :
402- port = None if port == DEFAULT_PORTS .get (scheme ) else port
403- if user is None and password is None :
404- netloc = _host if port is None else f"{ _host } :{ port } "
405- else :
406- netloc = make_netloc (user , password , _host , port , True )
407-
408- path = PATH_QUOTER (path ) if path else path
409- if path and netloc :
410- if "." in path :
411- path = normalize_path (path )
412- if path [0 ] != "/" :
413- msg = (
414- "Path in a URL with authority should "
415- "start with a slash ('/') if set"
416- )
417- raise ValueError (msg )
418-
419- query_string = QUERY_QUOTER (query_string ) if query_string else query_string
420- fragment = FRAGMENT_QUOTER (fragment ) if fragment else fragment
444+ self ._netloc = make_netloc (user , password , _host , port , True )
421445
422- if query :
423- query_string = get_str_query (query ) or ""
446+ path = PATH_QUOTER (path ) if path else path
447+ if path and self ._netloc :
448+ if "." in path :
449+ path = normalize_path (path )
450+ if path [0 ] != "/" :
451+ msg = (
452+ "Path in a URL with authority should "
453+ "start with a slash ('/') if set"
454+ )
455+ raise ValueError (msg )
424456
425- url = object .__new__ (cls )
426- url ._scheme = scheme
427- url ._netloc = netloc
428- url ._path = path
429- url ._query = query_string
430- url ._fragment = fragment
431- url ._cache = {}
432- return url
457+ self ._path = path
458+ if not query and query_string :
459+ query_string = QUERY_QUOTER (query_string )
460+ self ._query = query_string
461+ self ._fragment = FRAGMENT_QUOTER (fragment ) if fragment else fragment
462+ self ._cache = {}
463+ return self
433464
434465 def __init_subclass__ (cls ):
435466 raise TypeError (f"Inheriting a class { cls !r} from URL is forbidden" )
0 commit comments