Skip to content

Commit

Permalink
Improve performance of path functions on cache miss (#1443)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Dec 1, 2024
1 parent 7585a96 commit 558e4b0
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGES/1443.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved performances of multiple path method on cache miss -- by :user:`bdraco`.
23 changes: 23 additions & 0 deletions tests/test_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,17 @@ def test_path_safe_with_25():
assert unquoted == "/foo/bar%2Fbaz"


def test_path_safe_with_no_netloc():
"""Path safe should not decode %2F, otherwise it may look like a path separator."""

url = URL("/foo/bar%2fbaz")
assert url.path_safe == "/foo/bar%2Fbaz"
url = URL("")
assert url.path_safe == ""
url = URL("http://example.com")
assert url.path_safe == "/"


@pytest.mark.parametrize(
"original_path",
[
Expand Down Expand Up @@ -513,6 +524,12 @@ def test_path_qs():
assert url.path_qs == "/?б=в&ю=к"
url = URL("http://example.com/path?б=в&ю=к")
assert url.path_qs == "/path?б=в&ю=к"
url = URL("/path?б=в&ю=к")
assert url.path_qs == "/path?б=в&ю=к"
url = URL("")
assert url.path_qs == ""
url = URL("http://example.com")
assert url.path_qs == "/"


def test_raw_path_qs():
Expand All @@ -524,6 +541,12 @@ def test_raw_path_qs():
assert url.raw_path_qs == "/path?%D0%B1=%D0%B2&%D1%8E=%D0%BA"
url = URL("http://example.com/шлях?a=1&b=2")
assert url.raw_path_qs == "/%D1%88%D0%BB%D1%8F%D1%85?a=1&b=2"
url = URL("/шлях?a=1&b=2")
assert url.raw_path_qs == "/%D1%88%D0%BB%D1%8F%D1%85?a=1&b=2"
url = URL("")
assert url.raw_path_qs == ""
url = URL("http://example.com")
assert url.raw_path_qs == "/"


def test_query_string_spaces():
Expand Down
19 changes: 11 additions & 8 deletions yarl/_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,14 +790,14 @@ def host_port_subcomponent(self) -> Union[str, None]:
"""
if (raw := self.raw_host) is None:
return None
port = self.explicit_port
if raw[-1] == ".":
# Remove all trailing dots from the netloc as while
# they are valid FQDNs in DNS, TLS validation fails.
# See https://github.com/aio-libs/aiohttp/issues/3636.
# To avoid string manipulation we only call rstrip if
# the last character is a dot.
raw = raw.rstrip(".")
port = self.explicit_port
if port is None or port == DEFAULT_PORTS.get(self._scheme):
return f"[{raw}]" if ":" in raw else raw
return f"[{raw}]:{port}" if ":" in raw else f"{raw}:{port}"
Expand Down Expand Up @@ -831,7 +831,7 @@ def raw_path(self) -> str:
/ for absolute URLs without path part.
"""
return "/" if not self._path and self._netloc else self._path
return self._path if self._path or not self._netloc else "/"

@cached_property
def path(self) -> str:
Expand All @@ -840,7 +840,7 @@ def path(self) -> str:
/ for absolute URLs without path part.
"""
return PATH_UNQUOTER(self.raw_path)
return PATH_UNQUOTER(self._path) if self._path else "/" if self._netloc else ""

@cached_property
def path_safe(self) -> str:
Expand All @@ -851,7 +851,9 @@ def path_safe(self) -> str:
/ (%2F) and % (%25) are not decoded
"""
return PATH_SAFE_UNQUOTER(self.raw_path)
if self._path:
return PATH_SAFE_UNQUOTER(self._path)
return "/" if self._netloc else ""

@cached_property
def _parsed_query(self) -> list[tuple[str, str]]:
Expand Down Expand Up @@ -884,7 +886,7 @@ def query_string(self) -> str:
Empty string if query is missing.
"""
return QS_UNQUOTER(self._query)
return QS_UNQUOTER(self._query) if self._query else ""

@cached_property
def path_qs(self) -> str:
Expand All @@ -894,8 +896,9 @@ def path_qs(self) -> str:
@cached_property
def raw_path_qs(self) -> str:
"""Encoded path of URL with query."""
query = self._query
return self.raw_path if not query else f"{self.raw_path}?{query}"
if q := self._query:
return f"{self._path}?{q}" if self._path or not self._netloc else f"/?{q}"
return self._path if self._path or not self._netloc else "/"

@cached_property
def raw_fragment(self) -> str:
Expand All @@ -913,7 +916,7 @@ def fragment(self) -> str:
Empty string if fragment is missing.
"""
return UNQUOTER(self._fragment)
return UNQUOTER(self._fragment) if self._fragment else ""

@cached_property
def raw_parts(self) -> tuple[str, ...]:
Expand Down

0 comments on commit 558e4b0

Please sign in to comment.