Skip to content

Commit 1e969ab

Browse files
authored
Small speed up to normalizing the path (#1137)
1 parent 07c4e03 commit 1e969ab

File tree

4 files changed

+36
-1
lines changed

4 files changed

+36
-1
lines changed

CHANGES/1137.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved performance of normalizing paths -- by :user:`bdraco`.

tests/test_normalize_path.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
("/", "/"),
99
("//", "//"),
1010
("///", "///"),
11+
("path", "path"),
1112
# Single-dot
1213
("path/to", "path/to"),
1314
("././path/to", "path/to"),
1415
("path/./to", "path/to"),
1516
("path/././to", "path/to"),
1617
("path/to/.", "path/to/"),
1718
("path/to/./.", "path/to/"),
19+
("/path/to/.", "/path/to/"),
1820
# Double-dots
1921
("../path/to", "path/to"),
2022
("path/../to", "to"),

tests/test_url.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,35 @@ def test_joinpath_path_starting_from_slash_is_forbidden():
993993
assert url.joinpath("/to/others")
994994

995995

996+
PATHS = [
997+
# No dots
998+
("", ""),
999+
("path", "path"),
1000+
# Single-dot
1001+
("path/to", "path/to"),
1002+
("././path/to", "path/to"),
1003+
("path/./to", "path/to"),
1004+
("path/././to", "path/to"),
1005+
("path/to/.", "path/to/"),
1006+
("path/to/./.", "path/to/"),
1007+
# Double-dots
1008+
("../path/to", "path/to"),
1009+
("path/../to", "to"),
1010+
("path/../../to", "to"),
1011+
# Non-ASCII characters
1012+
("μονοπάτι/../../να/ᴜɴɪ/ᴄᴏᴅᴇ", "να/ᴜɴɪ/ᴄᴏᴅᴇ"),
1013+
("μονοπάτι/../../να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/.", "να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/"),
1014+
]
1015+
1016+
1017+
@pytest.mark.parametrize("original,expected", PATHS)
1018+
def test_join_path_normalized(original: str, expected: str) -> None:
1019+
"""Test that joinpath normalizes paths."""
1020+
base_url = URL("http://example.com")
1021+
new_url = base_url.joinpath(original)
1022+
assert new_url.path == f"/{expected}"
1023+
1024+
9961025
# with_path
9971026

9981027

yarl/_url.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,9 +899,12 @@ def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL":
899899
@classmethod
900900
def _normalize_path(cls, path: str) -> str:
901901
# Drop '.' and '..' from str path
902+
if "." not in path:
903+
# No need to normalize if there are no '.' or '..' segments
904+
return path
902905

903906
prefix = ""
904-
if path.startswith("/"):
907+
if path and path[0] == "/":
905908
# preserve the "/" root element of absolute paths, copying it to the
906909
# normalised output as per sections 5.2.4 and 6.2.2.3 of rfc3986.
907910
prefix = "/"

0 commit comments

Comments
 (0)