Commit 9d03170f by Riccardo Albertazzi Committed by GitHub

perf: use cached file for wheel inspection (#7916)

parent 8f571352
...@@ -2,14 +2,13 @@ from __future__ import annotations ...@@ -2,14 +2,13 @@ from __future__ import annotations
import functools import functools
import hashlib import hashlib
import os
import urllib
import urllib.parse
from collections import defaultdict from collections import defaultdict
from contextlib import contextmanager
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Iterator
import requests import requests
...@@ -75,34 +74,28 @@ class HTTPRepository(CachedRepository): ...@@ -75,34 +74,28 @@ class HTTPRepository(CachedRepository):
def _download(self, url: str, dest: Path) -> None: def _download(self, url: str, dest: Path) -> None:
return download_file(url, dest, session=self.session) return download_file(url, dest, session=self.session)
@contextmanager
def _cached_or_downloaded_file(self, link: Link) -> Iterator[Path]:
filepath = self._authenticator.get_cached_file_for_url(link.url)
if filepath:
yield filepath
else:
self._log(f"Downloading: {link.url}", level="debug")
with temporary_directory() as temp_dir:
filepath = Path(temp_dir) / link.filename
self._download(link.url, filepath)
yield filepath
def _get_info_from_wheel(self, url: str) -> PackageInfo: def _get_info_from_wheel(self, url: str) -> PackageInfo:
from poetry.inspection.info import PackageInfo from poetry.inspection.info import PackageInfo
wheel_name = urllib.parse.urlparse(url).path.rsplit("/")[-1] with self._cached_or_downloaded_file(Link(url)) as filepath:
self._log(f"Downloading wheel: {wheel_name}", level="debug")
filename = os.path.basename(wheel_name)
with temporary_directory() as temp_dir:
filepath = Path(temp_dir) / filename
self._download(url, filepath)
return PackageInfo.from_wheel(filepath) return PackageInfo.from_wheel(filepath)
def _get_info_from_sdist(self, url: str) -> PackageInfo: def _get_info_from_sdist(self, url: str) -> PackageInfo:
from poetry.inspection.info import PackageInfo from poetry.inspection.info import PackageInfo
sdist_name = urllib.parse.urlparse(url).path with self._cached_or_downloaded_file(Link(url)) as filepath:
sdist_name_log = sdist_name.rsplit("/")[-1]
self._log(f"Downloading sdist: {sdist_name_log}", level="debug")
filename = os.path.basename(sdist_name)
with temporary_directory() as temp_dir:
filepath = Path(temp_dir) / filename
self._download(url, filepath)
return PackageInfo.from_sdist(filepath) return PackageInfo.from_sdist(filepath)
def _get_info_from_urls(self, urls: dict[str, list[str]]) -> PackageInfo: def _get_info_from_urls(self, urls: dict[str, list[str]]) -> PackageInfo:
...@@ -237,10 +230,7 @@ class HTTPRepository(CachedRepository): ...@@ -237,10 +230,7 @@ class HTTPRepository(CachedRepository):
and link.hash_name not in ("sha256", "sha384", "sha512") and link.hash_name not in ("sha256", "sha384", "sha512")
and hasattr(hashlib, link.hash_name) and hasattr(hashlib, link.hash_name)
): ):
with temporary_directory() as temp_dir: with self._cached_or_downloaded_file(link) as filepath:
filepath = Path(temp_dir) / link.filename
self._download(link.url, filepath)
known_hash = ( known_hash = (
getattr(hashlib, link.hash_name)() if link.hash_name else None getattr(hashlib, link.hash_name)() if link.hash_name else None
) )
......
...@@ -19,6 +19,7 @@ import requests.exceptions ...@@ -19,6 +19,7 @@ import requests.exceptions
from cachecontrol import CacheControlAdapter from cachecontrol import CacheControlAdapter
from cachecontrol.caches import FileCache from cachecontrol.caches import FileCache
from cachecontrol.caches.file_cache import url_to_file_path
from filelock import FileLock from filelock import FileLock
from poetry.config.config import Config from poetry.config.config import Config
...@@ -463,6 +464,13 @@ class Authenticator: ...@@ -463,6 +464,13 @@ class Authenticator:
return selected.certs(config=self._config) return selected.certs(config=self._config)
return RepositoryCertificateConfig() return RepositoryCertificateConfig()
def get_cached_file_for_url(self, url: str) -> Path | None:
if self._cache_control is None:
return None
path = Path(url_to_file_path(url, self._cache_control))
return path if path.exists() else None
_authenticator: Authenticator | None = None _authenticator: Authenticator | None = None
......
...@@ -627,6 +627,22 @@ def test_authenticator_git_repositories( ...@@ -627,6 +627,22 @@ def test_authenticator_git_repositories(
assert not three.password assert not three.password
def test_authenticator_get_cached_file_for_url__cache_miss(config: Config) -> None:
authenticator = Authenticator(config, NullIO())
assert (
authenticator.get_cached_file_for_url("https://foo.bar/cache/miss.whl") is None
)
def test_authenticator_get_cached_file_for_url__cache_hit(config: Config) -> None:
authenticator = Authenticator(config, NullIO())
url = "https://foo.bar/files/foo-0.1.0.tar.gz"
authenticator._cache_control.set(url, b"hello")
assert authenticator.get_cached_file_for_url(url)
@pytest.mark.parametrize( @pytest.mark.parametrize(
("ca_cert", "client_cert", "result"), ("ca_cert", "client_cert", "result"),
[ [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment