Skip to content

Commit

Permalink
Speed up methods that create new URL objects (#1226)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Oct 12, 2024
1 parent 041c63c commit c02ba7f
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGES/1226.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved performance of all :class:`~yarl.URL` methods that create new :class:`~yarl.URL` objects -- by :user:`bdraco`.
45 changes: 21 additions & 24 deletions yarl/_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ def _origin(self) -> "URL":
encoded_host = self._encode_host(v.hostname) if v.hostname else ""
netloc = self._make_netloc(None, None, encoded_host, v.port)
val = v._replace(netloc=netloc, path="", query="", fragment="")
return URL(val, encoded=True)
return self._from_val(val)

def relative(self) -> "URL":
"""Return a relative part of the URL.
Expand All @@ -578,7 +578,7 @@ def relative(self) -> "URL":
if not self.absolute:
raise ValueError("URL should be absolute")
val = self._val._replace(scheme="", netloc="")
return URL(val, encoded=True)
return self._from_val(val)

@cached_property
def absolute(self) -> bool:
Expand Down Expand Up @@ -870,11 +870,11 @@ def parent(self) -> "URL":
path = self.raw_path
if not path or path == "/":
if self._val.fragment or self._val.query:
return URL(self._val._replace(query="", fragment=""), encoded=True)
return self._from_val(self._val._replace(query="", fragment=""))
return self
parts = path.split("/")
val = self._val._replace(path="/".join(parts[:-1]), query="", fragment="")
return URL(val, encoded=True)
return self._from_val(val)

@cached_property
def raw_name(self) -> str:
Expand Down Expand Up @@ -961,9 +961,7 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL":
# where there was none before
parsed = ["", *parsed]
new_path = "/".join(parsed)
return URL(
self._val._replace(path=new_path, query="", fragment=""), encoded=True
)
return self._from_val(self._val._replace(path=new_path, query="", fragment=""))

@classmethod
def _normalize_path(cls, path: str) -> str:
Expand Down Expand Up @@ -1140,7 +1138,7 @@ def with_scheme(self, scheme: str) -> "URL":
f"relative URLs for the {lower_scheme} scheme"
)
raise ValueError(msg)
return URL(self._val._replace(scheme=lower_scheme), encoded=True)
return self._from_val(self._val._replace(scheme=lower_scheme))

def with_user(self, user: Union[str, None]) -> "URL":
"""Return a new URL with user replaced.
Expand All @@ -1163,7 +1161,7 @@ def with_user(self, user: Union[str, None]) -> "URL":
raise ValueError("user replacement is not allowed for relative URLs")
encoded_host = self._encode_host(val.hostname) if val.hostname else ""
netloc = self._make_netloc(user, password, encoded_host, val.port)
return URL(val._replace(netloc=netloc), encoded=True)
return self._from_val(val._replace(netloc=netloc))

def with_password(self, password: Union[str, None]) -> "URL":
"""Return a new URL with password replaced.
Expand All @@ -1185,7 +1183,7 @@ def with_password(self, password: Union[str, None]) -> "URL":
val = self._val
encoded_host = self._encode_host(val.hostname) if val.hostname else ""
netloc = self._make_netloc(val.username, password, encoded_host, val.port)
return URL(val._replace(netloc=netloc), encoded=True)
return self._from_val(val._replace(netloc=netloc))

def with_host(self, host: str) -> "URL":
"""Return a new URL with host replaced.
Expand All @@ -1206,7 +1204,7 @@ def with_host(self, host: str) -> "URL":
val = self._val
encoded_host = self._encode_host(host) if host else ""
netloc = self._make_netloc(val.username, val.password, encoded_host, val.port)
return URL(self._val._replace(netloc=netloc), encoded=True)
return self._from_val(self._val._replace(netloc=netloc))

def with_port(self, port: Union[int, None]) -> "URL":
"""Return a new URL with port replaced.
Expand All @@ -1225,7 +1223,7 @@ def with_port(self, port: Union[int, None]) -> "URL":
val = self._val
encoded_host = self._encode_host(val.hostname) if val.hostname else ""
netloc = self._make_netloc(val.username, val.password, encoded_host, port)
return URL(val._replace(netloc=netloc), encoded=True)
return self._from_val(val._replace(netloc=netloc))

def with_path(self, path: str, *, encoded: bool = False) -> "URL":
"""Return a new URL with path replaced."""
Expand All @@ -1235,7 +1233,7 @@ def with_path(self, path: str, *, encoded: bool = False) -> "URL":
path = self._normalize_path(path) if "." in path else path
if len(path) > 0 and path[0] != "/":
path = "/" + path
return URL(self._val._replace(path=path, query="", fragment=""), encoded=True)
return self._from_val(self._val._replace(path=path, query="", fragment=""))

def _get_str_query_from_sequence_iterable(
self,
Expand Down Expand Up @@ -1350,7 +1348,7 @@ def with_query(self, *args: Any, **kwargs: Any) -> "URL":
# N.B. doesn't cleanup query/fragment

new_query = self._get_str_query(*args, **kwargs) or ""
return URL(self._val._replace(query=new_query), encoded=True)
return self._from_val(self._val._replace(query=new_query))

@overload
def extend_query(self, query: Query) -> "URL": ...
Expand Down Expand Up @@ -1380,7 +1378,7 @@ def extend_query(self, *args: Any, **kwargs: Any) -> "URL":
combined_query = f"{current_query}&{new_query_string}"
else:
combined_query = new_query_string
return URL(self._val._replace(query=combined_query), encoded=True)
return self._from_val(self._val._replace(query=combined_query))

@overload
def update_query(self, query: Query) -> "URL": ...
Expand All @@ -1400,12 +1398,12 @@ def update_query(self, *args: Any, **kwargs: Any) -> "URL":
"""
s = self._get_str_query(*args, **kwargs)
if s is None:
return URL(self._val._replace(query=""), encoded=True)
return self._from_val(self._val._replace(query=""))

query = MultiDict(self._parsed_query)
query.update(parse_qsl(s, keep_blank_values=True))
new_str = self._get_str_query_from_iterable(query.items())
return URL(self._val._replace(query=new_str), encoded=True)
return self._from_val(self._val._replace(query=new_str))

def without_query_params(self, *query_params: str) -> "URL":
"""Remove some keys from query part and return new URL."""
Expand Down Expand Up @@ -1437,7 +1435,7 @@ def with_fragment(self, fragment: Union[str, None]) -> "URL":
raw_fragment = self._FRAGMENT_QUOTER(fragment)
if self._val.fragment == raw_fragment:
return self
return URL(self._val._replace(fragment=raw_fragment), encoded=True)
return self._from_val(self._val._replace(fragment=raw_fragment))

def with_name(self, name: str) -> "URL":
"""Return a new URL with name (last part of path) replaced.
Expand Down Expand Up @@ -1466,9 +1464,8 @@ def with_name(self, name: str) -> "URL":
parts[-1] = name
if parts[0] == "/":
parts[0] = "" # replace leading '/'
return URL(
self._val._replace(path="/".join(parts), query="", fragment=""),
encoded=True,
return self._from_val(
self._val._replace(path="/".join(parts), query="", fragment="")
)

def with_suffix(self, suffix: str) -> "URL":
Expand Down Expand Up @@ -1512,7 +1509,7 @@ def join(self, url: "URL") -> "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 URL(other_val._replace(scheme=scheme), encoded=True)
return self._from_val(other_val._replace(scheme=scheme))

parts: _SplitResultDict = {"scheme": scheme}
if other_val.path or other_val.fragment:
Expand All @@ -1521,7 +1518,7 @@ def join(self, url: "URL") -> "URL":
parts["query"] = other_val.query

if not other_val.path:
return URL(val._replace(**parts), encoded=True)
return self._from_val(val._replace(**parts))

if other_val.path[0] == "/":
path = other_val.path
Expand All @@ -1540,7 +1537,7 @@ def join(self, url: "URL") -> "URL":
path = path[1:]

parts["path"] = self._normalize_path(path) if "." in path else path
return URL(val._replace(**parts), encoded=True)
return self._from_val(val._replace(**parts))

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 c02ba7f

Please sign in to comment.