Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support constraints file when resolving versions #4005

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion poetry/console/commands/debug/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,14 @@ def handle(self) -> Optional[int]:

pool = self.poetry.pool

solver = Solver(package, pool, Repository(), Repository(), self._io)
solver = Solver(
package,
pool,
Repository(),
Repository(),
self._io,
with_constranit_dependencies=True,
)

ops = solver.solve()

Expand Down
2 changes: 2 additions & 0 deletions poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ def _do_refresh(self) -> int:
locked_repository,
locked_repository,
self._io,
with_constranit_dependencies=True,
)

ops = solver.solve(use_latest=[])
Expand Down Expand Up @@ -247,6 +248,7 @@ def _do_install(self, local_repo: Repository) -> int:
locked_repository,
self._io,
remove_untracked=self._remove_untracked,
with_constranit_dependencies=True,
)

ops = solver.solve(use_latest=self._whitelist)
Expand Down
9 changes: 7 additions & 2 deletions poetry/mixology/incompatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,13 @@ def _terse(self, term: Term, allow_every: bool = False) -> str:
if term.dependency.is_root:
return term.dependency.pretty_name

return "{} ({})".format(
term.dependency.pretty_name, term.dependency.pretty_constraint
pretty_constraint_category = term.dependency.pretty_constraint_category
if pretty_constraint_category != "":
pretty_constraint_category = " " + pretty_constraint_category
return "{} ({}){}".format(
term.dependency.pretty_name,
term.dependency.pretty_constraint,
pretty_constraint_category,
)

def _single_term_where(self, callable: callable) -> Optional[Term]:
Expand Down
14 changes: 12 additions & 2 deletions poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,18 @@ class Provider:
UNSAFE_PACKAGES = set()

def __init__(
self, package: Package, pool: Pool, io: Any, env: Optional[Env] = None
self,
package: Package,
pool: Pool,
io: Any,
env: Optional[Env] = None,
with_constranit_dependencies: bool = False,
) -> None:
self._package = package
self._pool = pool
self._io = io
self._env = env
self._with_constraint_dependencies = with_constranit_dependencies
self._python_constraint = package.python_constraint
self._search_for = {}
self._is_debugging = self._io.is_debug() or self._io.is_very_verbose()
Expand Down Expand Up @@ -366,7 +372,11 @@ def incompatibilities_for(
previous call to _incompatibilities_for().
"""
if package.is_root():
dependencies = package.all_requires
dependencies = package.all_requires + (
package.constraint_requires
if self._with_constraint_dependencies
else []
)
else:
dependencies = package.requires

Expand Down
13 changes: 12 additions & 1 deletion poetry/puzzle/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(
locked: Repository,
io: IO,
remove_untracked: bool = False,
with_constranit_dependencies: bool = False,
provider: Optional[Provider] = None,
):
self._package = package
Expand All @@ -57,7 +58,12 @@ def __init__(
self._io = io

if provider is None:
provider = Provider(self._package, self._pool, self._io)
provider = Provider(
self._package,
self._pool,
self._io,
with_constranit_dependencies=with_constranit_dependencies,
)

self._provider = provider
self._overrides = []
Expand Down Expand Up @@ -287,6 +293,11 @@ def _solve(self, use_latest: List[str] = None) -> Tuple[List[Package], List[int]
final_packages = []
depths = []
for package in packages:
# The packages may contain constraint dependencies that won't be reachable,
# and in that case we don't consider them to be resolved packages
if package not in results:
continue

if package.features:
for _package in packages:
if (
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ generate-setup-file = false
[tool.poetry.dependencies]
python = "^3.6"

poetry-core = { git = "https://github.com/python-poetry/poetry-core.git", branch = "master"}
poetry-core = { git = "https://github.com/honnix/poetry-core.git", branch = "constraints"}
cleo = "^1.0.0a1"
crashtest = "^0.3.0"
requests = "^2.18"
Expand Down
15 changes: 15 additions & 0 deletions tests/installation/fixtures/lock-no-update.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[[package]]
name = "A"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"

[metadata]
python-versions = "*"
lock-version = "1.1"
content-hash = "123456789"

[metadata.files]
"A" = []
120 changes: 120 additions & 0 deletions tests/installation/test_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from poetry.installation.executor import Executor as BaseExecutor
from poetry.installation.noop_installer import NoopInstaller
from poetry.packages import Locker as BaseLocker
from poetry.puzzle.exceptions import SolverProblemError
from poetry.repositories import Pool
from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository
Expand Down Expand Up @@ -209,6 +210,46 @@ def test_run_with_dependencies(installer, locker, repo, package):
assert locker.written_data == expected


def test_run_with_dependencies_and_constraint_dependencies(
installer, locker, repo, package
):
package_a = get_package("A", "1.0")
package_b = get_package("B", "1.1")
repo.add_package(package_a)
repo.add_package(package_b)

package.add_dependency(Factory.create_dependency("A", "~1.0"))
package.add_dependency(Factory.create_dependency("B", "^1.0"))
package.add_dependency(
Factory.create_dependency("A", "<2.0", category="constraint")
)

installer.run()
expected = fixture("with-dependencies")

assert locker.written_data == expected


def test_run_with_dependencies_and_conflicting_constraint_dependencies(
installer, locker, repo, package
):
package_a = get_package("A", "1.0")
package_b = get_package("B", "1.1")
repo.add_package(package_a)
repo.add_package(package_b)

package.add_dependency(Factory.create_dependency("A", "~1.0"))
package.add_dependency(Factory.create_dependency("B", "^1.0"))
package.add_dependency(
Factory.create_dependency("A", ">=2.0", category="constraint")
)

with pytest.raises(
SolverProblemError, match=r"A \(>=2.0\) \[constraint dependency\]"
):
installer.run()


def test_run_update_after_removing_dependencies(
installer, locker, repo, package, installed
):
Expand Down Expand Up @@ -2021,3 +2062,82 @@ def test_installer_should_use_the_locked_version_of_git_dependencies(
source_reference="master",
source_resolved_reference="123456",
)


def test_lock_no_update(installer, locker, repo, package):
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": "A",
"version": "1.0",
"category": "dev",
"optional": True,
"platform": "*",
"python-versions": "*",
"checksum": [],
}
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {"A": []},
},
}
)
package_a = get_package("A", "1.1")
repo.add_package(get_package("A", "1.0"))
repo.add_package(package_a)

package.add_dependency(Factory.create_dependency("A", "*"))

installer.lock(False)

installer.run()
expected = fixture("lock-no-update")

assert locker.written_data == expected


def test_lock_no_update_with_conflicting_constraint_dependencies(
installer, locker, repo, package
):
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": "A",
"version": "1.0",
"category": "dev",
"optional": True,
"platform": "*",
"python-versions": "*",
"checksum": [],
}
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {"A": []},
},
}
)
package_a = get_package("A", "1.1")
repo.add_package(get_package("A", "1.0"))
repo.add_package(package_a)

package.add_dependency(Factory.create_dependency("A", "^1.0"))
package.add_dependency(
Factory.create_dependency("A", "<1.0", category="constraint")
)

installer.lock(False)

with pytest.raises(
SolverProblemError, match=r"A \(<1.0\) \[constraint dependency\]"
):
installer.run()
Loading