Skip to content

Commit e83e29d

Browse files
feat: use ArtifactCache in get_package_from_url (#7693)
Co-authored-by: Randy Döring <[email protected]>
1 parent 5edb992 commit e83e29d

File tree

16 files changed

+139
-44
lines changed

16 files changed

+139
-44
lines changed

src/poetry/console/commands/debug/resolve.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def handle(self) -> int:
113113

114114
if self.option("install"):
115115
env = EnvManager(self.poetry).get()
116-
pool = RepositoryPool()
116+
pool = RepositoryPool(config=self.poetry.config)
117117
locked_repository = Repository("poetry-locked")
118118
for op in ops:
119119
locked_repository.add_package(op.package)

src/poetry/console/commands/init.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,15 @@ def _parse_requirements(self, requirements: list[str]) -> list[dict[str, Any]]:
434434

435435
try:
436436
cwd = self.poetry.file.parent
437+
artifact_cache = self.poetry.pool.artifact_cache
437438
except (PyProjectException, RuntimeError):
438439
cwd = Path.cwd()
440+
artifact_cache = self._get_pool().artifact_cache
439441

440442
parser = RequirementsParser(
441-
self.env if isinstance(self, EnvCommand) else None, cwd
443+
artifact_cache=artifact_cache,
444+
env=self.env if isinstance(self, EnvCommand) else None,
445+
cwd=cwd,
442446
)
443447
return [parser.parse(requirement) for requirement in requirements]
444448

src/poetry/console/commands/show.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def _display_packages_information(
213213
from poetry.utils.helpers import get_package_version_display_string
214214

215215
locked_packages = locked_repository.packages
216-
pool = RepositoryPool(ignore_repository_names=True)
216+
pool = RepositoryPool(ignore_repository_names=True, config=self.poetry.config)
217217
pool.add_repository(locked_repository)
218218
solver = Solver(
219219
root,

src/poetry/factory.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def get_package(cls, name: str, version: str) -> ProjectPackage:
119119
@classmethod
120120
def create_pool(
121121
cls,
122-
auth_config: Config,
122+
config: Config,
123123
sources: Iterable[dict[str, Any]] = (),
124124
io: IO | None = None,
125125
disable_cache: bool = False,
@@ -133,12 +133,12 @@ def create_pool(
133133
if disable_cache:
134134
logger.debug("Disabling source caches")
135135

136-
pool = RepositoryPool()
136+
pool = RepositoryPool(config=config)
137137

138138
explicit_pypi = False
139139
for source in sources:
140140
repository = cls.create_package_source(
141-
source, auth_config, disable_cache=disable_cache
141+
source, config, disable_cache=disable_cache
142142
)
143143
priority = Priority[source.get("priority", Priority.PRIMARY.name).upper()]
144144
if "default" in source or "secondary" in source:
@@ -207,7 +207,7 @@ def create_pool(
207207

208208
@classmethod
209209
def create_package_source(
210-
cls, source: dict[str, str], auth_config: Config, disable_cache: bool = False
210+
cls, source: dict[str, str], config: Config, disable_cache: bool = False
211211
) -> HTTPRepository:
212212
from poetry.repositories.exceptions import InvalidSourceError
213213
from poetry.repositories.legacy_repository import LegacyRepository
@@ -239,7 +239,7 @@ def create_package_source(
239239
return repository_class(
240240
name,
241241
url,
242-
config=auth_config,
242+
config=config,
243243
disable_cache=disable_cache,
244244
)
245245

src/poetry/installation/installer.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(
4747
self._package = package
4848
self._locker = locker
4949
self._pool = pool
50+
self._config = config
5051

5152
self._dry_run = False
5253
self._requires_synchronization = False
@@ -290,7 +291,7 @@ def _do_install(self) -> int:
290291
)
291292

292293
# We resolve again by only using the lock file
293-
pool = RepositoryPool(ignore_repository_names=True)
294+
pool = RepositoryPool(ignore_repository_names=True, config=self._config)
294295

295296
# Making a new repo containing the packages
296297
# newly resolved and the ones from the current lock file

src/poetry/packages/direct_origin.py

+22-11
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import functools
44
import os
5-
import tempfile
65
import urllib.parse
76

87
from pathlib import Path
98
from typing import TYPE_CHECKING
109

10+
from poetry.core.packages.utils.link import Link
11+
1112
from poetry.inspection.info import PackageInfo
1213
from poetry.inspection.info import PackageInfoError
1314
from poetry.utils.helpers import download_file
@@ -18,6 +19,8 @@
1819
if TYPE_CHECKING:
1920
from poetry.core.packages.package import Package
2021

22+
from poetry.utils.cache import ArtifactCache
23+
2124

2225
@functools.lru_cache(maxsize=None)
2326
def _get_package_from_git(
@@ -53,6 +56,9 @@ def _get_package_from_git(
5356

5457

5558
class DirectOrigin:
59+
def __init__(self, artifact_cache: ArtifactCache) -> None:
60+
self._artifact_cache = artifact_cache
61+
5662
@classmethod
5763
def get_package_from_file(cls, file_path: Path) -> Package:
5864
try:
@@ -70,17 +76,22 @@ def get_package_from_file(cls, file_path: Path) -> Package:
7076
def get_package_from_directory(cls, directory: Path) -> Package:
7177
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)
7278

73-
@classmethod
74-
def get_package_from_url(cls, url: str) -> Package:
79+
def get_package_from_url(self, url: str) -> Package:
7580
file_name = os.path.basename(urllib.parse.urlparse(url).path)
76-
with tempfile.TemporaryDirectory() as temp_dir:
77-
dest = Path(temp_dir) / file_name
78-
download_file(url, dest)
79-
package = cls.get_package_from_file(dest)
80-
81-
package.files = [
82-
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
83-
]
81+
link = Link(url)
82+
artifact = self._artifact_cache.get_cached_archive_for_link(link, strict=True)
83+
84+
if not artifact:
85+
artifact = (
86+
self._artifact_cache.get_cache_directory_for_link(link) / file_name
87+
)
88+
artifact.parent.mkdir(parents=True, exist_ok=True)
89+
download_file(url, artifact)
90+
91+
package = self.get_package_from_file(artifact)
92+
package.files = [
93+
{"file": file_name, "hash": "sha256:" + get_file_hash(artifact)}
94+
]
8495

8596
package._source_type = "url"
8697
package._source_url = url

src/poetry/poetry.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(
4949

5050
self._locker = locker
5151
self._config = config
52-
self._pool = RepositoryPool()
52+
self._pool = RepositoryPool(config=config)
5353
self._plugin_manager: PluginManager | None = None
5454
self._disable_cache = disable_cache
5555

src/poetry/puzzle/provider.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def __init__(
107107
) -> None:
108108
self._package = package
109109
self._pool = pool
110+
self._direct_origin = DirectOrigin(self._pool.artifact_cache)
110111
self._io = io
111112
self._env: Env | None = None
112113
self._python_constraint = package.python_constraint
@@ -311,7 +312,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
311312
Basically, we clone the repository in a temporary directory
312313
and get the information we need by checking out the specified reference.
313314
"""
314-
package = DirectOrigin.get_package_from_vcs(
315+
package = self._direct_origin.get_package_from_vcs(
315316
dependency.vcs,
316317
dependency.source,
317318
branch=dependency.branch,
@@ -330,7 +331,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
330331

331332
def _search_for_file(self, dependency: FileDependency) -> Package:
332333
dependency.validate(raise_error=True)
333-
package = DirectOrigin.get_package_from_file(dependency.full_path)
334+
package = self._direct_origin.get_package_from_file(dependency.full_path)
334335

335336
self.validate_package_for_dependency(dependency=dependency, package=package)
336337

@@ -348,7 +349,7 @@ def _search_for_file(self, dependency: FileDependency) -> Package:
348349

349350
def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
350351
dependency.validate(raise_error=True)
351-
package = DirectOrigin.get_package_from_directory(dependency.full_path)
352+
package = self._direct_origin.get_package_from_directory(dependency.full_path)
352353

353354
self.validate_package_for_dependency(dependency=dependency, package=package)
354355

@@ -360,7 +361,7 @@ def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
360361
return package
361362

362363
def _search_for_url(self, dependency: URLDependency) -> Package:
363-
package = DirectOrigin.get_package_from_url(dependency.url)
364+
package = self._direct_origin.get_package_from_url(dependency.url)
364365

365366
self.validate_package_for_dependency(dependency=dependency, package=package)
366367

src/poetry/repositories/repository_pool.py

+12
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
from enum import IntEnum
99
from typing import TYPE_CHECKING
1010

11+
from poetry.config.config import Config
1112
from poetry.repositories.abstract_repository import AbstractRepository
1213
from poetry.repositories.exceptions import PackageNotFound
14+
from poetry.utils.cache import ArtifactCache
1315

1416

1517
if TYPE_CHECKING:
@@ -40,6 +42,8 @@ def __init__(
4042
self,
4143
repositories: list[Repository] | None = None,
4244
ignore_repository_names: bool = False,
45+
*,
46+
config: Config | None = None,
4347
) -> None:
4448
super().__init__("poetry-repository-pool")
4549
self._repositories: OrderedDict[str, PrioritizedRepository] = OrderedDict()
@@ -50,6 +54,10 @@ def __init__(
5054
for repository in repositories:
5155
self.add_repository(repository)
5256

57+
self._artifact_cache = ArtifactCache(
58+
cache_dir=(config or Config.create()).artifacts_cache_directory
59+
)
60+
5361
@property
5462
def repositories(self) -> list[Repository]:
5563
"""
@@ -77,6 +85,10 @@ def _sorted_repositories(self) -> list[PrioritizedRepository]:
7785
self._repositories.values(), key=lambda prio_repo: prio_repo.priority
7886
)
7987

88+
@property
89+
def artifact_cache(self) -> ArtifactCache:
90+
return self._artifact_cache
91+
8092
def has_default(self) -> bool:
8193
return self._contains_priority(Priority.DEFAULT)
8294

src/poetry/utils/dependency_specification.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
if TYPE_CHECKING:
2323
from poetry.core.packages.vcs_dependency import VCSDependency
2424

25+
from poetry.utils.cache import ArtifactCache
2526
from poetry.utils.env import Env
2627

2728

@@ -57,7 +58,14 @@ def dependency_to_specification(
5758

5859

5960
class RequirementsParser:
60-
def __init__(self, env: Env | None = None, cwd: Path | None = None) -> None:
61+
def __init__(
62+
self,
63+
*,
64+
artifact_cache: ArtifactCache,
65+
env: Env | None = None,
66+
cwd: Path | None = None,
67+
) -> None:
68+
self._direct_origin = DirectOrigin(artifact_cache)
6169
self._env = env
6270
self._cwd = cwd or Path.cwd()
6371

@@ -120,7 +128,7 @@ def _parse_git_url(self, requirement: str) -> DependencySpec | None:
120128
pair["subdirectory"] = parsed.subdirectory
121129

122130
source_root = self._env.path.joinpath("src") if self._env else None
123-
package = DirectOrigin.get_package_from_vcs(
131+
package = self._direct_origin.get_package_from_vcs(
124132
"git",
125133
url=url.url,
126134
rev=pair.get("rev"),
@@ -139,7 +147,7 @@ def _parse_url(self, requirement: str) -> DependencySpec | None:
139147
return self._parse_git_url(requirement)
140148

141149
if url_parsed.scheme in ["http", "https"]:
142-
package = DirectOrigin.get_package_from_url(requirement)
150+
package = self._direct_origin.get_package_from_url(requirement)
143151
assert package.source_url is not None
144152
return {"name": package.name, "url": package.source_url}
145153

@@ -158,9 +166,9 @@ def _parse_path(self, requirement: str) -> DependencySpec | None:
158166
path = self._cwd.joinpath(requirement)
159167

160168
if path.is_file():
161-
package = DirectOrigin.get_package_from_file(path.resolve())
169+
package = self._direct_origin.get_package_from_file(path.resolve())
162170
else:
163-
package = DirectOrigin.get_package_from_directory(path.resolve())
171+
package = self._direct_origin.get_package_from_directory(path.resolve())
164172

165173
return {
166174
"name": package.name,

tests/conftest.py

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from poetry.layouts import layout
2525
from poetry.repositories import Repository
2626
from poetry.repositories import RepositoryPool
27+
from poetry.utils.cache import ArtifactCache
2728
from poetry.utils.env import EnvManager
2829
from poetry.utils.env import SystemEnv
2930
from poetry.utils.env import VirtualEnv
@@ -222,6 +223,11 @@ def config(
222223
return c
223224

224225

226+
@pytest.fixture
227+
def artifact_cache(config: Config) -> ArtifactCache:
228+
return ArtifactCache(cache_dir=config.artifacts_cache_directory)
229+
230+
225231
@pytest.fixture()
226232
def config_dir(tmp_path: Path) -> Path:
227233
path = tmp_path / "config"

tests/installation/test_chef.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
from poetry.factory import Factory
1515
from poetry.installation.chef import Chef
1616
from poetry.repositories import RepositoryPool
17-
from poetry.utils.cache import ArtifactCache
1817
from poetry.utils.env import EnvManager
1918
from tests.repositories.test_pypi_repository import MockRepository
2019

2120

2221
if TYPE_CHECKING:
2322
from pytest_mock import MockerFixture
2423

24+
from poetry.utils.cache import ArtifactCache
2525
from tests.conftest import Config
2626
from tests.types import FixtureDirGetter
2727

@@ -40,11 +40,6 @@ def setup(mocker: MockerFixture, pool: RepositoryPool) -> None:
4040
mocker.patch.object(Factory, "create_pool", return_value=pool)
4141

4242

43-
@pytest.fixture
44-
def artifact_cache(config: Config) -> ArtifactCache:
45-
return ArtifactCache(cache_dir=config.artifacts_cache_directory)
46-
47-
4843
def test_prepare_sdist(
4944
config: Config,
5045
config_cache_dir: Path,

tests/installation/test_executor.py

-5
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ def pool() -> RepositoryPool:
135135
return pool
136136

137137

138-
@pytest.fixture
139-
def artifact_cache(config: Config) -> ArtifactCache:
140-
return ArtifactCache(cache_dir=config.artifacts_cache_directory)
141-
142-
143138
@pytest.fixture
144139
def mock_file_downloads(
145140
http: type[httpretty.httpretty], fixture_dir: FixtureDirGetter

0 commit comments

Comments
 (0)