Skip to content

Commit

Permalink
Refactor URL.join to avoid intermediate dict (#1313)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Oct 17, 2024
1 parent 67bd066 commit 995abe0
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 42 deletions.
1 change: 1 addition & 0 deletions CHANGES/1313.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved performance of :py:meth:`~yarl.URL.join` -- by :user:`bdraco`.
79 changes: 37 additions & 42 deletions yarl/_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,6 @@ class CacheInfo(TypedDict):
host_validate: _CacheInfo


class _SplitResultDict(TypedDict, total=False):

scheme: str
netloc: str
path: str
query: str
fragment: str


class _InternalURLCache(TypedDict, total=False):

_origin: "URL"
Expand Down Expand Up @@ -1565,44 +1556,48 @@ def join(self, url: "URL") -> "URL":
"""
if type(url) is not URL:
raise TypeError("url should be URL")
val = self._val
other_val = url._val
scheme = other_val.scheme or val.scheme
orig_scheme, orig_netloc, orig_path, orig_query, orig_fragment = self._val
join_scheme, join_netloc, join_path, join_query, join_fragment = url._val
scheme = join_scheme or orig_scheme

if scheme != val.scheme or scheme not in USES_RELATIVE:
if scheme != orig_scheme or scheme not in USES_RELATIVE:
return url

# scheme is in uses_authority as uses_authority is a superset of uses_relative
if other_val.netloc and scheme in USES_AUTHORITY:
return self._from_val(other_val._replace(scheme=scheme))

parts: _SplitResultDict = {"scheme": scheme}
if other_val.path or other_val.fragment:
parts["fragment"] = other_val.fragment
if other_val.path or other_val.query:
parts["query"] = other_val.query

if not other_val.path:
return self._from_val(val._replace(**parts))

if other_val.path[0] == "/":
path = other_val.path
elif not val.path:
path = f"/{other_val.path}"
elif val.path[-1] == "/":
path = f"{val.path}{other_val.path}"
if join_netloc and scheme in USES_AUTHORITY:
return self._from_val(
tuple.__new__(
SplitResult,
(scheme, join_netloc, join_path, join_query, join_fragment),
)
)

fragment = join_fragment if join_path or join_fragment else orig_fragment
query = join_query if join_path or join_query else orig_query

if not join_path:
path = orig_path
else:
# …
# and relativizing ".."
# parts[0] is / for absolute urls, this join will add a double slash there
path = "/".join([*self.parts[:-1], ""])
path += other_val.path
# which has to be removed
if val.path[0] == "/":
path = path[1:]

parts["path"] = self._normalize_path(path) if "." in path else path
return self._from_val(val._replace(**parts))
if join_path[0] == "/":
path = join_path
elif not orig_path:
path = f"/{join_path}"
elif orig_path[-1] == "/":
path = f"{orig_path}{join_path}"
else:
# …
# and relativizing ".."
# parts[0] is / for absolute urls,
# this join will add a double slash there
path = "/".join([*self.parts[:-1], ""]) + join_path
# which has to be removed
if orig_path[0] == "/":
path = path[1:]
path = self._normalize_path(path) if "." in path else path

return self._from_val(
tuple.__new__(SplitResult, (scheme, orig_netloc, path, query, fragment))
)

def joinpath(self, *other: str, encoded: bool = False) -> "URL":
"""Return a new URL with the elements in other appended to the path."""
Expand Down

0 comments on commit 995abe0

Please sign in to comment.