Skip to content

Commit a013c5c

Browse files
radoeringneersighted
authored andcommitted
performance: cache pages of PyPI repository in the same way as for legacy repository to fix performance regression caused by replacing cachy
1 parent 82eb934 commit a013c5c

File tree

8 files changed

+47
-40
lines changed

8 files changed

+47
-40
lines changed

Diff for: src/poetry/repositories/http_repository.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@
3030

3131

3232
if TYPE_CHECKING:
33+
from packaging.utils import NormalizedName
34+
3335
from poetry.config.config import Config
3436
from poetry.inspection.info import PackageInfo
37+
from poetry.repositories.link_sources.base import LinkSource
3538
from poetry.utils.authenticator import RepositoryCertificateConfig
3639

3740

@@ -293,8 +296,8 @@ def _get_response(self, endpoint: str) -> requests.Response | None:
293296
)
294297
return response
295298

296-
def _get_page(self, endpoint: str) -> HTMLPage | None:
297-
response = self._get_response(endpoint)
299+
def _get_page(self, name: NormalizedName) -> LinkSource | None:
300+
response = self._get_response(f"/{name}/")
298301
if not response:
299302
return None
300303
return HTMLPage(response.url, response.text)

Diff for: src/poetry/repositories/legacy_repository.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def package(
7272
return package
7373

7474
def find_links_for_package(self, package: Package) -> list[Link]:
75-
page = self.get_page(f"/{package.name}/")
75+
page = self.get_page(package.name)
7676
if page is None:
7777
return []
7878

@@ -90,12 +90,9 @@ def _find_packages(
9090
if not constraint.is_any():
9191
key = f"{key}:{constraint!s}"
9292

93-
page = self.get_page(f"/{name}/")
93+
page = self.get_page(name)
9494
if page is None:
95-
self._log(
96-
f"No packages found for {name}",
97-
level="debug",
98-
)
95+
self._log(f"No packages found for {name}", level="debug")
9996
return []
10097

10198
versions = [
@@ -119,7 +116,7 @@ def _find_packages(
119116
def _get_release_info(
120117
self, name: NormalizedName, version: Version
121118
) -> dict[str, Any]:
122-
page = self.get_page(f"/{name}/")
119+
page = self.get_page(name)
123120
if page is None:
124121
raise PackageNotFound(f'No package named "{name}"')
125122

@@ -141,8 +138,8 @@ def _get_release_info(
141138
),
142139
)
143140

144-
def _get_page(self, endpoint: str) -> SimpleRepositoryPage | None:
145-
response = self._get_response(endpoint)
141+
def _get_page(self, name: NormalizedName) -> SimpleRepositoryPage | None:
142+
response = self._get_response(f"/{name}/")
146143
if not response:
147144
return None
148145
return SimpleRepositoryPage(response.url, response.text)

Diff for: src/poetry/repositories/pypi_repository.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,11 @@ def _find_packages(
111111
Find packages on the remote server.
112112
"""
113113
try:
114-
json_page = self.get_json_page(name)
114+
json_page = self.get_page(name)
115115
except PackageNotFound:
116-
self._log(
117-
f"No packages found for {name}",
118-
level="debug",
119-
)
116+
self._log(f"No packages found for {name}", level="debug")
120117
return []
118+
assert isinstance(json_page, SimpleJsonPage)
121119

122120
versions: list[tuple[Version, str | bool]]
123121

@@ -226,7 +224,7 @@ def _get_release_info(
226224

227225
return data.asdict()
228226

229-
def get_json_page(self, name: NormalizedName) -> SimpleJsonPage:
227+
def _get_page(self, name: NormalizedName) -> SimpleJsonPage:
230228
source = self._base_url + f"simple/{name}/"
231229
info = self.get_package_info(name)
232230
return SimpleJsonPage(source, info)

Diff for: src/poetry/repositories/single_page_repository.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING
4+
35
from poetry.repositories.legacy_repository import LegacyRepository
46
from poetry.repositories.link_sources.html import SimpleRepositoryPage
57

68

9+
if TYPE_CHECKING:
10+
from packaging.utils import NormalizedName
11+
12+
713
class SinglePageRepository(LegacyRepository):
8-
def _get_page(self, endpoint: str | None = None) -> SimpleRepositoryPage | None:
14+
def _get_page(self, name: NormalizedName) -> SimpleRepositoryPage | None:
915
"""
1016
Single page repositories only have one page irrespective of endpoint.
1117
"""

Diff for: tests/installation/test_chooser.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def callback(
9898
parts = uri.rsplit("/")
9999
name = parts[-2]
100100

101-
fixture = LEGACY_FIXTURES / (name + "_partial_yank" + ".html")
101+
fixture = LEGACY_FIXTURES / (name + "-partial-yank" + ".html")
102102

103103
with fixture.open(encoding="utf-8") as f:
104104
return [200, headers, f.read()]

Diff for: tests/repositories/test_legacy_repository.py

+18-20
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import httpretty
3131

3232
from _pytest.monkeypatch import MonkeyPatch
33+
from packaging.utils import NormalizedName
3334

3435
from poetry.config.config import Config
3536

@@ -45,16 +46,13 @@ class MockRepository(LegacyRepository):
4546
def __init__(self) -> None:
4647
super().__init__("legacy", url="http://legacy.foo.bar", disable_cache=True)
4748

48-
def _get_page(self, endpoint: str) -> SimpleRepositoryPage | None:
49-
parts = endpoint.split("/")
50-
name = parts[1]
51-
49+
def _get_page(self, name: NormalizedName) -> SimpleRepositoryPage | None:
5250
fixture = self.FIXTURES / (name + ".html")
5351
if not fixture.exists():
5452
return None
5553

5654
with fixture.open(encoding="utf-8") as f:
57-
return SimpleRepositoryPage(self._url + endpoint, f.read())
55+
return SimpleRepositoryPage(self._url + f"/{name}/", f.read())
5856

5957
def _download(self, url: str, dest: Path) -> None:
6058
filename = urlparse.urlparse(url).path.rsplit("/")[-1]
@@ -73,7 +71,7 @@ def test_packages_property_returns_empty_list() -> None:
7371
def test_page_relative_links_path_are_correct() -> None:
7472
repo = MockRepository()
7573

76-
page = repo.get_page("/relative")
74+
page = repo.get_page("relative")
7775
assert page is not None
7876

7977
for link in page.links:
@@ -84,7 +82,7 @@ def test_page_relative_links_path_are_correct() -> None:
8482
def test_page_absolute_links_path_are_correct() -> None:
8583
repo = MockRepository()
8684

87-
page = repo.get_page("/absolute")
85+
page = repo.get_page("absolute")
8886
assert page is not None
8987

9088
for link in page.links:
@@ -95,7 +93,7 @@ def test_page_absolute_links_path_are_correct() -> None:
9593
def test_page_clean_link() -> None:
9694
repo = MockRepository()
9795

98-
page = repo.get_page("/relative")
96+
page = repo.get_page("relative")
9997
assert page is not None
10098

10199
cleaned = page.clean_link('https://legacy.foo.bar/test /the"/cleaning\0')
@@ -105,7 +103,7 @@ def test_page_clean_link() -> None:
105103
def test_page_invalid_version_link() -> None:
106104
repo = MockRepository()
107105

108-
page = repo.get_page("/invalid-version")
106+
page = repo.get_page("invalid-version")
109107
assert page is not None
110108

111109
links = list(page.links)
@@ -123,7 +121,7 @@ def test_page_invalid_version_link() -> None:
123121

124122
def test_sdist_format_support() -> None:
125123
repo = MockRepository()
126-
page = repo.get_page("/relative")
124+
page = repo.get_page("relative")
127125
assert page is not None
128126
bz2_links = list(filter(lambda link: link.ext == ".tar.bz2", page.links))
129127
assert len(bz2_links) == 1
@@ -434,8 +432,8 @@ def test_package_yanked(
434432

435433
def test_package_partial_yank():
436434
class SpecialMockRepository(MockRepository):
437-
def _get_page(self, endpoint: str) -> SimpleRepositoryPage | None:
438-
return super()._get_page(f"/{endpoint.strip('/')}_partial_yank/")
435+
def _get_page(self, name: NormalizedName) -> SimpleRepositoryPage | None:
436+
return super()._get_page(canonicalize_name(f"{name}-partial-yank"))
439437

440438
repo = MockRepository()
441439
package = repo.package("futures", Version.parse("3.2.0"))
@@ -481,31 +479,31 @@ def __init__(
481479

482480

483481
def test_get_200_returns_page(http: type[httpretty.httpretty]) -> None:
484-
repo = MockHttpRepository({"/foo": 200}, http)
482+
repo = MockHttpRepository({"/foo/": 200}, http)
485483

486-
assert repo.get_page("/foo")
484+
assert repo.get_page("foo")
487485

488486

489487
@pytest.mark.parametrize("status_code", [401, 403, 404])
490488
def test_get_40x_and_returns_none(
491489
http: type[httpretty.httpretty], status_code: int
492490
) -> None:
493-
repo = MockHttpRepository({"/foo": status_code}, http)
491+
repo = MockHttpRepository({"/foo/": status_code}, http)
494492

495-
assert repo.get_page("/foo") is None
493+
assert repo.get_page("foo") is None
496494

497495

498496
def test_get_5xx_raises(http: type[httpretty.httpretty]) -> None:
499-
repo = MockHttpRepository({"/foo": 500}, http)
497+
repo = MockHttpRepository({"/foo/": 500}, http)
500498

501499
with pytest.raises(RepositoryError):
502-
repo.get_page("/foo")
500+
repo.get_page("foo")
503501

504502

505503
def test_get_redirected_response_url(
506504
http: type[httpretty.httpretty], monkeypatch: MonkeyPatch
507505
) -> None:
508-
repo = MockHttpRepository({"/foo": 200}, http)
506+
repo = MockHttpRepository({"/foo/": 200}, http)
509507
redirect_url = "http://legacy.redirect.bar"
510508

511509
def get_mock(
@@ -517,7 +515,7 @@ def get_mock(
517515
return response
518516

519517
monkeypatch.setattr(repo.session, "get", get_mock)
520-
page = repo.get_page("/foo")
518+
page = repo.get_page("foo")
521519
assert page is not None
522520
assert page._url == "http://legacy.redirect.bar/foo/"
523521

Diff for: tests/repositories/test_single_page_repository.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
import re
44

55
from pathlib import Path
6+
from typing import TYPE_CHECKING
67

78
from poetry.core.packages.dependency import Dependency
89

910
from poetry.repositories.link_sources.html import SimpleRepositoryPage
1011
from poetry.repositories.single_page_repository import SinglePageRepository
1112

1213

14+
if TYPE_CHECKING:
15+
from packaging.utils import NormalizedName
16+
17+
1318
class MockSinglePageRepository(SinglePageRepository):
1419
FIXTURES = Path(__file__).parent / "fixtures" / "single-page"
1520

@@ -20,7 +25,7 @@ def __init__(self, page: str) -> None:
2025
disable_cache=True,
2126
)
2227

23-
def _get_page(self, endpoint: str = None) -> SimpleRepositoryPage | None:
28+
def _get_page(self, name: NormalizedName) -> SimpleRepositoryPage | None:
2429
fixture = self.FIXTURES / self.url.rsplit("/", 1)[-1]
2530
if not fixture.exists():
2631
return

0 commit comments

Comments
 (0)