Skip to content

Commit

Permalink
Support constraints file when resolving versions
Browse files Browse the repository at this point in the history
  • Loading branch information
honnix committed May 11, 2021
1 parent 9591e88 commit c94b737
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 15 deletions.
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

0 comments on commit c94b737

Please sign in to comment.