Skip to content

Commit

Permalink
Improve constraint union (python-poetry#283)
Browse files Browse the repository at this point in the history
* Refactoring in preparation to increase coverage by adding additional tests

* Increase test coverage for constraint intersection

* Improve constraint union
  • Loading branch information
radoering authored and DavidVujic committed Mar 26, 2022
1 parent 94f8afa commit d6baff3
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 41 deletions.
15 changes: 14 additions & 1 deletion src/poetry/core/packages/constraints/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Any
from typing import Union

from poetry.core.packages.constraints import AnyConstraint
from poetry.core.packages.constraints.base_constraint import BaseConstraint
from poetry.core.packages.constraints.empty_constraint import EmptyConstraint

Expand Down Expand Up @@ -106,7 +107,19 @@ def union(self, other: "BaseConstraint") -> "BaseConstraint":
UnionConstraint,
)

return UnionConstraint(self, other)
if other == self:
return self

if self.operator == "!=" and other.operator == "==" and self.allows(other):
return self

if other.operator == "!=" and self.operator == "==" and other.allows(self):
return other

if other.operator == "==" and self.operator == "==":
return UnionConstraint(self, other)

return AnyConstraint()

return other.union(self)

Expand Down
147 changes: 107 additions & 40 deletions tests/packages/constraints/test_constraint.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from typing import TYPE_CHECKING

import pytest

from poetry.core.packages.constraints import AnyConstraint
from poetry.core.packages.constraints.constraint import Constraint
from poetry.core.packages.constraints.empty_constraint import EmptyConstraint
from poetry.core.packages.constraints.multi_constraint import MultiConstraint
from poetry.core.packages.constraints.union_constraint import UnionConstraint


if TYPE_CHECKING:
from poetry.core.packages.constraints import BaseConstraint


def test_allows():
c = Constraint("win32")

Expand Down Expand Up @@ -41,46 +50,104 @@ def test_allows_all():
assert not c.allows_all(UnionConstraint(Constraint("win32"), Constraint("linux")))


def test_intersect():
c = Constraint("win32")

intersection = c.intersect(Constraint("linux"))
assert intersection == EmptyConstraint()

intersection = c.intersect(
UnionConstraint(Constraint("win32"), Constraint("linux"))
)
assert intersection == Constraint("win32")

intersection = c.intersect(
UnionConstraint(Constraint("linux"), Constraint("linux2"))
)
assert intersection == EmptyConstraint()

intersection = c.intersect(Constraint("linux", "!="))
assert intersection == c

c = Constraint("win32", "!=")

intersection = c.intersect(Constraint("linux", "!="))
assert intersection == MultiConstraint(
Constraint("win32", "!="), Constraint("linux", "!=")
)


def test_union():
c = Constraint("win32")

union = c.union(Constraint("linux"))
assert union == UnionConstraint(Constraint("win32"), Constraint("linux"))

union = c.union(UnionConstraint(Constraint("win32"), Constraint("linux")))
assert union == UnionConstraint(Constraint("win32"), Constraint("linux"))

union = c.union(UnionConstraint(Constraint("linux"), Constraint("linux2")))
assert union == UnionConstraint(
Constraint("win32"), Constraint("linux"), Constraint("linux2")
)
@pytest.mark.parametrize(
("constraint1", "constraint2", "expected"),
[
(
Constraint("win32"),
Constraint("win32"),
Constraint("win32"),
),
(
Constraint("win32"),
Constraint("linux"),
EmptyConstraint(),
),
(
Constraint("win32"),
UnionConstraint(Constraint("win32"), Constraint("linux")),
Constraint("win32"),
),
(
Constraint("win32"),
UnionConstraint(Constraint("linux"), Constraint("linux2")),
EmptyConstraint(),
),
(
Constraint("win32"),
Constraint("linux", "!="),
Constraint("win32"),
),
(
Constraint("win32", "!="),
Constraint("linux"),
Constraint("linux"),
),
(
Constraint("win32", "!="),
Constraint("linux", "!="),
MultiConstraint(Constraint("win32", "!="), Constraint("linux", "!=")),
),
],
)
def test_intersect(
constraint1: "BaseConstraint",
constraint2: "BaseConstraint",
expected: "BaseConstraint",
):
intersection = constraint1.intersect(constraint2)
assert intersection == expected


@pytest.mark.parametrize(
("constraint1", "constraint2", "expected"),
[
(
Constraint("win32"),
Constraint("win32"),
Constraint("win32"),
),
(
Constraint("win32"),
Constraint("linux"),
UnionConstraint(Constraint("win32"), Constraint("linux")),
),
(
Constraint("win32"),
UnionConstraint(Constraint("win32"), Constraint("linux")),
UnionConstraint(Constraint("win32"), Constraint("linux")),
),
(
Constraint("win32"),
UnionConstraint(Constraint("linux"), Constraint("linux2")),
UnionConstraint(
Constraint("win32"), Constraint("linux"), Constraint("linux2")
),
),
(
Constraint("win32"),
Constraint("linux", "!="),
Constraint("linux", "!="),
),
(
Constraint("win32", "!="),
Constraint("linux"),
Constraint("win32", "!="),
),
(
Constraint("win32", "!="),
Constraint("linux", "!="),
AnyConstraint(),
),
],
)
def test_union(
constraint1: "BaseConstraint",
constraint2: "BaseConstraint",
expected: "BaseConstraint",
):
union = constraint1.union(constraint2)
assert union == expected


def test_difference():
Expand Down

0 comments on commit d6baff3

Please sign in to comment.