Commit ea8fb8c6 by Sébastien Eustace

Improve package operations management

parent df77c800
......@@ -163,11 +163,19 @@ The `--dev-only` option is now deprecated. You should use the `--only dev` notat
See [Dependency groups]({{< relref "managing-dependencies#dependency-groups" >}}) for more information
about dependency groups.
If you want to remove old dependencies no longer present in the lock file, use the
`--remove-untracked` option.
If you want to synchronize your environment – and ensure it matches the lock file – use the
`--sync` option.
```bash
poetry install --remove-untracked
poetry install --sync
```
The `--sync` can be combined with group-related options:
```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev
```
You can also specify the extras you want installed
......@@ -204,12 +212,14 @@ option is used.
* `--with`: The optional dependency groups to include for installation.
* `--only`: The only dependency groups to install.
* `--default`: Only install the default dependencies.
* `--no-dev`: Do not install dev dependencies. (**Deprecated**)
* `--dev-only`: Only install dev dependencies. (**Deprecated**)
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
* `--no-root`: Do not install the root package (your project).
* `--dry-run`: Output the operations but do not execute anything (implicitly enables --verbose).
* `--remove-untracked`: Remove dependencies not presented in the lock file
* `--extras (-E)`: Features to install (multiple values allowed).
* `--no-dev`: Do not install dev dependencies. (**Deprecated**)
* `--dev-only`: Only install dev dependencies. (**Deprecated**)
* `--remove-untracked`: Remove dependencies not presented in the lock file. (**Deprecated**)
## update
......
......@@ -146,3 +146,29 @@ to remove packages from a specific group:
```bash
poetry remove mkdocs --group docs
```
## Synchronizing dependencies
Poetry supports what's called dependency synchronization. What this does is ensuring
that the locked dependencies in the `poetry.lock` file are the only ones present
in the environment, removing anything that's not necessary.
This is done by using the `--sync` option of the `install` command:
```bash
poetry install --sync
```
The `--sync` option can be combined with any [dependency groups]({{< relref "#dependency-groups" >}}) related options
to synchronize the environment with specific groups.
```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev
```
{{% note %}}
The `--sync` option replaces the `--remove-untracked` option which is now deprecated.
{{% /note %}}
......@@ -86,7 +86,7 @@ class DebugResolveCommand(InitCommand):
solver = Solver(package, pool, Repository(), Repository(), self._io)
ops = solver.solve()
ops = solver.solve().calculate_operations()
self.line("")
self.line("Resolution results:")
......@@ -123,7 +123,7 @@ class DebugResolveCommand(InitCommand):
solver = Solver(package, pool, Repository(), Repository(), NullIO())
with solver.use_environment(env):
ops = solver.solve()
ops = solver.solve().calculate_operations()
for op in ops:
if self.option("install") and op.skipped:
......
......@@ -42,6 +42,11 @@ class InstallCommand(InstallerCommand):
"Only install the development dependencies. (<warning>Deprecated</warning>)",
),
option(
"sync",
None,
"Synchronize the environment with the locked packages and the specified groups.",
),
option(
"no-root", None, "Do not install the root package (the current project)."
),
option(
......@@ -138,11 +143,20 @@ dependencies and not including the current project, run the command with the
if self.option("default"):
only_groups.append("default")
with_synchronization = self.option("sync")
if self.option("remove-untracked"):
self.line(
"<warning>The `<fg=yellow;options=bold>--remove-untracked</>` option is deprecated,"
"use the `<fg=yellow;options=bold>--sync</>` option instead.</warning>"
)
with_synchronization = True
self._installer.only_groups(only_groups)
self._installer.without_groups(excluded_groups)
self._installer.with_groups(included_groups)
self._installer.dry_run(self.option("dry-run"))
self._installer.remove_untracked(self.option("remove-untracked"))
self._installer.requires_synchronization(with_synchronization)
self._installer.verbose(self._io.is_verbose())
return_code = self._installer.run()
......
......@@ -161,7 +161,7 @@ lists all packages available."""
)
solver.provider.load_deferred(False)
with solver.use_environment(self.env):
ops = solver.solve()
ops = solver.solve().calculate_operations()
required_locked_packages = set([op.package for op in ops if not op.skipped])
......
......@@ -50,7 +50,7 @@ class Installer:
self._pool = pool
self._dry_run = False
self._remove_untracked = False
self._requires_synchronization = False
self._update = False
self._verbose = False
self._write_lock = True
......@@ -122,14 +122,13 @@ class Installer:
def is_dry_run(self) -> bool:
return self._dry_run
def remove_untracked(self, remove_untracked: bool = True) -> "Installer":
self._remove_untracked = remove_untracked
def requires_synchronization(
self, requires_synchronization: bool = True
) -> "Installer":
self._requires_synchronization = requires_synchronization
return self
def is_remove_untracked(self) -> bool:
return self._remove_untracked
def verbose(self, verbose: bool = True) -> "Installer":
self._verbose = verbose
self._executor.verbose(verbose)
......@@ -212,7 +211,7 @@ class Installer:
self._io,
)
ops = solver.solve(use_latest=[])
ops = solver.solve(use_latest=[]).calculate_operations()
local_repo = Repository()
self._populate_local_repo(local_repo, ops)
......@@ -247,10 +246,9 @@ class Installer:
self._installed_repository,
locked_repository,
self._io,
remove_untracked=self._remove_untracked,
)
ops = solver.solve(use_latest=self._whitelist)
ops = solver.solve(use_latest=self._whitelist).calculate_operations()
else:
self._io.write_line("<info>Installing dependencies from lock file</>")
......@@ -318,19 +316,35 @@ class Installer:
pool.add_repository(repo)
solver = Solver(
root,
pool,
self._installed_repository,
locked_repository,
NullIO(),
remove_untracked=self._remove_untracked,
root, pool, self._installed_repository, locked_repository, NullIO()
)
# Everything is resolved at this point, so we no longer need
# to load deferred dependencies (i.e. VCS, URL and path dependencies)
solver.provider.load_deferred(False)
with solver.use_environment(self._env):
ops = solver.solve(use_latest=self._whitelist)
ops = solver.solve(use_latest=self._whitelist).calculate_operations(
with_uninstalls=self._requires_synchronization,
synchronize=self._requires_synchronization,
)
if not self._requires_synchronization:
# If no packages synchronisation has been requested we need
# to calculate the uninstall operations
from poetry.puzzle.transaction import Transaction
transaction = Transaction(
locked_repository.packages,
[(package, 0) for package in local_repo.packages],
installed_packages=self._installed_repository.packages,
root_package=root,
)
ops = [
op
for op in transaction.calculate_operations(with_uninstalls=True)
if op.job_type == "uninstall"
] + ops
# We need to filter operations so that packages
# not compatible with the current system,
......
......@@ -16,9 +16,6 @@ from cleo.io.io import IO
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage
from poetry.installation.operations import Install
from poetry.installation.operations import Uninstall
from poetry.installation.operations import Update
from poetry.mixology import resolve_version
from poetry.mixology.failure import SolveFailure
from poetry.packages import DependencyPackage
......@@ -37,7 +34,8 @@ if TYPE_CHECKING:
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.packages.url_dependency import URLDependency
from poetry.core.packages.vcs_dependency import VCSDependency
from poetry.installation.operations import OperationTypes
from .transaction import Transaction
class Solver:
......@@ -48,7 +46,6 @@ class Solver:
installed: Repository,
locked: Repository,
io: IO,
remove_untracked: bool = False,
provider: Optional[Provider] = None,
):
self._package = package
......@@ -62,39 +59,19 @@ class Solver:
self._provider = provider
self._overrides = []
self._remove_untracked = remove_untracked
self._preserved_package_names = None
@property
def provider(self) -> Provider:
return self._provider
@property
def preserved_package_names(self):
if self._preserved_package_names is None:
self._preserved_package_names = {
self._package.name,
*Provider.UNSAFE_PACKAGES,
}
deps = {package.name for package in self._locked.packages}
# preserve pip/setuptools/wheel when not managed by poetry, this is so
# to avoid externally managed virtual environments causing unnecessary
# removals.
for name in {"pip", "wheel", "setuptools"}:
if name not in deps:
self._preserved_package_names.add(name)
return self._preserved_package_names
@contextmanager
def use_environment(self, env: Env) -> None:
with self.provider.use_environment(env):
yield
def solve(self, use_latest: List[str] = None) -> List["OperationTypes"]:
def solve(self, use_latest: List[str] = None) -> "Transaction":
from .transaction import Transaction
with self._provider.progress():
start = time.time()
packages, depths = self._solve(use_latest=use_latest)
......@@ -110,121 +87,11 @@ class Solver:
f"Resolved with overrides: {', '.join(f'({b})' for b in self._overrides)}"
)
operations = []
for i, package in enumerate(packages):
installed = False
for pkg in self._installed.packages:
if package.name == pkg.name:
installed = True
if pkg.source_type == "git" and package.source_type == "git":
from poetry.core.vcs.git import Git
# Trying to find the currently installed version
pkg_source_url = Git.normalize_url(pkg.source_url)
package_source_url = Git.normalize_url(package.source_url)
for locked in self._locked.packages:
if locked.name != pkg.name or locked.source_type != "git":
continue
locked_source_url = Git.normalize_url(locked.source_url)
if (
locked.name == pkg.name
and locked.source_type == pkg.source_type
and locked_source_url == pkg_source_url
and locked.source_reference == pkg.source_reference
and locked.source_resolved_reference
== pkg.source_resolved_reference
):
pkg = Package(
pkg.name,
locked.version,
source_type="git",
source_url=locked.source_url,
source_reference=locked.source_reference,
source_resolved_reference=locked.source_resolved_reference,
)
break
if pkg_source_url != package_source_url or (
(
not pkg.source_resolved_reference
or not package.source_resolved_reference
)
and pkg.source_reference != package.source_reference
and not pkg.source_reference.startswith(
package.source_reference
)
or (
pkg.source_resolved_reference
and package.source_resolved_reference
and pkg.source_resolved_reference
!= package.source_resolved_reference
and not pkg.source_resolved_reference.startswith(
package.source_resolved_reference
)
)
):
operations.append(Update(pkg, package, priority=depths[i]))
else:
operations.append(
Install(package).skip("Already installed")
)
elif package.version != pkg.version:
# Checking version
operations.append(Update(pkg, package, priority=depths[i]))
elif pkg.source_type and package.source_type != pkg.source_type:
operations.append(Update(pkg, package, priority=depths[i]))
else:
operations.append(
Install(package, priority=depths[i]).skip(
"Already installed"
)
)
break
if not installed:
operations.append(Install(package, priority=depths[i]))
# Checking for removals
for pkg in self._locked.packages:
remove = True
for package in packages:
if pkg.name == package.name:
remove = False
break
if remove:
skip = True
for installed in self._installed.packages:
if installed.name == pkg.name:
skip = False
break
op = Uninstall(pkg)
if skip:
op.skip("Not currently installed")
operations.append(op)
if self._remove_untracked:
locked_names = {locked.name for locked in self._locked.packages}
for installed in self._installed.packages:
if installed.name in self.preserved_package_names:
continue
if installed.name not in locked_names:
operations.append(Uninstall(installed))
return sorted(
operations,
key=lambda o: (
-o.priority,
o.package.name,
o.package.version,
),
return Transaction(
self._locked.packages,
list(zip(packages, depths)),
installed_packages=self._installed.packages,
root_package=self._package,
)
def solve_in_compatibility_mode(
......
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
from typing import Tuple
if TYPE_CHECKING:
from poetry.core.packages.package import Package
from poetry.installation.operations import OperationTypes
class Transaction:
def __init__(
self,
current_packages: List["Package"],
result_packages: List[Tuple["Package", int]],
installed_packages: Optional[List["Package"]] = None,
root_package: Optional["Package"] = None,
) -> None:
self._current_packages = current_packages
self._result_packages = result_packages
if installed_packages is None:
installed_packages = []
self._installed_packages = installed_packages
self._root_package = root_package
def calculate_operations(
self, with_uninstalls: bool = True, synchronize: bool = False
) -> List["OperationTypes"]:
from poetry.installation.operations.install import Install
from poetry.installation.operations.uninstall import Uninstall
from poetry.installation.operations.update import Update
operations = []
for result_package, priority in self._result_packages:
installed = False
for installed_package in self._installed_packages:
if result_package.name == installed_package.name:
installed = True
if result_package.version != installed_package.version:
operations.append(
Update(installed_package, result_package, priority=priority)
)
elif (
installed_package.source_type
or result_package.source_type != "legacy"
) and not result_package.is_same_package_as(installed_package):
operations.append(
Update(installed_package, result_package, priority=priority)
)
else:
operations.append(
Install(result_package).skip("Already installed")
)
break
if not installed:
operations.append(Install(result_package, priority=priority))
if with_uninstalls:
for current_package in self._current_packages:
found = False
for result_package, _ in self._result_packages:
if current_package.name == result_package.name:
found = True
break
if not found:
for installed_package in self._installed_packages:
if installed_package.name == current_package.name:
operations.append(Uninstall(current_package))
if synchronize:
current_package_names = {
current_package.name for current_package in self._current_packages
}
# We preserve pip/setuptools/wheel when not managed by poetry, this is done
# to avoid externally managed virtual environments causing unnecessary
# removals.
preserved_package_names = {
"pip",
"setuptools",
"wheel",
} - current_package_names
for installed_package in self._installed_packages:
if (
self._root_package
and installed_package.name == self._root_package.name
):
continue
if installed_package.name in preserved_package_names:
continue
if installed_package.name not in current_package_names:
operations.append(Uninstall(installed_package))
return sorted(
operations,
key=lambda o: (
-o.priority,
o.package.name,
o.package.version,
),
)
......@@ -17,3 +17,14 @@ def test_group_options_are_passed_to_the_installer(tester, mocker):
assert tester.command.installer._with_groups == ["foo", "bar"]
assert tester.command.installer._without_groups == ["baz", "bim"]
assert tester.command.installer._only_groups == ["bam"]
def test_sync_option_is_passed_to_the_installer(tester, mocker):
"""
The --sync option is passed properly to the installer.
"""
mocker.patch.object(tester.command.installer, "run", return_value=1)
tester.execute("--sync")
assert tester.command.installer._requires_synchronization
......@@ -351,7 +351,7 @@ def test_run_install_no_group(installer, locker, repo, package, installed):
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 1 == installer.executor.removals_count
assert 0 == installer.executor.removals_count
def test_run_install_group_only(installer, locker, repo, package, installed):
......@@ -362,7 +362,7 @@ def test_run_install_group_only(installer, locker, repo, package, installed):
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 2 == installer.executor.removals_count
assert 0 == installer.executor.removals_count
def test_run_install_with_optional_group_not_selected(
......@@ -376,7 +376,207 @@ def test_run_install_with_optional_group_not_selected(
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 1 == installer.executor.removals_count
assert 0 == installer.executor.removals_count
def test_run_install_does_not_remove_locked_packages_if_installed_but_not_required(
installer, locker, repo, package, installed
):
package_a = get_package("a", "1.0")
package_b = get_package("b", "1.1")
package_c = get_package("c", "1.2")
repo.add_package(package_a)
installed.add_package(package_a)
repo.add_package(package_b)
installed.add_package(package_b)
repo.add_package(package_c)
installed.add_package(package_c)
installed.add_package(package) # Root package never removed.
package.add_dependency(Factory.create_dependency(package_a.name, package_a.version))
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": package_a.name,
"version": package_a.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_b.name,
"version": package_b.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_c.name,
"version": package_c.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {package_a.name: [], package_b.name: [], package_c.name: []},
},
}
)
installer.run()
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 0 == installer.executor.removals_count
def test_run_install_removes_locked_packages_if_installed_and_synchronization_is_required(
installer, locker, repo, package, installed
):
package_a = get_package("a", "1.0")
package_b = get_package("b", "1.1")
package_c = get_package("c", "1.2")
repo.add_package(package_a)
installed.add_package(package_a)
repo.add_package(package_b)
installed.add_package(package_b)
repo.add_package(package_c)
installed.add_package(package_c)
installed.add_package(package) # Root package never removed.
package.add_dependency(Factory.create_dependency(package_a.name, package_a.version))
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": package_a.name,
"version": package_a.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_b.name,
"version": package_b.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_c.name,
"version": package_c.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {package_a.name: [], package_b.name: [], package_c.name: []},
},
}
)
installer.requires_synchronization(True)
installer.run()
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 2 == installer.executor.removals_count
def test_run_install_removes_no_longer_locked_packages_if_installed(
installer, locker, repo, package, installed
):
package_a = get_package("a", "1.0")
package_b = get_package("b", "1.1")
package_c = get_package("c", "1.2")
repo.add_package(package_a)
installed.add_package(package_a)
repo.add_package(package_b)
installed.add_package(package_b)
repo.add_package(package_c)
installed.add_package(package_c)
installed.add_package(package) # Root package never removed.
package.add_dependency(Factory.create_dependency(package_a.name, package_a.version))
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": package_a.name,
"version": package_a.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_b.name,
"version": package_b.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": package_c.name,
"version": package_c.version.text,
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {package_a.name: [], package_b.name: [], package_c.name: []},
},
}
)
installer.update(True)
installer.run()
assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 2 == installer.executor.removals_count
def test_run_install_with_optional_group_selected(
......@@ -406,7 +606,7 @@ def test_run_install_with_optional_group_selected(
)
],
)
def test_run_install_remove_untracked(
def test_run_install_with_synchronization(
managed_reserved_package_names, installer, locker, repo, package, installed
):
package_a = get_package("a", "1.0")
......@@ -462,7 +662,7 @@ def test_run_install_remove_untracked(
}
)
installer.remove_untracked(True)
installer.requires_synchronization(True)
installer.run()
assert 0 == installer.executor.installations_count
......
......@@ -293,7 +293,7 @@ def test_run_install_no_group(installer, locker, repo, package, installed):
assert len(updates) == 0
removals = installer.installer.removals
assert len(removals) == 1
assert len(removals) == 0
@pytest.mark.parametrize(
......@@ -308,7 +308,7 @@ def test_run_install_no_group(installer, locker, repo, package, installed):
)
],
)
def test_run_install_remove_untracked(
def test_run_install_with_synchronization(
managed_reserved_package_names, installer, locker, repo, package, installed
):
package_a = get_package("a", "1.0")
......@@ -364,7 +364,7 @@ def test_run_install_remove_untracked(
}
)
installer.remove_untracked(True)
installer.requires_synchronization(True)
installer.run()
installs = installer.installer.installs
......@@ -374,6 +374,7 @@ def test_run_install_remove_untracked(
assert len(updates) == 0
removals = installer.installer.removals
expected_removals = {
package_b.name,
package_c.name,
......
......@@ -67,12 +67,13 @@ def solver(package, pool, installed, locked, io):
)
def check_solver_result(ops, expected):
def check_solver_result(transaction, expected, synchronize=False):
for e in expected:
if "skipped" not in e:
e["skipped"] = False
result = []
ops = transaction.calculate_operations(synchronize=synchronize)
for op in ops:
if "update" == op.job_type:
result.append(
......@@ -92,6 +93,8 @@ def check_solver_result(ops, expected):
assert expected == result
return ops
def test_solver_install_single(solver, repo, package):
package.add_dependency(Factory.create_dependency("A", "*"))
......@@ -99,9 +102,9 @@ def test_solver_install_single(solver, repo, package):
package_a = get_package("A", "1.0")
repo.add_package(package_a)
ops = solver.solve([get_dependency("A")])
transaction = solver.solve([get_dependency("A")])
check_solver_result(ops, [{"job": "install", "package": package_a}])
check_solver_result(transaction, [{"job": "install", "package": package_a}])
def test_solver_remove_if_no_longer_locked(solver, locked, installed):
......@@ -109,9 +112,9 @@ def test_solver_remove_if_no_longer_locked(solver, locked, installed):
installed.add_package(package_a)
locked.add_package(package_a)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "remove", "package": package_a}])
check_solver_result(transaction, [{"job": "remove", "package": package_a}])
def test_remove_non_installed(solver, repo, locked):
......@@ -122,9 +125,9 @@ def test_remove_non_installed(solver, repo, locked):
request = []
ops = solver.solve(request)
transaction = solver.solve(request)
check_solver_result(ops, [{"job": "remove", "package": package_a, "skipped": True}])
check_solver_result(transaction, [])
def test_install_non_existing_package_fail(solver, repo, package):
......@@ -150,10 +153,10 @@ def test_solver_with_deps(solver, repo, package):
package_a.add_dependency(get_dependency("B", "<1.1"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
......@@ -178,10 +181,10 @@ def test_install_honours_not_equal(solver, repo, package):
package_a.add_dependency(get_dependency("B", "<=1.3,!=1.3,!=1.2"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": new_package_b11},
{"job": "install", "package": package_a},
......@@ -206,10 +209,10 @@ def test_install_with_deps_in_order(solver, repo, package):
package_c.add_dependency(get_dependency("A", ">=1.0"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_c},
......@@ -225,10 +228,10 @@ def test_install_installed(solver, repo, installed, package):
installed.add_package(package_a)
repo.add_package(package_a)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops, [{"job": "install", "package": package_a, "skipped": True}]
transaction, [{"job": "install", "package": package_a, "skipped": True}]
)
......@@ -242,10 +245,10 @@ def test_update_installed(solver, repo, installed, package):
repo.add_package(package_a)
repo.add_package(new_package_a)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops, [{"job": "update", "from": package_a, "to": new_package_a}]
transaction, [{"job": "update", "from": package_a, "to": new_package_a}]
)
......@@ -267,10 +270,10 @@ def test_update_with_use_latest(solver, repo, installed, package, locked):
locked.add_package(package_a)
locked.add_package(package_b)
ops = solver.solve(use_latest=[package_b.name])
transaction = solver.solve(use_latest=[package_b.name])
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a, "skipped": True},
{"job": "install", "package": new_package_b},
......@@ -291,10 +294,10 @@ def test_solver_sets_groups(solver, repo, package):
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_a},
......@@ -326,10 +329,10 @@ def test_solver_respects_root_package_python_versions(solver, repo, package):
repo.add_package(package_c)
repo.add_package(package_c11)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_a},
......@@ -379,10 +382,10 @@ def test_solver_solves_optional_and_compatible_packages(solver, repo, package):
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_a},
......@@ -405,10 +408,10 @@ def test_solver_does_not_return_extras_if_not_requested(solver, repo, package):
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_b},
......@@ -435,10 +438,10 @@ def test_solver_returns_extras_if_requested(solver, repo, package):
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_a},
......@@ -482,7 +485,7 @@ def test_solver_returns_extras_only_requested(solver, repo, package, enabled_ext
repo.add_package(package_c10)
repo.add_package(package_c20)
ops = solver.solve()
transaction = solver.solve()
expected = [
{"job": "install", "package": package_a},
......@@ -498,8 +501,8 @@ def test_solver_returns_extras_only_requested(solver, repo, package, enabled_ext
},
)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
expected,
)
......@@ -534,7 +537,7 @@ def test_solver_returns_extras_when_multiple_extras_use_same_dependency(
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
expected = [
{"job": "install", "package": package_b},
......@@ -544,8 +547,8 @@ def test_solver_returns_extras_when_multiple_extras_use_same_dependency(
if enabled_extra is not None:
expected.insert(0, {"job": "install", "package": package_c})
check_solver_result(
ops,
ops = check_solver_result(
transaction,
expected,
)
......@@ -587,7 +590,7 @@ def test_solver_returns_extras_only_requested_nested(
repo.add_package(package_c10)
repo.add_package(package_c20)
ops = solver.solve()
transaction = solver.solve()
expected = [
{"job": "install", "package": package_b},
......@@ -603,7 +606,7 @@ def test_solver_returns_extras_only_requested_nested(
},
)
check_solver_result(ops, expected)
ops = check_solver_result(transaction, expected)
assert ops[-1].package.marker.is_any()
assert ops[0].package.marker.is_any()
......@@ -626,10 +629,10 @@ def test_solver_returns_prereleases_if_requested(solver, repo, package):
repo.add_package(package_c)
repo.add_package(package_c_dev)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_b},
......@@ -653,10 +656,10 @@ def test_solver_does_not_return_prereleases_if_not_requested(solver, repo, packa
repo.add_package(package_c)
repo.add_package(package_c_dev)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_b},
......@@ -685,10 +688,10 @@ def test_solver_sub_dependencies_with_requirements(solver, repo, package):
repo.add_package(package_c)
repo.add_package(package_d)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_d},
{"job": "install", "package": package_c},
......@@ -743,10 +746,10 @@ def test_solver_sub_dependencies_with_requirements_complex(solver, repo, package
repo.add_package(package_e)
repo.add_package(package_f)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_e},
{"job": "install", "package": package_f},
......@@ -775,9 +778,9 @@ def test_solver_sub_dependencies_with_not_supported_python_version(
repo.add_package(package_a)
repo.add_package(package_b)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "install", "package": package_a}])
check_solver_result(transaction, [{"job": "install", "package": package_a}])
def test_solver_sub_dependencies_with_not_supported_python_version_transitive(
......@@ -812,10 +815,10 @@ def test_solver_sub_dependencies_with_not_supported_python_version_transitive(
repo.add_package(sniffio)
repo.add_package(sniffio_1_1_0)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": sniffio, "skipped": False},
{"job": "install", "package": httpcore, "skipped": False},
......@@ -854,10 +857,10 @@ def test_solver_with_dependency_in_both_default_and_dev_dependencies(
repo.add_package(package_c)
repo.add_package(package_d)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_d},
{"job": "install", "package": package_b},
......@@ -911,10 +914,10 @@ def test_solver_with_dependency_in_both_main_and_dev_dependencies_with_one_more_
repo.add_package(package_d)
repo.add_package(package_e)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_d},
......@@ -951,10 +954,10 @@ def test_solver_with_dependency_and_prerelease_sub_dependencies(solver, repo, pa
package_b = get_package("B", "1.0.0.dev4")
repo.add_package(package_b)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
......@@ -978,10 +981,10 @@ def test_solver_circular_dependency(solver, repo, package):
repo.add_package(package_b)
repo.add_package(package_c)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_b},
......@@ -1012,10 +1015,10 @@ def test_solver_circular_dependency_chain(solver, repo, package):
repo.add_package(package_c)
repo.add_package(package_d)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_d},
{"job": "install", "package": package_c},
......@@ -1041,10 +1044,10 @@ def test_solver_dense_dependencies(solver, repo, package):
for j in range(i):
package_ai.add_dependency(Factory.create_dependency("a" + str(j), "^1.0"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops, [{"job": "install", "package": packages[i]} for i in range(n)]
transaction, [{"job": "install", "package": packages[i]} for i in range(n)]
)
......@@ -1064,10 +1067,10 @@ def test_solver_duplicate_dependencies_same_constraint(solver, repo, package):
repo.add_package(package_a)
repo.add_package(package_b)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
......@@ -1093,10 +1096,10 @@ def test_solver_duplicate_dependencies_different_constraints(solver, repo, packa
repo.add_package(package_b10)
repo.add_package(package_b20)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b10},
{"job": "install", "package": package_b20},
......@@ -1157,10 +1160,10 @@ def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package):
repo.add_package(package_c12)
repo.add_package(package_c15)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_c12},
{"job": "install", "package": package_c15},
......@@ -1198,10 +1201,10 @@ def test_solver_does_not_get_stuck_in_recursion_on_circular_dependency(
package.add_dependency(Factory.create_dependency("A", "^1.0"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_b},
......@@ -1220,7 +1223,7 @@ def test_solver_can_resolve_git_dependencies(solver, repo, package):
Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"})
)
ops = solver.solve()
transaction = solver.solve()
demo = Package(
"demo",
......@@ -1231,8 +1234,8 @@ def test_solver_can_resolve_git_dependencies(solver, repo, package):
source_resolved_reference="9cf87a285a2d3fbb0b9fa621997b3acc3631ed24",
)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)
......@@ -1255,7 +1258,7 @@ def test_solver_can_resolve_git_dependencies_with_extras(solver, repo, package):
)
)
ops = solver.solve()
transaction = solver.solve()
demo = Package(
"demo",
......@@ -1267,7 +1270,7 @@ def test_solver_can_resolve_git_dependencies_with_extras(solver, repo, package):
)
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": cleo},
{"job": "install", "package": pendulum},
......@@ -1300,10 +1303,10 @@ def test_solver_can_resolve_git_dependencies_with_ref(solver, repo, package, ref
git_config.update(ref)
package.add_dependency(Factory.create_dependency("demo", git_config))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)
......@@ -1327,9 +1330,9 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir
repo.add_package(package_a)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "install", "package": package_a}])
check_solver_result(transaction, [{"job": "install", "package": package_a}])
def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible_multiple(
......@@ -1353,10 +1356,10 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir
repo.add_package(package_a)
repo.add_package(package_b)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
......@@ -1398,9 +1401,9 @@ def test_solver_finds_compatible_package_for_dependency_python_not_fully_compati
repo.add_package(package_a100)
repo.add_package(package_a101)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "install", "package": package_a100}])
check_solver_result(transaction, [{"job": "install", "package": package_a100}])
def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_only_extras(
......@@ -1427,10 +1430,10 @@ def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_onl
repo.add_package(package_b1)
repo.add_package(package_b2)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": package_b2},
{"job": "install", "package": package_a},
......@@ -1462,10 +1465,10 @@ def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies(
repo.add_package(package_b)
solver._locked = Repository([package_a])
ops = solver.solve(use_latest=[package_b.name])
transaction = solver.solve(use_latest=[package_b.name])
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_b},
......@@ -1499,10 +1502,10 @@ def test_solver_returns_extras_if_requested_in_dependencies_and_not_in_root_pack
repo.add_package(package_c)
repo.add_package(package_d)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_d},
{"job": "install", "package": package_c},
......@@ -1552,10 +1555,10 @@ def test_solver_ignores_dependencies_with_incompatible_python_full_version_marke
repo.add_package(package_b100)
repo.add_package(package_b200)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a},
{"job": "install", "package": package_b200},
......@@ -1591,10 +1594,10 @@ def test_solver_git_dependencies_update(solver, repo, package, installed):
Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"})
)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": pendulum},
{"job": "update", "from": demo_installed, "to": demo},
......@@ -1630,10 +1633,10 @@ def test_solver_git_dependencies_update_skipped(solver, repo, package, installed
Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"})
)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": pendulum},
{"job": "install", "package": demo, "skipped": True},
......@@ -1654,7 +1657,7 @@ def test_solver_git_dependencies_short_hash_update_skipped(
"0.1.2",
source_type="git",
source_url="https://github.com/demo/demo.git",
source_reference="master",
source_reference="9cf87a285a2d3fbb0b9fa621997b3acc3631ed24",
source_resolved_reference="9cf87a285a2d3fbb0b9fa621997b3acc3631ed24",
)
installed.add_package(demo)
......@@ -1665,10 +1668,10 @@ def test_solver_git_dependencies_short_hash_update_skipped(
)
)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": pendulum},
{
......@@ -1702,12 +1705,12 @@ def test_solver_can_resolve_directory_dependencies(solver, repo, package):
package.add_dependency(Factory.create_dependency("demo", {"path": path}))
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.2", source_type="directory", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)
......@@ -1730,10 +1733,10 @@ def test_solver_can_resolve_directory_dependencies_nested_editable(
package, pool, installed, locked, io, provider=Provider(package, pool, io)
)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -1792,12 +1795,12 @@ def test_solver_can_resolve_directory_dependencies_with_extras(solver, repo, pac
Factory.create_dependency("demo", {"path": path, "extras": ["foo"]})
)
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.2", source_type="directory", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": cleo},
{"job": "install", "package": pendulum},
......@@ -1826,12 +1829,12 @@ def test_solver_can_resolve_sdist_dependencies(solver, repo, package):
package.add_dependency(Factory.create_dependency("demo", {"path": path}))
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.0", source_type="file", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)
......@@ -1860,12 +1863,12 @@ def test_solver_can_resolve_sdist_dependencies_with_extras(solver, repo, package
Factory.create_dependency("demo", {"path": path, "extras": ["foo"]})
)
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.0", source_type="file", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": cleo},
{"job": "install", "package": pendulum},
......@@ -1894,12 +1897,12 @@ def test_solver_can_resolve_wheel_dependencies(solver, repo, package):
package.add_dependency(Factory.create_dependency("demo", {"path": path}))
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.0", source_type="file", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)
......@@ -1928,12 +1931,12 @@ def test_solver_can_resolve_wheel_dependencies_with_extras(solver, repo, package
Factory.create_dependency("demo", {"path": path, "extras": ["foo"]})
)
ops = solver.solve()
transaction = solver.solve()
demo = Package("demo", "0.1.0", source_type="file", source_url=path)
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{"job": "install", "package": cleo},
{"job": "install", "package": pendulum},
......@@ -1959,10 +1962,10 @@ def test_solver_can_solve_with_legacy_repository_using_proper_dists(
package.add_dependency(Factory.create_dependency("isort", "4.3.4"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -2003,10 +2006,10 @@ def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_
package.add_dependency(Factory.create_dependency("isort", "4.3.4"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{
"job": "install",
......@@ -2032,10 +2035,10 @@ def test_solver_skips_invalid_versions(package, installed, locked, io):
package.add_dependency(Factory.create_dependency("trackpy", "^0.4"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops, [{"job": "install", "package": get_package("trackpy", "0.4.1")}]
transaction, [{"job": "install", "package": get_package("trackpy", "0.4.1")}]
)
......@@ -2053,10 +2056,10 @@ def test_multiple_constraints_on_root(package, solver, repo):
repo.add_package(foo15)
repo.add_package(foo25)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[{"job": "install", "package": foo15}, {"job": "install", "package": foo25}],
)
......@@ -2072,10 +2075,10 @@ def test_solver_chooses_most_recent_version_amongst_repositories(
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops, [{"job": "install", "package": get_package("tomlkit", "0.5.3")}]
ops = check_solver_result(
transaction, [{"job": "install", "package": get_package("tomlkit", "0.5.3")}]
)
assert ops[0].package.source_type is None
......@@ -2095,10 +2098,10 @@ def test_solver_chooses_from_correct_repository_if_forced(
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -2133,10 +2136,10 @@ def test_solver_chooses_from_correct_repository_if_forced_and_transitive_depende
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -2170,10 +2173,10 @@ def test_solver_does_not_choose_from_secondary_repository_by_default(
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -2217,10 +2220,10 @@ def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, i
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
ops = check_solver_result(
transaction,
[
{
"job": "install",
......@@ -2269,10 +2272,10 @@ def test_solver_discards_packages_with_empty_markers(
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_c},
{"job": "install", "package": package_a},
......@@ -2301,10 +2304,10 @@ def test_solver_does_not_raise_conflict_for_conditional_dev_dependencies(
repo.add_package(package_a100)
repo.add_package(package_a200)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a100},
{"job": "install", "package": package_a200},
......@@ -2335,10 +2338,10 @@ def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras(
repo.add_package(requests)
repo.add_package(idna)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[{"job": "install", "package": idna}, {"job": "install", "package": requests}],
)
......@@ -2370,10 +2373,10 @@ def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies(
solver = Solver(package, pool, installed, locked, io)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": get_package("a", "1.2.3")},
{"job": "install", "package": git_package, "skipped": True},
......@@ -2396,10 +2399,10 @@ def test_ignore_python_constraint_no_overlap_dependencies(solver, repo, package)
repo.add_package(pytest)
repo.add_package(get_package("configparser", "1.2.3"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[{"job": "install", "package": pytest}],
)
......@@ -2425,10 +2428,10 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies(
repo.add_package(package_b10)
repo.add_package(package_b20)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_b10},
{"job": "install", "package": package_b20},
......@@ -2437,27 +2440,29 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies(
)
def test_solver_remove_untracked_single(package, pool, installed, locked, io):
solver = Solver(package, pool, installed, locked, io, remove_untracked=True)
def test_solver_synchronize_single(package, pool, installed, locked, io):
solver = Solver(package, pool, installed, locked, io)
package_a = get_package("a", "1.0")
installed.add_package(package_a)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "remove", "package": package_a}])
check_solver_result(
transaction, [{"job": "remove", "package": package_a}], synchronize=True
)
@pytest.mark.skip(reason="Poetry no longer has critical package requirements")
def test_solver_remove_untracked_keeps_critical_package(
def test_solver_with_synchronization_keeps_critical_package(
package, pool, installed, locked, io
):
solver = Solver(package, pool, installed, locked, io, remove_untracked=True)
solver = Solver(package, pool, installed, locked, io)
package_pip = get_package("setuptools", "1.0")
installed.add_package(package_pip)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [])
check_solver_result(transaction, [])
def test_solver_cannot_choose_another_version_for_directory_dependencies(
......@@ -2591,9 +2596,11 @@ def test_solver_should_not_update_same_version_packages_if_installed_has_no_sour
repo.add_package(foo)
installed.add_package(get_package("foo", "1.0.0"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "install", "package": foo, "skipped": True}])
check_solver_result(
transaction, [{"job": "install", "package": foo, "skipped": True}]
)
def test_solver_should_use_the_python_constraint_from_the_environment_if_available(
......@@ -2615,10 +2622,10 @@ def test_solver_should_use_the_python_constraint_from_the_environment_if_availab
repo.add_package(b)
with solver.use_environment(MockEnv((2, 7, 18))):
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[{"job": "install", "package": b}, {"job": "install", "package": a}],
)
......@@ -2658,10 +2665,10 @@ def test_solver_should_resolve_all_versions_for_multiple_duplicate_dependencies(
repo.add_package(package_b30)
repo.add_package(package_b40)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": package_a10},
{"job": "install", "package": package_a20},
......@@ -2684,9 +2691,9 @@ def test_solver_should_not_raise_errors_for_irrelevant_python_constraints(
dataclasses.python_versions = ">=3.6, <3.7"
repo.add_package(dataclasses)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(ops, [{"job": "install", "package": dataclasses}])
check_solver_result(transaction, [{"job": "install", "package": dataclasses}])
def test_solver_can_resolve_transitive_extras(solver, repo, package):
......@@ -2712,10 +2719,10 @@ def test_solver_can_resolve_transitive_extras(solver, repo, package):
repo.add_package(get_package("certifi", "2017.4.17"))
repo.add_package(get_package("pyopenssl", "0.14"))
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": get_package("certifi", "2017.4.17")},
{"job": "install", "package": get_package("pyopenssl", "0.14")},
......@@ -2748,10 +2755,10 @@ def test_solver_can_resolve_for_packages_with_missing_extras(solver, repo, packa
repo.add_package(boto3)
repo.add_package(requests)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": django},
{"job": "install", "package": requests},
......@@ -2782,10 +2789,10 @@ def test_solver_can_resolve_python_restricted_package_dependencies(
repo.add_package(futures)
repo.add_package(pre_commit)
ops = solver.solve(use_latest=["pre-commit"])
transaction = solver.solve(use_latest=["pre-commit"])
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": futures},
{"job": "install", "package": pre_commit},
......@@ -2831,10 +2838,10 @@ def test_solver_should_not_raise_errors_for_irrelevant_transitive_python_constra
repo.add_package(pre_commit)
repo.add_package(importlib_resources)
repo.add_package(importlib_resources_3_2_1)
ops = solver.solve()
transaction = solver.solve()
check_solver_result(
ops,
transaction,
[
{"job": "install", "package": importlib_resources_3_2_1},
{"job": "install", "package": pre_commit},
......
from poetry.core.packages.package import Package
from poetry.puzzle.transaction import Transaction
def check_operations(ops, expected):
for e in expected:
if "skipped" not in e:
e["skipped"] = False
result = []
for op in ops:
if "update" == op.job_type:
result.append(
{
"job": "update",
"from": op.initial_package,
"to": op.target_package,
"skipped": op.skipped,
}
)
else:
job = "install"
if op.job_type == "uninstall":
job = "remove"
result.append({"job": job, "package": op.package, "skipped": op.skipped})
assert expected == result
def test_it_should_calculate_operations_in_correct_order():
transaction = Transaction(
[Package("a", "1.0.0"), Package("b", "2.0.0"), Package("c", "3.0.0")],
[
(Package("a", "1.0.0"), 1),
(Package("b", "2.1.0"), 2),
(Package("d", "4.0.0"), 0),
],
)
check_operations(
transaction.calculate_operations(),
[
{"job": "install", "package": Package("b", "2.1.0")},
{"job": "install", "package": Package("a", "1.0.0")},
{"job": "install", "package": Package("d", "4.0.0")},
],
)
def test_it_should_calculate_operations_for_installed_packages():
transaction = Transaction(
[Package("a", "1.0.0"), Package("b", "2.0.0"), Package("c", "3.0.0")],
[
(Package("a", "1.0.0"), 1),
(Package("b", "2.1.0"), 2),
(Package("d", "4.0.0"), 0),
],
installed_packages=[
Package("a", "1.0.0"),
Package("b", "2.0.0"),
Package("c", "3.0.0"),
Package("e", "5.0.0"),
],
)
check_operations(
transaction.calculate_operations(),
[
{"job": "remove", "package": Package("c", "3.0.0")},
{
"job": "update",
"from": Package("b", "2.0.0"),
"to": Package("b", "2.1.0"),
},
{"job": "install", "package": Package("a", "1.0.0"), "skipped": True},
{"job": "install", "package": Package("d", "4.0.0")},
],
)
def test_it_should_remove_installed_packages_if_required():
transaction = Transaction(
[Package("a", "1.0.0"), Package("b", "2.0.0"), Package("c", "3.0.0")],
[
(Package("a", "1.0.0"), 1),
(Package("b", "2.1.0"), 2),
(Package("d", "4.0.0"), 0),
],
installed_packages=[
Package("a", "1.0.0"),
Package("b", "2.0.0"),
Package("c", "3.0.0"),
Package("e", "5.0.0"),
],
)
check_operations(
transaction.calculate_operations(synchronize=True),
[
{"job": "remove", "package": Package("c", "3.0.0")},
{"job": "remove", "package": Package("e", "5.0.0")},
{
"job": "update",
"from": Package("b", "2.0.0"),
"to": Package("b", "2.1.0"),
},
{"job": "install", "package": Package("a", "1.0.0"), "skipped": True},
{"job": "install", "package": Package("d", "4.0.0")},
],
)
def test_it_should_update_installed_packages_if_sources_are_different():
transaction = Transaction(
[Package("a", "1.0.0")],
[
(
Package(
"a",
"1.0.0",
source_url="https://github.com/demo/demo.git",
source_type="git",
source_reference="main",
source_resolved_reference="123456",
),
1,
)
],
installed_packages=[Package("a", "1.0.0")],
)
check_operations(
transaction.calculate_operations(synchronize=True),
[
{
"job": "update",
"from": Package("a", "1.0.0"),
"to": Package(
"a",
"1.0.0",
source_url="https://github.com/demo/demo.git",
source_type="git",
source_reference="main",
source_resolved_reference="123456",
),
}
],
)
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