diff --git a/.flake8 b/.flake8 index 2d16cf2abc3..2780c9c145e 100644 --- a/.flake8 +++ b/.flake8 @@ -6,7 +6,7 @@ ban-relative-imports = true format-greedy = 1 inline-quotes = double enable-extensions = TC, TC1 -type-checking-exempt-modules = typing, typing-extensions +type-checking-strict = true eradicate-whitelist-extend = ^-.*; extend-ignore = # E203: Whitespace before ':' (pycqa/pycodestyle#373) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c4e363a2d8f..34d488fee6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: os: [Ubuntu, macOS, Windows] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] include: - os: Ubuntu image: ubuntu-22.04 @@ -83,11 +83,6 @@ jobs: # Using `timeout` is a safeguard against the Poetry command hanging for some reason. timeout 10s poetry run pip --version || rm -rf .venv - # XXX: https://github.com/pypa/pip/issues/11352 causes random failures -- remove once fixed in a release. - - name: Upgrade pip on Python 3.11 - if: ${{ matrix.python-version == '3.11-dev' }} - run: poetry run pip install git+https://github.com/pypa/pip.git@f8a25921e5c443b07483017b0ffdeb08b9ba2fdf - - name: Install dependencies run: poetry install --with github-actions diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 27563811d61..17577f47aca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,7 @@ repos: - flake8-quotes==3.3.1 - flake8-simplify==0.19.3 - flake8-tidy-imports==4.8.0 - - flake8-type-checking==2.1.2 + - flake8-type-checking==2.2.0 - flake8-typing-imports==1.12.0 - flake8-use-fstring==1.4 - pep8-naming==0.13.1 diff --git a/LICENSE b/LICENSE index 44cf2b30e68..81a8e1e4739 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 Sébastien Eustace +Copyright (c) 2018-present Sébastien Eustace Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/docs/dependency-specification.md b/docs/dependency-specification.md index b841d68bc10..3e7f55f755f 100644 --- a/docs/dependency-specification.md +++ b/docs/dependency-specification.md @@ -247,7 +247,7 @@ for extras in your project refer to [`extras`]({{< relref "pyproject#extras" >}} ## `source` dependencies -To depend on a package from an [alternate repository]({{< relref "repositories/#install-dependencies-from-a-private-repository" >}}), +To depend on a package from an [alternate repository]({{< relref "repositories#installing-from-private-package-sources" >}}), you can use the `source` property: ```toml @@ -267,7 +267,7 @@ poetry add my-cool-package --source foo ``` {{% note %}} -In this example, we expect `foo` to be configured correctly. See [using a private repository](repositories.md#using-a-private-repository) +In this example, we expect `foo` to be configured correctly. See [using a private repository]({{< relref "repositories#installing-from-private-package-sources" >}}) for further information. {{% /note %}} diff --git a/pyproject.toml b/pyproject.toml index ecf47ae886d..bf72dca129e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ pexpect = "^4.7.0" pkginfo = "^1.5" platformdirs = "^2.5.2" requests = "^2.18" -requests-toolbelt = "^0.9.1" +requests-toolbelt = ">=0.9.1,<0.11.0" shellingham = "^1.5" # exclude 0.11.2 and 0.11.3 due to https://github.com/sdispater/tomlkit/issues/225 tomlkit = ">=0.11.1,<1.0.0,!=0.11.2,!=0.11.3" diff --git a/src/poetry/console/commands/debug/resolve.py b/src/poetry/console/commands/debug/resolve.py index 61b87352cc0..cd8bd3ed466 100644 --- a/src/poetry/console/commands/debug/resolve.py +++ b/src/poetry/console/commands/debug/resolve.py @@ -36,8 +36,8 @@ def handle(self) -> int: from poetry.factory import Factory from poetry.puzzle.solver import Solver - from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository + from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import EnvManager packages = self.argument("package") @@ -107,7 +107,7 @@ def handle(self) -> int: if self.option("install"): env = EnvManager(self.poetry).get() - pool = Pool() + pool = RepositoryPool() locked_repository = Repository("poetry-locked") for op in ops: locked_repository.add_package(op.package) diff --git a/src/poetry/console/commands/init.py b/src/poetry/console/commands/init.py index e2ebf9cf9b7..af259f5c059 100644 --- a/src/poetry/console/commands/init.py +++ b/src/poetry/console/commands/init.py @@ -23,7 +23,7 @@ from poetry.core.packages.package import Package from tomlkit.items import InlineTable - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool Requirements = Dict[str, Union[str, Mapping[str, Any]]] @@ -66,7 +66,7 @@ class InitCommand(Command): def __init__(self) -> None: super().__init__() - self._pool: Pool | None = None + self._pool: RepositoryPool | None = None def handle(self) -> int: from pathlib import Path @@ -462,15 +462,15 @@ def _validate_package(package: str | None) -> str | None: return package - def _get_pool(self) -> Pool: - from poetry.repositories import Pool + def _get_pool(self) -> RepositoryPool: + from poetry.repositories import RepositoryPool from poetry.repositories.pypi_repository import PyPiRepository if isinstance(self, EnvCommand): return self.poetry.pool if self._pool is None: - self._pool = Pool() + self._pool = RepositoryPool() self._pool.add_repository(PyPiRepository()) return self._pool diff --git a/src/poetry/console/commands/show.py b/src/poetry/console/commands/show.py index 7b0c55b3e24..5f8e4f0db0f 100644 --- a/src/poetry/console/commands/show.py +++ b/src/poetry/console/commands/show.py @@ -194,11 +194,11 @@ def _display_packages_information( from poetry.puzzle.solver import Solver from poetry.repositories.installed_repository import InstalledRepository - from poetry.repositories.pool import Pool + from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.helpers import get_package_version_display_string locked_packages = locked_repository.packages - pool = Pool(ignore_repository_names=True) + pool = RepositoryPool(ignore_repository_names=True) pool.add_repository(locked_repository) solver = Solver( root, diff --git a/src/poetry/console/commands/source/add.py b/src/poetry/console/commands/source/add.py index 3011980c529..e5750d77472 100644 --- a/src/poetry/console/commands/source/add.py +++ b/src/poetry/console/commands/source/add.py @@ -34,7 +34,7 @@ class SourceAddCommand(Command): def handle(self) -> int: from poetry.factory import Factory - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool from poetry.utils.source import source_to_table name = self.argument("name") @@ -83,7 +83,7 @@ def handle(self) -> int: sources.append(source_to_table(new_source)) # ensure new source is valid. eg: invalid name etc. - self.poetry._pool = Pool() + self.poetry._pool = RepositoryPool() try: Factory.configure_sources( self.poetry, sources, self.poetry.config, NullIO() diff --git a/src/poetry/factory.py b/src/poetry/factory.py index 46856736354..c20f224272c 100644 --- a/src/poetry/factory.py +++ b/src/poetry/factory.py @@ -257,7 +257,8 @@ def create_pyproject_from_package( constraint["optional"] = True if len(constraint) == 1 and "version" in constraint: - constraint = cast(str, constraint["version"]) + assert isinstance(constraint["version"], str) + constraint = constraint["version"] elif not constraint: constraint = "*" diff --git a/src/poetry/installation/chooser.py b/src/poetry/installation/chooser.py index d5ee2c6d57f..a5432cdd386 100644 --- a/src/poetry/installation/chooser.py +++ b/src/poetry/installation/chooser.py @@ -18,7 +18,7 @@ from poetry.core.packages.package import Package from poetry.core.packages.utils.link import Link - from poetry.repositories.pool import Pool + from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import Env @@ -61,7 +61,9 @@ class Chooser: A Chooser chooses an appropriate release archive for packages. """ - def __init__(self, pool: Pool, env: Env, config: Config | None = None) -> None: + def __init__( + self, pool: RepositoryPool, env: Env, config: Config | None = None + ) -> None: self._pool = pool self._env = env self._config = config or Config.create() diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py index c97a4f249e5..0a01fee2b98 100644 --- a/src/poetry/installation/executor.py +++ b/src/poetry/installation/executor.py @@ -13,7 +13,6 @@ from subprocess import CalledProcessError from typing import TYPE_CHECKING from typing import Any -from typing import cast from cleo.io.null_io import NullIO from poetry.core.packages.file_dependency import FileDependency @@ -42,7 +41,7 @@ from poetry.config.config import Config from poetry.installation.operations.operation import Operation - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool from poetry.utils.env import Env @@ -50,7 +49,7 @@ class Executor: def __init__( self, env: Env, - pool: Pool, + pool: RepositoryPool, config: Config, io: IO, parallel: bool | None = None, @@ -772,7 +771,8 @@ def _save_url_reference(self, operation: Operation) -> None: for dist in self._env.site_packages.distributions( name=package.name, writable_only=True ): - dist_path = cast(Path, dist._path) # type: ignore[attr-defined] + dist_path = dist._path # type: ignore[attr-defined] + assert isinstance(dist_path, Path) url = dist_path / "direct_url.json" url.write_text(json.dumps(url_reference), encoding="utf-8") diff --git a/src/poetry/installation/installer.py b/src/poetry/installation/installer.py index 83082020d21..9b906f7678f 100644 --- a/src/poetry/installation/installer.py +++ b/src/poetry/installation/installer.py @@ -10,8 +10,8 @@ from poetry.installation.operations import Uninstall from poetry.installation.operations import Update from poetry.installation.pip_installer import PipInstaller -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool from poetry.repositories.installed_repository import InstalledRepository from poetry.repositories.lockfile_repository import LockfileRepository from poetry.utils.extras import get_extra_package_names @@ -39,7 +39,7 @@ def __init__( env: Env, package: ProjectPackage, locker: Locker, - pool: Pool, + pool: RepositoryPool, config: Config, installed: Repository | None = None, executor: Executor | None = None, @@ -201,10 +201,16 @@ def _do_refresh(self) -> int: self._io, ) + # Always re-solve directory dependencies, otherwise we can't determine + # if anything has changed (and the lock file contains an invalid version). + use_latest = [ + p.name for p in locked_repository.packages if p.source_type == "directory" + ] + with solver.provider.use_source_root( source_root=self._env.path.joinpath("src") ): - ops = solver.solve(use_latest=[]).calculate_operations() + ops = solver.solve(use_latest=use_latest).calculate_operations() lockfile_repo = LockfileRepository() self._populate_lockfile_repo(lockfile_repo, ops) @@ -294,7 +300,7 @@ def _do_install(self) -> int: ) # We resolve again by only using the lock file - pool = Pool(ignore_repository_names=True) + pool = RepositoryPool(ignore_repository_names=True) # Making a new repo containing the packages # newly resolved and the ones from the current lock file diff --git a/src/poetry/installation/pip_installer.py b/src/poetry/installation/pip_installer.py index 7ee24915f62..884dd1895df 100644 --- a/src/poetry/installation/pip_installer.py +++ b/src/poetry/installation/pip_installer.py @@ -14,7 +14,7 @@ from poetry.core.pyproject.toml import PyProjectTOML from poetry.installation.base_installer import BaseInstaller -from poetry.repositories.http import HTTPRepository +from poetry.repositories.http_repository import HTTPRepository from poetry.utils._compat import encode from poetry.utils.helpers import remove_directory from poetry.utils.pip import pip_install @@ -25,12 +25,12 @@ from poetry.core.masonry.builders.builder import Builder from poetry.core.packages.package import Package - from poetry.repositories.pool import Pool + from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import Env class PipInstaller(BaseInstaller): - def __init__(self, env: Env, io: IO, pool: Pool) -> None: + def __init__(self, env: Env, io: IO, pool: RepositoryPool) -> None: self._env = env self._io = io self._pool = pool diff --git a/src/poetry/mixology/failure.py b/src/poetry/mixology/failure.py index f4629aa56c7..448d39786bb 100644 --- a/src/poetry/mixology/failure.py +++ b/src/poetry/mixology/failure.py @@ -1,7 +1,6 @@ from __future__ import annotations from typing import TYPE_CHECKING -from typing import cast from poetry.core.constraints.version import parse_constraint @@ -114,7 +113,8 @@ def _visit( conjunction = "So," if conclusion or incompatibility == self._root else "And" incompatibility_string = str(incompatibility) - cause: ConflictCause = cast(ConflictCause, incompatibility.cause) + cause = incompatibility.cause + assert isinstance(cause, ConflictCause) if isinstance(cause.conflict.cause, ConflictCause) and isinstance( cause.other.cause, ConflictCause @@ -198,7 +198,8 @@ def _visit( numbered=numbered, ) elif self._is_collapsible(derived): - derived_cause: ConflictCause = cast(ConflictCause, derived.cause) + derived_cause = derived.cause + assert isinstance(derived_cause, ConflictCause) if isinstance(derived_cause.conflict.cause, ConflictCause): collapsed_derived = derived_cause.conflict collapsed_ext = derived_cause.other @@ -233,7 +234,8 @@ def _is_collapsible(self, incompatibility: Incompatibility) -> bool: if self._derivations[incompatibility] > 1: return False - cause: ConflictCause = cast(ConflictCause, incompatibility.cause) + cause = incompatibility.cause + assert isinstance(cause, ConflictCause) if isinstance(cause.conflict.cause, ConflictCause) and isinstance( cause.other.cause, ConflictCause ): diff --git a/src/poetry/poetry.py b/src/poetry/poetry.py index 42ceff2e47e..e9cb6e5db04 100644 --- a/src/poetry/poetry.py +++ b/src/poetry/poetry.py @@ -17,7 +17,7 @@ from poetry.config.config import Config from poetry.packages.locker import Locker from poetry.plugins.plugin_manager import PluginManager - from poetry.repositories.pool import Pool + from poetry.repositories.repository_pool import RepositoryPool class Poetry(BasePoetry): @@ -32,13 +32,13 @@ def __init__( config: Config, disable_cache: bool = False, ) -> None: - from poetry.repositories.pool import Pool + from poetry.repositories.repository_pool import RepositoryPool super().__init__(file, local_config, package) self._locker = locker self._config = config - self._pool = Pool() + self._pool = RepositoryPool() self._plugin_manager: PluginManager | None = None self._disable_cache = disable_cache @@ -47,7 +47,7 @@ def locker(self) -> Locker: return self._locker @property - def pool(self) -> Pool: + def pool(self) -> RepositoryPool: return self._pool @property @@ -63,7 +63,7 @@ def set_locker(self, locker: Locker) -> Poetry: return self - def set_pool(self, pool: Pool) -> Poetry: + def set_pool(self, pool: RepositoryPool) -> Poetry: self._pool = pool return self diff --git a/src/poetry/puzzle/provider.py b/src/poetry/puzzle/provider.py index 1e634995dd7..4d2e2d30b67 100644 --- a/src/poetry/puzzle/provider.py +++ b/src/poetry/puzzle/provider.py @@ -52,7 +52,7 @@ from poetry.core.packages.vcs_dependency import VCSDependency from poetry.core.version.markers import BaseMarker - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool from poetry.utils.env import Env @@ -124,7 +124,7 @@ class Provider: def __init__( self, package: Package, - pool: Pool, + pool: RepositoryPool, io: IO, *, installed: list[Package] | None = None, @@ -156,7 +156,7 @@ def __init__( ) @property - def pool(self) -> Pool: + def pool(self) -> RepositoryPool: return self._pool @property diff --git a/src/poetry/puzzle/solver.py b/src/poetry/puzzle/solver.py index 3a9f9b89d22..d38a2e0c277 100644 --- a/src/poetry/puzzle/solver.py +++ b/src/poetry/puzzle/solver.py @@ -31,7 +31,7 @@ from poetry.packages import DependencyPackage from poetry.puzzle.transaction import Transaction - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool from poetry.utils.env import Env @@ -39,7 +39,7 @@ class Solver: def __init__( self, package: ProjectPackage, - pool: Pool, + pool: RepositoryPool, installed: list[Package], locked: list[Package], io: IO, diff --git a/src/poetry/repositories/__init__.py b/src/poetry/repositories/__init__.py index ca887e51aa5..78c59562ab8 100644 --- a/src/poetry/repositories/__init__.py +++ b/src/poetry/repositories/__init__.py @@ -2,6 +2,7 @@ from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository +from poetry.repositories.repository_pool import RepositoryPool -__all__ = ["Pool", "Repository"] +__all__ = ["Pool", "Repository", "RepositoryPool"] diff --git a/src/poetry/repositories/cached.py b/src/poetry/repositories/cached.py index b593feb44a2..8a9443966de 100644 --- a/src/poetry/repositories/cached.py +++ b/src/poetry/repositories/cached.py @@ -1,78 +1,15 @@ from __future__ import annotations -from abc import ABC -from abc import abstractmethod -from typing import TYPE_CHECKING -from typing import Any +import warnings -from packaging.utils import canonicalize_name -from poetry.core.constraints.version import parse_constraint -from poetry.config.config import Config -from poetry.repositories.repository import Repository -from poetry.utils.cache import FileCache +from poetry.repositories.cached_repository import ( # isort: skip # nopycln: import # noqa: E501, F401 + CachedRepository, +) - -if TYPE_CHECKING: - from packaging.utils import NormalizedName - from poetry.core.constraints.version import Version - from poetry.core.packages.package import Package - - from poetry.inspection.info import PackageInfo - - -class CachedRepository(Repository, ABC): - CACHE_VERSION = parse_constraint("1.1.0") - - def __init__( - self, name: str, disable_cache: bool = False, config: Config | None = None - ) -> None: - super().__init__(name) - self._disable_cache = disable_cache - self._cache_dir = (config or Config.create()).repository_cache_directory / name - self._release_cache: FileCache[dict[str, Any]] = FileCache(path=self._cache_dir) - - @abstractmethod - def _get_release_info( - self, name: NormalizedName, version: Version - ) -> dict[str, Any]: - ... - - def get_release_info(self, name: NormalizedName, version: Version) -> PackageInfo: - """ - Return the release information given a package name and a version. - - The information is returned from the cache if it exists - or retrieved from the remote server. - """ - from poetry.inspection.info import PackageInfo - - if self._disable_cache: - return PackageInfo.load(self._get_release_info(name, version)) - - cached = self._release_cache.remember( - f"{name}:{version}", lambda: self._get_release_info(name, version) - ) - - cache_version = cached.get("_cache_version", "0.0.0") - if parse_constraint(cache_version) != self.CACHE_VERSION: - # The cache must be updated - self._log( - f"The cache for {name} {version} is outdated. Refreshing.", - level="debug", - ) - cached = self._get_release_info(name, version) - - self._release_cache.put(f"{name}:{version}", cached) - - return PackageInfo.load(cached) - - def package( - self, - name: str, - version: Version, - extras: list[str] | None = None, - ) -> Package: - return self.get_release_info(canonicalize_name(name), version).to_package( - name=name, extras=extras - ) +warnings.warn( + "Module poetry.repositories.cached is renamed and scheduled for removal in poetry" + " release 1.4.0. Please migrate to poetry.repositories.cached_repository.", + DeprecationWarning, + stacklevel=2, +) diff --git a/src/poetry/repositories/cached_repository.py b/src/poetry/repositories/cached_repository.py new file mode 100644 index 00000000000..b593feb44a2 --- /dev/null +++ b/src/poetry/repositories/cached_repository.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from abc import ABC +from abc import abstractmethod +from typing import TYPE_CHECKING +from typing import Any + +from packaging.utils import canonicalize_name +from poetry.core.constraints.version import parse_constraint + +from poetry.config.config import Config +from poetry.repositories.repository import Repository +from poetry.utils.cache import FileCache + + +if TYPE_CHECKING: + from packaging.utils import NormalizedName + from poetry.core.constraints.version import Version + from poetry.core.packages.package import Package + + from poetry.inspection.info import PackageInfo + + +class CachedRepository(Repository, ABC): + CACHE_VERSION = parse_constraint("1.1.0") + + def __init__( + self, name: str, disable_cache: bool = False, config: Config | None = None + ) -> None: + super().__init__(name) + self._disable_cache = disable_cache + self._cache_dir = (config or Config.create()).repository_cache_directory / name + self._release_cache: FileCache[dict[str, Any]] = FileCache(path=self._cache_dir) + + @abstractmethod + def _get_release_info( + self, name: NormalizedName, version: Version + ) -> dict[str, Any]: + ... + + def get_release_info(self, name: NormalizedName, version: Version) -> PackageInfo: + """ + Return the release information given a package name and a version. + + The information is returned from the cache if it exists + or retrieved from the remote server. + """ + from poetry.inspection.info import PackageInfo + + if self._disable_cache: + return PackageInfo.load(self._get_release_info(name, version)) + + cached = self._release_cache.remember( + f"{name}:{version}", lambda: self._get_release_info(name, version) + ) + + cache_version = cached.get("_cache_version", "0.0.0") + if parse_constraint(cache_version) != self.CACHE_VERSION: + # The cache must be updated + self._log( + f"The cache for {name} {version} is outdated. Refreshing.", + level="debug", + ) + cached = self._get_release_info(name, version) + + self._release_cache.put(f"{name}:{version}", cached) + + return PackageInfo.load(cached) + + def package( + self, + name: str, + version: Version, + extras: list[str] | None = None, + ) -> Package: + return self.get_release_info(canonicalize_name(name), version).to_package( + name=name, extras=extras + ) diff --git a/src/poetry/repositories/http.py b/src/poetry/repositories/http.py index 07315736d5a..3de1408a0ce 100644 --- a/src/poetry/repositories/http.py +++ b/src/poetry/repositories/http.py @@ -1,298 +1,15 @@ from __future__ import annotations -import hashlib -import os -import urllib -import urllib.parse +import warnings -from collections import defaultdict -from pathlib import Path -from typing import TYPE_CHECKING -from typing import Any -import requests +from poetry.repositories.http_repository import ( # isort: skip # nopycln: import # noqa: E501, F401 + HTTPRepository, +) -from poetry.core.constraints.version import parse_constraint -from poetry.core.packages.dependency import Dependency -from poetry.core.packages.utils.link import Link -from poetry.core.utils.helpers import temporary_directory -from poetry.core.version.markers import parse_marker - -from poetry.repositories.cached import CachedRepository -from poetry.repositories.exceptions import PackageNotFound -from poetry.repositories.exceptions import RepositoryError -from poetry.repositories.link_sources.html import HTMLPage -from poetry.utils.authenticator import Authenticator -from poetry.utils.constants import REQUESTS_TIMEOUT -from poetry.utils.helpers import download_file -from poetry.utils.patterns import wheel_file_re - - -if TYPE_CHECKING: - from poetry.config.config import Config - from poetry.inspection.info import PackageInfo - from poetry.utils.authenticator import RepositoryCertificateConfig - - -class HTTPRepository(CachedRepository): - def __init__( - self, - name: str, - url: str, - config: Config | None = None, - disable_cache: bool = False, - ) -> None: - super().__init__(name, disable_cache, config) - self._url = url - self._authenticator = Authenticator( - config=config, - cache_id=name, - disable_cache=disable_cache, - ) - self._authenticator.add_repository(name, url) - - @property - def session(self) -> Authenticator: - return self._authenticator - - @property - def url(self) -> str: - return self._url - - @property - def certificates(self) -> RepositoryCertificateConfig: - return self._authenticator.get_certs_for_url(self.url) - - @property - def authenticated_url(self) -> str: - return self._authenticator.authenticated_url(url=self.url) - - def _download(self, url: str, dest: Path) -> None: - return download_file(url, dest, session=self.session) - - def _get_info_from_wheel(self, url: str) -> PackageInfo: - from poetry.inspection.info import PackageInfo - - wheel_name = urllib.parse.urlparse(url).path.rsplit("/")[-1] - 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) - - def _get_info_from_sdist(self, url: str) -> PackageInfo: - from poetry.inspection.info import PackageInfo - - sdist_name = urllib.parse.urlparse(url).path - 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) - - def _get_info_from_urls(self, urls: dict[str, list[str]]) -> PackageInfo: - # Prefer to read data from wheels: this is faster and more reliable - wheels = urls.get("bdist_wheel") - if wheels: - # We ought just to be able to look at any of the available wheels to read - # metadata, they all should give the same answer. - # - # In practice this hasn't always been true. - # - # Most of the code in here is to deal with cases such as isort 4.3.4 which - # published separate python3 and python2 wheels with quite different - # dependencies. We try to detect such cases and combine the data from the - # two wheels into what ought to have been published in the first place... - universal_wheel = None - universal_python2_wheel = None - universal_python3_wheel = None - platform_specific_wheels = [] - for wheel in wheels: - link = Link(wheel) - m = wheel_file_re.match(link.filename) - if not m: - continue - - pyver = m.group("pyver") - abi = m.group("abi") - plat = m.group("plat") - if abi == "none" and plat == "any": - # Universal wheel - if pyver == "py2.py3": - # Any Python - universal_wheel = wheel - elif pyver == "py2": - universal_python2_wheel = wheel - else: - universal_python3_wheel = wheel - else: - platform_specific_wheels.append(wheel) - - if universal_wheel is not None: - return self._get_info_from_wheel(universal_wheel) - - info = None - if universal_python2_wheel and universal_python3_wheel: - info = self._get_info_from_wheel(universal_python2_wheel) - - py3_info = self._get_info_from_wheel(universal_python3_wheel) - - if info.requires_python or py3_info.requires_python: - info.requires_python = str( - parse_constraint(info.requires_python or "^2.7").union( - parse_constraint(py3_info.requires_python or "^3") - ) - ) - - if py3_info.requires_dist: - if not info.requires_dist: - info.requires_dist = py3_info.requires_dist - - return info - - py2_requires_dist = { - Dependency.create_from_pep_508(r).to_pep_508() - for r in info.requires_dist - } - py3_requires_dist = { - Dependency.create_from_pep_508(r).to_pep_508() - for r in py3_info.requires_dist - } - base_requires_dist = py2_requires_dist & py3_requires_dist - py2_only_requires_dist = py2_requires_dist - py3_requires_dist - py3_only_requires_dist = py3_requires_dist - py2_requires_dist - - # Normalizing requires_dist - requires_dist = list(base_requires_dist) - for requirement in py2_only_requires_dist: - dep = Dependency.create_from_pep_508(requirement) - dep.marker = dep.marker.intersect( - parse_marker("python_version == '2.7'") - ) - requires_dist.append(dep.to_pep_508()) - - for requirement in py3_only_requires_dist: - dep = Dependency.create_from_pep_508(requirement) - dep.marker = dep.marker.intersect( - parse_marker("python_version >= '3'") - ) - requires_dist.append(dep.to_pep_508()) - - info.requires_dist = sorted(set(requires_dist)) - - if info: - return info - - # Prefer non platform specific wheels - if universal_python3_wheel: - return self._get_info_from_wheel(universal_python3_wheel) - - if universal_python2_wheel: - return self._get_info_from_wheel(universal_python2_wheel) - - if platform_specific_wheels: - first_wheel = platform_specific_wheels[0] - return self._get_info_from_wheel(first_wheel) - - return self._get_info_from_sdist(urls["sdist"][0]) - - def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict[str, Any]: - if not links: - raise PackageNotFound( - f'No valid distribution links found for package: "{data.name}" version:' - f' "{data.version}"' - ) - urls = defaultdict(list) - files: list[dict[str, Any]] = [] - for link in links: - if link.yanked and not data.yanked: - # drop yanked files unless the entire release is yanked - continue - if link.is_wheel: - urls["bdist_wheel"].append(link.url) - elif link.filename.endswith( - (".tar.gz", ".zip", ".bz2", ".xz", ".Z", ".tar") - ): - urls["sdist"].append(link.url) - - file_hash = f"{link.hash_name}:{link.hash}" if link.hash else None - - if not link.hash or ( - link.hash_name is not None - and link.hash_name not in ("sha256", "sha384", "sha512") - and hasattr(hashlib, link.hash_name) - ): - with temporary_directory() as temp_dir: - filepath = Path(temp_dir) / link.filename - self._download(link.url, filepath) - - known_hash = ( - getattr(hashlib, link.hash_name)() if link.hash_name else None - ) - required_hash = hashlib.sha256() - - chunksize = 4096 - with filepath.open("rb") as f: - while True: - chunk = f.read(chunksize) - if not chunk: - break - if known_hash: - known_hash.update(chunk) - required_hash.update(chunk) - - if not known_hash or known_hash.hexdigest() == link.hash: - file_hash = f"{required_hash.name}:{required_hash.hexdigest()}" - - files.append({"file": link.filename, "hash": file_hash}) - - data.files = files - - info = self._get_info_from_urls(urls) - - data.summary = info.summary - data.requires_dist = info.requires_dist - data.requires_python = info.requires_python - - return data.asdict() - - def _get_response(self, endpoint: str) -> requests.Response | None: - url = self._url + endpoint - try: - response: requests.Response = self.session.get( - url, raise_for_status=False, timeout=REQUESTS_TIMEOUT - ) - if response.status_code in (401, 403): - self._log( - f"Authorization error accessing {url}", - level="warning", - ) - return None - if response.status_code == 404: - return None - response.raise_for_status() - except requests.exceptions.HTTPError as e: - raise RepositoryError(e) - - if response.url != url: - self._log( - f"Response URL {response.url} differs from request URL {url}", - level="debug", - ) - return response - - def _get_page(self, endpoint: str) -> HTMLPage | None: - response = self._get_response(endpoint) - if not response: - return None - return HTMLPage(response.url, response.text) +warnings.warn( + "Module poetry.repositories.http is renamed and scheduled for removal in poetry" + " release 1.4.0. Please migrate to poetry.repositories.http_repository.", + DeprecationWarning, + stacklevel=2, +) diff --git a/src/poetry/repositories/http_repository.py b/src/poetry/repositories/http_repository.py new file mode 100644 index 00000000000..d0dafcccd36 --- /dev/null +++ b/src/poetry/repositories/http_repository.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import hashlib +import os +import urllib +import urllib.parse + +from collections import defaultdict +from pathlib import Path +from typing import TYPE_CHECKING +from typing import Any + +import requests + +from poetry.core.constraints.version import parse_constraint +from poetry.core.packages.dependency import Dependency +from poetry.core.packages.utils.link import Link +from poetry.core.utils.helpers import temporary_directory +from poetry.core.version.markers import parse_marker + +from poetry.repositories.cached_repository import CachedRepository +from poetry.repositories.exceptions import PackageNotFound +from poetry.repositories.exceptions import RepositoryError +from poetry.repositories.link_sources.html import HTMLPage +from poetry.utils.authenticator import Authenticator +from poetry.utils.constants import REQUESTS_TIMEOUT +from poetry.utils.helpers import download_file +from poetry.utils.patterns import wheel_file_re + + +if TYPE_CHECKING: + from poetry.config.config import Config + from poetry.inspection.info import PackageInfo + from poetry.utils.authenticator import RepositoryCertificateConfig + + +class HTTPRepository(CachedRepository): + def __init__( + self, + name: str, + url: str, + config: Config | None = None, + disable_cache: bool = False, + ) -> None: + super().__init__(name, disable_cache, config) + self._url = url + self._authenticator = Authenticator( + config=config, + cache_id=name, + disable_cache=disable_cache, + ) + self._authenticator.add_repository(name, url) + + @property + def session(self) -> Authenticator: + return self._authenticator + + @property + def url(self) -> str: + return self._url + + @property + def certificates(self) -> RepositoryCertificateConfig: + return self._authenticator.get_certs_for_url(self.url) + + @property + def authenticated_url(self) -> str: + return self._authenticator.authenticated_url(url=self.url) + + def _download(self, url: str, dest: Path) -> None: + return download_file(url, dest, session=self.session) + + def _get_info_from_wheel(self, url: str) -> PackageInfo: + from poetry.inspection.info import PackageInfo + + wheel_name = urllib.parse.urlparse(url).path.rsplit("/")[-1] + 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) + + def _get_info_from_sdist(self, url: str) -> PackageInfo: + from poetry.inspection.info import PackageInfo + + sdist_name = urllib.parse.urlparse(url).path + 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) + + def _get_info_from_urls(self, urls: dict[str, list[str]]) -> PackageInfo: + # Prefer to read data from wheels: this is faster and more reliable + wheels = urls.get("bdist_wheel") + if wheels: + # We ought just to be able to look at any of the available wheels to read + # metadata, they all should give the same answer. + # + # In practice this hasn't always been true. + # + # Most of the code in here is to deal with cases such as isort 4.3.4 which + # published separate python3 and python2 wheels with quite different + # dependencies. We try to detect such cases and combine the data from the + # two wheels into what ought to have been published in the first place... + universal_wheel = None + universal_python2_wheel = None + universal_python3_wheel = None + platform_specific_wheels = [] + for wheel in wheels: + link = Link(wheel) + m = wheel_file_re.match(link.filename) + if not m: + continue + + pyver = m.group("pyver") + abi = m.group("abi") + plat = m.group("plat") + if abi == "none" and plat == "any": + # Universal wheel + if pyver == "py2.py3": + # Any Python + universal_wheel = wheel + elif pyver == "py2": + universal_python2_wheel = wheel + else: + universal_python3_wheel = wheel + else: + platform_specific_wheels.append(wheel) + + if universal_wheel is not None: + return self._get_info_from_wheel(universal_wheel) + + info = None + if universal_python2_wheel and universal_python3_wheel: + info = self._get_info_from_wheel(universal_python2_wheel) + + py3_info = self._get_info_from_wheel(universal_python3_wheel) + + if info.requires_python or py3_info.requires_python: + info.requires_python = str( + parse_constraint(info.requires_python or "^2.7").union( + parse_constraint(py3_info.requires_python or "^3") + ) + ) + + if py3_info.requires_dist: + if not info.requires_dist: + info.requires_dist = py3_info.requires_dist + + return info + + py2_requires_dist = { + Dependency.create_from_pep_508(r).to_pep_508() + for r in info.requires_dist + } + py3_requires_dist = { + Dependency.create_from_pep_508(r).to_pep_508() + for r in py3_info.requires_dist + } + base_requires_dist = py2_requires_dist & py3_requires_dist + py2_only_requires_dist = py2_requires_dist - py3_requires_dist + py3_only_requires_dist = py3_requires_dist - py2_requires_dist + + # Normalizing requires_dist + requires_dist = list(base_requires_dist) + for requirement in py2_only_requires_dist: + dep = Dependency.create_from_pep_508(requirement) + dep.marker = dep.marker.intersect( + parse_marker("python_version == '2.7'") + ) + requires_dist.append(dep.to_pep_508()) + + for requirement in py3_only_requires_dist: + dep = Dependency.create_from_pep_508(requirement) + dep.marker = dep.marker.intersect( + parse_marker("python_version >= '3'") + ) + requires_dist.append(dep.to_pep_508()) + + info.requires_dist = sorted(set(requires_dist)) + + if info: + return info + + # Prefer non platform specific wheels + if universal_python3_wheel: + return self._get_info_from_wheel(universal_python3_wheel) + + if universal_python2_wheel: + return self._get_info_from_wheel(universal_python2_wheel) + + if platform_specific_wheels: + first_wheel = platform_specific_wheels[0] + return self._get_info_from_wheel(first_wheel) + + return self._get_info_from_sdist(urls["sdist"][0]) + + def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict[str, Any]: + if not links: + raise PackageNotFound( + f'No valid distribution links found for package: "{data.name}" version:' + f' "{data.version}"' + ) + urls = defaultdict(list) + files: list[dict[str, Any]] = [] + for link in links: + if link.yanked and not data.yanked: + # drop yanked files unless the entire release is yanked + continue + if link.is_wheel: + urls["bdist_wheel"].append(link.url) + elif link.filename.endswith( + (".tar.gz", ".zip", ".bz2", ".xz", ".Z", ".tar") + ): + urls["sdist"].append(link.url) + + file_hash = f"{link.hash_name}:{link.hash}" if link.hash else None + + if not link.hash or ( + link.hash_name is not None + and link.hash_name not in ("sha256", "sha384", "sha512") + and hasattr(hashlib, link.hash_name) + ): + with temporary_directory() as temp_dir: + filepath = Path(temp_dir) / link.filename + self._download(link.url, filepath) + + known_hash = ( + getattr(hashlib, link.hash_name)() if link.hash_name else None + ) + required_hash = hashlib.sha256() + + chunksize = 4096 + with filepath.open("rb") as f: + while True: + chunk = f.read(chunksize) + if not chunk: + break + if known_hash: + known_hash.update(chunk) + required_hash.update(chunk) + + if not known_hash or known_hash.hexdigest() == link.hash: + file_hash = f"{required_hash.name}:{required_hash.hexdigest()}" + + files.append({"file": link.filename, "hash": file_hash}) + + data.files = files + + info = self._get_info_from_urls(urls) + + data.summary = info.summary + data.requires_dist = info.requires_dist + data.requires_python = info.requires_python + + return data.asdict() + + def _get_response(self, endpoint: str) -> requests.Response | None: + url = self._url + endpoint + try: + response: requests.Response = self.session.get( + url, raise_for_status=False, timeout=REQUESTS_TIMEOUT + ) + if response.status_code in (401, 403): + self._log( + f"Authorization error accessing {url}", + level="warning", + ) + return None + if response.status_code == 404: + return None + response.raise_for_status() + except requests.exceptions.HTTPError as e: + raise RepositoryError(e) + + if response.url != url: + self._log( + f"Response URL {response.url} differs from request URL {url}", + level="debug", + ) + return response + + def _get_page(self, endpoint: str) -> HTMLPage | None: + response = self._get_response(endpoint) + if not response: + return None + return HTMLPage(response.url, response.text) diff --git a/src/poetry/repositories/legacy_repository.py b/src/poetry/repositories/legacy_repository.py index 9eaf286928b..6ab2d819ea9 100644 --- a/src/poetry/repositories/legacy_repository.py +++ b/src/poetry/repositories/legacy_repository.py @@ -7,7 +7,7 @@ from poetry.inspection.info import PackageInfo from poetry.repositories.exceptions import PackageNotFound -from poetry.repositories.http import HTTPRepository +from poetry.repositories.http_repository import HTTPRepository from poetry.repositories.link_sources.html import SimpleRepositoryPage diff --git a/src/poetry/repositories/pool.py b/src/poetry/repositories/pool.py index 8a345b16cfc..5f67f1768a5 100644 --- a/src/poetry/repositories/pool.py +++ b/src/poetry/repositories/pool.py @@ -1,143 +1,27 @@ from __future__ import annotations -import enum +import warnings -from collections import OrderedDict -from dataclasses import dataclass -from enum import IntEnum from typing import TYPE_CHECKING -from poetry.repositories.abstract_repository import AbstractRepository -from poetry.repositories.exceptions import PackageNotFound +from poetry.repositories.repository_pool import RepositoryPool if TYPE_CHECKING: - from poetry.core.constraints.version import Version - from poetry.core.packages.dependency import Dependency - from poetry.core.packages.package import Package - from poetry.repositories.repository import Repository -class Priority(IntEnum): - # The order of the members below dictates the actual priority. The first member has - # top priority. - DEFAULT = enum.auto() - PRIMARY = enum.auto() - SECONDARY = enum.auto() - - -@dataclass(frozen=True) -class PrioritizedRepository: - repository: Repository - priority: Priority - - -class Pool(AbstractRepository): +class Pool(RepositoryPool): def __init__( self, repositories: list[Repository] | None = None, ignore_repository_names: bool = False, ) -> None: - super().__init__("poetry-pool") - self._repositories: OrderedDict[str, PrioritizedRepository] = OrderedDict() - self._ignore_repository_names = ignore_repository_names - - if repositories is None: - repositories = [] - for repository in repositories: - self.add_repository(repository) - - @property - def repositories(self) -> list[Repository]: - unsorted_repositories = self._repositories.values() - sorted_repositories = sorted( - unsorted_repositories, key=lambda prio_repo: prio_repo.priority - ) - return [prio_repo.repository for prio_repo in sorted_repositories] - - def has_default(self) -> bool: - return self._contains_priority(Priority.DEFAULT) - - def has_primary_repositories(self) -> bool: - return self._contains_priority(Priority.PRIMARY) - - def _contains_priority(self, priority: Priority) -> bool: - return any( - prio_repo.priority is priority for prio_repo in self._repositories.values() - ) - - def has_repository(self, name: str) -> bool: - return name.lower() in self._repositories - - def repository(self, name: str) -> Repository: - name = name.lower() - if self.has_repository(name): - return self._repositories[name].repository - raise IndexError(f'Repository "{name}" does not exist.') - - def add_repository( - self, repository: Repository, default: bool = False, secondary: bool = False - ) -> Pool: - """ - Adds a repository to the pool. - """ - repository_name = repository.name.lower() - if self.has_repository(repository_name): - raise ValueError( - f"A repository with name {repository_name} was already added." - ) - - if default and self.has_default(): - raise ValueError("Only one repository can be the default.") - - priority = Priority.PRIMARY - if default: - priority = Priority.DEFAULT - elif secondary: - priority = Priority.SECONDARY - self._repositories[repository_name] = PrioritizedRepository( - repository, priority + warnings.warn( + "Object Pool from poetry.repositories.pool is renamed and scheduled for" + " removal in poetry release 1.4.0. Please migrate to RepositoryPool from" + " poetry.repositories.repository_pool.", + DeprecationWarning, + stacklevel=2, ) - return self - - def remove_repository(self, name: str) -> Pool: - if not self.has_repository(name): - raise IndexError(f"Pool can not remove unknown repository '{name}'.") - del self._repositories[name.lower()] - return self - - def package( - self, - name: str, - version: Version, - extras: list[str] | None = None, - repository_name: str | None = None, - ) -> Package: - if repository_name and not self._ignore_repository_names: - return self.repository(repository_name).package( - name, version, extras=extras - ) - - for repo in self.repositories: - try: - return repo.package(name, version, extras=extras) - except PackageNotFound: - continue - raise PackageNotFound(f"Package {name} ({version}) not found.") - - def find_packages(self, dependency: Dependency) -> list[Package]: - repository_name = dependency.source_name - if repository_name and not self._ignore_repository_names: - return self.repository(repository_name).find_packages(dependency) - - packages: list[Package] = [] - for repo in self.repositories: - packages += repo.find_packages(dependency) - return packages - - def search(self, query: str) -> list[Package]: - results: list[Package] = [] - for repository in self.repositories: - results += repository.search(query) - return results + super().__init__(repositories, ignore_repository_names) diff --git a/src/poetry/repositories/pypi_repository.py b/src/poetry/repositories/pypi_repository.py index 8846b417739..236dabadfda 100644 --- a/src/poetry/repositories/pypi_repository.py +++ b/src/poetry/repositories/pypi_repository.py @@ -15,7 +15,7 @@ from poetry.core.version.exceptions import InvalidVersion from poetry.repositories.exceptions import PackageNotFound -from poetry.repositories.http import HTTPRepository +from poetry.repositories.http_repository import HTTPRepository from poetry.repositories.link_sources.json import SimpleJsonPage from poetry.utils._compat import to_str from poetry.utils.constants import REQUESTS_TIMEOUT diff --git a/src/poetry/repositories/repository_pool.py b/src/poetry/repositories/repository_pool.py new file mode 100644 index 00000000000..79d70479c82 --- /dev/null +++ b/src/poetry/repositories/repository_pool.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import enum + +from collections import OrderedDict +from dataclasses import dataclass +from enum import IntEnum +from typing import TYPE_CHECKING + +from poetry.repositories.abstract_repository import AbstractRepository +from poetry.repositories.exceptions import PackageNotFound + + +if TYPE_CHECKING: + from poetry.core.constraints.version import Version + from poetry.core.packages.dependency import Dependency + from poetry.core.packages.package import Package + + from poetry.repositories.repository import Repository + + +class Priority(IntEnum): + # The order of the members below dictates the actual priority. The first member has + # top priority. + DEFAULT = enum.auto() + PRIMARY = enum.auto() + SECONDARY = enum.auto() + + +@dataclass(frozen=True) +class PrioritizedRepository: + repository: Repository + priority: Priority + + +class RepositoryPool(AbstractRepository): + def __init__( + self, + repositories: list[Repository] | None = None, + ignore_repository_names: bool = False, + ) -> None: + super().__init__("poetry-repository-pool") + self._repositories: OrderedDict[str, PrioritizedRepository] = OrderedDict() + self._ignore_repository_names = ignore_repository_names + + if repositories is None: + repositories = [] + for repository in repositories: + self.add_repository(repository) + + @property + def repositories(self) -> list[Repository]: + unsorted_repositories = self._repositories.values() + sorted_repositories = sorted( + unsorted_repositories, key=lambda prio_repo: prio_repo.priority + ) + return [prio_repo.repository for prio_repo in sorted_repositories] + + def has_default(self) -> bool: + return self._contains_priority(Priority.DEFAULT) + + def has_primary_repositories(self) -> bool: + return self._contains_priority(Priority.PRIMARY) + + def _contains_priority(self, priority: Priority) -> bool: + return any( + prio_repo.priority is priority for prio_repo in self._repositories.values() + ) + + def has_repository(self, name: str) -> bool: + return name.lower() in self._repositories + + def repository(self, name: str) -> Repository: + name = name.lower() + if self.has_repository(name): + return self._repositories[name].repository + raise IndexError(f'Repository "{name}" does not exist.') + + def add_repository( + self, repository: Repository, default: bool = False, secondary: bool = False + ) -> RepositoryPool: + """ + Adds a repository to the pool. + """ + repository_name = repository.name.lower() + if self.has_repository(repository_name): + raise ValueError( + f"A repository with name {repository_name} was already added." + ) + + if default and self.has_default(): + raise ValueError("Only one repository can be the default.") + + priority = Priority.PRIMARY + if default: + priority = Priority.DEFAULT + elif secondary: + priority = Priority.SECONDARY + self._repositories[repository_name] = PrioritizedRepository( + repository, priority + ) + return self + + def remove_repository(self, name: str) -> RepositoryPool: + if not self.has_repository(name): + raise IndexError(f"Pool can not remove unknown repository '{name}'.") + del self._repositories[name.lower()] + return self + + def package( + self, + name: str, + version: Version, + extras: list[str] | None = None, + repository_name: str | None = None, + ) -> Package: + if repository_name and not self._ignore_repository_names: + return self.repository(repository_name).package( + name, version, extras=extras + ) + + for repo in self.repositories: + try: + return repo.package(name, version, extras=extras) + except PackageNotFound: + continue + raise PackageNotFound(f"Package {name} ({version}) not found.") + + def find_packages(self, dependency: Dependency) -> list[Package]: + repository_name = dependency.source_name + if repository_name and not self._ignore_repository_names: + return self.repository(repository_name).find_packages(dependency) + + packages: list[Package] = [] + for repo in self.repositories: + packages += repo.find_packages(dependency) + return packages + + def search(self, query: str) -> list[Package]: + results: list[Package] = [] + for repository in self.repositories: + results += repository.search(query) + return results diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index d76972ca50d..7de0d60d2bc 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -451,12 +451,6 @@ def find( if value[-1] is True ] - def __getattr__(self, item: str) -> Any: - try: - return super().__getattribute__(item) - except AttributeError: - return getattr(self.path, item) - class EnvError(Exception): pass diff --git a/src/poetry/utils/helpers.py b/src/poetry/utils/helpers.py index b50d9e9acfc..c4ef660d547 100644 --- a/src/poetry/utils/helpers.py +++ b/src/poetry/utils/helpers.py @@ -12,7 +12,6 @@ from typing import Any from typing import Iterator from typing import Mapping -from typing import cast from poetry.utils.constants import REQUESTS_TIMEOUT @@ -189,7 +188,8 @@ def _get_win_folder_from_registry(csidl_name: str) -> str: ) dir, type = _winreg.QueryValueEx(key, shell_folder_name) - return cast(str, dir) + assert isinstance(dir, str) + return dir def _get_win_folder_with_ctypes(csidl_name: str) -> str: diff --git a/src/poetry/version/version_selector.py b/src/poetry/version/version_selector.py index 476e3635444..d00e52f3c7c 100644 --- a/src/poetry/version/version_selector.py +++ b/src/poetry/version/version_selector.py @@ -8,11 +8,11 @@ if TYPE_CHECKING: from poetry.core.packages.package import Package - from poetry.repositories import Pool + from poetry.repositories import RepositoryPool class VersionSelector: - def __init__(self, pool: Pool) -> None: + def __init__(self, pool: RepositoryPool) -> None: self._pool = pool def find_best_candidate( diff --git a/tests/conftest.py b/tests/conftest.py index 5de0afdd013..8209d2b286e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,8 +24,8 @@ from poetry.inspection.info import PackageInfo from poetry.inspection.info import PackageInfoError from poetry.layouts import layout -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool from poetry.utils.env import EnvManager from poetry.utils.env import SystemEnv from poetry.utils.env import VirtualEnv @@ -231,7 +231,7 @@ def download_mock(mocker: MockerFixture) -> None: # Patch download to not download anything but to just copy from fixtures mocker.patch("poetry.utils.helpers.download_file", new=mock_download) mocker.patch("poetry.puzzle.provider.download_file", new=mock_download) - mocker.patch("poetry.repositories.http.download_file", new=mock_download) + mocker.patch("poetry.repositories.http_repository.download_file", new=mock_download) @pytest.fixture(autouse=True) @@ -419,7 +419,7 @@ def _factory( poetry.set_locker(locker) poetry.set_config(config) - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo) poetry.set_pool(pool) diff --git a/tests/console/commands/self/conftest.py b/tests/console/commands/self/conftest.py index 6a175b5fdf0..e6fa5a052bf 100644 --- a/tests/console/commands/self/conftest.py +++ b/tests/console/commands/self/conftest.py @@ -7,7 +7,7 @@ from poetry.core.packages.package import Package from poetry.__version__ import __version__ -from poetry.repositories import Pool +from poetry.repositories import RepositoryPool from poetry.utils.env import EnvManager @@ -34,8 +34,8 @@ def save_environ(environ: None) -> Repository: @pytest.fixture() -def pool(repo: TestRepository) -> Pool: - return Pool([repo]) +def pool(repo: TestRepository) -> RepositoryPool: + return RepositoryPool([repo]) @pytest.fixture(autouse=True) @@ -43,12 +43,17 @@ def setup_mocks( mocker: MockerFixture, tmp_venv: VirtualEnv, installed: Repository, - pool: Pool, + pool: RepositoryPool, http: type[httpretty.httpretty], ) -> None: mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv) - mocker.patch("poetry.repositories.pool.Pool.find_packages", pool.find_packages) - mocker.patch("poetry.repositories.pool.Pool.package", pool.package) + mocker.patch( + "poetry.repositories.repository_pool.RepositoryPool.find_packages", + pool.find_packages, + ) + mocker.patch( + "poetry.repositories.repository_pool.RepositoryPool.package", pool.package + ) mocker.patch("poetry.installation.executor.pip_install") mocker.patch( "poetry.installation.installer.Installer._get_installed", diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index 5f176ba0eb9..935e58e636e 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -13,7 +13,7 @@ from packaging.utils import canonicalize_name from poetry.console.commands.init import InitCommand -from poetry.repositories import Pool +from poetry.repositories import RepositoryPool from poetry.utils._compat import decode from tests.helpers import PoetryTestApplication from tests.helpers import get_package @@ -46,7 +46,8 @@ def source_dir(tmp_path: Path) -> Iterator[Path]: def patches(mocker: MockerFixture, source_dir: Path, repo: TestRepository) -> None: mocker.patch("pathlib.Path.cwd", return_value=source_dir) mocker.patch( - "poetry.console.commands.init.InitCommand._get_pool", return_value=Pool([repo]) + "poetry.console.commands.init.InitCommand._get_pool", + return_value=RepositoryPool([repo]), ) diff --git a/tests/console/commands/test_lock.py b/tests/console/commands/test_lock.py index 69de642e117..a8ef7c2aac9 100644 --- a/tests/console/commands/test_lock.py +++ b/tests/console/commands/test_lock.py @@ -43,6 +43,7 @@ def _project_factory( name="foobar", pyproject_content=pyproject_content, poetry_lock_content=poetry_lock_content, + source=source, ) @@ -67,6 +68,13 @@ def poetry_with_old_lockfile( return _project_factory("old_lock", project_factory, fixture_dir) +@pytest.fixture +def poetry_with_nested_path_deps_old_lockfile( + project_factory: ProjectFactory, fixture_dir: FixtureDirGetter +) -> Poetry: + return _project_factory("old_lock_path_dependency", project_factory, fixture_dir) + + @pytest.fixture def poetry_with_incompatible_lockfile( project_factory: ProjectFactory, fixture_dir: FixtureDirGetter @@ -166,6 +174,36 @@ def test_lock_no_update( assert locked_repository.find_packages(package.to_dependency()) +def test_lock_no_update_path_dependencies( + command_tester_factory: CommandTesterFactory, + poetry_with_nested_path_deps_old_lockfile: Poetry, + repo: TestRepository, +): + """ + The lock file contains a variant of the directory dependency "quix" that does + not depend on "sampleproject". Although the version of "quix" has not been changed, + it should be re-solved because there is always only one valid version + of a directory dependency at any time. + """ + repo.add_package(get_package("sampleproject", "1.3.1")) + + locker = Locker( + lock=poetry_with_nested_path_deps_old_lockfile.pyproject.file.path.parent + / "poetry.lock", + local_config=poetry_with_nested_path_deps_old_lockfile.locker._local_config, + ) + poetry_with_nested_path_deps_old_lockfile.set_locker(locker) + + tester = command_tester_factory( + "lock", poetry=poetry_with_nested_path_deps_old_lockfile + ) + tester.execute("--no-update") + + packages = locker.locked_repository().packages + + assert {p.name for p in packages} == {"quix", "sampleproject"} + + @pytest.mark.parametrize("is_no_update", [False, True]) def test_lock_with_incompatible_lockfile( command_tester_factory: CommandTesterFactory, diff --git a/tests/console/commands/test_show.py b/tests/console/commands/test_show.py index bd6d8382ea9..a927cee5bf3 100644 --- a/tests/console/commands/test_show.py +++ b/tests/console/commands/test_show.py @@ -1368,6 +1368,103 @@ def test_show_all_shows_incompatible_package( assert tester.io.fetch_output() == expected +def test_show_hides_incompatible_package_with_duplicate( + tester: CommandTester, + poetry: Poetry, + installed: Repository, + repo: TestRepository, +): + poetry.package.add_dependency( + Factory.create_dependency("cachy", {"version": "0.1.0", "platform": "linux"}) + ) + poetry.package.add_dependency( + Factory.create_dependency("cachy", {"version": "0.1.1", "platform": "darwin"}) + ) + + poetry.locker.mock_lock_data( + { + "package": [ + { + "name": "cachy", + "version": "0.1.0", + "description": "Cachy package", + "optional": False, + "platform": "*", + "python-versions": "*", + "files": [], + }, + { + "name": "cachy", + "version": "0.1.1", + "description": "Cachy package", + "optional": False, + "platform": "*", + "python-versions": "*", + "files": [], + }, + ], + "metadata": {"content-hash": "123456789"}, + } + ) + + tester.execute() + + expected = """\ +cachy (!) 0.1.1 Cachy package +""" + + assert tester.io.fetch_output() == expected + + +def test_show_all_shows_all_duplicates( + tester: CommandTester, + poetry: Poetry, + installed: Repository, + repo: TestRepository, +): + poetry.package.add_dependency( + Factory.create_dependency("cachy", {"version": "0.1.0", "platform": "linux"}) + ) + poetry.package.add_dependency( + Factory.create_dependency("cachy", {"version": "0.1.1", "platform": "darwin"}) + ) + + poetry.locker.mock_lock_data( + { + "package": [ + { + "name": "cachy", + "version": "0.1.0", + "description": "Cachy package", + "optional": False, + "platform": "*", + "python-versions": "*", + "files": [], + }, + { + "name": "cachy", + "version": "0.1.1", + "description": "Cachy package", + "optional": False, + "platform": "*", + "python-versions": "*", + "files": [], + }, + ], + "metadata": {"content-hash": "123456789"}, + } + ) + + tester.execute("--all") + + expected = """\ +cachy 0.1.0 Cachy package +cachy (!) 0.1.1 Cachy package +""" + + assert tester.io.fetch_output() == expected + + def test_show_non_dev_with_basic_installed_packages( tester: CommandTester, poetry: Poetry, installed: Repository ): diff --git a/tests/fixtures/old_lock_path_dependency/poetry.lock b/tests/fixtures/old_lock_path_dependency/poetry.lock new file mode 100644 index 00000000000..45c6e792d7f --- /dev/null +++ b/tests/fixtures/old_lock_path_dependency/poetry.lock @@ -0,0 +1,20 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "quix" +version = "1.2.3" +description = "Some description." +category = "main" +optional = false +python-versions = "~2.7 || ^3.4" +files = [] +develop = true + +[package.source] +type = "directory" +url = "quix" + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "d2e1cf4390093213432fb8b58f90774a5247bfe860dedc2b023b27accc14cfad" diff --git a/tests/fixtures/old_lock_path_dependency/pyproject.toml b/tests/fixtures/old_lock_path_dependency/pyproject.toml new file mode 100644 index 00000000000..00547cfee26 --- /dev/null +++ b/tests/fixtures/old_lock_path_dependency/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "foobar" +version = "0.1.0" +description = "" +authors = ["Poetry Developer "] + +[tool.poetry.dependencies] +python = "^3.8" +quix = { path = "./quix", develop = true} + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/fixtures/old_lock_path_dependency/quix/pyproject.toml b/tests/fixtures/old_lock_path_dependency/quix/pyproject.toml new file mode 100644 index 00000000000..1bec75cf124 --- /dev/null +++ b/tests/fixtures/old_lock_path_dependency/quix/pyproject.toml @@ -0,0 +1,11 @@ +[tool.poetry] +name = "quix" +version = "1.2.3" +description = "Some description." +authors = ["Poetry Maintainer "] +license = "MIT" + +# Requirements +[tool.poetry.dependencies] +python = "~2.7 || ^3.4" +sampleproject = ">=1.3.1" diff --git a/tests/inspection/test_info.py b/tests/inspection/test_info.py index 389f2a739bf..c789fae8185 100644 --- a/tests/inspection/test_info.py +++ b/tests/inspection/test_info.py @@ -101,12 +101,23 @@ def demo_check_info(info: PackageInfo, requires_dist: set[str] = None) -> None: assert info.version == "0.1.0" assert info.requires_dist - requires_dist = requires_dist or { - 'cleo; extra == "foo"', - "pendulum (>=1.4.4)", - 'tomlkit; extra == "bar"', - } - assert set(info.requires_dist) == requires_dist + if requires_dist: + assert set(info.requires_dist) == requires_dist + else: + assert set(info.requires_dist) in ( + # before https://github.com/python-poetry/poetry-core/pull/510 + { + 'cleo; extra == "foo"', + "pendulum (>=1.4.4)", + 'tomlkit; extra == "bar"', + }, + # after https://github.com/python-poetry/poetry-core/pull/510 + { + 'cleo ; extra == "foo"', + "pendulum (>=1.4.4)", + 'tomlkit ; extra == "bar"', + }, + ) def test_info_from_sdist(demo_sdist: Path): diff --git a/tests/installation/test_chooser.py b/tests/installation/test_chooser.py index b4a8d36bc26..0c82faacf61 100644 --- a/tests/installation/test_chooser.py +++ b/tests/installation/test_chooser.py @@ -13,8 +13,8 @@ from poetry.installation.chooser import Chooser from poetry.repositories.legacy_repository import LegacyRepository -from poetry.repositories.pool import Pool from poetry.repositories.pypi_repository import PyPiRepository +from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import MockEnv @@ -111,8 +111,8 @@ def callback( @pytest.fixture() -def pool() -> Pool: - pool = Pool() +def pool() -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(PyPiRepository(disable_cache=True)) pool.add_repository( @@ -127,7 +127,11 @@ def pool() -> Pool: @pytest.mark.parametrize("source_type", ["", "legacy"]) def test_chooser_chooses_universal_wheel_link_if_available( - env: MockEnv, mock_pypi: None, mock_legacy: None, source_type: str, pool: Pool + env: MockEnv, + mock_pypi: None, + mock_legacy: None, + source_type: str, + pool: RepositoryPool, ): chooser = Chooser(pool, env) @@ -162,7 +166,7 @@ def test_chooser_no_binary_policy( mock_pypi: None, mock_legacy: None, source_type: str, - pool: Pool, + pool: RepositoryPool, policy: str, filename: str, config: Config, @@ -188,7 +192,11 @@ def test_chooser_no_binary_policy( @pytest.mark.parametrize("source_type", ["", "legacy"]) def test_chooser_chooses_specific_python_universal_wheel_link_if_available( - env: MockEnv, mock_pypi: None, mock_legacy: None, source_type: str, pool: Pool + env: MockEnv, + mock_pypi: None, + mock_legacy: None, + source_type: str, + pool: RepositoryPool, ): chooser = Chooser(pool, env) @@ -209,7 +217,7 @@ def test_chooser_chooses_specific_python_universal_wheel_link_if_available( @pytest.mark.parametrize("source_type", ["", "legacy"]) def test_chooser_chooses_system_specific_wheel_link_if_available( - mock_pypi: None, mock_legacy: None, source_type: str, pool: Pool + mock_pypi: None, mock_legacy: None, source_type: str, pool: RepositoryPool ): env = MockEnv( supported_tags=[Tag("cp37", "cp37m", "win32"), Tag("py3", "none", "any")] @@ -237,7 +245,7 @@ def test_chooser_chooses_sdist_if_no_compatible_wheel_link_is_available( mock_pypi: None, mock_legacy: None, source_type: str, - pool: Pool, + pool: RepositoryPool, ): chooser = Chooser(pool, env) @@ -262,7 +270,7 @@ def test_chooser_chooses_distributions_that_match_the_package_hashes( mock_pypi: None, mock_legacy: None, source_type: str, - pool: Pool, + pool: RepositoryPool, ): chooser = Chooser(pool, env) @@ -295,7 +303,7 @@ def test_chooser_chooses_yanked_if_no_others( mock_pypi: None, mock_legacy: None, source_type: str, - pool: Pool, + pool: RepositoryPool, ) -> None: chooser = Chooser(pool, env) @@ -326,7 +334,7 @@ def test_chooser_chooses_yanked_if_no_others( def test_chooser_does_not_choose_yanked_if_others( mock_legacy: None, mock_legacy_partial_yank: None, - pool: Pool, + pool: RepositoryPool, ) -> None: chooser = Chooser(pool, MockEnv(supported_tags=[Tag("py2", "none", "any")])) @@ -372,7 +380,7 @@ def test_chooser_throws_an_error_if_package_hashes_do_not_match( mock_pypi: None, mock_legacy: None, source_type: None, - pool: Pool, + pool: RepositoryPool, ): chooser = Chooser(pool, env) diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py index a5aa06b110e..6b8de09546b 100644 --- a/tests/installation/test_executor.py +++ b/tests/installation/test_executor.py @@ -20,7 +20,7 @@ from poetry.installation.operations import Install from poetry.installation.operations import Uninstall from poetry.installation.operations import Update -from poetry.repositories.pool import Pool +from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import MockEnv from tests.repositories.test_pypi_repository import MockRepository @@ -73,8 +73,8 @@ def io_not_decorated() -> BufferedIO: @pytest.fixture() -def pool() -> Pool: - pool = Pool() +def pool() -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(MockRepository()) return pool @@ -102,7 +102,7 @@ def callback( def test_execute_executes_a_batch_of_operations( mocker: MockerFixture, config: Config, - pool: Pool, + pool: RepositoryPool, io: BufferedIO, tmp_dir: str, mock_file_downloads: None, @@ -203,7 +203,7 @@ def test_execute_executes_a_batch_of_operations( ) def test_execute_prints_warning_for_yanked_package( config: Config, - pool: Pool, + pool: RepositoryPool, io: BufferedIO, tmp_dir: str, mock_file_downloads: None, @@ -234,7 +234,11 @@ def test_execute_prints_warning_for_yanked_package( def test_execute_shows_skipped_operations_if_verbose( - config: Config, pool: Pool, io: BufferedIO, config_cache_dir: Path, env: MockEnv + config: Config, + pool: RepositoryPool, + io: BufferedIO, + config_cache_dir: Path, + env: MockEnv, ): config.merge({"cache-dir": config_cache_dir.as_posix()}) @@ -258,7 +262,11 @@ def test_execute_shows_skipped_operations_if_verbose( def test_execute_should_show_errors( - config: Config, pool: Pool, mocker: MockerFixture, io: BufferedIO, env: MockEnv + config: Config, + pool: RepositoryPool, + mocker: MockerFixture, + io: BufferedIO, + env: MockEnv, ): executor = Executor(env, pool, config, io) executor.verbose() @@ -283,7 +291,7 @@ def test_execute_should_show_errors( def test_execute_works_with_ansi_output( mocker: MockerFixture, config: Config, - pool: Pool, + pool: RepositoryPool, io_decorated: BufferedIO, tmp_dir: str, mock_file_downloads: None, @@ -325,7 +333,7 @@ def test_execute_works_with_ansi_output( def test_execute_works_with_no_ansi_output( mocker: MockerFixture, config: Config, - pool: Pool, + pool: RepositoryPool, io_not_decorated: BufferedIO, tmp_dir: str, mock_file_downloads: None, @@ -358,7 +366,11 @@ def test_execute_works_with_no_ansi_output( def test_execute_should_show_operation_as_cancelled_on_subprocess_keyboard_interrupt( - config: Config, pool: Pool, mocker: MockerFixture, io: BufferedIO, env: MockEnv + config: Config, + pool: RepositoryPool, + mocker: MockerFixture, + io: BufferedIO, + env: MockEnv, ): executor = Executor(env, pool, config, io) executor.verbose() @@ -379,7 +391,11 @@ def test_execute_should_show_operation_as_cancelled_on_subprocess_keyboard_inter def test_execute_should_gracefully_handle_io_error( - config: Config, pool: Pool, mocker: MockerFixture, io: BufferedIO, env: MockEnv + config: Config, + pool: RepositoryPool, + mocker: MockerFixture, + io: BufferedIO, + env: MockEnv, ): executor = Executor(env, pool, config, io) executor.verbose() @@ -410,7 +426,7 @@ def test_executor_should_delete_incomplete_downloads( io: BufferedIO, tmp_dir: str, mocker: MockerFixture, - pool: Pool, + pool: RepositoryPool, mock_file_downloads: None, env: MockEnv, ): @@ -488,7 +504,7 @@ def test_executor_should_not_write_pep610_url_references_for_cached_package( mocker: MockerFixture, fixture_dir: FixtureDirGetter, tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, ): @@ -504,7 +520,7 @@ def test_executor_should_not_write_pep610_url_references_for_cached_package( def test_executor_should_write_pep610_url_references_for_files( - tmp_venv: VirtualEnv, pool: Pool, config: Config, io: BufferedIO + tmp_venv: VirtualEnv, pool: RepositoryPool, config: Config, io: BufferedIO ): url = ( Path(__file__) @@ -523,7 +539,7 @@ def test_executor_should_write_pep610_url_references_for_files( def test_executor_should_write_pep610_url_references_for_directories( - tmp_venv: VirtualEnv, pool: Pool, config: Config, io: BufferedIO + tmp_venv: VirtualEnv, pool: RepositoryPool, config: Config, io: BufferedIO ): url = Path(__file__).parent.parent.joinpath("fixtures/simple_project").resolve() package = Package( @@ -538,7 +554,7 @@ def test_executor_should_write_pep610_url_references_for_directories( def test_executor_should_write_pep610_url_references_for_editable_directories( - tmp_venv: VirtualEnv, pool: Pool, config: Config, io: BufferedIO + tmp_venv: VirtualEnv, pool: RepositoryPool, config: Config, io: BufferedIO ): url = Path(__file__).parent.parent.joinpath("fixtures/simple_project").resolve() package = Package( @@ -558,7 +574,7 @@ def test_executor_should_write_pep610_url_references_for_editable_directories( def test_executor_should_write_pep610_url_references_for_urls( tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, mock_file_downloads: None, @@ -579,7 +595,7 @@ def test_executor_should_write_pep610_url_references_for_urls( def test_executor_should_write_pep610_url_references_for_git( tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, mock_file_downloads: None, @@ -611,7 +627,7 @@ def test_executor_should_write_pep610_url_references_for_git( def test_executor_should_write_pep610_url_references_for_git_with_subdirectories( tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, mock_file_downloads: None, @@ -645,7 +661,7 @@ def test_executor_should_write_pep610_url_references_for_git_with_subdirectories def test_executor_should_use_cached_link_and_hash( tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, mocker: MockerFixture, @@ -688,7 +704,7 @@ def test_executor_should_use_cached_link_and_hash( ) def test_executor_should_be_initialized_with_correct_workers( tmp_venv: VirtualEnv, - pool: Pool, + pool: RepositoryPool, config: Config, io: BufferedIO, mocker: MockerFixture, @@ -709,7 +725,7 @@ def test_executor_should_be_initialized_with_correct_workers( def test_executer_fallback_on_poetry_create_error( mocker: MockerFixture, config: Config, - pool: Pool, + pool: RepositoryPool, io: BufferedIO, tmp_dir: str, mock_file_downloads: None, diff --git a/tests/installation/test_installer.py b/tests/installation/test_installer.py index f7fd6213c58..ed3f54b532e 100644 --- a/tests/installation/test_installer.py +++ b/tests/installation/test_installer.py @@ -25,8 +25,8 @@ from poetry.installation.executor import Executor as BaseExecutor from poetry.installation.noop_installer import NoopInstaller from poetry.packages import Locker as BaseLocker -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool from poetry.repositories.installed_repository import InstalledRepository from poetry.utils.env import MockEnv from poetry.utils.env import NullEnv @@ -156,8 +156,8 @@ def repo() -> Repository: @pytest.fixture() -def pool(repo: Repository) -> Pool: - pool = Pool() +def pool(repo: Repository) -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(repo) return pool @@ -181,7 +181,7 @@ def env() -> NullEnv: @pytest.fixture() def installer( package: ProjectPackage, - pool: Pool, + pool: RepositoryPool, locker: Locker, env: NullEnv, installed: CustomInstalledRepository, @@ -1152,7 +1152,7 @@ def test_installer_with_pypi_repository( installed: CustomInstalledRepository, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -1911,7 +1911,7 @@ def test_installer_required_extras_should_not_be_removed_when_updating_single_de package: ProjectPackage, installed: CustomInstalledRepository, env: NullEnv, - pool: Pool, + pool: RepositoryPool, config: Config, ): package.add_dependency(Factory.create_dependency("A", {"version": "^1.0"})) @@ -1982,7 +1982,7 @@ def test_installer_required_extras_should_not_be_removed_when_updating_single_de ): mocker.patch("sys.platform", "darwin") - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -2043,7 +2043,7 @@ def test_installer_required_extras_should_be_installed( env: NullEnv, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -2185,7 +2185,7 @@ def test_installer_can_install_dependencies_from_forced_source( Factory.create_dependency("tomlkit", {"version": "^0.5", "source": "legacy"}) ) - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockLegacyRepository()) pool.add_repository(MockRepository()) @@ -2228,7 +2228,7 @@ def test_run_installs_with_url_file( @pytest.mark.parametrize("env_platform", ["linux", "win32"]) def test_run_installs_with_same_version_url_files( - pool: Pool, + pool: RepositoryPool, locker: Locker, installed: CustomInstalledRepository, config: Config, @@ -2313,7 +2313,7 @@ def test_installer_can_handle_old_lock_files( installed: CustomInstalledRepository, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) package.add_dependency(Factory.create_dependency("pytest", "^3.5", groups=["dev"])) diff --git a/tests/installation/test_installer_old.py b/tests/installation/test_installer_old.py index 3c7fe7f2e6f..26dd19f6925 100644 --- a/tests/installation/test_installer_old.py +++ b/tests/installation/test_installer_old.py @@ -15,8 +15,8 @@ from poetry.installation import Installer as BaseInstaller from poetry.installation.noop_installer import NoopInstaller from poetry.packages import Locker as BaseLocker -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool from poetry.repositories.installed_repository import InstalledRepository from poetry.utils.env import MockEnv from poetry.utils.env import NullEnv @@ -108,8 +108,8 @@ def repo() -> Repository: @pytest.fixture() -def pool(repo: Repository) -> Pool: - pool = Pool() +def pool(repo: Repository) -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(repo) return pool @@ -133,7 +133,7 @@ def env() -> NullEnv: @pytest.fixture() def installer( package: ProjectPackage, - pool: Pool, + pool: RepositoryPool, locker: Locker, env: NullEnv, installed: CustomInstalledRepository, @@ -820,7 +820,7 @@ def test_installer_with_pypi_repository( installed: CustomInstalledRepository, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -1567,7 +1567,7 @@ def test_installer_required_extras_should_not_be_removed_when_updating_single_de package: ProjectPackage, installed: CustomInstalledRepository, env: NullEnv, - pool: Pool, + pool: RepositoryPool, config: Config, ): package.add_dependency(Factory.create_dependency("A", {"version": "^1.0"})) @@ -1630,7 +1630,7 @@ def test_installer_required_extras_should_not_be_removed_when_updating_single_de ): mocker.patch("sys.platform", "darwin") - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -1675,7 +1675,7 @@ def test_installer_required_extras_should_be_installed( env: NullEnv, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) installer = Installer( @@ -1801,7 +1801,7 @@ def test_installer_can_install_dependencies_from_forced_source( Factory.create_dependency("tomlkit", {"version": "^0.5", "source": "legacy"}) ) - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockLegacyRepository()) pool.add_repository(MockRepository()) @@ -1871,7 +1871,7 @@ def test_installer_can_handle_old_lock_files( installed: CustomInstalledRepository, config: Config, ): - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockRepository()) package.add_dependency(Factory.create_dependency("pytest", "^3.5", groups=["dev"])) diff --git a/tests/installation/test_pip_installer.py b/tests/installation/test_pip_installer.py index eab8303cba3..117a45d40db 100644 --- a/tests/installation/test_pip_installer.py +++ b/tests/installation/test_pip_installer.py @@ -13,7 +13,7 @@ from poetry.installation.pip_installer import PipInstaller from poetry.repositories.legacy_repository import LegacyRepository -from poetry.repositories.pool import Pool +from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.authenticator import RepositoryCertificateConfig from poetry.utils.env import NullEnv @@ -53,12 +53,12 @@ def package_git_with_subdirectory() -> Package: @pytest.fixture -def pool() -> Pool: - return Pool() +def pool() -> RepositoryPool: + return RepositoryPool() @pytest.fixture -def installer(pool: Pool) -> PipInstaller: +def installer(pool: RepositoryPool) -> PipInstaller: return PipInstaller(NullEnv(), NullIO(), pool) @@ -84,7 +84,7 @@ def test_requirement(installer: PipInstaller): def test_requirement_source_type_url(): - installer = PipInstaller(NullEnv(), NullIO(), Pool()) + installer = PipInstaller(NullEnv(), NullIO(), RepositoryPool()) foo = Package( "foo", @@ -100,7 +100,7 @@ def test_requirement_source_type_url(): def test_requirement_git_subdirectory( - pool: Pool, package_git_with_subdirectory: Package + pool: RepositoryPool, package_git_with_subdirectory: Package ) -> None: null_env = NullEnv() installer = PipInstaller(null_env, NullIO(), pool) @@ -125,7 +125,9 @@ def test_requirement_git_develop_false(installer: PipInstaller, package_git: Pac assert result == expected -def test_install_with_non_pypi_default_repository(pool: Pool, installer: PipInstaller): +def test_install_with_non_pypi_default_repository( + pool: RepositoryPool, installer: PipInstaller +): default = LegacyRepository("default", "https://default.com") another = LegacyRepository("another", "https://another.com") @@ -166,7 +168,7 @@ def test_install_with_certs(mocker: MockerFixture, key: str, option: str): ) default = LegacyRepository("default", "https://foo.bar") - pool = Pool() + pool = RepositoryPool() pool.add_repository(default, default=True) null_env = NullEnv() @@ -200,7 +202,7 @@ def test_requirement_git_develop_true(installer: PipInstaller, package_git: Pack def test_uninstall_git_package_nspkg_pth_cleanup( - mocker: MockerFixture, tmp_venv: VirtualEnv, pool: Pool + mocker: MockerFixture, tmp_venv: VirtualEnv, pool: RepositoryPool ): # this test scenario requires a real installation using the pip installer installer = PipInstaller(tmp_venv, NullIO(), pool) @@ -244,7 +246,7 @@ def test_install_with_trusted_host(config: Config): config.merge({"certificates": {"default": {"cert": False}}}) default = LegacyRepository("default", "https://foo.bar") - pool = Pool() + pool = RepositoryPool() pool.add_repository(default, default=True) null_env = NullEnv() @@ -269,7 +271,7 @@ def test_install_with_trusted_host(config: Config): def test_install_directory_fallback_on_poetry_create_error( - mocker: MockerFixture, tmp_venv: VirtualEnv, pool: Pool + mocker: MockerFixture, tmp_venv: VirtualEnv, pool: RepositoryPool ): mock_create_poetry = mocker.patch( "poetry.factory.Factory.create_poetry", side_effect=RuntimeError diff --git a/tests/mixology/version_solver/conftest.py b/tests/mixology/version_solver/conftest.py index 453cc004399..33bb6a3a724 100644 --- a/tests/mixology/version_solver/conftest.py +++ b/tests/mixology/version_solver/conftest.py @@ -8,8 +8,8 @@ from poetry.core.packages.project_package import ProjectPackage from poetry.puzzle.provider import Provider as BaseProvider -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool if TYPE_CHECKING: @@ -28,8 +28,8 @@ def repo() -> Repository: @pytest.fixture -def pool(repo: TestRepository) -> Pool: - pool = Pool() +def pool(repo: TestRepository) -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(repo) return pool @@ -41,5 +41,5 @@ def root() -> ProjectPackage: @pytest.fixture -def provider(pool: Pool, root: ProjectPackage) -> Provider: +def provider(pool: RepositoryPool, root: ProjectPackage) -> Provider: return Provider(root, pool, NullIO()) diff --git a/tests/mixology/version_solver/test_with_lock.py b/tests/mixology/version_solver/test_with_lock.py index caa7790f856..79f428491ae 100644 --- a/tests/mixology/version_solver/test_with_lock.py +++ b/tests/mixology/version_solver/test_with_lock.py @@ -16,12 +16,12 @@ if TYPE_CHECKING: from poetry.core.packages.project_package import ProjectPackage - from poetry.repositories import Pool from poetry.repositories import Repository + from poetry.repositories import RepositoryPool def test_with_compatible_locked_dependencies( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "*")) @@ -43,7 +43,7 @@ def test_with_compatible_locked_dependencies( def test_with_incompatible_locked_dependencies( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", ">1.0.1")) @@ -65,7 +65,7 @@ def test_with_incompatible_locked_dependencies( def test_with_unrelated_locked_dependencies( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "*")) @@ -88,7 +88,7 @@ def test_with_unrelated_locked_dependencies( def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_satisfied( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "*")) root.add_dependency(Factory.create_dependency("newdep", "2.0.0")) @@ -125,7 +125,7 @@ def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_sa def test_with_compatible_locked_dependencies_use_latest( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "*")) root.add_dependency(Factory.create_dependency("baz", "*")) @@ -155,7 +155,7 @@ def test_with_compatible_locked_dependencies_use_latest( def test_with_compatible_locked_dependencies_with_extras( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "^1.0")) @@ -189,7 +189,7 @@ def test_with_compatible_locked_dependencies_with_extras( def test_with_yanked_package_in_lock( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "*")) @@ -218,7 +218,7 @@ def test_with_yanked_package_in_lock( def test_no_update_is_respected_for_legacy_repository( - root: ProjectPackage, repo: Repository, pool: Pool + root: ProjectPackage, repo: Repository, pool: RepositoryPool ): root.add_dependency(Factory.create_dependency("foo", "^1.0")) diff --git a/tests/puzzle/test_provider.py b/tests/puzzle/test_provider.py index 753a0fcbcb4..a5126a47337 100644 --- a/tests/puzzle/test_provider.py +++ b/tests/puzzle/test_provider.py @@ -19,8 +19,8 @@ from poetry.inspection.info import PackageInfo from poetry.packages import DependencyPackage from poetry.puzzle.provider import Provider -from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository +from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import EnvCommandError from poetry.utils.env import MockEnv as BaseMockEnv from tests.helpers import get_dependency @@ -49,15 +49,15 @@ def repository() -> Repository: @pytest.fixture -def pool(repository: Repository) -> Pool: - pool = Pool() +def pool(repository: Repository) -> RepositoryPool: + pool = RepositoryPool() pool.add_repository(repository) return pool @pytest.fixture -def provider(root: ProjectPackage, pool: Pool) -> Provider: +def provider(root: ProjectPackage, pool: RepositoryPool) -> Provider: return Provider(root, pool, NullIO()) diff --git a/tests/puzzle/test_solver.py b/tests/puzzle/test_solver.py index 601151eab16..d55ea5b2915 100644 --- a/tests/puzzle/test_solver.py +++ b/tests/puzzle/test_solver.py @@ -19,8 +19,8 @@ from poetry.packages import DependencyPackage from poetry.puzzle import Solver from poetry.puzzle.exceptions import SolverProblemError -from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository +from poetry.repositories.repository_pool import RepositoryPool from poetry.utils.env import MockEnv from tests.helpers import MOCK_DEFAULT_GIT_REVISION from tests.helpers import get_dependency @@ -67,12 +67,12 @@ def repo() -> Repository: @pytest.fixture() -def pool(repo: Repository) -> Pool: - return Pool([repo]) +def pool(repo: Repository) -> RepositoryPool: + return RepositoryPool([repo]) @pytest.fixture() -def solver(package: ProjectPackage, pool: Pool, io: NullIO) -> Solver: +def solver(package: ProjectPackage, pool: RepositoryPool, io: NullIO) -> Solver: return Solver(package, pool, [], [], io) @@ -123,7 +123,7 @@ def test_solver_install_single( def test_solver_remove_if_no_longer_locked( - package: ProjectPackage, pool: Pool, io: NullIO + package: ProjectPackage, pool: RepositoryPool, io: NullIO ): package_a = get_package("A", "1.0") @@ -134,7 +134,7 @@ def test_solver_remove_if_no_longer_locked( def test_remove_non_installed( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package_a = get_package("A", "1.0") repo.add_package(package_a) @@ -158,7 +158,7 @@ def test_install_non_existing_package_fail( def test_install_unpublished_package_does_not_fail( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency(Factory.create_dependency("B", "1")) @@ -270,7 +270,7 @@ def test_install_with_deps_in_order( def test_install_installed( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency(Factory.create_dependency("A", "*")) @@ -286,7 +286,7 @@ def test_install_installed( def test_update_installed( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency(Factory.create_dependency("A", "*")) @@ -304,7 +304,7 @@ def test_update_installed( def test_update_with_use_latest( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("B", "*")) @@ -757,7 +757,7 @@ def test_solver_finds_extras_next_to_non_extras( def test_solver_merge_extras_into_base_package_multiple_repos_fixes_5727( - solver: Solver, repo: Repository, pool: Pool, package: ProjectPackage + solver: Solver, repo: Repository, pool: RepositoryPool, package: ProjectPackage ): package.add_dependency( Factory.create_dependency("A", {"version": "*", "source": "legacy"}) @@ -2094,7 +2094,7 @@ def test_solver_ignores_dependencies_with_incompatible_python_full_version_marke def test_solver_git_dependencies_update( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): pendulum = get_package("pendulum", "2.0.3") cleo = get_package("cleo", "1.0.0") @@ -2143,7 +2143,7 @@ def test_solver_git_dependencies_update( def test_solver_git_dependencies_update_skipped( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): pendulum = get_package("pendulum", "2.0.3") cleo = get_package("cleo", "1.0.0") @@ -2176,7 +2176,7 @@ def test_solver_git_dependencies_update_skipped( def test_solver_git_dependencies_short_hash_update_skipped( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): pendulum = get_package("pendulum", "2.0.3") cleo = get_package("cleo", "1.0.0") @@ -2257,7 +2257,7 @@ def test_solver_can_resolve_directory_dependencies( def test_solver_can_resolve_directory_dependencies_nested_editable( repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, ): base = Path(__file__).parent.parent / "fixtures" / "project_with_nested_local" @@ -2499,7 +2499,7 @@ def test_solver_can_solve_with_legacy_repository_using_proper_dists( package: ProjectPackage, io: NullIO ): repo = MockLegacyRepository() - pool = Pool([repo]) + pool = RepositoryPool([repo]) solver = Solver(package, pool, [], [], io) @@ -2544,7 +2544,7 @@ def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_ package.python_versions = "^3.7" repo = MockLegacyRepository() - pool = Pool([repo]) + pool = RepositoryPool([repo]) solver = Solver(package, pool, [], [], io) @@ -2573,7 +2573,7 @@ def test_solver_skips_invalid_versions(package: ProjectPackage, io: NullIO): package.python_versions = "^3.7" repo = MockPyPIRepository() - pool = Pool([repo]) + pool = RepositoryPool([repo]) solver = Solver(package, pool, [], [], io) @@ -2617,7 +2617,7 @@ def test_solver_chooses_most_recent_version_amongst_repositories( package.add_dependency(Factory.create_dependency("tomlkit", {"version": "^0.5"})) repo = MockLegacyRepository() - pool = Pool([repo, MockPyPIRepository()]) + pool = RepositoryPool([repo, MockPyPIRepository()]) solver = Solver(package, pool, [], [], io) @@ -2640,7 +2640,7 @@ def test_solver_chooses_from_correct_repository_if_forced( ) repo = MockLegacyRepository() - pool = Pool([repo, MockPyPIRepository()]) + pool = RepositoryPool([repo, MockPyPIRepository()]) solver = Solver(package, pool, [], [], io) @@ -2679,7 +2679,7 @@ def test_solver_chooses_from_correct_repository_if_forced_and_transitive_depende foo = get_package("foo", "1.0.0") foo.add_dependency(Factory.create_dependency("tomlkit", "^0.5.0")) repo.add_package(foo) - pool = Pool([MockLegacyRepository(), repo, MockPyPIRepository()]) + pool = RepositoryPool([MockLegacyRepository(), repo, MockPyPIRepository()]) solver = Solver(package, pool, [], [], io) @@ -2714,7 +2714,7 @@ def test_solver_does_not_choose_from_secondary_repository_by_default( package.python_versions = "^3.7" package.add_dependency(Factory.create_dependency("clikit", {"version": "^0.2.0"})) - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockPyPIRepository(), secondary=True) pool.add_repository(MockLegacyRepository()) @@ -2764,7 +2764,7 @@ def test_solver_chooses_from_secondary_if_explicit( Factory.create_dependency("clikit", {"version": "^0.2.0", "source": "PyPI"}) ) - pool = Pool() + pool = RepositoryPool() pool.add_repository(MockPyPIRepository(), secondary=True) pool.add_repository(MockLegacyRepository()) @@ -2800,7 +2800,7 @@ def test_solver_chooses_from_secondary_if_explicit( def test_solver_discards_packages_with_empty_markers( package: ProjectPackage, repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, ): package.python_versions = "~2.7 || ^3.4" @@ -2902,7 +2902,7 @@ def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras( def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies( package: ProjectPackage, repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, ): package.add_dependency( @@ -2995,7 +2995,9 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies( ) -def test_solver_synchronize_single(package: ProjectPackage, pool: Pool, io: NullIO): +def test_solver_synchronize_single( + package: ProjectPackage, pool: RepositoryPool, io: NullIO +): package_a = get_package("a", "1.0") solver = Solver(package, pool, [package_a], [], io) @@ -3009,7 +3011,7 @@ def test_solver_synchronize_single(package: ProjectPackage, pool: Pool, io: Null @pytest.mark.skip(reason="Poetry no longer has critical package requirements") def test_solver_with_synchronization_keeps_critical_package( package: ProjectPackage, - pool: Pool, + pool: RepositoryPool, io: NullIO, ): package_pip = get_package("setuptools", "1.0") @@ -3140,7 +3142,7 @@ def test_solver_cannot_choose_another_version_for_url_dependencies( def test_solver_should_not_update_same_version_packages_if_installed_has_no_source_type( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency(Factory.create_dependency("foo", "1.0.0")) @@ -3330,7 +3332,7 @@ def test_solver_can_resolve_for_packages_with_missing_extras( def test_solver_can_resolve_python_restricted_package_dependencies( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): package.add_dependency( Factory.create_dependency("futures", {"version": "^3.3.0", "python": "~2.7"}) @@ -3414,7 +3416,7 @@ def test_solver_should_not_raise_errors_for_irrelevant_transitive_python_constra def test_solver_keeps_multiple_locked_dependencies_for_same_package( package: ProjectPackage, repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, is_locked: bool, ): @@ -3468,7 +3470,7 @@ def test_solver_keeps_multiple_locked_dependencies_for_same_package( def test_solver_does_not_update_ref_of_locked_vcs_package( package: ProjectPackage, repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, is_locked: bool, ): @@ -3524,7 +3526,7 @@ def test_solver_does_not_update_ref_of_locked_vcs_package( def test_solver_does_not_fetch_locked_vcs_package_with_ref( package: ProjectPackage, repo: Repository, - pool: Pool, + pool: RepositoryPool, io: NullIO, mocker: MockerFixture, ): @@ -3660,7 +3662,7 @@ def test_solver_incompatible_dependency_with_and_without_extras( def test_update_with_prerelease_and_no_solution( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO + package: ProjectPackage, repo: Repository, pool: RepositoryPool, io: NullIO ): # Locked and installed: cleo which depends on an old version of crashtest. cleo = get_package("cleo", "1.0.0a5") @@ -3689,7 +3691,7 @@ def test_update_with_prerelease_and_no_solution( def test_solver_yanked_warning( package: ProjectPackage, - pool: Pool, + pool: RepositoryPool, repo: Repository, ) -> None: package.add_dependency(Factory.create_dependency("foo", "==1")) @@ -3728,7 +3730,11 @@ def test_solver_yanked_warning( @pytest.mark.parametrize("is_locked", [False, True]) def test_update_with_use_latest_vs_lock( - package: ProjectPackage, repo: Repository, pool: Pool, io: NullIO, is_locked: bool + package: ProjectPackage, + repo: Repository, + pool: RepositoryPool, + io: NullIO, + is_locked: bool, ): """ A1 depends on B2, A2 and A3 depend on B1. Same for C. diff --git a/tests/repositories/test_pool.py b/tests/repositories/test_repository_pool.py similarity index 91% rename from tests/repositories/test_pool.py rename to tests/repositories/test_repository_pool.py index dc68bf0015b..ccc0e269224 100644 --- a/tests/repositories/test_pool.py +++ b/tests/repositories/test_repository_pool.py @@ -4,8 +4,8 @@ from poetry.core.constraints.version import Version -from poetry.repositories import Pool from poetry.repositories import Repository +from poetry.repositories import RepositoryPool from poetry.repositories.exceptions import PackageNotFound from poetry.repositories.legacy_repository import LegacyRepository from tests.helpers import get_dependency @@ -13,7 +13,7 @@ def test_pool() -> None: - pool = Pool() + pool = RepositoryPool() assert len(pool.repositories) == 0 assert not pool.has_default() @@ -22,7 +22,7 @@ def test_pool() -> None: def test_pool_with_initial_repositories() -> None: repo = Repository("repo") - pool = Pool([repo]) + pool = RepositoryPool([repo]) assert len(pool.repositories) == 1 assert not pool.has_default() @@ -30,7 +30,7 @@ def test_pool_with_initial_repositories() -> None: def test_repository_no_repository() -> None: - pool = Pool() + pool = RepositoryPool() with pytest.raises(IndexError): pool.repository("foo") @@ -41,15 +41,15 @@ def test_adding_repositories_with_same_name_twice_raises_value_error() -> None: repo2 = Repository("repo") with pytest.raises(ValueError): - Pool([repo1, repo2]) + RepositoryPool([repo1, repo2]) with pytest.raises(ValueError): - Pool([repo1]).add_repository(repo2) + RepositoryPool([repo1]).add_repository(repo2) def test_repository_from_normal_pool() -> None: repo = LegacyRepository("foo", "https://foo.bar") - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo) assert pool.repository("foo") is repo @@ -57,7 +57,7 @@ def test_repository_from_normal_pool() -> None: def test_repository_from_secondary_pool() -> None: repo = LegacyRepository("foo", "https://foo.bar") - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo, secondary=True) assert pool.repository("foo") is repo @@ -69,7 +69,7 @@ def test_repository_with_normal_default_and_secondary_repositories() -> None: repo1 = LegacyRepository("foo", "https://foo.bar") repo2 = LegacyRepository("bar", "https://bar.baz") - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo1) pool.add_repository(secondary, secondary=True) pool.add_repository(repo2) @@ -84,7 +84,7 @@ def test_repository_with_normal_default_and_secondary_repositories() -> None: def test_remove_non_existing_repository_raises_indexerror() -> None: - pool = Pool() + pool = RepositoryPool() with pytest.raises(IndexError): pool.remove_repository("foo") @@ -95,7 +95,7 @@ def test_remove_existing_repository_successful() -> None: repo2 = LegacyRepository("bar", "https://bar.baz") repo3 = LegacyRepository("baz", "https://baz.quux") - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo1) pool.add_repository(repo2) pool.add_repository(repo3) @@ -112,7 +112,7 @@ def test_remove_default_repository() -> None: repo2 = LegacyRepository("bar", "https://bar.baz") new_default = LegacyRepository("new_default", "https://new.default.com") - pool = Pool() + pool = RepositoryPool() pool.add_repository(repo1) pool.add_repository(repo2) pool.add_repository(default, default=True) @@ -140,7 +140,7 @@ def test_repository_ordering() -> None: secondary2 = LegacyRepository("secondary2", "https://secondary2.com") secondary3 = LegacyRepository("secondary3", "https://secondary3.com") - pool = Pool() + pool = RepositoryPool() pool.add_repository(secondary1, secondary=True) pool.add_repository(primary1) pool.add_repository(default1, default=True) @@ -163,7 +163,7 @@ def test_pool_get_package_in_any_repository() -> None: repo1 = Repository("repo1", [package1]) package2 = get_package("bar", "1.0.0") repo2 = Repository("repo2", [package1, package2]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) returned_package1 = pool.package("foo", Version.parse("1.0.0")) returned_package2 = pool.package("bar", Version.parse("1.0.0")) @@ -176,7 +176,7 @@ def test_pool_get_package_in_specified_repository() -> None: package = get_package("foo", "1.0.0") repo1 = Repository("repo1") repo2 = Repository("repo2", [package]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) returned_package = pool.package( "foo", Version.parse("1.0.0"), repository_name="repo2" @@ -186,7 +186,7 @@ def test_pool_get_package_in_specified_repository() -> None: def test_pool_no_package_from_any_repository_raises_package_not_found() -> None: - pool = Pool() + pool = RepositoryPool() pool.add_repository(Repository("repo")) with pytest.raises(PackageNotFound): @@ -197,7 +197,7 @@ def test_pool_no_package_from_specified_repository_raises_package_not_found() -> package = get_package("foo", "1.0.0") repo1 = Repository("repo1") repo2 = Repository("repo2", [package]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) with pytest.raises(PackageNotFound): pool.package("foo", Version.parse("1.0.0"), repository_name="repo1") @@ -210,7 +210,7 @@ def test_pool_find_packages_in_any_repository() -> None: package4 = get_package("bar", "1.2.3") repo1 = Repository("repo1", [package1, package3]) repo2 = Repository("repo2", [package1, package2, package4]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) available_dependency = get_dependency("foo", "^1.0.0") returned_packages_available = pool.find_packages(available_dependency) @@ -228,7 +228,7 @@ def test_pool_find_packages_in_specified_repository() -> None: package_bar = get_package("bar", "1.2.3") repo1 = Repository("repo1", [package_foo1, package_foo3]) repo2 = Repository("repo2", [package_foo1, package_foo2, package_bar]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) available_dependency = get_dependency("foo", "^1.0.0") available_dependency.source_name = "repo2" @@ -247,7 +247,7 @@ def test_search_no_legacy_repositories() -> None: package_foobar = get_package("foobar", "1.0.0") repo1 = Repository("repo1", [package_foo1, package_foo2]) repo2 = Repository("repo2", [package_foo1, package_foobar]) - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) assert pool.search("foo") == [ package_foo1, @@ -263,6 +263,6 @@ def test_search_legacy_repositories_are_skipped() -> None: package = get_package("foo", "1.0.0") repo1 = Repository("repo1", [package]) repo2 = LegacyRepository("repo2", "https://fake.repo/") - pool = Pool([repo1, repo2]) + pool = RepositoryPool([repo1, repo2]) assert pool.search("foo") == [package]