Skip to content

Commit

Permalink
feat: use ArtifactCache in get_package_from_url (#7693)
Browse files Browse the repository at this point in the history
Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com>
  • Loading branch information
ralbertazzi and radoering committed May 5, 2023
1 parent 5edb992 commit e83e29d
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/poetry/console/commands/debug/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def handle(self) -> int:

if self.option("install"):
env = EnvManager(self.poetry).get()
pool = RepositoryPool()
pool = RepositoryPool(config=self.poetry.config)
locked_repository = Repository("poetry-locked")
for op in ops:
locked_repository.add_package(op.package)
Expand Down
6 changes: 5 additions & 1 deletion src/poetry/console/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,11 +434,15 @@ def _parse_requirements(self, requirements: list[str]) -> list[dict[str, Any]]:

try:
cwd = self.poetry.file.parent
artifact_cache = self.poetry.pool.artifact_cache
except (PyProjectException, RuntimeError):
cwd = Path.cwd()
artifact_cache = self._get_pool().artifact_cache

parser = RequirementsParser(
self.env if isinstance(self, EnvCommand) else None, cwd
artifact_cache=artifact_cache,
env=self.env if isinstance(self, EnvCommand) else None,
cwd=cwd,
)
return [parser.parse(requirement) for requirement in requirements]

Expand Down
2 changes: 1 addition & 1 deletion src/poetry/console/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def _display_packages_information(
from poetry.utils.helpers import get_package_version_display_string

locked_packages = locked_repository.packages
pool = RepositoryPool(ignore_repository_names=True)
pool = RepositoryPool(ignore_repository_names=True, config=self.poetry.config)
pool.add_repository(locked_repository)
solver = Solver(
root,
Expand Down
10 changes: 5 additions & 5 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def get_package(cls, name: str, version: str) -> ProjectPackage:
@classmethod
def create_pool(
cls,
auth_config: Config,
config: Config,
sources: Iterable[dict[str, Any]] = (),
io: IO | None = None,
disable_cache: bool = False,
Expand All @@ -133,12 +133,12 @@ def create_pool(
if disable_cache:
logger.debug("Disabling source caches")

pool = RepositoryPool()
pool = RepositoryPool(config=config)

explicit_pypi = False
for source in sources:
repository = cls.create_package_source(
source, auth_config, disable_cache=disable_cache
source, config, disable_cache=disable_cache
)
priority = Priority[source.get("priority", Priority.PRIMARY.name).upper()]
if "default" in source or "secondary" in source:
Expand Down Expand Up @@ -207,7 +207,7 @@ def create_pool(

@classmethod
def create_package_source(
cls, source: dict[str, str], auth_config: Config, disable_cache: bool = False
cls, source: dict[str, str], config: Config, disable_cache: bool = False
) -> HTTPRepository:
from poetry.repositories.exceptions import InvalidSourceError
from poetry.repositories.legacy_repository import LegacyRepository
Expand Down Expand Up @@ -239,7 +239,7 @@ def create_package_source(
return repository_class(
name,
url,
config=auth_config,
config=config,
disable_cache=disable_cache,
)

Expand Down
3 changes: 2 additions & 1 deletion src/poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
self._package = package
self._locker = locker
self._pool = pool
self._config = config

self._dry_run = False
self._requires_synchronization = False
Expand Down Expand Up @@ -290,7 +291,7 @@ def _do_install(self) -> int:
)

# We resolve again by only using the lock file
pool = RepositoryPool(ignore_repository_names=True)
pool = RepositoryPool(ignore_repository_names=True, config=self._config)

# Making a new repo containing the packages
# newly resolved and the ones from the current lock file
Expand Down
33 changes: 22 additions & 11 deletions src/poetry/packages/direct_origin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import functools
import os
import tempfile
import urllib.parse

from pathlib import Path
from typing import TYPE_CHECKING

from poetry.core.packages.utils.link import Link

from poetry.inspection.info import PackageInfo
from poetry.inspection.info import PackageInfoError
from poetry.utils.helpers import download_file
Expand All @@ -18,6 +19,8 @@
if TYPE_CHECKING:
from poetry.core.packages.package import Package

from poetry.utils.cache import ArtifactCache


@functools.lru_cache(maxsize=None)
def _get_package_from_git(
Expand Down Expand Up @@ -53,6 +56,9 @@ def _get_package_from_git(


class DirectOrigin:
def __init__(self, artifact_cache: ArtifactCache) -> None:
self._artifact_cache = artifact_cache

@classmethod
def get_package_from_file(cls, file_path: Path) -> Package:
try:
Expand All @@ -70,17 +76,22 @@ def get_package_from_file(cls, file_path: Path) -> Package:
def get_package_from_directory(cls, directory: Path) -> Package:
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)

@classmethod
def get_package_from_url(cls, url: str) -> Package:
def get_package_from_url(self, url: str) -> Package:
file_name = os.path.basename(urllib.parse.urlparse(url).path)
with tempfile.TemporaryDirectory() as temp_dir:
dest = Path(temp_dir) / file_name
download_file(url, dest)
package = cls.get_package_from_file(dest)

package.files = [
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
]
link = Link(url)
artifact = self._artifact_cache.get_cached_archive_for_link(link, strict=True)

if not artifact:
artifact = (
self._artifact_cache.get_cache_directory_for_link(link) / file_name
)
artifact.parent.mkdir(parents=True, exist_ok=True)
download_file(url, artifact)

package = self.get_package_from_file(artifact)
package.files = [
{"file": file_name, "hash": "sha256:" + get_file_hash(artifact)}
]

package._source_type = "url"
package._source_url = url
Expand Down
2 changes: 1 addition & 1 deletion src/poetry/poetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(

self._locker = locker
self._config = config
self._pool = RepositoryPool()
self._pool = RepositoryPool(config=config)
self._plugin_manager: PluginManager | None = None
self._disable_cache = disable_cache

Expand Down
9 changes: 5 additions & 4 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__(
) -> None:
self._package = package
self._pool = pool
self._direct_origin = DirectOrigin(self._pool.artifact_cache)
self._io = io
self._env: Env | None = None
self._python_constraint = package.python_constraint
Expand Down Expand Up @@ -311,7 +312,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
Basically, we clone the repository in a temporary directory
and get the information we need by checking out the specified reference.
"""
package = DirectOrigin.get_package_from_vcs(
package = self._direct_origin.get_package_from_vcs(
dependency.vcs,
dependency.source,
branch=dependency.branch,
Expand All @@ -330,7 +331,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:

def _search_for_file(self, dependency: FileDependency) -> Package:
dependency.validate(raise_error=True)
package = DirectOrigin.get_package_from_file(dependency.full_path)
package = self._direct_origin.get_package_from_file(dependency.full_path)

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

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

def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
dependency.validate(raise_error=True)
package = DirectOrigin.get_package_from_directory(dependency.full_path)
package = self._direct_origin.get_package_from_directory(dependency.full_path)

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

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

def _search_for_url(self, dependency: URLDependency) -> Package:
package = DirectOrigin.get_package_from_url(dependency.url)
package = self._direct_origin.get_package_from_url(dependency.url)

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

Expand Down
12 changes: 12 additions & 0 deletions src/poetry/repositories/repository_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from enum import IntEnum
from typing import TYPE_CHECKING

from poetry.config.config import Config
from poetry.repositories.abstract_repository import AbstractRepository
from poetry.repositories.exceptions import PackageNotFound
from poetry.utils.cache import ArtifactCache


if TYPE_CHECKING:
Expand Down Expand Up @@ -40,6 +42,8 @@ def __init__(
self,
repositories: list[Repository] | None = None,
ignore_repository_names: bool = False,
*,
config: Config | None = None,
) -> None:
super().__init__("poetry-repository-pool")
self._repositories: OrderedDict[str, PrioritizedRepository] = OrderedDict()
Expand All @@ -50,6 +54,10 @@ def __init__(
for repository in repositories:
self.add_repository(repository)

self._artifact_cache = ArtifactCache(
cache_dir=(config or Config.create()).artifacts_cache_directory
)

@property
def repositories(self) -> list[Repository]:
"""
Expand Down Expand Up @@ -77,6 +85,10 @@ def _sorted_repositories(self) -> list[PrioritizedRepository]:
self._repositories.values(), key=lambda prio_repo: prio_repo.priority
)

@property
def artifact_cache(self) -> ArtifactCache:
return self._artifact_cache

def has_default(self) -> bool:
return self._contains_priority(Priority.DEFAULT)

Expand Down
18 changes: 13 additions & 5 deletions src/poetry/utils/dependency_specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
if TYPE_CHECKING:
from poetry.core.packages.vcs_dependency import VCSDependency

from poetry.utils.cache import ArtifactCache
from poetry.utils.env import Env


Expand Down Expand Up @@ -57,7 +58,14 @@ def dependency_to_specification(


class RequirementsParser:
def __init__(self, env: Env | None = None, cwd: Path | None = None) -> None:
def __init__(
self,
*,
artifact_cache: ArtifactCache,
env: Env | None = None,
cwd: Path | None = None,
) -> None:
self._direct_origin = DirectOrigin(artifact_cache)
self._env = env
self._cwd = cwd or Path.cwd()

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

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

if url_parsed.scheme in ["http", "https"]:
package = DirectOrigin.get_package_from_url(requirement)
package = self._direct_origin.get_package_from_url(requirement)
assert package.source_url is not None
return {"name": package.name, "url": package.source_url}

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

if path.is_file():
package = DirectOrigin.get_package_from_file(path.resolve())
package = self._direct_origin.get_package_from_file(path.resolve())
else:
package = DirectOrigin.get_package_from_directory(path.resolve())
package = self._direct_origin.get_package_from_directory(path.resolve())

return {
"name": package.name,
Expand Down
6 changes: 6 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from poetry.layouts import layout
from poetry.repositories import Repository
from poetry.repositories import RepositoryPool
from poetry.utils.cache import ArtifactCache
from poetry.utils.env import EnvManager
from poetry.utils.env import SystemEnv
from poetry.utils.env import VirtualEnv
Expand Down Expand Up @@ -222,6 +223,11 @@ def config(
return c


@pytest.fixture
def artifact_cache(config: Config) -> ArtifactCache:
return ArtifactCache(cache_dir=config.artifacts_cache_directory)


@pytest.fixture()
def config_dir(tmp_path: Path) -> Path:
path = tmp_path / "config"
Expand Down
7 changes: 1 addition & 6 deletions tests/installation/test_chef.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
from poetry.factory import Factory
from poetry.installation.chef import Chef
from poetry.repositories import RepositoryPool
from poetry.utils.cache import ArtifactCache
from poetry.utils.env import EnvManager
from tests.repositories.test_pypi_repository import MockRepository


if TYPE_CHECKING:
from pytest_mock import MockerFixture

from poetry.utils.cache import ArtifactCache
from tests.conftest import Config
from tests.types import FixtureDirGetter

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


@pytest.fixture
def artifact_cache(config: Config) -> ArtifactCache:
return ArtifactCache(cache_dir=config.artifacts_cache_directory)


def test_prepare_sdist(
config: Config,
config_cache_dir: Path,
Expand Down
5 changes: 0 additions & 5 deletions tests/installation/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,6 @@ def pool() -> RepositoryPool:
return pool


@pytest.fixture
def artifact_cache(config: Config) -> ArtifactCache:
return ArtifactCache(cache_dir=config.artifacts_cache_directory)


@pytest.fixture
def mock_file_downloads(
http: type[httpretty.httpretty], fixture_dir: FixtureDirGetter
Expand Down
Loading

0 comments on commit e83e29d

Please sign in to comment.