Skip to content

Commit

Permalink
provider: ensure ony activated extras are used
Browse files Browse the repository at this point in the history
Resolves: #3022
  • Loading branch information
abn authored and finswimmer committed Oct 5, 2020
1 parent 417ce64 commit 88e0ebb
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 7 deletions.
14 changes: 7 additions & 7 deletions poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def complete_package(
self._pool.package(
package.name,
package.version.text,
extras=package.dependency.extras,
extras=list(package.dependency.extras),
repository=package.dependency.source_name,
),
)
Expand Down Expand Up @@ -478,12 +478,12 @@ def complete_package(
if self._env and not dep.marker.validate(self._env.marker_env):
continue

if (
dep.is_optional()
and dep.name not in optional_dependencies
and not package.is_root()
):
continue
if not package.is_root():
if (dep.is_optional() and dep.name not in optional_dependencies) or (
dep.in_extras
and not set(dep.in_extras).intersection(package.dependency.extras)
):
continue

_dependencies.append(dep)

Expand Down
157 changes: 157 additions & 0 deletions tests/puzzle/test_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,163 @@ def test_solver_returns_extras_if_requested(solver, repo, package):
assert ops[0].package.marker.is_any()


@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)])
def test_solver_returns_extras_only_requested(solver, repo, package, enabled_extra):
extras = [enabled_extra] if enabled_extra is not None else []

package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(
Factory.create_dependency("B", {"version": "*", "extras": extras})
)

package_a = get_package("A", "1.0")
package_b = get_package("B", "1.0")
package_c10 = get_package("C", "1.0")
package_c20 = get_package("C", "2.0")

dep10 = get_dependency("C", "1.0", optional=True)
dep10._in_extras.append("one")
dep10.marker = parse_marker("extra == 'one'")

dep20 = get_dependency("C", "2.0", optional=True)
dep20._in_extras.append("two")
dep20.marker = parse_marker("extra == 'two'")

package_b.extras = {"one": [dep10], "two": [dep20]}

package_b.requires.append(dep10)
package_b.requires.append(dep20)

repo.add_package(package_a)
repo.add_package(package_b)
repo.add_package(package_c10)
repo.add_package(package_c20)

ops = solver.solve()

expected = [
{"job": "install", "package": package_a},
{"job": "install", "package": package_b},
]

if enabled_extra is not None:
expected.insert(
0,
{
"job": "install",
"package": package_c10 if enabled_extra == "one" else package_c20,
},
)

check_solver_result(
ops, expected,
)

assert ops[-1].package.marker.is_any()
assert ops[0].package.marker.is_any()


@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)])
def test_solver_returns_extras_when_multiple_extras_use_same_dependency(
solver, repo, package, enabled_extra
):
package.add_dependency(Factory.create_dependency("A", "*"))

package_a = get_package("A", "1.0")
package_b = get_package("B", "1.0")
package_c = get_package("C", "1.0")

dep = get_dependency("C", "*", optional=True)
dep._in_extras.append("one")
dep._in_extras.append("two")

package_b.extras = {"one": [dep], "two": [dep]}

package_b.requires.append(dep)

extras = [enabled_extra] if enabled_extra is not None else []
package_a.add_dependency(
Factory.create_dependency("B", {"version": "*", "extras": extras})
)

repo.add_package(package_a)
repo.add_package(package_b)
repo.add_package(package_c)

ops = solver.solve()

expected = [
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
]

if enabled_extra is not None:
expected.insert(0, {"job": "install", "package": package_c})

check_solver_result(
ops, expected,
)

assert ops[-1].package.marker.is_any()
assert ops[0].package.marker.is_any()


@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)])
def test_solver_returns_extras_only_requested_nested(
solver, repo, package, enabled_extra
):
package.add_dependency(Factory.create_dependency("A", "*"))

package_a = get_package("A", "1.0")
package_b = get_package("B", "1.0")
package_c10 = get_package("C", "1.0")
package_c20 = get_package("C", "2.0")

dep10 = get_dependency("C", "1.0", optional=True)
dep10._in_extras.append("one")
dep10.marker = parse_marker("extra == 'one'")

dep20 = get_dependency("C", "2.0", optional=True)
dep20._in_extras.append("two")
dep20.marker = parse_marker("extra == 'two'")

package_b.extras = {"one": [dep10], "two": [dep20]}

package_b.requires.append(dep10)
package_b.requires.append(dep20)

extras = [enabled_extra] if enabled_extra is not None else []
package_a.add_dependency(
Factory.create_dependency("B", {"version": "*", "extras": extras})
)

repo.add_package(package_a)
repo.add_package(package_b)
repo.add_package(package_c10)
repo.add_package(package_c20)

ops = solver.solve()

expected = [
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
]

if enabled_extra is not None:
expected.insert(
0,
{
"job": "install",
"package": package_c10 if enabled_extra == "one" else package_c20,
},
)

check_solver_result(ops, expected)

assert ops[-1].package.marker.is_any()
assert ops[0].package.marker.is_any()


def test_solver_returns_prereleases_if_requested(solver, repo, package):
package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*"))
Expand Down

0 comments on commit 88e0ebb

Please sign in to comment.