Commit b1b3ce90 by Randy Döring

installer: support for duplicate direct origin dependencies with same version

parent 801a549a
......@@ -12,6 +12,7 @@ from poetry.installation.pip_installer import PipInstaller
from poetry.repositories import Pool
from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.lockfile_repository import LockfileRepository
from poetry.utils.extras import get_extra_package_names
from poetry.utils.helpers import canonicalize_name
from poetry.utils.helpers import pluralize
......@@ -107,9 +108,7 @@ class Installer:
self._write_lock = False
self._execute_operations = False
local_repo = Repository()
return self._do_install(local_repo)
return self._do_install()
def dry_run(self, dry_run: bool = True) -> Installer:
self._dry_run = dry_run
......@@ -204,14 +203,14 @@ class Installer:
):
ops = solver.solve(use_latest=[]).calculate_operations()
local_repo = Repository()
self._populate_local_repo(local_repo, ops)
lockfile_repo = LockfileRepository()
self._populate_lockfile_repo(lockfile_repo, ops)
self._write_lock_file(local_repo, force=True)
self._write_lock_file(lockfile_repo, force=True)
return 0
def _do_install(self, local_repo: Repository) -> int:
def _do_install(self) -> int:
from poetry.puzzle.solver import Solver
locked_repository = Repository()
......@@ -266,10 +265,11 @@ class Installer:
# currently installed
ops = self._get_operations_from_lock(locked_repository)
self._populate_local_repo(local_repo, ops)
lockfile_repo = LockfileRepository()
self._populate_lockfile_repo(lockfile_repo, ops)
if self._update:
self._write_lock_file(local_repo)
self._write_lock_file(lockfile_repo)
if self._lock:
# If we are only in lock mode, no need to go any further
......@@ -292,8 +292,8 @@ class Installer:
# Making a new repo containing the packages
# newly resolved and the ones from the current lock file
repo = Repository()
for package in local_repo.packages + locked_repository.packages:
if not repo.has_package(package):
for package in lockfile_repo.packages + locked_repository.packages:
if not package.is_direct_origin() and not repo.has_package(package):
repo.add_package(package)
pool.add_repository(repo)
......@@ -318,7 +318,7 @@ class Installer:
transaction = Transaction(
locked_repository.packages,
[(package, 0) for package in local_repo.packages],
[(package, 0) for package in lockfile_repo.packages],
installed_packages=self._installed_repository.packages,
root_package=root,
)
......@@ -332,12 +332,12 @@ class Installer:
# We need to filter operations so that packages
# not compatible with the current system,
# or optional and not requested, are dropped
self._filter_operations(ops, local_repo)
self._filter_operations(ops, lockfile_repo)
# Execute operations
return self._execute(ops)
def _write_lock_file(self, repo: Repository, force: bool = False) -> None:
def _write_lock_file(self, repo: LockfileRepository, force: bool = False) -> None:
if self._write_lock and (force or self._update):
updated_lock = self._locker.set_lock_data(self._package, repo.packages)
......@@ -460,8 +460,8 @@ class Installer:
self._installer.remove(operation.package)
def _populate_local_repo(
self, local_repo: Repository, ops: Sequence[Operation]
def _populate_lockfile_repo(
self, repo: LockfileRepository, ops: Sequence[Operation]
) -> None:
for op in ops:
if isinstance(op, Uninstall):
......@@ -471,8 +471,8 @@ class Installer:
else:
package = op.package
if not local_repo.has_package(package):
local_repo.add_package(package)
if not repo.has_package(package):
repo.add_package(package)
def _get_operations_from_lock(
self, locked_repository: Repository
......
[[package]]
name = "demo"
version = "0.1.0"
description = ""
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.source]
type = "url"
url = "https://python-poetry.org/distributions/demo-0.1.0-py2.py3-none-any.whl"
[package.dependencies]
pendulum = ">=1.4.4"
[package.extras]
bar = ["tomlkit"]
foo = ["cleo"]
[[package]]
name = "demo"
version = "0.1.0"
description = ""
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.source]
type = "url"
url = "https://python-poetry.org/distributions/demo-0.1.0.tar.gz"
[package.dependencies]
pendulum = ">=1.4.4"
[package.extras]
bar = ["tomlkit"]
foo = ["cleo"]
[[package]]
name = "pendulum"
version = "1.4.4"
description = ""
category = "main"
optional = false
python-versions = "*"
[metadata]
python-versions = "*"
lock-version = "1.1"
content-hash = "123456789"
[metadata.files]
demo = []
pendulum = []
......@@ -2231,6 +2231,56 @@ def test_run_installs_with_url_file(
assert installer.executor.installations_count == 2
@pytest.mark.parametrize("env_platform", ["linux", "win32"])
def test_run_installs_with_same_version_url_files(
pool: Pool,
locker: Locker,
installed: CustomInstalledRepository,
config: Config,
repo: Repository,
package: ProjectPackage,
env_platform: str,
) -> None:
urls = {
"linux": "https://python-poetry.org/distributions/demo-0.1.0.tar.gz",
"win32": (
"https://python-poetry.org/distributions/demo-0.1.0-py2.py3-none-any.whl"
),
}
for platform, url in urls.items():
package.add_dependency(
Factory.create_dependency(
"demo",
{"url": url, "markers": f"sys_platform == '{platform}'"},
)
)
repo.add_package(get_package("pendulum", "1.4.4"))
installer = Installer(
NullIO(),
MockEnv(platform=env_platform),
package,
locker,
pool,
config,
installed=installed,
executor=Executor(
MockEnv(platform=env_platform),
pool,
config,
NullIO(),
),
)
installer.use_executor(True)
installer.run()
expected = fixture("with-same-version-url-dependencies")
assert locker.written_data == expected
assert installer.executor.installations_count == 2
demo_package = next(p for p in installer.executor.installations if p.name == "demo")
assert demo_package.source_url == urls[env_platform]
def test_installer_uses_prereleases_if_they_are_compatible(
installer: Installer, locker: Locker, package: ProjectPackage, repo: Repository
):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment