From aa30b7945030c3fe38a2e819321ba14670158bb2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 17 Oct 2024 07:23:42 -1000 Subject: [PATCH 1/2] Small cleanups to making children paths This function was a bit hard to unpack so I have added some comments about what is going on. Since we reconstruct nearly everything, create a new tuple instead of replacing --- yarl/_url.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/yarl/_url.py b/yarl/_url.py index 59ebf6865..3e3ee750d 100644 --- a/yarl/_url.py +++ b/yarl/_url.py @@ -983,6 +983,10 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL": raise ValueError( f"Appending path {path!r} starting from slash is forbidden" ) + # We need to quote the path if it is not already encoded + # This cannot be done at the end because the existing + # path is already quoted and we do not want to double quote + # the existing path. path = path if encoded else self._PATH_QUOTER(path) needs_normalize |= "." in path segments = path.split("/") @@ -992,18 +996,26 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL": parsed += segments[segment_slice_start:] parsed.reverse() - if self._val.path and (old_path_segments := self._val.path.split("/")): + v = self._val + if v.path and (old_path_segments := v.path.split("/")): + # If the old path ends with a slash, the last segment is an empty string + # and should be removed before adding the new path segments. old_path_cutoff = -1 if old_path_segments[-1] == "" else None parsed = [*old_path_segments[:old_path_cutoff], *parsed] - if self._val.netloc: + if netloc := v.netloc: + # If the netloc is present, we need to ensure that the path is normalized parsed = _normalize_path_segments(parsed) if needs_normalize else parsed if parsed and parsed[0] != "": # inject a leading slash when adding a path to an absolute URL # where there was none before parsed = ["", *parsed] + new_path = "/".join(parsed) - return self._from_val(self._val._replace(path=new_path, query="", fragment="")) + + return self._from_val( + tuple.__new__(SplitResult, (v.scheme, netloc, new_path, "", "")) + ) @classmethod def _normalize_path(cls, path: str) -> str: From 26646122d2bb8c0ad48bc547465d514ffee32733 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 17 Oct 2024 10:01:59 -1000 Subject: [PATCH 2/2] changelog --- CHANGES/1304.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/1304.misc.rst diff --git a/CHANGES/1304.misc.rst b/CHANGES/1304.misc.rst new file mode 100644 index 000000000..135b1c940 --- /dev/null +++ b/CHANGES/1304.misc.rst @@ -0,0 +1 @@ +Improved performance of :py:meth:`~yarl.URL.joinpath` -- by :user:`bdraco`.